From c714c32a587cb17c1336d4a536e37493179d3428 Mon Sep 17 00:00:00 2001 From: Amirhossein Khalili Date: Sat, 26 Sep 2026 12:23:18 +0330 Subject: [PATCH] feat: add dedicated notifications page Replace the bell popover with an RTL notification inbox, inline Markdown details, read filters, and explicit destination and delete actions. Remove retired email-link screens and client calls. --- README.md | 2 +- src/app/notifications/page.tsx | 11 + src/app/reset-password/[token]/page.tsx | 11 - src/app/robots.ts | 1 - src/app/verify-email/[token]/page.tsx | 11 - src/components/MobileBottomNav.tsx | 3 +- src/components/NotificationsBell.tsx | 190 ++------------- src/components/NotificationsPageContent.tsx | 255 ++++++++++++++++++++ src/contexts/NotificationsContext.tsx | 21 -- src/lib/api.ts | 69 +----- src/lib/swagger.json | 1 - src/lib/types.ts | 6 +- src/lib/utils.ts | 13 + src/views/ResetPasswordConfirm.tsx | 77 ------ src/views/VerifyEmail.tsx | 77 ------ 15 files changed, 308 insertions(+), 440 deletions(-) create mode 100644 src/app/notifications/page.tsx delete mode 100644 src/app/reset-password/[token]/page.tsx delete mode 100644 src/app/verify-email/[token]/page.tsx create mode 100644 src/components/NotificationsPageContent.tsx delete mode 100644 src/lib/swagger.json delete mode 100644 src/views/ResetPasswordConfirm.tsx delete mode 100644 src/views/VerifyEmail.tsx diff --git a/README.md b/README.md index 1cc5a7f..403dff6 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ The production runtime serves on port `3000` inside Docker. Dockerfiles live onl ## Routes - Public SEO pages: `/`, `/about`, `/blog`, `/blog/[slug]`, `/events`, `/events/[slug]` -- Client-heavy flows: `/auth`, `/profile`, `/logout`, `/payments/result`, `/reset-password/*`, `/verify-email/*` +- Client-heavy flows: `/auth`, `/profile`, `/notifications`, `/logout`, `/payments/result`, `/reset-password` - Admin: `/admin/*` ## Validation diff --git a/src/app/notifications/page.tsx b/src/app/notifications/page.tsx new file mode 100644 index 0000000..42f469b --- /dev/null +++ b/src/app/notifications/page.tsx @@ -0,0 +1,11 @@ +import type { Metadata } from "next"; +import NotificationsPageContent from "@/components/NotificationsPageContent"; + +export const metadata: Metadata = { + title: "اعلان‌های من", + robots: { index: false, follow: false }, +}; + +export default function NotificationsPage() { + return ; +} diff --git a/src/app/reset-password/[token]/page.tsx b/src/app/reset-password/[token]/page.tsx deleted file mode 100644 index 7a77c8b..0000000 --- a/src/app/reset-password/[token]/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import type { Metadata } from "next"; -import ResetPasswordConfirm from "@/views/ResetPasswordConfirm"; - -export const metadata: Metadata = { - title: "تعیین رمز جدید", - robots: { index: false, follow: false }, -}; - -export default function ResetPasswordConfirmPage() { - return ; -} diff --git a/src/app/robots.ts b/src/app/robots.ts index a499d44..4ed1483 100644 --- a/src/app/robots.ts +++ b/src/app/robots.ts @@ -14,7 +14,6 @@ export default function robots(): MetadataRoute.Robots { "/profile", "/payments/", "/reset-password", - "/verify-email/", ], }, ], diff --git a/src/app/verify-email/[token]/page.tsx b/src/app/verify-email/[token]/page.tsx deleted file mode 100644 index 2214493..0000000 --- a/src/app/verify-email/[token]/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import type { Metadata } from "next"; -import VerifyEmail from "@/views/VerifyEmail"; - -export const metadata: Metadata = { - title: "تأیید ایمیل", - robots: { index: false, follow: false }, -}; - -export default function VerifyEmailPage() { - return ; -} diff --git a/src/components/MobileBottomNav.tsx b/src/components/MobileBottomNav.tsx index 041f09e..d591b8d 100644 --- a/src/components/MobileBottomNav.tsx +++ b/src/components/MobileBottomNav.tsx @@ -20,8 +20,7 @@ const isProfileOrAuthPath = (pathname: string) => pathname.startsWith("/profile/") || pathname === "/auth" || pathname.startsWith("/auth/") || - pathname.startsWith("/reset-password") || - pathname.startsWith("/verify-email"); + pathname.startsWith("/reset-password"); export default function MobileBottomNav() { const pathname = usePathname() || "/"; diff --git a/src/components/NotificationsBell.tsx b/src/components/NotificationsBell.tsx index 49096c5..7f25810 100644 --- a/src/components/NotificationsBell.tsx +++ b/src/components/NotificationsBell.tsx @@ -1,184 +1,24 @@ "use client"; -import { Bell, CheckCheck, Loader2, Trash2 } from "lucide-react"; -import ConfirmAction from "@/components/ConfirmAction"; -import { Button } from "@/components/ui/button"; -import { Badge } from "@/components/ui/badge"; -import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; -import { ScrollArea } from "@/components/ui/scroll-area"; +import { Bell } from "lucide-react"; import { useNotifications } from "@/contexts/NotificationsContext"; -import type { NotificationSchema } from "@/lib/types"; -import { cn, formatJalali } from "@/lib/utils"; - -const connectionLabels = { - idle: "خاموش", - connecting: "در حال اتصال", - connected: "متصل", - disconnected: "قطع شده", -} as const; - -function NotificationItem({ - notification, - onOpen, - onDelete, -}: { - notification: NotificationSchema; - onOpen: (notification: NotificationSchema) => Promise; - onDelete: (notification: NotificationSchema) => Promise; -}) { - return ( -
-
- onDelete(notification)} - trigger={ - - } - /> - -
-
- ); -} +import { Link } from "@/lib/router"; export default function NotificationsBell() { - const { - notifications, - unreadCount, - totalCount, - hasMore, - isLoading, - isLoadingMore, - connectionStatus, - loadMore, - markAllAsSeen, - deleteNotification, - openNotification, - } = useNotifications(); + const { unreadCount } = useNotifications(); return ( - - - - - -
-
-
- - {connectionLabels[connectionStatus]} - - {unreadCount > 0 ? ( - - ) : null} -
-
-

اعلان‌ها

-

- {totalCount > 0 ? `${totalCount} مورد ثبت شده` : "هنوز اعلانی ندارید."} -

-
-
-
- - -
- {isLoading ? ( -
- - در حال بارگذاری اعلان‌ها... -
- ) : notifications.length ? ( - notifications.map((notification) => ( - - )) - ) : ( -
- اعلان تازه‌ای برای شما ثبت نشده است. -
- )} -
-
- - {hasMore ? ( -
- -
- ) : null} -
-
+ +