From e25bfa91a539cc71919d565d28982ba72a42a3fa Mon Sep 17 00:00:00 2001 From: sazzadulalambd Date: Fri, 15 May 2026 18:25:29 +0600 Subject: [PATCH] feat: add notifications page and update navigation to redirect notifications to a dedicated route --- src/app/investor/dashboard/page.tsx | 2 +- src/app/investor/investments/[id]/page.tsx | 2 +- src/app/investor/notifications/page.tsx | 206 +++++++++++++++++++++ src/app/investor/plans/page.tsx | 2 +- src/app/investor/profile/page.tsx | 2 +- src/app/investor/rental-history/page.tsx | 2 +- src/app/investor/withdraw/page.tsx | 4 +- src/components/InvestorNotification.tsx | 160 ++-------------- src/components/LayoutContent.tsx | 2 +- src/components/Sidebar.tsx | 36 +--- 10 files changed, 238 insertions(+), 180 deletions(-) create mode 100644 src/app/investor/notifications/page.tsx diff --git a/src/app/investor/dashboard/page.tsx b/src/app/investor/dashboard/page.tsx index 9ff66b3..843d528 100644 --- a/src/app/investor/dashboard/page.tsx +++ b/src/app/investor/dashboard/page.tsx @@ -14,7 +14,7 @@ export default function InvestorDashboardPage() { return (
-
+

Welcome back, {investor.name.split(' ')[0]} 👋

diff --git a/src/app/investor/investments/[id]/page.tsx b/src/app/investor/investments/[id]/page.tsx index a71a836..9560dd9 100644 --- a/src/app/investor/investments/[id]/page.tsx +++ b/src/app/investor/investments/[id]/page.tsx @@ -52,7 +52,7 @@ export default function InvestorInvestmentDetailPage({ params }: { params: Promi return (
-
+
+ )} +
+
+ +
+
+
+ + +
+
+ +
+ {filteredNotifications.length === 0 ? ( +
+ +

No notifications found

+
+ ) : ( + filteredNotifications.map((notif) => { + const Icon = iconMap[notif.type] || iconMap.default; + return ( +
markAsRead(notif.id)} + className={`p-4 cursor-pointer transition-all hover:bg-slate-50 ${!notif.read ? 'bg-blue-50/50' : '' + }`} + > +
+
+ +
+
+
+

+ {notif.title} +

+ {!notif.read && ( +
+ )} +
+

{notif.message}

+

{notif.time}

+
+
+
+ ); + }) + )} +
+
+
+
+ ); +} + +import InvestorNotification from '@/components/InvestorNotification'; \ No newline at end of file diff --git a/src/app/investor/plans/page.tsx b/src/app/investor/plans/page.tsx index af16147..9efdee2 100644 --- a/src/app/investor/plans/page.tsx +++ b/src/app/investor/plans/page.tsx @@ -50,7 +50,7 @@ export default function MyInvestmentsPage() { return (
-
+
{/* Header */}
diff --git a/src/app/investor/profile/page.tsx b/src/app/investor/profile/page.tsx index aefb260..52885b9 100644 --- a/src/app/investor/profile/page.tsx +++ b/src/app/investor/profile/page.tsx @@ -128,7 +128,7 @@ export default function InvestorProfilePage() {
-
+
{/* Profile Header */}
diff --git a/src/app/investor/rental-history/page.tsx b/src/app/investor/rental-history/page.tsx index 4e7d95c..8f49af3 100644 --- a/src/app/investor/rental-history/page.tsx +++ b/src/app/investor/rental-history/page.tsx @@ -67,7 +67,7 @@ export default function RentalHistoryPage() { return (
-
+
{/* Header */}
diff --git a/src/app/investor/withdraw/page.tsx b/src/app/investor/withdraw/page.tsx index 392a07e..68ac7bc 100644 --- a/src/app/investor/withdraw/page.tsx +++ b/src/app/investor/withdraw/page.tsx @@ -108,9 +108,9 @@ export default function InvestorWithdrawPage() { }; return ( -
+
-
+
{/* Header */}
diff --git a/src/components/InvestorNotification.tsx b/src/components/InvestorNotification.tsx index 8dd14b1..85cccb0 100644 --- a/src/components/InvestorNotification.tsx +++ b/src/components/InvestorNotification.tsx @@ -1,55 +1,21 @@ 'use client'; -import { useState } from 'react'; -import { Bell, X, ArrowRight, Package, DollarSign, Bike, AlertCircle, CheckCircle } from 'lucide-react'; +import Link from 'next/link'; +import { Bell, Package, DollarSign, Bike, AlertCircle, CheckCircle } from 'lucide-react'; const mockNotifications = [ - { - id: '1', - type: 'rental', - title: 'New Rental Started', - message: 'Your bike AB-1234 has been rented by rider MR-456', - time: '5 min ago', - read: false, - }, - { - id: '2', - type: 'earning', - title: 'Earning Credited', - message: 'à§³450 has been added to your wallet from bike CD-5678', - time: '2 hours ago', - read: false, - }, - { - id: '3', - type: 'success', - title: 'Withdrawal Complete', - message: 'Your withdrawal of à§³5,000 has been processed successfully', - time: '1 day ago', - read: true, - }, - { - id: '4', - type: 'alert', - title: 'Maintenance Alert', - message: 'Bike XY-9012 requires maintenance attention', - time: '2 days ago', - read: true, - }, + { id: '1', type: 'rental', title: 'New Rental Started', message: 'Your bike AB-1234 has been rented by rider MR-456', time: '5 min ago', read: false }, + { id: '2', type: 'earning', title: 'Earning Credited', message: 'à§³450 has been added to your wallet from bike CD-5678', time: '2 hours ago', read: false }, + { id: '3', type: 'success', title: 'Withdrawal Complete', message: 'Your withdrawal of à§³5,000 has been processed successfully', time: '1 day ago', read: true }, + { id: '4', type: 'alert', title: 'Maintenance Alert', message: 'Bike XY-9012 requires maintenance attention', time: '2 days ago', read: true }, ]; const iconMap: Record = { - rental: Bike, - earning: DollarSign, - success: CheckCircle, - alert: AlertCircle, - default: Package, + rental: Bike, earning: DollarSign, success: CheckCircle, alert: AlertCircle, default: Package, }; export default function InvestorNotification({ isMobile = false }: { isMobile?: boolean }) { - const [isOpen, setIsOpen] = useState(false); - const [notifications] = useState(mockNotifications); - const unreadCount = notifications.filter(n => !n.read).length; + const unreadCount = mockNotifications.filter(n => !n.read).length; if (isMobile) { return ( @@ -58,117 +24,29 @@ export default function InvestorNotification({ isMobile = false }: { isMobile?:

JAIBEN

Investor
- - - {isOpen && ( - <> -
setIsOpen(false)} - /> -
-
-
-

Notifications

- -
-
- {notifications.map((notif) => { - const Icon = iconMap[notif.type] || iconMap.default; - return ( -
-
-
- -
-
-

- {notif.title} -

-

{notif.message}

-

{notif.time}

-
- {!notif.read && ( -
- )} -
-
- ); - })} -
-
-
- - )} +
); } return ( -
-
-
-

- - Notifications -

- {unreadCount > 0 && ( - - {unreadCount} new - - )} +
+ +
+ + Notifications
-
- {notifications.map((notif) => { - const Icon = iconMap[notif.type] || iconMap.default; - return ( -
-
-
- -
-
-

- {notif.title} -

-

{notif.message}

-

{notif.time}

-
- {!notif.read && ( -
- )} -
-
- ); - })} -
-
- -
-
+ {unreadCount > 0 && ( + {unreadCount} + )} +
); } \ No newline at end of file diff --git a/src/components/LayoutContent.tsx b/src/components/LayoutContent.tsx index 7a300fc..0aa03fa 100644 --- a/src/components/LayoutContent.tsx +++ b/src/components/LayoutContent.tsx @@ -13,7 +13,7 @@ export default function LayoutContent({ children }: LayoutContentProps) { return ( <> {showSidebar && } -
+
{children}
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index b2268f3..712e74b 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -26,7 +26,6 @@ import { Target, User, History, Bell } from 'lucide-react'; import { getUserName, getUserRole, logout } from '@/lib/auth'; -import InvestorNotification from './InvestorNotification'; const ROLE_LABELS: Record = { super_admin: 'Super Admin', @@ -72,7 +71,7 @@ const investorNavItems: NavItem[] = [ { label: 'My Investments', href: '/investor/plans', icon: Target }, { label: 'Rental History', href: '/investor/rental-history', icon: History }, { label: 'Withdraw', href: '/investor/withdraw', icon: CreditCard }, - { label: 'Notifications', href: '#', icon: Bell, isNotification: true }, + { label: 'Notifications', href: '/investor/notifications', icon: Bell }, { label: 'My Profile', href: '/investor/profile', icon: User }, ]; @@ -86,7 +85,6 @@ export default function Sidebar() { const pathname = usePathname(); const [mobileOpen, setMobileOpen] = useState(false); const [expandedMenu, setExpandedMenu] = useState(null); - const [notificationOpen, setNotificationOpen] = useState(false); const [userName, setUserName] = useState('User'); const [userRole, setUserRole] = useState('admin'); @@ -158,22 +156,7 @@ export default function Sidebar() { const isChild = item.href !== '/' && pathname.startsWith(item.href + '/'); const isActive = isExact || isChild; const Icon = item.icon; - - if (item.isNotification) { - return ( - - ); - } + const isNotification = item.label === 'Notifications'; return ( {item.label} + {isNotification && ( + 2 + )} ); })} - {isInvestor && notificationOpen && ( -
-
- Notifications - -
- -
- )} -