a99f86b2f9
- Refactored NotificationDetailsPage to utilize a presenter hook for better state management and loading handling. - Improved UI elements in NotificationDetailsPage, including a hero header and detail grid for displaying notification information. - Updated Notification component to streamline the marking of notifications as seen and enhance the display of notification details. - Added gradient backgrounds and improved tooltip functionality for better visual feedback and user experience.
190 lines
7.1 KiB
TypeScript
190 lines
7.1 KiB
TypeScript
"use client";
|
|
|
|
import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb";
|
|
import Loading from "@/components/loading";
|
|
import Status from "@/components/ui/Status";
|
|
import { BellIcon } from "@/components/Layouts/header/notification/icons";
|
|
import Link from "next/link";
|
|
import { useNotificationDetailsPresenter } from "./useNotificationDetailsPresenter";
|
|
|
|
interface IProps {
|
|
params: Promise<{ id: string }>;
|
|
}
|
|
|
|
const NotificationDetailsPage = ({ params }: IProps) => {
|
|
const { isLoading, rootRef, breadcrumbItems, meta, details } =
|
|
useNotificationDetailsPresenter({ params });
|
|
|
|
if (isLoading) return <Loading />;
|
|
|
|
return (
|
|
<div ref={rootRef} className="flex flex-col gap-6">
|
|
<div data-anim="breadcrumb">
|
|
<Breadcrumb items={breadcrumbItems} />
|
|
</div>
|
|
|
|
{/* Hero header */}
|
|
<section
|
|
data-anim="hero"
|
|
className="relative isolate overflow-hidden rounded-3xl border border-stroke/60 bg-gradient-to-br from-primary via-primary to-blue-700 p-6 text-white shadow-1 md:p-9 dark:border-transparent dark:shadow-card"
|
|
>
|
|
<div
|
|
data-anim="aurora"
|
|
aria-hidden
|
|
className="pointer-events-none absolute -inset-[40%] z-0 opacity-50"
|
|
style={{
|
|
backgroundImage:
|
|
"conic-gradient(from 0deg at 50% 50%, #5750F1 0deg, #0ABEF9 80deg, transparent 140deg, #8155FF 200deg, #5750F1 280deg, transparent 320deg, #5750F1 360deg)",
|
|
filter: "blur(64px)",
|
|
}}
|
|
/>
|
|
<div
|
|
data-orb="a"
|
|
aria-hidden
|
|
className="pointer-events-none absolute -right-24 -top-32 z-0 h-72 w-72 rounded-full bg-white/20 blur-3xl"
|
|
/>
|
|
<div
|
|
data-orb="b"
|
|
aria-hidden
|
|
className="pointer-events-none absolute -bottom-32 -left-16 z-0 h-64 w-64 rounded-full bg-[#0ABEF9]/40 blur-3xl"
|
|
/>
|
|
<div
|
|
data-orb="c"
|
|
aria-hidden
|
|
className="pointer-events-none absolute left-1/2 top-1/3 z-0 h-52 w-52 -translate-x-1/2 rounded-full bg-[#8155FF]/30 blur-3xl"
|
|
/>
|
|
<div
|
|
aria-hidden
|
|
className="pointer-events-none absolute inset-0 z-0 rounded-3xl ring-1 ring-inset ring-white/10"
|
|
/>
|
|
|
|
<div className="relative z-10 flex flex-col gap-6 md:flex-row md:items-start">
|
|
<span
|
|
data-anim="hero-icon"
|
|
className="grid size-16 shrink-0 place-items-center rounded-2xl bg-white/20 text-white shadow-theme-sm ring-1 ring-white/30 backdrop-blur-md"
|
|
>
|
|
<BellIcon />
|
|
</span>
|
|
|
|
<div className="min-w-0 flex-1">
|
|
<h1
|
|
className="relative z-[1] text-2xl font-bold leading-tight md:text-3xl"
|
|
aria-label={meta?.title}
|
|
>
|
|
<span
|
|
data-title-inner
|
|
className="relative z-[1] inline-block will-change-transform"
|
|
>
|
|
{meta?.title}
|
|
</span>
|
|
<span
|
|
aria-hidden
|
|
className="pointer-events-none absolute inset-0 z-0 overflow-hidden"
|
|
>
|
|
<span
|
|
data-anim="shine"
|
|
className="absolute inset-y-0 block w-1/3 opacity-0 blur-[10px] [background:linear-gradient(100deg,transparent_0%,rgba(255,255,255,0.55)_50%,transparent_100%)]"
|
|
/>
|
|
</span>
|
|
</h1>
|
|
|
|
<div className="mt-4 flex flex-wrap items-center gap-2.5">
|
|
{meta?.priority && (
|
|
<span data-anim="badge" className="inline-flex">
|
|
<Status status={meta.priority}>{meta.priority}</Status>
|
|
</span>
|
|
)}
|
|
{meta?.type && (
|
|
<span
|
|
data-anim="badge"
|
|
className="rounded-full bg-white/20 px-3 py-1 text-xs font-semibold capitalize text-white ring-1 ring-white/25 backdrop-blur-sm"
|
|
>
|
|
{meta.type}
|
|
</span>
|
|
)}
|
|
{meta?.createdAt && (
|
|
<span
|
|
data-anim="badge"
|
|
className="rounded-full bg-white/15 px-3 py-1 text-xs font-medium text-white/85 ring-1 ring-white/15"
|
|
>
|
|
{meta.createdAt}
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
{meta?.link && (
|
|
<Link
|
|
data-anim="badge"
|
|
href={meta.link}
|
|
className="mt-4 inline-flex items-center gap-2 rounded-xl bg-white/95 px-4 py-2 text-sm font-semibold text-primary shadow-theme-sm transition-transform hover:scale-[1.03]"
|
|
>
|
|
Open link
|
|
<span aria-hidden>↗</span>
|
|
</Link>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Detail grid */}
|
|
<section className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
{details.map((item) => (
|
|
<div
|
|
key={item.label}
|
|
data-anim="card"
|
|
className="group relative overflow-hidden rounded-2xl border border-stroke/60 bg-white p-5 shadow-theme-xs transition-shadow hover:shadow-1 dark:border-dark-3 dark:bg-gray-dark"
|
|
>
|
|
<span
|
|
aria-hidden
|
|
className="pointer-events-none absolute -right-6 -top-6 size-16 rounded-full bg-primary/5 blur-xl transition-opacity group-hover:opacity-100 dark:bg-primary/10"
|
|
/>
|
|
<small className="text-xs font-medium uppercase tracking-wide text-dark-5 dark:text-dark-6">
|
|
{item.label}
|
|
</small>
|
|
<div className="mt-2">
|
|
{item.kind === "status" ? (
|
|
<Status status={item.tone ?? ""}>{item.value}</Status>
|
|
) : (
|
|
<p className="break-words text-base font-semibold text-dark dark:text-white">
|
|
{item.value}
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</section>
|
|
|
|
{/* Image + message */}
|
|
{(meta?.image || meta?.hasMessage) && (
|
|
<section
|
|
data-anim="message"
|
|
className="overflow-hidden rounded-3xl border border-stroke/60 bg-white shadow-theme-xs dark:border-dark-3 dark:bg-gray-dark"
|
|
>
|
|
{meta?.image && (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img
|
|
src={meta.image}
|
|
alt={meta.title}
|
|
className="max-h-72 w-full object-cover"
|
|
/>
|
|
)}
|
|
{meta?.hasMessage && (
|
|
<div className="p-6 md:p-8">
|
|
<h2 className="mb-4 flex items-center gap-2 text-lg font-bold text-dark dark:text-white">
|
|
<span className="inline-block h-5 w-1 rounded-full bg-gradient-to-b from-primary to-blue-700" />
|
|
Message
|
|
</h2>
|
|
<div
|
|
className="text-base leading-relaxed text-dark-4 dark:text-dark-6 [&_a]:text-primary [&_a]:underline"
|
|
dangerouslySetInnerHTML={{ __html: meta.messageHtml }}
|
|
/>
|
|
</div>
|
|
)}
|
|
</section>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default NotificationDetailsPage;
|