@@ -3,9 +3,13 @@ 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 { Notification as BskyNotification } from '@atproto/api/dist/client/types/app/bsky/notification/listNotifications' ;
7
6
import { useState } from 'react' ;
8
7
import { cn } from '../lib/utils' ;
8
+ import { BSkyNotification } from '../lib/bluesky/types/BSkyNotification' ;
9
+ import { Link } from '../components/ui/Link' ;
10
+ import { useBlueskyStore } from '../lib/bluesky/store' ;
11
+ import { Image } from '../components/ui/Image' ;
12
+ import { Handle } from '../components/ui/Handle' ;
9
13
10
14
export const Route = createFileRoute ( '/notifications' ) ( {
11
15
component : RouteComponent ,
@@ -62,7 +66,7 @@ function RouteComponent() {
62
66
</ Ariakit . TabList >
63
67
< div className = "p-2" >
64
68
< Ariakit . TabPanel tabId = "grouped" >
65
- < GroupedNotifications notifications = { notifications } />
69
+ { notifications && < GroupedNotifications notifications = { notifications } /> }
66
70
</ Ariakit . TabPanel >
67
71
< Ariakit . TabPanel tabId = "all" >
68
72
{ notifications ?. map ( ( notification ) => < Notification key = { notification . uri } notification = { notification } /> ) }
@@ -76,46 +80,63 @@ function RouteComponent() {
76
80
) ;
77
81
}
78
82
79
- // group notifications by uri and group up to 3 notifications per group
80
- function GroupedNotifications ( { notifications } : { notifications : BskyNotification [ ] } ) {
83
+ // group notifications by uri
84
+ function GroupedNotifications ( { notifications } : { notifications : BSkyNotification [ ] } ) {
81
85
const { t } = useTranslation ( 'notifications' ) ;
82
86
const grouped = notifications . reduce (
83
87
( acc , notification ) => {
84
- if ( notification . reason === 'follow' ) {
85
- return acc ;
88
+ if ( notification . reason === 'like' ) {
89
+ if ( acc [ notification . record . subject . uri ] ) {
90
+ acc [ notification . record . subject . uri ] ?. push ( notification ) ;
91
+ } else {
92
+ acc [ notification . record . subject . uri ] = [ notification ] ;
93
+ }
86
94
}
87
-
88
- if ( ! acc [ uri ] ) {
89
- acc [ uri ] = [ ] ;
90
- }
91
-
92
- acc [ uri ] . push ( notification . record ) ;
93
-
94
95
return acc ;
95
96
} ,
96
- { } as Record < string , BskyNotification [ ] > ,
97
+ { } as Record < string , BSkyNotification [ ] > ,
97
98
) ;
98
99
99
100
return (
100
101
< div >
101
102
{ Object . entries ( grouped ) . map ( ( [ uri , notifications ] ) => (
102
103
< div key = { uri } className = "p-2 bg-neutral-800 rounded-lg mb-2" >
103
104
< div className = "text-sm text-neutral-400" > { t ( 'groupedNotifications' ) } </ div >
104
- { notifications . map ( ( notification ) => (
105
- < Notification key = { notification . uri } notification = { notification } />
106
- ) ) }
105
+ < GroupNotification key = { notifications [ 0 ] ?. uri } notifications = { notifications } />
107
106
</ div >
108
107
) ) }
109
108
</ div >
110
109
) ;
111
110
}
112
111
113
- function Notification ( { notification } : { notification : BskyNotification } ) {
112
+ function GroupNotification ( { notifications } : { notifications : BSkyNotification [ ] } ) {
113
+ const notification = notifications [ 0 ] ;
114
+ if ( ! notification ) return null ;
115
+
116
+ switch ( notification ?. reason ) {
117
+ case 'follow' :
118
+ return < FollowNotification notification = { notification } /> ;
119
+ case 'like' :
120
+ return < LikeNotification notifications = { notifications } /> ;
121
+ case 'repost' :
122
+ return < RepostNotification notification = { notification } /> ;
123
+ case 'reply' :
124
+ return < ReplyNotification notification = { notification } /> ;
125
+ case 'mention' :
126
+ return < MentionNotification notification = { notification } /> ;
127
+ case 'quote' :
128
+ return < QuoteNotification notification = { notification } /> ;
129
+ case 'starterpack-joined' :
130
+ return < StarterpackJoinedNotification notification = { notification } /> ;
131
+ }
132
+ }
133
+
134
+ function Notification ( { notification } : { notification : BSkyNotification } ) {
114
135
switch ( notification . reason ) {
115
136
case 'follow' :
116
137
return < FollowNotification notification = { notification } /> ;
117
138
case 'like' :
118
- return < LikeNotification notification = { notification } /> ;
139
+ return < LikeNotification notifications = { [ notification ] } /> ;
119
140
case 'repost' :
120
141
return < RepostNotification notification = { notification } /> ;
121
142
case 'reply' :
@@ -136,7 +157,7 @@ function Notification({ notification }: { notification: BskyNotification }) {
136
157
) ;
137
158
}
138
159
139
- function FollowNotification ( { notification } : { notification : BskyNotification } ) {
160
+ function FollowNotification ( { notification } : { notification : BSkyNotification } ) {
140
161
const { t } = useTranslation ( 'notifications' ) ;
141
162
return (
142
163
< div >
@@ -145,16 +166,40 @@ function FollowNotification({ notification }: { notification: BskyNotification }
145
166
) ;
146
167
}
147
168
148
- function LikeNotification ( { notification } : { notification : BskyNotification } ) {
169
+ function LikeNotification ( { notifications } : { notifications : BSkyNotification [ ] } ) {
149
170
const { t } = useTranslation ( 'notifications' ) ;
171
+ const { session } = useBlueskyStore ( ) ;
172
+ const notification = notifications [ 0 ] ;
173
+ if ( ! notification || ! session ) return null ;
174
+ const othersCount = notifications . length - 1 ;
175
+
150
176
return (
151
177
< div >
152
- { notification . author . displayName } { t ( 'likedYourPost' ) }
178
+ < div className = "flex flex-row gap-1 overflow-hidden max-h-16" >
179
+ { notifications . map ( ( notification ) => (
180
+ < Image type = "avatar" classNames = { { wrapper : 'aspect-square size-8' } } src = { notification . author . avatar } />
181
+ ) ) }
182
+ </ div >
183
+ < div >
184
+ < Handle handle = { notification . author . handle } />
185
+ { notifications . map ( ( notification ) => notification . author . displayName ) . slice ( - 1 ) }
186
+ { notifications . length - 1 >= 1 &&
187
+ `${ t ( 'and' ) } ${ othersCount } ${ othersCount >= 1 && ( othersCount === 1 ? t ( 'other' ) : t ( 'others' ) ) } ` } { ' ' }
188
+ < Link
189
+ to = "/profile/$handle/post/$postId"
190
+ params = { {
191
+ handle : session . did ! ,
192
+ postId : notification . record . subject . uri . split ( '/' ) [ notification . record . subject . uri . split ( '/' ) . length - 1 ] ! ,
193
+ } }
194
+ >
195
+ { t ( 'likedYourPost' ) }
196
+ </ Link >
197
+ </ div >
153
198
</ div >
154
199
) ;
155
200
}
156
201
157
- function RepostNotification ( { notification } : { notification : BskyNotification } ) {
202
+ function RepostNotification ( { notification } : { notification : BSkyNotification } ) {
158
203
const { t } = useTranslation ( 'notifications' ) ;
159
204
return (
160
205
< div >
@@ -163,7 +208,7 @@ function RepostNotification({ notification }: { notification: BskyNotification }
163
208
) ;
164
209
}
165
210
166
- function ReplyNotification ( { notification } : { notification : BskyNotification } ) {
211
+ function ReplyNotification ( { notification } : { notification : BSkyNotification } ) {
167
212
const { t } = useTranslation ( 'notifications' ) ;
168
213
return (
169
214
< div >
@@ -172,7 +217,7 @@ function ReplyNotification({ notification }: { notification: BskyNotification })
172
217
) ;
173
218
}
174
219
175
- function MentionNotification ( { notification } : { notification : BskyNotification } ) {
220
+ function MentionNotification ( { notification } : { notification : BSkyNotification } ) {
176
221
const { t } = useTranslation ( 'notifications' ) ;
177
222
return (
178
223
< div >
@@ -181,7 +226,7 @@ function MentionNotification({ notification }: { notification: BskyNotification
181
226
) ;
182
227
}
183
228
184
- function QuoteNotification ( { notification } : { notification : BskyNotification } ) {
229
+ function QuoteNotification ( { notification } : { notification : BSkyNotification } ) {
185
230
const { t } = useTranslation ( 'notifications' ) ;
186
231
return (
187
232
< div >
@@ -190,7 +235,7 @@ function QuoteNotification({ notification }: { notification: BskyNotification })
190
235
) ;
191
236
}
192
237
193
- function StarterpackJoinedNotification ( { notification } : { notification : BskyNotification } ) {
238
+ function StarterpackJoinedNotification ( { notification } : { notification : BSkyNotification } ) {
194
239
const { t } = useTranslation ( 'notifications' ) ;
195
240
return (
196
241
< div >
0 commit comments