Files
pagodera/components/notifications/NotificationDropdown.tsx
2025-11-11 03:08:36 -03:00

170 lines
5.3 KiB
TypeScript

"use client";
import {
Bell,
ExternalLink,
MessageSquare,
ShoppingCart,
TrendingUp,
} from "lucide-react";
import Link from "next/link";
import { useLocale } from "next-intl";
import { Button } from "@/components/ui/button";
// ScrollArea não disponível, usando div com overflow
import { Separator } from "@/components/ui/separator";
interface Notification {
notification_id: number;
notification_type: string;
title: string;
message: string;
is_read: boolean;
related_id: number | null;
created_at: string;
}
interface NotificationDropdownProps {
notifications: Notification[];
onMarkAsRead: (notificationId: number) => Promise<void>;
onViewAll?: () => void;
}
function formatTimeAgo(date: Date): string {
const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
if (seconds < 60) return "há alguns segundos";
const minutes = Math.floor(seconds / 60);
if (minutes < 60)
return `há ${minutes} ${minutes === 1 ? "minuto" : "minutos"}`;
const hours = Math.floor(minutes / 60);
if (hours < 24) return `há ${hours} ${hours === 1 ? "hora" : "horas"}`;
const days = Math.floor(hours / 24);
if (days < 30) return `há ${days} ${days === 1 ? "dia" : "dias"}`;
const months = Math.floor(days / 30);
if (months < 12) return `há ${months} ${months === 1 ? "mês" : "meses"}`;
const years = Math.floor(months / 12);
return `há ${years} ${years === 1 ? "ano" : "anos"}`;
}
function getNotificationIcon(type: string) {
switch (type) {
case "purchase":
case "sale":
return <ShoppingCart className="h-4 w-4" />;
case "bid":
return <TrendingUp className="h-4 w-4" />;
case "system":
return <Bell className="h-4 w-4" />;
default:
return <MessageSquare className="h-4 w-4" />;
}
}
function getNotificationColor(type: string) {
switch (type) {
case "purchase":
case "sale":
return "bg-green-500";
case "bid":
return "bg-blue-500";
case "system":
return "bg-yellow-500";
default:
return "bg-gray-500";
}
}
export function NotificationDropdown({
notifications,
onMarkAsRead,
onViewAll,
}: NotificationDropdownProps) {
const locale = useLocale();
const handleNotificationClick = async (notification: Notification) => {
if (!notification.is_read) {
await onMarkAsRead(notification.notification_id);
}
};
if (notifications.length === 0) {
return (
<div className="w-80 p-4 text-center text-sm text-muted-foreground">
Nenhuma notificação
</div>
);
}
return (
<div className="w-80 flex flex-col">
<div className="p-4 border-b">
<div className="flex items-center justify-between">
<h3 className="font-semibold text-sm">Notificações</h3>
{onViewAll && (
<Button
variant="ghost"
size="sm"
onClick={onViewAll}
className="h-auto p-0 text-xs"
>
Ver todas
</Button>
)}
</div>
</div>
<div className="h-[400px] overflow-y-auto">
<div className="p-2">
{notifications.map((notification, index) => (
<div key={notification.notification_id}>
<button
onClick={() => handleNotificationClick(notification)}
className={`w-full text-left p-3 rounded-lg hover:bg-muted transition-colors ${
!notification.is_read ? "bg-muted/50" : ""
}`}
>
<div className="flex items-start gap-3">
<div
className={`${getNotificationColor(
notification.notification_type,
)} rounded-full p-2 text-white flex-shrink-0`}
>
{getNotificationIcon(notification.notification_type)}
</div>
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-2">
<h4 className="font-medium text-sm">
{notification.title}
</h4>
{!notification.is_read && (
<div className="h-2 w-2 bg-primary rounded-full flex-shrink-0 mt-1" />
)}
</div>
<p className="text-xs text-muted-foreground mt-1 line-clamp-2">
{notification.message}
</p>
<p className="text-xs text-muted-foreground mt-1">
{formatTimeAgo(new Date(notification.created_at))}
</p>
{notification.related_id && (
<Link
href={`/${locale}/market`}
onClick={(e) => e.stopPropagation()}
className="text-xs text-primary hover:underline mt-1 inline-flex items-center gap-1"
>
Ver anúncio <ExternalLink className="h-3 w-3" />
</Link>
)}
</div>
</div>
</button>
{index < notifications.length - 1 && (
<Separator className="my-2" />
)}
</div>
))}
</div>
</div>
</div>
);
}