diff --git a/app/(admin)/_components/header.tsx b/app/(admin)/_components/header.tsx new file mode 100644 index 0000000..7bc7ac6 --- /dev/null +++ b/app/(admin)/_components/header.tsx @@ -0,0 +1,211 @@ +"use client"; + +import { useState } from "react"; +import Link from "next/link"; +import { usePathname, useRouter } from "next/navigation"; +import { Button } from "@/components/ui/button"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { + Inbox, + Calendar, + LayoutGrid, + Heart, + UserCog, + Bell, + Settings, + LogOut, +} from "lucide-react"; + +export function Header() { + const pathname = usePathname(); + const router = useRouter(); + const [notificationsOpen, setNotificationsOpen] = useState(false); + const [userMenuOpen, setUserMenuOpen] = useState(false); + + // Mock notifications data + const notifications = [ + { + id: 1, + title: "New appointment scheduled", + message: "John Smith booked an appointment for tomorrow", + time: "2 hours ago", + type: "info", + read: false, + }, + { + id: 2, + title: "Payment received", + message: "Payment of $150 received from Jane Doe", + time: "5 hours ago", + type: "success", + read: false, + }, + ]; + + const unreadCount = notifications.filter((n) => !n.read).length; + + return ( +
+
+
+ {/* Logo */} + +
+ +
+ Attune Heart + + + {/* Navigation Links */} + + + {/* Right Side Actions */} +
+ + + + + + {/* Thumbtack Design at Top Right */} +
+
+
+
+
+

Notifications

+ {unreadCount > 0 && ( + + {unreadCount} new + + )} +
+
+ {notifications.length === 0 ? ( +
+ +

No notifications

+
+ ) : ( +
+ {notifications.map((notification) => { + return ( +
+
+
+

+ {notification.title} +

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

+ {notification.message} +

+

+ {notification.time} +

+
+
+ ); + })} +
+ )} +
+
+ setNotificationsOpen(false)} + className="block w-full text-center text-sm font-medium text-rose-600 hover:text-rose-700 hover:underline transition-colors" + > + View all notifications + +
+
+
+ + + + + + {/* Thumbtack Design at Top Right */} +
+
+
+
+
+ + +
+
+
+
+
+
+
+ ); +} + diff --git a/app/(admin)/_components/notifications.tsx b/app/(admin)/_components/notifications.tsx index a4959e9..835fe03 100644 --- a/app/(admin)/_components/notifications.tsx +++ b/app/(admin)/_components/notifications.tsx @@ -71,7 +71,7 @@ export function Notifications({

Notifications

{unreadCount > 0 && ( - + {unreadCount} )} diff --git a/app/(admin)/_components/side-nav.tsx b/app/(admin)/_components/side-nav.tsx index ba52334..47fade1 100644 --- a/app/(admin)/_components/side-nav.tsx +++ b/app/(admin)/_components/side-nav.tsx @@ -1,8 +1,9 @@ "use client"; import React, { useState, useEffect } from "react"; -import { usePathname } from "next/navigation"; +import { usePathname, useRouter } from "next/navigation"; import Link from "next/link"; +import { Button } from "@/components/ui/button"; import { LayoutGrid, Calendar, @@ -21,6 +22,7 @@ const navItems = [ export default function SideNav() { const [open, setOpen] = useState(false); const pathname = usePathname(); + const router = useRouter(); const getActiveIndex = () => { return navItems.findIndex((item) => pathname?.includes(item.href)) ?? -1; @@ -43,14 +45,19 @@ export default function SideNav() { {/* Mobile Top Bar */}
-
+
Attune Heart Therapy
- +
{/* Mobile Drawer Overlay */} @@ -68,16 +75,16 @@ export default function SideNav() { } md:translate-x-0`} > {/* Logo Section */} -
+
-
+
Attune Heart
-
+
{/* Navigation Items */} diff --git a/app/(admin)/booking/page.tsx b/app/(admin)/booking/page.tsx index 97bcdb5..4954381 100644 --- a/app/(admin)/booking/page.tsx +++ b/app/(admin)/booking/page.tsx @@ -1,14 +1,10 @@ "use client"; import { useState, useEffect } from "react"; -import SideNav from "@/app/(admin)/_components/side-nav"; import { - Search, - Bell, Calendar, Clock, User, - DollarSign, Video, FileText, MoreVertical, @@ -171,47 +167,20 @@ export default function Booking() { return (
- {/* Side Navigation */} - -
- {/* Top Header Bar */} -
-
-
-
- - setSearchTerm(e.target.value)} - className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-gray-200 focus:border-transparent" - /> -
-
-
- -
-
-
- - {/* Main Content */} -
+ {/* Main Content */} +
{/* Page Header */} -
+
-

+

Bookings

-

+

Manage and view all appointment bookings

-
@@ -236,25 +205,25 @@ export default function Booking() { - - - - - - - @@ -265,34 +234,37 @@ export default function Booking() { key={booking.ID} className="hover:bg-gray-50 transition-colors" > - - - - - - - + ) + }, + ...components, + }} + {...props} + /> + ) +} + +function CalendarDayButton({ + className, + day, + modifiers, + ...props +}: React.ComponentProps) { + const defaultClassNames = getDefaultClassNames() + + const ref = React.useRef(null) + React.useEffect(() => { + if (modifiers.focused) ref.current?.focus() + }, [modifiers.focused]) + + return ( +
+ Patient + Date & Time + Duration + Status + Payment + Amount + Actions
+
-
- +
+
-
-
+
+
{booking.user.first_name} {booking.user.last_name}
-
+
{booking.user.email}
+
+ {formatDate(booking.scheduled_at)} +
-
+
+
{formatDate(booking.scheduled_at)}
-
+
{formatTime(booking.scheduled_at)}
+ {booking.duration} min + + + ${booking.amount} -
+
+ @@ -347,7 +319,6 @@ export default function Booking() { )} - ); } diff --git a/app/(admin)/dashboard/page.tsx b/app/(admin)/dashboard/page.tsx index 50ec090..b1e9cf7 100644 --- a/app/(admin)/dashboard/page.tsx +++ b/app/(admin)/dashboard/page.tsx @@ -1,7 +1,13 @@ "use client"; import { useState, useEffect } from "react"; -import SideNav from "@/app/(admin)/_components/side-nav"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { Users, UserCheck, @@ -10,8 +16,8 @@ import { CalendarX, DollarSign, TrendingUp, - Search, - Bell, + ArrowUpRight, + ArrowDownRight, } from "lucide-react"; interface DashboardStats { @@ -28,6 +34,7 @@ interface DashboardStats { export default function Dashboard() { const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); + const [timePeriod, setTimePeriod] = useState("last_month"); useEffect(() => { // Simulate API call @@ -60,94 +67,86 @@ export default function Dashboard() { title: "Total Users", value: stats?.total_users ?? 0, icon: Users, - bgColor: "bg-gray-50", - iconColor: "text-gray-600", + trend: "+12%", + trendUp: true, }, { title: "Active Users", value: stats?.active_users ?? 0, icon: UserCheck, - bgColor: "bg-gray-50", - iconColor: "text-gray-600", + trend: "+8%", + trendUp: true, }, { title: "Total Bookings", value: stats?.total_bookings ?? 0, icon: Calendar, - bgColor: "bg-gray-50", - iconColor: "text-gray-600", + trend: "+24%", + trendUp: true, }, { title: "Upcoming Bookings", value: stats?.upcoming_bookings ?? 0, icon: CalendarCheck, - bgColor: "bg-gray-50", - iconColor: "text-gray-600", + trend: "+6", + trendUp: true, }, { title: "Completed Bookings", value: stats?.completed_bookings ?? 0, icon: CalendarCheck, - bgColor: "bg-gray-50", - iconColor: "text-green-600", + trend: "0%", + trendUp: true, }, { title: "Cancelled Bookings", value: stats?.cancelled_bookings ?? 0, icon: CalendarX, - bgColor: "bg-gray-50", - iconColor: "text-red-600", + trend: "0%", + trendUp: false, }, { title: "Total Revenue", value: `$${stats?.total_revenue.toLocaleString() ?? 0}`, icon: DollarSign, - bgColor: "bg-gray-50", - iconColor: "text-gray-600", + trend: "+18%", + trendUp: true, }, { title: "Monthly Revenue", value: `$${stats?.monthly_revenue.toLocaleString() ?? 0}`, icon: TrendingUp, - bgColor: "bg-gray-50", - iconColor: "text-gray-600", + trend: "+32%", + trendUp: true, }, ]; + return (
- {/* Side Navigation */} - -
- {/* Top Header Bar */} -
-
-
-
- - -
+ {/* Main Content */} +
+ {/* Welcome Section */} +
+
+

+ Welcome Back! Hammond +

+

+ Here's an overview of your practice today +

-
- -
-
-
- - {/* Main Content */} -
- {/* Page Header */} -
-

Dashboard

-

Overview of your practice statistics

+
{loading ? ( @@ -155,32 +154,53 @@ export default function Dashboard() {
) : ( -
- {statCards.map((card, index) => { - const Icon = card.icon; - return ( -
-
-
- + <> + {/* Stats Grid */} +
+ {statCards.map((card, index) => { + const Icon = card.icon; + return ( +
+
+
+ +
+
+ {card.trendUp ? ( + + ) : ( + + )} + {card.trend} +
+
+ +
+

+ {card.title} +

+

+ {card.value} +

+

+ vs last month +

-

- {card.title} -

-

- {card.value} -

-
- ); - })} -
+ ); + })} +
+ + )} - -
+
); } diff --git a/app/(admin)/layout.tsx b/app/(admin)/layout.tsx index db27d60..4cd0095 100644 --- a/app/(admin)/layout.tsx +++ b/app/(admin)/layout.tsx @@ -1,7 +1,12 @@ +import { Header } from "./_components/header"; + export default function AdminLayout({ children }: { children: React.ReactNode }) { return (
- {children} +
+
+ {children} +
) } \ No newline at end of file diff --git a/app/(admin)/notifications/page.tsx b/app/(admin)/notifications/page.tsx index d8b1822..fa65682 100644 --- a/app/(admin)/notifications/page.tsx +++ b/app/(admin)/notifications/page.tsx @@ -1,30 +1,34 @@ "use client"; import { useState } from "react"; -import SideNav from "@/app/(admin)/_components/side-nav"; -import { Notifications, Notification } from "@/app/(admin)/_components/notifications"; +import { Bell } from "lucide-react"; + +interface Notification { + id: string; + title: string; + message: string; + time: string; + read: boolean; +} export default function NotificationsPage() { const [notifications, setNotifications] = useState([ { id: "1", - type: "appointment", - title: "New Appointment Request", - message: "Sarah Johnson requested an appointment for tomorrow at 2:00 PM", - time: "2 minutes ago", + title: "New appointment scheduled", + message: "John Smith booked an appointment for tomorrow", + time: "2 hours ago", read: false, }, { id: "2", - type: "success", - title: "Appointment Confirmed", - message: "Your appointment with Michael Chen has been confirmed for today at 10:00 AM", - time: "1 hour ago", + title: "Payment received", + message: "Payment of $150 received from Jane Doe", + time: "5 hours ago", read: false, }, { id: "3", - type: "warning", title: "Appointment Reminder", message: "You have an appointment in 30 minutes with Emily Davis", time: "3 hours ago", @@ -32,7 +36,6 @@ export default function NotificationsPage() { }, { id: "4", - type: "info", title: "New Message", message: "You received a new message from John Smith", time: "5 hours ago", @@ -40,7 +43,6 @@ export default function NotificationsPage() { }, { id: "5", - type: "appointment", title: "Appointment Cancelled", message: "Robert Wilson cancelled his appointment scheduled for tomorrow", time: "1 day ago", @@ -48,35 +50,71 @@ export default function NotificationsPage() { }, ]); - const handleMarkAsRead = (id: string) => { - setNotifications((prev) => - prev.map((n) => (n.id === id ? { ...n, read: true } : n)) - ); - }; - - const handleDismiss = (id: string) => { - setNotifications((prev) => prev.filter((n) => n.id !== id)); - }; - - const handleMarkAllAsRead = () => { - setNotifications((prev) => prev.map((n) => ({ ...n, read: true }))); - }; + const unreadCount = notifications.filter((n) => !n.read).length; return (
- {/* Side Navigation */} - - -
-
- + {/* Main Content */} +
+ {/* Page Header */} +
+
+ +

+ Notifications +

+ {unreadCount > 0 && ( + + {unreadCount} new + + )} +
-
+ + {/* Notifications List */} +
+ {notifications.length === 0 ? ( +
+ +

No notifications

+
+ ) : ( +
+ {notifications.map((notification) => { + return ( +
+
+
+

+ {notification.title} +

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

+ {notification.message} +

+

+ {notification.time} +

+
+
+ ); + })} +
+ )} +
+
); } diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index b20b935..e500604 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -47,11 +47,10 @@ export default function Login() { className="ml-auto mb-6 w-8 h-8 rounded-full" aria-label="Close" > - {/* Heading */} -

+

Welcome back

@@ -64,7 +63,10 @@ export default function Login() {

{/* Login Form */} -
e.preventDefault()}> + { + e.preventDefault(); + router.push("/dashboard"); + }}> {/* Email Field */}
+
+ {children} +
+