mediahub-fe/components/partials/header/notifications.tsx

168 lines
5.8 KiB
TypeScript

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Link } from "@/i18n/routing";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { cn } from "@/lib/utils";
import shortImage from "@/public/images/all-img/short-image-2.png";
import { Icon } from "@/components/ui/icon";
import { useEffect, useState } from "react";
import { getNotifications } from "@/service/notifications/notifications";
import { format, formatDate } from "date-fns";
import {
CalendarCheck,
CheckCheck,
CircleAlert,
Clock7,
MessageCircle,
SquareCheck,
UploadIcon,
} from "lucide-react";
import { useRouter } from "next/navigation";
export type Notification = {
id: number;
notificationTypeId: number;
message: string;
createdAt: string;
isActive: boolean;
isPublic: boolean;
isRead: boolean;
redirectUrl: string;
userGroupIdDst: string | null;
userIdDst: string | null;
userLevelIdDst: string;
userLevelNumberDst: string | null;
userRoleIdDst: string;
};
const getNotificationIcon = (notificationTypeId: number) => {
switch (notificationTypeId) {
case 2:
return <MessageCircle className="h-8 w-8 text-success" />;
case 3:
return <UploadIcon className="h-5 w-5 text-warning" />;
case 4:
return <CheckCheck className="h-5 w-5 text-primary" />;
case 5:
return <SquareCheck className="h-5 w-5 text-warning" />;
case 6:
return <CalendarCheck className="h-5 w-5 text-danger" />;
case 7:
return <CircleAlert className="h-5 w-5 text-danger" />;
case 8:
return <Clock7 className="h-5 w-5 text-danger" />;
default:
return <SquareCheck className="h-5 w-5 text-danger" />;
}
};
const Notifications = () => {
const router = useRouter();
const [notifications, setNotifications] = useState<Notification[]>([]);
const [notificationTotal, setNotificationTotal] = useState(0);
useEffect(() => {
async function initState() {
const response = await getNotifications();
setNotifications(response.data?.data?.content);
setNotificationTotal(response.data?.data?.totalElements);
console.log("notif", response.data?.data?.content);
}
initState();
}, []);
const formatDate = (dateString: string) => {
const date = new Date(dateString);
return format(date, "dd/MM/yyyy HH:mm");
};
const handleNotificationClick = (redirectUrl: string) => {
router.push(redirectUrl);
};
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
type="button"
className="relative hidden focus:ring-none focus:outline-none md:h-8 md:w-8 md:bg-secondary text-secondary-foreground rounded-full md:flex flex-col items-center justify-center"
>
<Icon
icon="heroicons-outline:bell"
className="animate-tada h-5 w-5"
/>
<Badge
className=" w-4 h-4 p-0 text-[8px] rounded-full font-semibold items-center justify-center absolute left-[calc(100%-12px)] bottom-[calc(100%-10px)]"
color="destructive"
>
{notificationTotal > 99 ? "99+" : notificationTotal}
</Badge>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent
align="end"
className=" z-[999] mx-4 lg:w-[320px] p-0"
>
<DropdownMenuLabel>
<div className="flex justify-between px-4 py-3 border-b border-default-100 ">
<div className="text-sm text-default-800 font-medium ">
you have {notificationTotal > 99 ? "99+" : notificationTotal}{" "}
notifications
</div>
<div className="text-default-800 text-xs md:text-right">
<Link href="/notifications" className="underline">
View all
</Link>
</div>
</div>
</DropdownMenuLabel>
<div className="h-[300px] xl:h-[350px]">
<ScrollArea className="h-full">
{notifications.map((item: Notification, index: number) => (
<DropdownMenuItem
key={`inbox-${index}`}
className="flex gap-9 py-2 px-4 cursor-pointer group "
onClick={() => handleNotificationClick(item?.redirectUrl)}
>
<div className="flex items-start gap-2 flex-1 ">
<div className="flex-none">
{getNotificationIcon(item.notificationTypeId)}
</div>
<div className="flex-1 flex flex-col gap-0.5">
<div className="text-sm text-default-600 dark:group-hover:text-default-800 font-normal truncate whitespace-normal ">
{item?.message}
</div>
{/* <div className="text-xs text-default-600 dark:group-hover:text-default-700 font-light line-clamp-1 ">
{item?.desc}
</div> */}
<div className=" text-default-400 dark:group-hover:text-default-500 text-xs">
{" "}
{formatDate(item?.createdAt)}
</div>
</div>
</div>
{/* {item?.unreadmessage && (
<div className="flex-0">
<span className="h-[10px] w-[10px] bg-destructive border border-destructive-foreground dark:border-default-400 rounded-full inline-block" />
</div>
)} */}
</DropdownMenuItem>
))}
</ScrollArea>
</div>
</DropdownMenuContent>
</DropdownMenu>
);
};
export default Notifications;