/**
* NotificationItem Component
*
* Individual notification row with icon, message, and action
*/
'use client';
import { formatDistanceToNow } from 'date-fns';
import { useRouter } from 'next/navigation';
import Image from 'next/image';
import { MessageSquare, UserPlus, AtSign, MessageCircle, Heart, FileText, X } from 'lucide-react';
import { useNotificationsContext, type Notification } from '@/contexts/NotificationsContext';
import { cn } from '@/lib/utils';
interface NotificationItemProps {
notification: Notification;
onClose: () => void;
onDelete: (notificationId: string) => void;
}
const notificationIcons = {
new_message: MessageSquare,
new_follower: UserPlus,
mention: AtSign,
reply: MessageCircle,
like: Heart,
comment: MessageCircle,
system: FileText,
};
const notificationColors = {
new_message: 'text-blue-500',
new_follower: 'text-green-500',
mention: 'text-purple-500',
reply: 'text-orange-500',
like: 'text-red-500',
comment: 'text-yellow-500',
system: 'text-gray-500',
};
export function NotificationItem({ notification, onClose, onDelete }: NotificationItemProps) {
const router = useRouter();
const { markOneAsRead } = useNotificationsContext();
const Icon = notificationIcons[notification.type];
const iconColor = notificationColors[notification.type];
const timeAgo = formatDistanceToNow(new Date(notification.created_at), { addSuffix: true });
const isUnread = !notification.read_at;
const handleDismiss = (e: React.MouseEvent) => {
e.stopPropagation();
onDelete(notification.id);
};
const handleClick = () => {
// Mark as read
if (isUnread) {
markOneAsRead(notification.id);
}
// Navigate to related entity
if (notification.related_entity_type && notification.related_entity_id) {
switch (notification.related_entity_type) {
case 'message':
router.push('/messages');
break;
case 'user':
// Extract username from actor
if (notification.actor) {
router.push(`/users/${notification.actor.username}`);
}
break;
case 'post':
router.push(`/forum/posts/${notification.related_entity_id}`);
break;
case 'comment':
// Comments are part of posts, navigate to the post
router.push(`/forum/posts/${notification.related_entity_id}`);
break;
case 'bill':
router.push(`/bills/${notification.related_entity_id}`);
break;
case 'debate':
router.push(`/debates/${notification.related_entity_id}`);
break;
}
}
onClose();
};
return (
<button
onClick={handleClick}
className={cn(
'flex w-full items-start gap-3 p-4 text-left transition-colors hover:bg-gray-800',
isUnread && 'bg-blue-950/30'
)}
>
{/* Icon or Avatar */}
<div className="flex-shrink-0">
{notification.actor?.avatar_url ? (
<div className="relative h-10 w-10 rounded-full">
<Image
src={notification.actor.avatar_url}
alt={notification.actor.display_name}
fill
className="rounded-full object-cover"
/>
<div className={cn('absolute -bottom-1 -right-1 rounded-full bg-gray-900 p-1', iconColor)}>
<Icon className="h-3 w-3" />
</div>
</div>
) : (
<div className={cn('rounded-full bg-gray-800 p-2', iconColor)}>
<Icon className="h-5 w-5" />
</div>
)}
</div>
{/* Content */}
<div className="flex-1 overflow-hidden">
<p className={cn('text-sm text-gray-100', isUnread && 'font-semibold text-white')}>
{notification.message}
</p>
<p className="mt-1 text-xs text-gray-400">{timeAgo}</p>
</div>
{/* Unread indicator and dismiss button */}
<div className="flex flex-col items-center gap-2 flex-shrink-0">
{isUnread && (
<div className="h-2 w-2 rounded-full bg-blue-500" />
)}
<button
onClick={handleDismiss}
className="p-1 rounded-full text-gray-500 hover:text-white hover:bg-gray-700 transition-colors"
title="Dismiss notification"
>
<X className="h-4 w-4" />
</button>
</div>
</button>
);
}