This commit is contained in:
@@ -8,19 +8,21 @@ import {
|
|||||||
import { useUser } from "@/contexts";
|
import { useUser } from "@/contexts";
|
||||||
import Modal from "@/components/ui/modal";
|
import Modal from "@/components/ui/modal";
|
||||||
import Status from "@/components/ui/Status";
|
import Status from "@/components/ui/Status";
|
||||||
import { useMarkNotificationAsSeen } from "@/hooks/queries/useNotificationQueries";
|
import {
|
||||||
|
useGetMyNotifications,
|
||||||
|
useMarkNotificationAsSeen,
|
||||||
|
} from "@/hooks/queries/useNotificationQueries";
|
||||||
import { useIsMobile } from "@/hooks/use-mobile";
|
import { useIsMobile } from "@/hooks/use-mobile";
|
||||||
import { TNotificationDetailsResponse } from "@/lib/api/types/NotificationHistory";
|
import { TNotificationDetailsResponse } from "@/lib/api/types/NotificationHistory";
|
||||||
import { cn, sanitizeHtmlWithStyles } from "@/lib/utils";
|
import { cn, sanitizeHtmlWithStyles } from "@/lib/utils";
|
||||||
import { capitalize, unixToDate } from "@/utils/shared";
|
import { capitalize, unixToDate } from "@/utils/shared";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { BellIcon } from "./icons";
|
import { BellIcon } from "./icons";
|
||||||
import NotificationList from "./notification-list";
|
import NotificationList from "./notification-list";
|
||||||
|
|
||||||
export function Notification() {
|
export function Notification() {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [isDotVisible, setIsDotVisible] = useState(true);
|
|
||||||
const [unreadNotificationCount, setUnreadNotificationCount] =
|
const [unreadNotificationCount, setUnreadNotificationCount] =
|
||||||
useState<number>(0);
|
useState<number>(0);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
@@ -28,8 +30,15 @@ export function Notification() {
|
|||||||
useState<TNotificationDetailsResponse | null>(null);
|
useState<TNotificationDetailsResponse | null>(null);
|
||||||
|
|
||||||
const { mutate } = useMarkNotificationAsSeen();
|
const { mutate } = useMarkNotificationAsSeen();
|
||||||
|
const { data: unreadNotifications, isLoading: isLoadingNotifications } =
|
||||||
|
useGetMyNotifications({ seen: false });
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setUnreadNotificationCount(unreadNotifications?.data.length ?? 0);
|
||||||
|
}, [unreadNotifications]);
|
||||||
|
|
||||||
const notificationHistoryHref = useMemo(() => {
|
const notificationHistoryHref = useMemo(() => {
|
||||||
if (!user?.id) return "/notification-history";
|
if (!user?.id) return "/notification-history";
|
||||||
|
|
||||||
@@ -47,20 +56,14 @@ export function Notification() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dropdown
|
<Dropdown isOpen={isOpen} setIsOpen={setIsOpen}>
|
||||||
isOpen={isOpen}
|
|
||||||
setIsOpen={(open) => {
|
|
||||||
setIsOpen(open);
|
|
||||||
if (setIsDotVisible) setIsDotVisible(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownTrigger
|
<DropdownTrigger
|
||||||
className="shadow-theme-xs grid size-12 place-items-center rounded-full border border-stroke/70 bg-white/75 text-dark outline-none backdrop-blur-md transition-colors hover:text-primary focus-visible:border-primary focus-visible:text-primary dark:border-dark-3 dark:bg-dark-2/75 dark:text-white dark:focus-visible:border-primary"
|
className="shadow-theme-xs grid size-12 place-items-center rounded-full border border-stroke/70 bg-white/75 text-dark outline-none backdrop-blur-md transition-colors hover:text-primary focus-visible:border-primary focus-visible:text-primary dark:border-dark-3 dark:bg-dark-2/75 dark:text-white dark:focus-visible:border-primary"
|
||||||
aria-label="View Notifications"
|
aria-label="View Notifications"
|
||||||
>
|
>
|
||||||
<span className="relative">
|
<span className="relative">
|
||||||
<BellIcon />
|
<BellIcon />
|
||||||
{isDotVisible && unreadNotificationCount > 0 && (
|
{unreadNotificationCount > 0 && (
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"absolute -right-1.5 -top-1.5 z-1 grid min-w-[18px] place-items-center rounded-full bg-gradient-to-br from-rose-500 to-red-600 px-1 text-[10px] font-bold leading-none text-white shadow-[0_2px_8px_rgba(239,68,68,0.55)] ring-2 ring-white dark:ring-dark-2",
|
"absolute -right-1.5 -top-1.5 z-1 grid min-w-[18px] place-items-center rounded-full bg-gradient-to-br from-rose-500 to-red-600 px-1 text-[10px] font-bold leading-none text-white shadow-[0_2px_8px_rgba(239,68,68,0.55)] ring-2 ring-white dark:ring-dark-2",
|
||||||
@@ -88,7 +91,8 @@ export function Notification() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<NotificationList
|
<NotificationList
|
||||||
setUnreadNotificationCount={setUnreadNotificationCount}
|
notifications={unreadNotifications?.data}
|
||||||
|
isLoading={isLoadingNotifications}
|
||||||
onNotificationClick={handleNotificationClick}
|
onNotificationClick={handleNotificationClick}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -118,7 +122,7 @@ export function Notification() {
|
|||||||
<div className="pointer-events-none absolute -bottom-12 -left-6 size-28 rounded-full bg-white/10 blur-md" />
|
<div className="pointer-events-none absolute -bottom-12 -left-6 size-28 rounded-full bg-white/10 blur-md" />
|
||||||
|
|
||||||
<div className="relative flex items-start gap-4">
|
<div className="relative flex items-start gap-4">
|
||||||
<span className="grid size-12 shrink-0 place-items-center rounded-2xl bg-white/20 text-white shadow-theme-sm ring-1 ring-white/30 backdrop-blur-sm">
|
<span className="shadow-theme-sm grid size-12 shrink-0 place-items-center rounded-2xl bg-white/20 text-white ring-1 ring-white/30 backdrop-blur-sm">
|
||||||
<BellIcon />
|
<BellIcon />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -183,7 +187,7 @@ export function Notification() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setIsModalOpen(false)}
|
onClick={() => setIsModalOpen(false)}
|
||||||
className="rounded-xl bg-gradient-to-br from-primary to-blue-700 px-5 py-2 text-sm font-semibold text-white shadow-theme-sm transition-opacity hover:opacity-90"
|
className="shadow-theme-sm rounded-xl bg-gradient-to-br from-primary to-blue-700 px-5 py-2 text-sm font-semibold text-white transition-opacity hover:opacity-90"
|
||||||
>
|
>
|
||||||
Got it
|
Got it
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -2,36 +2,29 @@
|
|||||||
|
|
||||||
import Loading from "@/components/loading";
|
import Loading from "@/components/loading";
|
||||||
import IsVisible from "@/components/ui/IsVisible";
|
import IsVisible from "@/components/ui/IsVisible";
|
||||||
import { useGetMyNotifications } from "@/hooks/queries/useNotificationQueries";
|
|
||||||
import { TNotificationDetailsResponse } from "@/lib/api/types/NotificationHistory";
|
import { TNotificationDetailsResponse } from "@/lib/api/types/NotificationHistory";
|
||||||
import { truncateString } from "@/utils/shared";
|
import { truncateString } from "@/utils/shared";
|
||||||
import { Dispatch, SetStateAction, useEffect } from "react";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
setUnreadNotificationCount: Dispatch<SetStateAction<number>>;
|
notifications?: TNotificationDetailsResponse[];
|
||||||
|
isLoading: boolean;
|
||||||
onNotificationClick: (notification: TNotificationDetailsResponse) => void;
|
onNotificationClick: (notification: TNotificationDetailsResponse) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NotificationList = ({
|
const NotificationList = ({
|
||||||
setUnreadNotificationCount,
|
notifications,
|
||||||
|
isLoading,
|
||||||
onNotificationClick,
|
onNotificationClick,
|
||||||
}: IProps) => {
|
}: IProps) => {
|
||||||
const { data, isLoading } = useGetMyNotifications({ seen: false });
|
|
||||||
useEffect(() => {
|
|
||||||
setUnreadNotificationCount(data?.data.length ?? 0);
|
|
||||||
}, [data, isLoading]);
|
|
||||||
|
|
||||||
if (isLoading)
|
if (isLoading)
|
||||||
return (
|
return <Loading className="min-h-48 flex-none justify-center p-6" />;
|
||||||
<Loading className="min-h-48 flex-none justify-center p-6" />
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className="mb-3 max-h-[23rem] space-y-1.5 overflow-y-auto">
|
<ul className="mb-3 max-h-[23rem] space-y-1.5 overflow-y-auto">
|
||||||
<IsVisible condition={data?.data.length === 0}>
|
<IsVisible condition={notifications?.length === 0}>
|
||||||
<h2 className="cursor-default ps-2">No new notification</h2>
|
<h2 className="cursor-default ps-2">No new notification</h2>
|
||||||
</IsVisible>
|
</IsVisible>
|
||||||
{data?.data.map((notification) => (
|
{notifications?.map((notification) => (
|
||||||
<li
|
<li
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
key={notification.id}
|
key={notification.id}
|
||||||
|
|||||||
Reference in New Issue
Block a user