feat(notifications): Implement functional header notification dropdown

This commit replaces the static notification dropdown in the header with a fully functional component that fetches live data from the API.

Key features include:
- Fetches and displays the latest notifications.
- Shows a badge with the count of unseen notifications.
- Opens a modal with notification details upon clicking an item.
- Marks notifications as seen when they are viewed.

Additionally, this commit includes several related improvements:
- refactor: Replaced the global loading component with a custom Tailwind CSS spinner for a consistent look and feel.
- feat: Enhanced the DatePicker component to optionally include a time picker.
- style: Improved the layout of the notification details page by moving the message to a dedicated section and capitalizing the 'priority' and 'type' fields for better readability.
This commit is contained in:
AmirReza Jamali
2025-09-29 15:28:16 +03:30
parent dde2fc5a05
commit 021ee7d11e
11 changed files with 245 additions and 121 deletions
@@ -0,0 +1,51 @@
"use client";
import Loading from "@/app/loading";
import IsVisible from "@/components/ui/IsVisible";
import { useGetMyNotifications } from "@/hooks/queries/useNotificationQueries";
import { TNotificationDetailsResponse } from "@/lib/api/types/NotificationHistory";
import { truncateString } from "@/utils/shared";
import { Dispatch, SetStateAction, useEffect } from "react";
interface IProps {
setUnreadNotificationCount: Dispatch<SetStateAction<number>>;
onNotificationClick: (notification: TNotificationDetailsResponse) => void;
}
const NotificationList = ({
setUnreadNotificationCount,
onNotificationClick,
}: IProps) => {
const { data, isLoading } = useGetMyNotifications({ seen: false });
useEffect(() => {
setUnreadNotificationCount(data?.data.length ?? 0);
}, [data, isLoading]);
if (isLoading) return <Loading className={"p-6"} />;
return (
<ul className="mb-3 max-h-[23rem] space-y-1.5 overflow-y-auto">
<IsVisible condition={data?.data.length === 0}>
<h2 className="cursor-default ps-2">No new notification</h2>
</IsVisible>
{data?.data.map((notification) => (
<li
role="menuitem"
key={notification.id}
onClick={() => onNotificationClick(notification)}
>
<div className="cursor-pointer rounded-lg px-1 py-2 hover:bg-gray-2">
<strong className="block text-lg font-medium capitalize text-dark dark:text-white">
{notification.title}
</strong>
<span className="text-sm font-medium text-dark-5 dark:text-dark-6">
{truncateString(notification.message, 50, 50)}
</span>
</div>
</li>
))}
</ul>
);
};
export default NotificationList;