1-
21import React from 'react' ;
32import { useNavigate } from 'react-router-dom' ;
43import {
@@ -24,43 +23,61 @@ import {
2423import { Button } from '@/components/ui/button' ;
2524import { Badge } from '@/components/ui/badge' ;
2625import { formatDistanceToNow } from 'date-fns' ;
26+ import { UserProfile } from '../utils/firebase' ;
27+ import type { Timestamp } from 'firebase/firestore' ;
28+
29+ interface Notification {
30+ id : string ;
31+ type : 'achievement' | 'emergency' | 'friendRequest' | 'streakMilestone' | string ;
32+ message : string ;
33+ timestamp : Timestamp ;
34+ read : boolean ;
35+ senderInfo ?: {
36+ id : string ;
37+ name : string ;
38+ } ;
39+ }
2740
2841const NotificationsDropdown : React . FC = ( ) => {
29- const { notifications, unreadNotifications, refreshUserData } = useAuth ( ) ;
42+ const { notifications, unreadNotifications, refreshUserData, friends } = useAuth ( ) ;
3043 const navigate = useNavigate ( ) ;
44+ const [ localNotifications , setLocalNotifications ] = React . useState < Notification [ ] > ( notifications ) ;
45+
46+ React . useEffect ( ( ) => {
47+ setLocalNotifications ( notifications ) ;
48+ } , [ notifications ] ) ;
3149
32- const handleAcceptFriendRequest = async ( senderId : string ) => {
50+ const handleAcceptFriendRequest = async ( senderId : string , notificationId : string ) => {
3351 const result = await acceptFriendRequest ( auth . currentUser ?. uid || '' , senderId ) ;
3452 if ( result ) {
3553 toast . success ( 'Friend request accepted' ) ;
54+ setLocalNotifications ( ( prev ) => prev . filter ( n => n . id !== notificationId ) ) ;
3655 refreshUserData ( ) ;
3756 } else {
3857 toast . error ( 'Failed to accept friend request' ) ;
3958 }
4059 } ;
4160
42- const handleDeclineFriendRequest = async ( senderId : string ) => {
61+ const handleDeclineFriendRequest = async ( senderId : string , notificationId : string ) => {
4362 const result = await declineFriendRequest ( auth . currentUser ?. uid || '' , senderId ) ;
4463 if ( result ) {
4564 toast . success ( 'Friend request declined' ) ;
65+ setLocalNotifications ( ( prev ) => prev . filter ( n => n . id !== notificationId ) ) ;
4666 refreshUserData ( ) ;
4767 } else {
4868 toast . error ( 'Failed to decline friend request' ) ;
4969 }
5070 } ;
5171
52- const handleNotificationClick = async ( notification : any ) => {
72+ const handleNotificationClick = async ( notification : Notification ) => {
5373 if ( ! notification . read ) {
5474 await markNotificationAsRead ( auth . currentUser ?. uid || '' , notification . id ) ;
5575 }
56-
57- // Navigate based on notification type
5876 if ( notification . type === 'achievement' ) {
5977 navigate ( '/achievements' ) ;
6078 } else if ( notification . type === 'emergency' ) {
6179 navigate ( `/profile?friend=${ notification . senderInfo ?. id } ` ) ;
6280 }
63-
6481 refreshUserData ( ) ;
6582 } ;
6683
@@ -96,10 +113,32 @@ const NotificationsDropdown: React.FC = () => {
96113 < DropdownMenuLabel > Notifications</ DropdownMenuLabel >
97114 < DropdownMenuSeparator />
98115 < div className = "max-h-[400px] overflow-y-auto" >
99- { notifications && notifications . length > 0 ? (
116+ { localNotifications && localNotifications . length > 0 ? (
100117 < DropdownMenuGroup >
101- { notifications
102- . sort ( ( a , b ) => b . timestamp . toDate ( ) - a . timestamp . toDate ( ) )
118+ { localNotifications
119+ . sort ( ( a , b ) => {
120+ let aTime : number ;
121+ let bTime : number ;
122+ if ( typeof a . timestamp . toMillis === 'function' ) {
123+ aTime = a . timestamp . toMillis ( ) ;
124+ } else if ( typeof a . timestamp === 'number' ) {
125+ aTime = a . timestamp ;
126+ } else if ( typeof a . timestamp === 'object' && 'seconds' in a . timestamp ) {
127+ aTime = ( a . timestamp as { seconds : number } ) . seconds * 1000 ;
128+ } else {
129+ aTime = Date . now ( ) ; // fallback
130+ }
131+ if ( typeof b . timestamp . toMillis === 'function' ) {
132+ bTime = b . timestamp . toMillis ( ) ;
133+ } else if ( typeof b . timestamp === 'number' ) {
134+ bTime = b . timestamp ;
135+ } else if ( typeof b . timestamp === 'object' && 'seconds' in b . timestamp ) {
136+ bTime = ( b . timestamp as { seconds : number } ) . seconds * 1000 ;
137+ } else {
138+ bTime = Date . now ( ) ; // fallback
139+ }
140+ return bTime - aTime ;
141+ } )
103142 . map ( ( notification , index ) => (
104143 < React . Fragment key = { notification . id || index } >
105144 { notification . type === 'friendRequest' && notification . senderInfo ? (
@@ -119,15 +158,15 @@ const NotificationsDropdown: React.FC = () => {
119158 < Button
120159 size = "sm"
121160 variant = "outline"
122- onClick = { ( ) => handleAcceptFriendRequest ( notification . senderInfo . id ) }
161+ onClick = { ( ) => handleAcceptFriendRequest ( notification . senderInfo ! . id , notification . id ) }
123162 className = "h-7 w-7 p-0"
124163 >
125164 < Check className = "h-4 w-4" />
126165 </ Button >
127166 < Button
128167 size = "sm"
129168 variant = "outline"
130- onClick = { ( ) => handleDeclineFriendRequest ( notification . senderInfo . id ) }
169+ onClick = { ( ) => handleDeclineFriendRequest ( notification . senderInfo ! . id , notification . id ) }
131170 className = "h-7 w-7 p-0"
132171 >
133172 < X className = "h-4 w-4" />
0 commit comments