| // src/components/dashboard/NotificationsPanel.tsx | |
| import { Link } from "react-router-dom"; | |
| import { Bell, Heart, MessageCircle, User, AtSign, Sparkles, ArrowRight, CheckCheck } from "lucide-react"; | |
| import type { Notification } from "@/pages/DashboardPage"; | |
| interface NotificationsPanelProps { | |
| notifications: Notification[]; | |
| unreadCount: number; | |
| onMarkRead: (id: number) => void; | |
| onMarkAllRead: () => void; | |
| } | |
| function getNotificationIcon(type: string) { | |
| switch (type) { | |
| case "like": return <Heart className="h-4 w-4 text-pink-500" />; | |
| case "comment": return <MessageCircle className="h-4 w-4 text-blue-500" />; | |
| case "follow": return <User className="h-4 w-4 text-green-500" />; | |
| case "mention": return <AtSign className="h-4 w-4 text-purple-500" />; | |
| default: return <Bell className="h-4 w-4 text-gray-500" />; | |
| } | |
| } | |
| export function NotificationsPanel({ notifications: rawNotifications, unreadCount, onMarkRead, onMarkAllRead }: NotificationsPanelProps) { | |
| const notifications = Array.isArray(rawNotifications) ? rawNotifications : []; | |
| return ( | |
| <div className="rounded-[2rem] border border-slate-200 bg-white p-5 shadow-sm dark:border-slate-700 dark:bg-slate-800"> | |
| <div className="mb-4 flex flex-wrap items-start justify-between gap-4"> | |
| <div> | |
| <div className="inline-flex items-center gap-2 rounded-full bg-blue-50 px-3 py-1 text-xs font-semibold text-blue-700 dark:bg-blue-950/40 dark:text-blue-300"> | |
| <Sparkles className="h-3.5 w-3.5" /> | |
| Live updates | |
| </div> | |
| <h2 className="mt-3 flex items-center gap-2 text-xl font-semibold text-slate-900 dark:text-white"> | |
| <Bell className="h-5 w-5 text-primary" /> Notifications | |
| {unreadCount > 0 && ( | |
| <span className="rounded-full bg-rose-500 px-2.5 py-0.5 text-xs text-white"> | |
| {unreadCount} | |
| </span> | |
| )} | |
| </h2> | |
| <p className="mt-1 text-sm text-slate-500 dark:text-slate-400"> | |
| Keep track of reactions, mentions, follows, and system updates in one place. | |
| </p> | |
| </div> | |
| {unreadCount > 0 && ( | |
| <button | |
| onClick={onMarkAllRead} | |
| className="inline-flex items-center gap-2 rounded-full border border-slate-300 px-3 py-1.5 text-xs font-medium text-slate-700 transition hover:border-sky-200 hover:text-sky-600 dark:border-slate-700 dark:text-slate-200" | |
| > | |
| <CheckCheck className="h-3.5 w-3.5" /> | |
| Mark all read | |
| </button> | |
| )} | |
| </div> | |
| <div className="space-y-2 max-h-[420px] overflow-y-auto pr-1"> | |
| {notifications.length === 0 ? ( | |
| <div className="rounded-[1.75rem] border border-dashed border-slate-200 bg-slate-50/80 p-6 text-center dark:border-slate-700 dark:bg-slate-900/60"> | |
| <Bell className="mx-auto h-10 w-10 text-slate-400" /> | |
| <p className="mt-2 text-sm font-medium text-slate-700 dark:text-slate-200">You’re all caught up</p> | |
| <p className="mt-1 text-xs text-slate-500 dark:text-slate-400"> | |
| New likes, comments, follows, and mentions will appear here as they come in. | |
| </p> | |
| <Link to="/notifications" className="mt-4 inline-flex items-center gap-2 rounded-full bg-primary px-4 py-2 text-xs font-medium text-white transition hover:bg-primary/90"> | |
| Open notifications <ArrowRight className="h-3.5 w-3.5" /> | |
| </Link> | |
| </div> | |
| ) : ( | |
| notifications.map((notification) => ( | |
| <Link | |
| key={notification.id} | |
| to={notification.link || "#"} | |
| onClick={() => onMarkRead(notification.id)} | |
| className={`block rounded-[1.5rem] border p-3 transition hover:-translate-y-0.5 ${ | |
| !notification.read | |
| ? "border-blue-100 bg-blue-50/70 dark:border-blue-900/40 dark:bg-blue-950/20" | |
| : "border-slate-200 bg-slate-50/70 dark:border-slate-700 dark:bg-slate-900/60" | |
| }`} | |
| > | |
| <div className="flex gap-3"> | |
| <div className="flex-shrink-0"> | |
| {getNotificationIcon(notification.type)} | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <p className="text-sm font-medium text-slate-900 dark:text-white">{notification.title}</p> | |
| <p className="mt-0.5 text-xs leading-5 text-slate-500 dark:text-slate-400">{notification.body}</p> | |
| <p className="mt-1 text-xs text-slate-400 dark:text-slate-500"> | |
| {new Date(notification.createdAt).toLocaleDateString()} | |
| </p> | |
| </div> | |
| </div> | |
| </Link> | |
| )) | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |
Xet Storage Details
- Size:
- 4.83 kB
- Xet hash:
- 91cddabc6e520a0d215c9446baba803495efe0bd1393a979959077ce1cc5ec1f
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.