source: chapterx-frontend/src/components/notifications/NotificationDropdown.tsx@ 7fbb91c

main
Last change on this file since 7fbb91c was 73b69b2, checked in by kikisrbinoska <srbinoskakristina07@…>, 3 months ago

Fixed reading lists,comments and likes

  • Property mode set to 100644
File size: 3.9 KB
Line 
1import React from 'react'
2import { useNavigate } from 'react-router-dom'
3import { Heart, MessageCircle, Users, Bell, Settings, Check } from 'lucide-react'
4import { useNotificationStore } from '../../store/notificationStore'
5import { NotificationType } from '../../types'
6
7const typeIcon = (type: NotificationType) => {
8 const props = { size: 14 }
9 switch (type) {
10 case 'like': return <Heart {...props} className="text-rose-400" />
11 case 'comment': return <MessageCircle {...props} className="text-blue-400" />
12 case 'collaboration': return <Users {...props} className="text-violet-400" />
13 case 'follow': return <Bell {...props} className="text-amber-400" />
14 case 'system': return <Settings {...props} className="text-slate-400" />
15 default: return <Bell {...props} className="text-slate-400" />
16 }
17}
18
19const typeTitle = (type: NotificationType) => {
20 switch (type) {
21 case 'like': return 'New Like'
22 case 'comment': return 'New Comment'
23 case 'collaboration': return 'Collaboration'
24 case 'follow': return 'New Follower'
25 case 'system': return 'System'
26 default: return 'Notification'
27 }
28}
29
30function timeAgo(dateStr: string): string {
31 const diff = Date.now() - new Date(dateStr).getTime()
32 const mins = Math.floor(diff / 60000)
33 if (mins < 1) return 'just now'
34 if (mins < 60) return `${mins}m ago`
35 const hrs = Math.floor(mins / 60)
36 if (hrs < 24) return `${hrs}h ago`
37 return `${Math.floor(hrs / 24)}d ago`
38}
39
40interface Props {
41 onClose: () => void
42}
43
44export const NotificationDropdown: React.FC<Props> = ({ onClose }) => {
45 const navigate = useNavigate()
46 const { notifications, markAllRead, markRead } = useNotificationStore()
47 const recent = notifications.slice(0, 5)
48
49 return (
50 <div className="absolute right-0 top-full mt-2 w-80 bg-slate-900 border border-slate-700 rounded-2xl shadow-2xl z-50 overflow-hidden">
51 <div className="flex items-center justify-between px-4 py-3 border-b border-slate-700">
52 <span className="text-sm font-semibold text-white">Notifications</span>
53 <button
54 onClick={markAllRead}
55 className="text-xs text-indigo-400 hover:text-indigo-300 flex items-center gap-1 transition-colors"
56 >
57 <Check size={12} />
58 Mark all read
59 </button>
60 </div>
61 <div className="divide-y divide-slate-800">
62 {recent.length === 0 ? (
63 <div className="px-4 py-8 text-center text-slate-500 text-sm">
64 No notifications yet
65 </div>
66 ) : (
67 recent.map(n => (
68 <div
69 key={n.notification_id}
70 className={`flex gap-3 px-4 py-3 cursor-pointer transition-colors ${
71 !n.is_read ? 'bg-indigo-500/5 hover:bg-indigo-500/10' : 'hover:bg-slate-800'
72 }`}
73 onClick={() => {
74 markRead(n.notification_id)
75 if (n.link) { navigate(n.link); onClose() }
76 }}
77 >
78 <div className="mt-0.5 w-6 h-6 rounded-full bg-slate-800 flex items-center justify-center flex-shrink-0">
79 {typeIcon(n.type)}
80 </div>
81 <div className="flex-1 min-w-0">
82 <p className="text-xs font-medium text-white">{typeTitle(n.type)}</p>
83 <p className="text-xs text-slate-400 line-clamp-2">{n.message}</p>
84 <p className="text-xs text-slate-600 mt-0.5">{timeAgo(n.created_at)}</p>
85 </div>
86 {!n.is_read && (
87 <div className="w-2 h-2 rounded-full bg-indigo-400 flex-shrink-0 mt-1.5" />
88 )}
89 </div>
90 ))
91 )}
92 </div>
93 <div className="border-t border-slate-700 p-2">
94 <button
95 onClick={() => { navigate('/notifications'); onClose() }}
96 className="w-full text-center text-xs text-indigo-400 hover:text-indigo-300 py-1.5 rounded-lg hover:bg-slate-800 transition-colors"
97 >
98 View all notifications
99 </button>
100 </div>
101 </div>
102 )
103}
Note: See TracBrowser for help on using the repository browser.