@@ -3,21 +3,24 @@ import { createFileRoute } from '@tanstack/react-router';
3
3
import { useTranslation } from 'react-i18next' ;
4
4
import { useNotifications } from '../lib/bluesky/hooks/useNotifications' ;
5
5
import { Debug } from '../components/ui/Debug' ;
6
- import { useState } from 'react' ;
6
+ import { forwardRef , useState } from 'react' ;
7
7
import { cn } from '../lib/utils' ;
8
8
import { BSkyNotification } from '../lib/bluesky/types/BSkyNotification' ;
9
9
import { Link } from '../components/ui/Link' ;
10
10
import { useBlueskyStore } from '../lib/bluesky/store' ;
11
11
import { Image } from '../components/ui/Image' ;
12
12
import { Handle } from '../components/ui/Handle' ;
13
+ import { Virtuoso } from 'react-virtuoso' ;
14
+ import { Button } from '../components/ui/Button' ;
13
15
14
16
export const Route = createFileRoute ( '/notifications' ) ( {
15
17
component : RouteComponent ,
16
18
} ) ;
17
19
18
20
function RouteComponent ( ) {
19
21
const { t } = useTranslation ( [ 'app' , 'notifications' ] ) ;
20
- const { data : notifications , isLoading } = useNotifications ( ) ;
22
+ const { data, isLoading } = useNotifications ( ) ;
23
+ const notifications = data ?. pages . flatMap ( ( page ) => page . notifications ) ;
21
24
const mentions = notifications ?. filter (
22
25
( notification ) =>
23
26
notification . reason === 'mention' || notification . reason === 'reply' || notification . reason === 'quote' ,
@@ -65,9 +68,7 @@ function RouteComponent() {
65
68
</ Ariakit . Tab >
66
69
</ Ariakit . TabList >
67
70
< div className = "p-2" >
68
- < Ariakit . TabPanel tabId = "grouped" >
69
- { notifications && < GroupedNotifications notifications = { notifications } /> }
70
- </ Ariakit . TabPanel >
71
+ < Ariakit . TabPanel tabId = "grouped" > { notifications && < GroupedNotifications /> } </ Ariakit . TabPanel >
71
72
< Ariakit . TabPanel tabId = "all" >
72
73
{ notifications ?. map ( ( notification ) => < Notification key = { notification . uri } notification = { notification } /> ) }
73
74
</ Ariakit . TabPanel >
@@ -81,8 +82,11 @@ function RouteComponent() {
81
82
}
82
83
83
84
// group notifications by uri
84
- function GroupedNotifications ( { notifications } : { notifications : BSkyNotification [ ] } ) {
85
+ function GroupedNotifications ( ) {
85
86
const { t } = useTranslation ( 'notifications' ) ;
87
+ const { data, isLoading, fetchNextPage, isFetching } = useNotifications ( ) ;
88
+ const notifications = data ?. pages . flatMap ( ( page ) => page . notifications ) ;
89
+ if ( ! notifications ) return null ;
86
90
const grouped = notifications . reduce (
87
91
( acc , notification ) => {
88
92
if ( notification . reason === 'like' ) {
@@ -97,15 +101,43 @@ function GroupedNotifications({ notifications }: { notifications: BSkyNotificati
97
101
{ } as Record < string , BSkyNotification [ ] > ,
98
102
) ;
99
103
104
+ if ( isLoading ) return < div > { t ( 'loading' ) } </ div > ;
105
+
106
+ const list = Object . values ( grouped ) ;
107
+
100
108
return (
101
- < div >
102
- { Object . entries ( grouped ) . map ( ( [ uri , notifications ] ) => (
103
- < div key = { uri } className = "p-2 bg-neutral-800 rounded-lg mb-2" >
104
- < div className = "text-sm text-neutral-400" > { t ( 'groupedNotifications' ) } </ div >
105
- < GroupNotification key = { notifications [ 0 ] ?. uri } notifications = { notifications } />
106
- </ div >
107
- ) ) }
108
- </ div >
109
+ < Virtuoso
110
+ useWindowScroll
111
+ totalCount = { list . length }
112
+ endReached = { ( ) => fetchNextPage ( ) }
113
+ components = { {
114
+ List : forwardRef ( ( props , ref ) => < div ref = { ref } { ...props } className = "flex flex-col gap-2" /> ) ,
115
+ Footer : ( ) => {
116
+ return isFetching ? (
117
+ < div className = "p-2 text-center" > { t ( 'loading' ) } </ div >
118
+ ) : (
119
+ < div className = "p-2 text-center" >
120
+ < Button
121
+ onClick = { ( ) => {
122
+ fetchNextPage ( ) ;
123
+ } }
124
+ >
125
+ load more
126
+ </ Button >
127
+ </ div >
128
+ ) ;
129
+ } ,
130
+ } }
131
+ itemContent = { ( index : number ) => {
132
+ if ( ! list [ index ] ) return null ;
133
+ return (
134
+ < div key = { list [ index ] [ 0 ] ?. uri } className = "p-2 bg-neutral-800 rounded-lg mb-2" >
135
+ < div className = "text-sm text-neutral-400" > { t ( 'groupedNotifications' ) } </ div >
136
+ < GroupNotification key = { list [ index ] [ 0 ] ?. uri } notifications = { list [ index ] } />
137
+ </ div >
138
+ ) ;
139
+ } }
140
+ />
109
141
) ;
110
142
}
111
143
0 commit comments