Integrate dark mode support across admin components, including Header, Notifications, SideNav, and Booking pages. Update styles to ensure visual consistency and responsiveness based on the selected theme, enhancing user experience in both light and dark modes.

This commit is contained in:
iamkiddy 2025-11-13 11:42:56 +00:00
parent f4c3fe0c51
commit 35e654cf46
8 changed files with 271 additions and 176 deletions

View File

@ -4,11 +4,7 @@ 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 { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import {
Inbox,
Calendar,
@ -19,12 +15,16 @@ import {
Settings,
LogOut,
} from "lucide-react";
import { useAppTheme } from "@/components/ThemeProvider";
import { ThemeToggle } from "@/components/ThemeToggle";
export function Header() {
const pathname = usePathname();
const router = useRouter();
const [notificationsOpen, setNotificationsOpen] = useState(false);
const [userMenuOpen, setUserMenuOpen] = useState(false);
const { theme } = useAppTheme();
const isDark = theme === "dark";
// Mock notifications data
const notifications = [
@ -49,15 +49,15 @@ export function Header() {
const unreadCount = notifications.filter((n) => !n.read).length;
return (
<header className="bg-white border-b border-gray-200 fixed top-0 left-0 right-0 z-50">
<header className={`fixed top-0 left-0 right-0 z-50 ${isDark ? "bg-gray-900 border-gray-800" : "bg-white border-gray-200"} border-b`}>
<div className="px-3 sm:px-4 md:px-6 lg:px-8">
<div className="flex items-center justify-between h-14 sm:h-16">
{/* Logo */}
<Link href="/" className="flex items-center gap-2 sm:gap-3">
<div className="flex items-center justify-center w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-linear-to-r from-rose-100 to-pink-100">
<Heart className="w-4 h-4 sm:w-6 sm:h-6 text-rose-600" fill="currentColor" />
<div className={`flex items-center justify-center w-8 h-8 sm:w-10 sm:h-10 rounded-lg ${isDark ? "bg-gray-800" : "bg-linear-to-r from-rose-100 to-pink-100"}`}>
<Heart className={`w-4 h-4 sm:w-6 sm:h-6 ${isDark ? "text-rose-400" : "text-rose-600"}`} fill="currentColor" />
</div>
<span className="text-base sm:text-lg md:text-xl font-semibold text-gray-900 hidden sm:inline">Attune Heart</span>
<span className={`text-base sm:text-lg md:text-xl font-semibold hidden sm:inline ${isDark ? "text-white" : "text-gray-900"}`}>Attune Heart</span>
</Link>
{/* Navigation Links */}
@ -67,7 +67,9 @@ export function Header() {
className={`flex items-center gap-1 sm:gap-2 px-2 sm:px-3 md:px-4 py-1.5 sm:py-2 rounded-lg text-xs sm:text-sm font-medium transition-colors ${
pathname === "/admin/dashboard"
? "bg-linear-to-r from-rose-500 to-pink-600 text-white"
: "text-gray-600 hover:bg-gray-100"
: isDark
? "text-gray-300 hover:bg-gray-800"
: "text-gray-600 hover:bg-gray-100"
}`}
>
<LayoutGrid className="w-4 h-4 sm:w-5 sm:h-5" />
@ -78,7 +80,9 @@ export function Header() {
className={`flex items-center gap-1 sm:gap-2 px-2 sm:px-3 md:px-4 py-1.5 sm:py-2 rounded-lg text-xs sm:text-sm font-medium transition-colors ${
pathname === "/admin/booking"
? "bg-linear-to-r from-rose-500 to-pink-600 text-white"
: "text-gray-600 hover:bg-gray-100"
: isDark
? "text-gray-300 hover:bg-gray-800"
: "text-gray-600 hover:bg-gray-100"
}`}
>
<Calendar className="w-4 h-4 sm:w-5 sm:h-5" />
@ -88,23 +92,24 @@ export function Header() {
{/* Right Side Actions */}
<div className="flex items-center gap-1.5 sm:gap-2 md:gap-3">
<ThemeToggle />
<Popover open={notificationsOpen} onOpenChange={setNotificationsOpen}>
<PopoverTrigger asChild>
<Button variant="ghost" size="icon" className="relative w-8 h-8 sm:w-9 sm:h-9 md:w-10 md:h-10 cursor-pointer">
<Inbox className="w-5 h-5 sm:w-6 sm:h-6 md:w-8 md:h-8 text-gray-600" />
<Inbox className={`w-5 h-5 sm:w-6 sm:h-6 md:w-8 md:h-8 ${isDark ? "text-gray-300" : "text-gray-600"}`} />
{unreadCount > 0 && (
<span className="absolute top-0.5 right-0.5 sm:top-1 sm:right-1 w-1.5 h-1.5 sm:w-2 sm:h-2 bg-green-500 rounded-full"></span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-[calc(100vw-2rem)] sm:w-80 md:w-96 p-0 bg-white shadow-xl border border-gray-200" align="end">
<PopoverContent className={`w-[calc(100vw-2rem)] sm:w-80 md:w-96 p-0 shadow-xl border ${isDark ? "bg-gray-900 border-gray-800" : "bg-white border-gray-200"}`} align="end">
{/* Thumbtack Design at Top Right */}
<div className="relative">
<div className="absolute -top-2 right-8 w-4 h-4 bg-white border-l border-t border-gray-200 rotate-45"></div>
<div className="absolute -top-1 right-8 w-2 h-2 bg-white translate-x-1/2"></div>
<div className={`absolute -top-2 right-8 w-4 h-4 rotate-45 ${isDark ? "bg-gray-900 border-l border-t border-gray-800" : "bg-white border-l border-t border-gray-200"}`}></div>
<div className={`absolute -top-1 right-8 w-2 h-2 translate-x-1/2 ${isDark ? "bg-gray-900" : "bg-white"}`}></div>
</div>
<div className="flex items-center justify-between p-4 border-b">
<h3 className="font-semibold text-gray-900">Notifications</h3>
<div className={`flex items-center justify-between p-4 border-b ${isDark ? "border-gray-800" : ""}`}>
<h3 className={`font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>Notifications</h3>
{unreadCount > 0 && (
<span className="px-2 py-1 text-xs font-medium bg-rose-100 text-rose-700 rounded-full">
{unreadCount} new
@ -113,24 +118,28 @@ export function Header() {
</div>
<div className="max-h-96 overflow-y-auto">
{notifications.length === 0 ? (
<div className="p-8 text-center text-gray-500">
<Bell className="w-12 h-12 mx-auto mb-2 text-gray-300" />
<div className={`p-8 text-center ${isDark ? "text-gray-400" : "text-gray-500"}`}>
<Bell className={`w-12 h-12 mx-auto mb-2 ${isDark ? "text-gray-600" : "text-gray-300"}`} />
<p className="text-sm">No notifications</p>
</div>
) : (
<div className="divide-y">
<div className={`divide-y ${isDark ? "divide-gray-800" : ""}`}>
{notifications.map((notification) => {
return (
<div
key={notification.id}
className={`p-4 hover:bg-gray-50 transition-colors cursor-pointer ${
!notification.read ? "bg-rose-50/50" : ""
className={`p-4 transition-colors cursor-pointer ${
!notification.read
? isDark
? "bg-rose-500/10"
: "bg-rose-50/50"
: ""
}`}
>
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-2">
<p
className={`text-sm font-medium text-gray-900 ${
className={`text-sm font-medium ${isDark ? "text-white" : "text-gray-900"} ${
!notification.read ? "font-semibold" : ""
}`}
>
@ -140,10 +149,10 @@ export function Header() {
<span className="shrink-0 w-2 h-2 bg-green-500 rounded-full mt-1"></span>
)}
</div>
<p className="text-sm text-gray-600 mt-1">
<p className={`text-sm mt-1 ${isDark ? "text-gray-400" : "text-gray-600"}`}>
{notification.message}
</p>
<p className="text-xs text-gray-400 mt-1">
<p className={`text-xs mt-1 ${isDark ? "text-gray-500" : "text-gray-400"}`}>
{notification.time}
</p>
</div>
@ -153,11 +162,11 @@ export function Header() {
</div>
)}
</div>
<div className="p-3 border-t bg-gray-50">
<div className={`p-3 border-t ${isDark ? "border-gray-800 bg-gray-900/80" : "bg-gray-50"}`}>
<Link
href="/admin/notifications"
onClick={() => setNotificationsOpen(false)}
className="block w-full text-center text-sm font-medium text-rose-600 hover:text-rose-700 hover:underline transition-colors"
className={`block w-full text-center text-sm font-medium hover:underline transition-colors ${isDark ? "text-rose-300 hover:text-rose-200" : "text-rose-600 hover:text-rose-700"}`}
>
View all notifications
</Link>
@ -166,15 +175,23 @@ export function Header() {
</Popover>
<Popover open={userMenuOpen} onOpenChange={setUserMenuOpen}>
<PopoverTrigger asChild>
<Button variant="ghost" size="icon" className="rounded-full bg-linear-to-r from-rose-100 to-pink-100 hover:from-rose-200 hover:to-pink-200 cursor-pointer w-8 h-8 sm:w-9 sm:h-9 md:w-10 md:h-10">
<UserCog className="w-4 h-4 sm:w-5 sm:h-5 text-rose-600" />
<Button
variant="ghost"
size="icon"
className={`rounded-full cursor-pointer w-8 h-8 sm:w-9 sm:h-9 md:w-10 md:h-10 ${
isDark
? "bg-gray-800 hover:bg-gray-700"
: "bg-linear-to-r from-rose-100 to-pink-100 hover:from-rose-200 hover:to-pink-200"
}`}
>
<UserCog className={`w-4 h-4 sm:w-5 sm:h-5 ${isDark ? "text-rose-300" : "text-rose-600"}`} />
</Button>
</PopoverTrigger>
<PopoverContent className="w-56 sm:w-64 p-0 bg-white shadow-xl border border-gray-200" align="end">
<PopoverContent className={`w-56 sm:w-64 p-0 shadow-xl border ${isDark ? "bg-gray-900 border-gray-800" : "bg-white border-gray-200"}`} align="end">
{/* Thumbtack Design at Top Right */}
<div className="relative">
<div className="absolute -top-2 right-8 w-4 h-4 bg-white border-l border-t border-gray-200 rotate-45"></div>
<div className="absolute -top-1 right-8 w-2 h-2 bg-white translate-x-1/2"></div>
<div className={`absolute -top-2 right-8 w-4 h-4 rotate-45 ${isDark ? "bg-gray-900 border-l border-t border-gray-800" : "bg-white border-l border-t border-gray-200"}`}></div>
<div className={`absolute -top-1 right-8 w-2 h-2 translate-x-1/2 ${isDark ? "bg-gray-900" : "bg-white"}`}></div>
</div>
<div className="py-2">
<Button
@ -183,10 +200,12 @@ export function Header() {
setUserMenuOpen(false);
router.push("/admin/settings");
}}
className="w-full flex items-center gap-3 px-4 py-3 justify-start hover:bg-gray-50 transition-colors cursor-pointer"
className={`w-full flex items-center gap-3 px-4 py-3 justify-start transition-colors cursor-pointer ${
isDark ? "hover:bg-gray-800" : "hover:bg-gray-50"
}`}
>
<Settings className="w-5 h-5 text-gray-600" />
<span className="text-sm font-medium text-gray-900">Settings</span>
<Settings className={`w-5 h-5 ${isDark ? "text-gray-300" : "text-gray-600"}`} />
<span className={`text-sm font-medium ${isDark ? "text-white" : "text-gray-900"}`}>Settings</span>
</Button>
<Button
variant="ghost"
@ -194,7 +213,9 @@ export function Header() {
setUserMenuOpen(false);
router.push("/");
}}
className="w-full flex items-center gap-3 px-4 py-3 justify-start hover:bg-gray-50 transition-colors cursor-pointer"
className={`w-full flex items-center gap-3 px-4 py-3 justify-start transition-colors cursor-pointer ${
isDark ? "hover:bg-gray-800" : "hover:bg-gray-50"
}`}
>
<LogOut className="w-5 h-5 text-red-500" />
<span className="text-sm font-medium text-red-500">Logout</span>

View File

@ -12,6 +12,7 @@ import {
Clock,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { useAppTheme } from "@/components/ThemeProvider";
export interface Notification {
id: string;
@ -36,30 +37,32 @@ export function Notifications({
onMarkAllAsRead,
}: NotificationsProps) {
const unreadCount = notifications.filter((n) => !n.read).length;
const { theme } = useAppTheme();
const isDark = theme === "dark";
const getIcon = (type: Notification["type"]) => {
switch (type) {
case "success":
return <CheckCircle className="w-5 h-5 text-green-600" />;
return <CheckCircle className={`w-5 h-5 ${isDark ? "text-green-300" : "text-green-600"}`} />;
case "warning":
return <AlertCircle className="w-5 h-5 text-orange-600" />;
return <AlertCircle className={`w-5 h-5 ${isDark ? "text-orange-300" : "text-orange-600"}`} />;
case "info":
return <Info className="w-5 h-5 text-blue-600" />;
return <Info className={`w-5 h-5 ${isDark ? "text-blue-300" : "text-blue-600"}`} />;
case "appointment":
return <Calendar className="w-5 h-5 text-rose-600" />;
return <Calendar className={`w-5 h-5 ${isDark ? "text-rose-300" : "text-rose-600"}`} />;
}
};
const getBgColor = (type: Notification["type"]) => {
switch (type) {
case "success":
return "bg-[#4A90A4]/10 border-[#4A90A4]/30";
return isDark ? "bg-green-500/10 border-green-500/30" : "bg-[#4A90A4]/10 border-[#4A90A4]/30";
case "warning":
return "bg-rose-100 border-rose-300";
return isDark ? "bg-rose-500/10 border-rose-400/40" : "bg-rose-100 border-rose-300";
case "info":
return "bg-pink-50 border-pink-200";
return isDark ? "bg-pink-500/10 border-pink-400/40" : "bg-pink-50 border-pink-200";
case "appointment":
return "bg-gradient-to-br from-rose-50 to-pink-50 border-rose-300";
return isDark ? "bg-rose-500/10 border-rose-400/40" : "bg-gradient-to-br from-rose-50 to-pink-50 border-rose-300";
}
};
@ -68,8 +71,8 @@ export function Notifications({
{/* Header */}
<div className="flex items-center justify-between mb-6">
<div className="flex items-center gap-3">
<Bell className="w-6 h-6 text-gray-900" />
<h2 className="text-2xl font-bold text-gray-900">Notifications</h2>
<Bell className={`w-6 h-6 ${isDark ? "text-white" : "text-gray-900"}`} />
<h2 className={`text-2xl font-bold ${isDark ? "text-white" : "text-gray-900"}`}>Notifications</h2>
{unreadCount > 0 && (
<span className="px-2.5 py-0.5 bg-linear-to-r from-rose-500 to-pink-500 text-white text-sm font-medium rounded-full">
{unreadCount}
@ -77,7 +80,12 @@ export function Notifications({
)}
</div>
{unreadCount > 0 && onMarkAllAsRead && (
<Button variant="outline" size="sm" onClick={onMarkAllAsRead}>
<Button
variant="outline"
size="sm"
onClick={onMarkAllAsRead}
className={isDark ? "border-gray-700 text-gray-200 hover:bg-gray-800" : ""}
>
Mark all as read
</Button>
)}
@ -87,8 +95,8 @@ export function Notifications({
<div className="space-y-3">
{notifications.length === 0 ? (
<div className="text-center py-12">
<Bell className="w-12 h-12 text-gray-400 mx-auto mb-4" />
<p className="text-gray-600">No notifications</p>
<Bell className={`w-12 h-12 mx-auto mb-4 ${isDark ? "text-gray-600" : "text-gray-400"}`} />
<p className={isDark ? "text-gray-400" : "text-gray-600"}>No notifications</p>
</div>
) : (
notifications.map((notification) => (
@ -97,7 +105,7 @@ export function Notifications({
className={cn(
"p-4 rounded-lg border-2 transition-all",
getBgColor(notification.type),
!notification.read && "ring-2 ring-offset-2 ring-rose-300"
!notification.read && (isDark ? "ring-2 ring-offset-2 ring-rose-400 ring-offset-gray-900" : "ring-2 ring-offset-2 ring-rose-300")
)}
>
<div className="flex items-start gap-3">
@ -108,13 +116,15 @@ export function Notifications({
<h3
className={cn(
"font-semibold mb-1",
!notification.read ? "text-gray-900" : "text-gray-700"
!notification.read
? isDark ? "text-white" : "text-gray-900"
: isDark ? "text-gray-300" : "text-gray-700"
)}
>
{notification.title}
</h3>
<p className="text-sm text-gray-600 mb-2">{notification.message}</p>
<div className="flex items-center gap-2 text-xs text-gray-500">
<p className={`text-sm mb-2 ${isDark ? "text-gray-400" : "text-gray-600"}`}>{notification.message}</p>
<div className={`flex items-center gap-2 text-xs ${isDark ? "text-gray-500" : "text-gray-500"}`}>
<Clock className="w-3 h-3" />
{notification.time}
</div>
@ -125,7 +135,7 @@ export function Notifications({
variant="ghost"
size="icon-sm"
onClick={() => onMarkAsRead(notification.id)}
className="h-7 w-7"
className={`h-7 w-7 ${isDark ? "text-gray-300 hover:bg-gray-800" : ""}`}
>
<CheckCircle className="w-4 h-4" />
</Button>
@ -135,7 +145,7 @@ export function Notifications({
variant="ghost"
size="icon-sm"
onClick={() => onDismiss(notification.id)}
className="h-7 w-7"
className={`h-7 w-7 ${isDark ? "text-gray-300 hover:bg-gray-800" : ""}`}
>
<X className="w-4 h-4" />
</Button>

View File

@ -13,6 +13,7 @@ import {
X,
Heart,
} from "lucide-react";
import { useAppTheme } from "@/components/ThemeProvider";
const navItems = [
{ label: "Dashboard", icon: LayoutGrid, href: "/admin/dashboard" },
@ -23,6 +24,8 @@ export default function SideNav() {
const [open, setOpen] = useState(false);
const pathname = usePathname();
const router = useRouter();
const { theme } = useAppTheme();
const isDark = theme === "dark";
const getActiveIndex = () => {
return navItems.findIndex((item) => pathname?.includes(item.href)) ?? -1;
@ -43,12 +46,12 @@ export default function SideNav() {
return (
<>
{/* Mobile Top Bar */}
<div className="flex md:hidden items-center justify-between px-4 py-3 border-b border-gray-200 bg-white z-30 fixed top-0 left-0 right-0">
<div className={`flex md:hidden items-center justify-between px-4 py-3 border-b z-30 fixed top-0 left-0 right-0 ${isDark ? "bg-gray-900 border-gray-800" : "bg-white border-gray-200"}`}>
<Link href="/" className="flex items-center gap-3">
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-linear-to-r from-rose-100 to-pink-100">
<Heart className="w-5 h-5 text-rose-600" fill="currentColor" />
<div className={`flex items-center justify-center w-8 h-8 rounded-lg ${isDark ? "bg-gray-800" : "bg-linear-to-r from-rose-100 to-pink-100"}`}>
<Heart className={`w-5 h-5 ${isDark ? "text-rose-300" : "text-rose-600"}`} fill="currentColor" />
</div>
<span className="text-lg font-semibold text-gray-900">Attune Heart Therapy</span>
<span className={`text-lg font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>Attune Heart Therapy</span>
</Link>
<Button
variant="ghost"
@ -70,21 +73,21 @@ export default function SideNav() {
{/* Side Navigation */}
<aside
className={`fixed top-0 left-0 z-50 h-screen bg-white border-r border-gray-200 flex flex-col transition-transform duration-200 w-[85vw] max-w-[200px] min-w-[160px] md:translate-x-0 md:w-[200px] md:min-w-[200px] md:max-w-[200px] ${
className={`fixed top-0 left-0 z-50 h-screen flex flex-col transition-transform duration-200 w-[85vw] max-w-[200px] min-w-[160px] md:translate-x-0 md:w-[200px] md:min-w-[200px] md:max-w-[200px] ${isDark ? "bg-gray-900 border-r border-gray-800" : "bg-white border-r border-gray-200"} ${
open ? "translate-x-0" : "-translate-x-full"
} md:translate-x-0`}
>
{/* Logo Section */}
<div className="shrink-0 px-3 pb-4 flex flex-col gap-1 md:block mb-5 pt-16 md:pt-4">
<Link href="/" className="flex items-center gap-2 mb-1 ml-2 md:ml-3">
<div className="flex items-center justify-center w-8 h-8 rounded-lg bg-linear-to-r from-rose-100 to-pink-100">
<Heart className="w-5 h-5 text-rose-600" fill="currentColor" />
<div className={`flex items-center justify-center w-8 h-8 rounded-lg ${isDark ? "bg-gray-800" : "bg-linear-to-r from-rose-100 to-pink-100"}`}>
<Heart className={`w-5 h-5 ${isDark ? "text-rose-300" : "text-rose-600"}`} fill="currentColor" />
</div>
<span className="text-sm font-semibold text-gray-900">Attune Heart</span>
<span className={`text-sm font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>Attune Heart</span>
</Link>
</div>
<hr className="shrink-0 -mt-10 mb-4 mx-3 border-gray-200 md:block hidden" />
<hr className={`shrink-0 -mt-10 mb-4 mx-3 md:block hidden ${isDark ? "border-gray-800" : "border-gray-200"}`} />
{/* Navigation Items */}
<nav className="flex-1 overflow-y-auto flex flex-col gap-2 px-2 md:px-0">
@ -106,7 +109,9 @@ export default function SideNav() {
className={`group flex items-center gap-2 py-2.5 pl-3 md:pl-3 pr-3 md:pr-3 transition-colors duration-200 focus:outline-none w-[90%] md:w-[90%] ml-1 md:ml-2 cursor-pointer justify-start ${
isActive
? "bg-linear-to-r from-rose-500 to-pink-600 text-white border border-rose-500 rounded-[5px] shadow-sm"
: "bg-transparent text-gray-600 hover:bg-rose-50 hover:text-rose-600 rounded-lg"
: isDark
? "bg-transparent text-gray-300 hover:bg-gray-800 hover:text-rose-300 rounded-lg"
: "bg-transparent text-gray-600 hover:bg-rose-50 hover:text-rose-600 rounded-lg"
}`}
style={isActive ? { height: 40 } : {}}
>
@ -116,7 +121,9 @@ export default function SideNav() {
className={
isActive
? "text-white"
: "text-gray-700 group-hover:text-rose-600"
: isDark
? "text-gray-400 group-hover:text-rose-300"
: "text-gray-700 group-hover:text-rose-600"
}
/>
<span
@ -131,7 +138,7 @@ export default function SideNav() {
})}
{/* Bottom Actions */}
<div className="mt-auto pt-4 pb-4 border-t border-gray-200">
<div className={`mt-auto pt-4 pb-4 border-t ${isDark ? "border-gray-800" : "border-gray-200"}`}>
<div className="relative flex items-center w-full">
{pathname === "/admin/settings" && (
<span
@ -145,7 +152,9 @@ export default function SideNav() {
className={`group flex items-center gap-2 py-2.5 pl-3 md:pl-3 pr-3 md:pr-3 transition-colors duration-200 w-[90%] md:w-[90%] ml-1 md:ml-2 cursor-pointer justify-start rounded-lg ${
pathname === "/admin/settings"
? "bg-linear-to-r from-rose-500 to-pink-600 text-white border border-rose-500 rounded-[5px] shadow-sm"
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900"
: isDark
? "text-gray-300 hover:bg-gray-800 hover:text-rose-300"
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900"
}`}
style={pathname === "/admin/settings" ? { height: 40 } : {}}
>
@ -155,7 +164,9 @@ export default function SideNav() {
className={
pathname === "/admin/settings"
? "text-white"
: "text-gray-700 group-hover:text-gray-900"
: isDark
? "text-gray-400 group-hover:text-rose-300"
: "text-gray-700 group-hover:text-gray-900"
}
/>
<span className="font-light leading-none text-[12px]" style={{ fontWeight: 300 }}>
@ -169,9 +180,13 @@ export default function SideNav() {
setOpen(false);
router.push("/");
}}
className="group flex items-center gap-2 py-2.5 pl-3 md:pl-3 pr-3 md:pr-3 transition-colors duration-200 w-[90%] md:w-[90%] ml-1 md:ml-2 cursor-pointer justify-start text-gray-600 hover:bg-gray-50 hover:text-gray-900 rounded-lg"
className={`group flex items-center gap-2 py-2.5 pl-3 md:pl-3 pr-3 md:pr-3 transition-colors duration-200 w-[90%] md:w-[90%] ml-1 md:ml-2 cursor-pointer justify-start rounded-lg ${
isDark
? "text-gray-300 hover:bg-gray-800 hover:text-rose-300"
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900"
}`}
>
<LogOut size={18} strokeWidth={1.5} className="text-gray-700 group-hover:text-gray-900" />
<LogOut size={18} strokeWidth={1.5} className={isDark ? "text-gray-400 group-hover:text-rose-300" : "text-gray-700 group-hover:text-gray-900"} />
<span className="font-light leading-none text-[12px]" style={{ fontWeight: 300 }}>
Logout
</span>

View File

@ -9,6 +9,7 @@ import {
FileText,
MoreVertical,
} from "lucide-react";
import { useAppTheme } from "@/components/ThemeProvider";
interface User {
ID: number;
@ -54,6 +55,8 @@ export default function Booking() {
const [bookings, setBookings] = useState<Booking[]>([]);
const [loading, setLoading] = useState(true);
const [searchTerm, setSearchTerm] = useState("");
const { theme } = useAppTheme();
const isDark = theme === "dark";
useEffect(() => {
// Simulate API call
@ -127,7 +130,22 @@ export default function Booking() {
};
const getStatusColor = (status: string) => {
switch (status.toLowerCase()) {
const normalized = status.toLowerCase();
if (isDark) {
switch (normalized) {
case "scheduled":
return "bg-blue-500/20 text-blue-200";
case "completed":
return "bg-green-500/20 text-green-200";
case "cancelled":
return "bg-red-500/20 text-red-200";
case "pending":
return "bg-yellow-500/20 text-yellow-200";
default:
return "bg-gray-700 text-gray-200";
}
}
switch (normalized) {
case "scheduled":
return "bg-blue-100 text-blue-700";
case "completed":
@ -142,7 +160,20 @@ export default function Booking() {
};
const getPaymentStatusColor = (status: string) => {
switch (status.toLowerCase()) {
const normalized = status.toLowerCase();
if (isDark) {
switch (normalized) {
case "paid":
return "bg-green-500/20 text-green-200";
case "pending":
return "bg-yellow-500/20 text-yellow-200";
case "failed":
return "bg-red-500/20 text-red-200";
default:
return "bg-gray-700 text-gray-200";
}
}
switch (normalized) {
case "paid":
return "bg-green-100 text-green-700";
case "pending":
@ -166,102 +197,104 @@ export default function Booking() {
);
return (
<div className="min-h-screen bg-gray-50">
<div className={`min-h-screen ${isDark ? "bg-gray-900" : "bg-gray-50"}`}>
{/* Main Content */}
<main className="p-3 sm:p-4 md:p-6 lg:p-8">
{/* Page Header */}
<div className="mb-4 sm:mb-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-4">
<div>
<h1 className="text-xl sm:text-2xl font-semibold text-gray-900 mb-1">
<h1 className={`text-xl sm:text-2xl font-semibold mb-1 ${isDark ? "text-white" : "text-gray-900"}`}>
Bookings
</h1>
<p className="text-xs sm:text-sm text-gray-500">
<p className={`text-xs sm:text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Manage and view all appointment bookings
</p>
</div>
<button className="w-full sm:w-auto px-3 sm:px-4 py-2 bg-gray-900 text-white rounded-lg text-xs sm:text-sm font-medium hover:bg-gray-800 transition-colors">
<button className={`w-full sm:w-auto px-3 sm:px-4 py-2 rounded-lg text-xs sm:text-sm font-medium transition-colors ${
isDark ? "bg-rose-500 text-white hover:bg-rose-600" : "bg-gray-900 text-white hover:bg-gray-800"
}`}>
+ New Booking
</button>
</div>
{loading ? (
<div className="flex items-center justify-center py-12">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-400"></div>
<div className={`animate-spin rounded-full h-8 w-8 border-b-2 ${isDark ? "border-gray-600" : "border-gray-400"}`}></div>
</div>
) : filteredBookings.length === 0 ? (
<div className="bg-white rounded-lg border border-gray-200 p-12 text-center">
<Calendar className="w-12 h-12 text-gray-400 mx-auto mb-4" />
<p className="text-gray-600 font-medium mb-1">No bookings found</p>
<p className="text-sm text-gray-500">
<div className={`rounded-lg border p-12 text-center ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}>
<Calendar className={`w-12 h-12 mx-auto mb-4 ${isDark ? "text-gray-500" : "text-gray-400"}`} />
<p className={`font-medium mb-1 ${isDark ? "text-gray-200" : "text-gray-600"}`}>No bookings found</p>
<p className={`text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`}>
{searchTerm
? "Try adjusting your search terms"
: "Create a new booking to get started"}
</p>
</div>
) : (
<div className="bg-white rounded-lg border border-gray-200 overflow-hidden">
<div className={`rounded-lg border overflow-hidden ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}>
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-gray-50 border-b border-gray-200">
<thead className={`${isDark ? "bg-gray-800 border-b border-gray-700" : "bg-gray-50 border-b border-gray-200"}`}>
<tr>
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Patient
</th>
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden md:table-cell">
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider hidden md:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Date & Time
</th>
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden lg:table-cell">
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider hidden lg:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Duration
</th>
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Status
</th>
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden lg:table-cell">
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider hidden lg:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Payment
</th>
<th className="px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider hidden xl:table-cell">
<th className={`px-3 sm:px-4 md:px-6 py-3 text-left text-xs font-medium uppercase tracking-wider hidden xl:table-cell ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Amount
</th>
<th className="px-3 sm:px-4 md:px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
<th className={`px-3 sm:px-4 md:px-6 py-3 text-right text-xs font-medium uppercase tracking-wider ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Actions
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
<tbody className={`${isDark ? "bg-gray-800 divide-gray-700" : "bg-white divide-gray-200"}`}>
{filteredBookings.map((booking) => (
<tr
key={booking.ID}
className="hover:bg-gray-50 transition-colors"
className={`transition-colors ${isDark ? "hover:bg-gray-700" : "hover:bg-gray-50"}`}
>
<td className="px-3 sm:px-4 md:px-6 py-4">
<div className="flex items-center">
<div className="shrink-0 h-8 w-8 sm:h-10 sm:w-10 rounded-full bg-gray-100 flex items-center justify-center">
<User className="w-4 h-4 sm:w-5 sm:h-5 text-gray-600" />
<div className={`shrink-0 h-8 w-8 sm:h-10 sm:w-10 rounded-full flex items-center justify-center ${isDark ? "bg-gray-700" : "bg-gray-100"}`}>
<User className={`w-4 h-4 sm:w-5 sm:h-5 ${isDark ? "text-gray-200" : "text-gray-600"}`} />
</div>
<div className="ml-2 sm:ml-4 min-w-0">
<div className="text-xs sm:text-sm font-medium text-gray-900 truncate">
<div className={`text-xs sm:text-sm font-medium truncate ${isDark ? "text-white" : "text-gray-900"}`}>
{booking.user.first_name} {booking.user.last_name}
</div>
<div className="text-xs sm:text-sm text-gray-500 truncate hidden sm:block">
<div className={`text-xs sm:text-sm truncate hidden sm:block ${isDark ? "text-gray-400" : "text-gray-500"}`}>
{booking.user.email}
</div>
<div className="text-xs text-gray-500 sm:hidden mt-0.5">
<div className={`text-xs sm:hidden mt-0.5 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
{formatDate(booking.scheduled_at)}
</div>
</div>
</div>
</td>
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap hidden md:table-cell">
<div className="text-xs sm:text-sm text-gray-900">
<div className={`text-xs sm:text-sm ${isDark ? "text-white" : "text-gray-900"}`}>
{formatDate(booking.scheduled_at)}
</div>
<div className="text-xs sm:text-sm text-gray-500 flex items-center gap-1">
<div className={`text-xs sm:text-sm flex items-center gap-1 ${isDark ? "text-gray-400" : "text-gray-500"}`}>
<Clock className="w-3 h-3" />
{formatTime(booking.scheduled_at)}
</div>
</td>
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-xs sm:text-sm text-gray-900 hidden lg:table-cell">
<td className={`px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-xs sm:text-sm hidden lg:table-cell ${isDark ? "text-white" : "text-gray-900"}`}>
{booking.duration} min
</td>
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap">
@ -282,7 +315,7 @@ export default function Booking() {
{booking.payment_status}
</span>
</td>
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-xs sm:text-sm font-medium text-gray-900 hidden xl:table-cell">
<td className={`px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-xs sm:text-sm font-medium hidden xl:table-cell ${isDark ? "text-white" : "text-gray-900"}`}>
${booking.amount}
</td>
<td className="px-3 sm:px-4 md:px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
@ -292,7 +325,7 @@ export default function Booking() {
href={booking.jitsi_room_url}
target="_blank"
rel="noopener noreferrer"
className="p-1.5 sm:p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
className={`p-1.5 sm:p-2 rounded-lg transition-colors ${isDark ? "text-gray-300 hover:text-white hover:bg-gray-700" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`}
title="Join Meeting"
>
<Video className="w-4 h-4" />
@ -300,13 +333,13 @@ export default function Booking() {
)}
{booking.notes && (
<button
className="p-1.5 sm:p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
className={`p-1.5 sm:p-2 rounded-lg transition-colors ${isDark ? "text-gray-300 hover:text-white hover:bg-gray-700" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`}
title="View Notes"
>
<FileText className="w-4 h-4" />
</button>
)}
<button className="p-1.5 sm:p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors">
<button className={`p-1.5 sm:p-2 rounded-lg transition-colors ${isDark ? "text-gray-300 hover:text-white hover:bg-gray-700" : "text-gray-600 hover:text-gray-900 hover:bg-gray-100"}`}>
<MoreVertical className="w-4 h-4" />
</button>
</div>

View File

@ -19,6 +19,7 @@ import {
ArrowUpRight,
ArrowDownRight,
} from "lucide-react";
import { useAppTheme } from "@/components/ThemeProvider";
interface DashboardStats {
total_users: number;
@ -35,6 +36,8 @@ export default function Dashboard() {
const [stats, setStats] = useState<DashboardStats | null>(null);
const [loading, setLoading] = useState(true);
const [timePeriod, setTimePeriod] = useState<string>("last_month");
const { theme } = useAppTheme();
const isDark = theme === "dark";
useEffect(() => {
// Simulate API call
@ -122,36 +125,43 @@ export default function Dashboard() {
];
const getTrendClasses = (trendUp: boolean) => {
if (isDark) {
return trendUp ? "bg-green-500/20 text-green-200" : "bg-red-500/20 text-red-200";
}
return trendUp ? "bg-green-50 text-green-700" : "bg-red-50 text-red-700";
};
return (
<div className="min-h-screen bg-gray-50">
<div className={`min-h-screen ${isDark ? "bg-gray-900" : "bg-gray-50"}`}>
{/* Main Content */}
<main className="p-4 sm:p-6 lg:p-8 space-y-6">
{/* Welcome Section */}
<div className="flex items-center justify-between mb-6">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
<div>
<h1 className="text-2xl font-semibold text-gray-900 mb-1">
<h1 className={`text-2xl font-semibold mb-1 ${isDark ? "text-white" : "text-gray-900"}`}>
Welcome Back! Hammond
</h1>
<p className="text-sm text-gray-500">
<p className={`text-sm ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Here's an overview of your practice today
</p>
</div>
<Select value={timePeriod} onValueChange={setTimePeriod}>
<SelectTrigger className="w-[180px] cursor-pointer">
<SelectTrigger className={`w-full sm:w-[200px] cursor-pointer ${isDark ? "bg-gray-800 border-gray-700 text-gray-100" : "bg-white border-gray-200 text-gray-900"}`}>
<SelectValue placeholder="Select period" />
</SelectTrigger>
<SelectContent className="bg-white cursor-pointer">
<SelectItem value="last_week">Last Week</SelectItem>
<SelectItem value="last_month">Last Month</SelectItem>
<SelectItem value="last_year">Last Year</SelectItem>
<SelectContent className={`${isDark ? "bg-gray-800 border-gray-700 text-gray-100" : "bg-white border-gray-200 text-gray-900"} cursor-pointer`}>
<SelectItem className={isDark ? "focus:bg-gray-700" : ""} value="last_week">Last Week</SelectItem>
<SelectItem className={isDark ? "focus:bg-gray-700" : ""} value="last_month">Last Month</SelectItem>
<SelectItem className={isDark ? "focus:bg-gray-700" : ""} value="last_year">Last Year</SelectItem>
</SelectContent>
</Select>
</div>
{loading ? (
<div className="flex items-center justify-center py-12">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-400"></div>
<div className={`animate-spin rounded-full h-8 w-8 border-b-2 ${isDark ? "border-gray-600" : "border-gray-400"}`}></div>
</div>
) : (
<>
@ -162,17 +172,13 @@ export default function Dashboard() {
return (
<div
key={index}
className="bg-white rounded-lg border border-gray-200 p-4 sm:p-5 md:p-6 hover:shadow-md transition-shadow"
className={`rounded-lg border p-4 sm:p-5 md:p-6 hover:shadow-md transition-shadow ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}
>
<div className="flex items-start justify-between mb-3 sm:mb-4">
<div className="p-2 sm:p-2.5 rounded-lg bg-gray-50">
<Icon className="w-4 h-4 sm:w-5 sm:h-5 text-gray-600" />
<div className={`p-2 sm:p-2.5 rounded-lg ${isDark ? "bg-gray-700" : "bg-gray-50"}`}>
<Icon className={`w-4 h-4 sm:w-5 sm:h-5 ${isDark ? "text-gray-200" : "text-gray-600"}`} />
</div>
<div className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium ${
card.trendUp
? "bg-green-50 text-green-700"
: "bg-red-50 text-red-700"
}`}>
<div className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium ${getTrendClasses(card.trendUp)}`}>
{card.trendUp ? (
<ArrowUpRight className="w-3 h-3" />
) : (
@ -183,13 +189,13 @@ export default function Dashboard() {
</div>
<div>
<h3 className="text-xs font-medium text-rose-600 mb-1 sm:mb-2 uppercase tracking-wider">
<h3 className={`text-xs font-medium mb-1 sm:mb-2 uppercase tracking-wider ${isDark ? "text-rose-300" : "text-rose-600"}`}>
{card.title}
</h3>
<p className="text-xl sm:text-2xl font-bold text-gray-900 mb-1">
<p className={`text-xl sm:text-2xl font-bold mb-1 ${isDark ? "text-white" : "text-gray-900"}`}>
{card.value}
</p>
<p className="text-xs text-gray-500">
<p className={`text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`}>
vs last month
</p>
</div>

View File

@ -2,6 +2,7 @@
import { useState } from "react";
import { Bell } from "lucide-react";
import { useAppTheme } from "@/components/ThemeProvider";
interface Notification {
id: string;
@ -51,16 +52,18 @@ export default function NotificationsPage() {
]);
const unreadCount = notifications.filter((n) => !n.read).length;
const { theme } = useAppTheme();
const isDark = theme === "dark";
return (
<div className="min-h-screen bg-gray-50">
<div className={`min-h-screen ${isDark ? "bg-gray-900" : "bg-gray-50"}`}>
{/* Main Content */}
<main className="p-3 sm:p-4 md:p-6 lg:p-8">
{/* Page Header */}
<div className="mb-4 sm:mb-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-4">
<div className="flex items-center gap-3">
<Bell className="w-5 h-5 sm:w-6 sm:h-6 text-gray-900" />
<h1 className="text-xl sm:text-2xl font-semibold text-gray-900">
<Bell className={`w-5 h-5 sm:w-6 sm:h-6 ${isDark ? "text-white" : "text-gray-900"}`} />
<h1 className={`text-xl sm:text-2xl font-semibold ${isDark ? "text-white" : "text-gray-900"}`}>
Notifications
</h1>
{unreadCount > 0 && (
@ -72,26 +75,30 @@ export default function NotificationsPage() {
</div>
{/* Notifications List */}
<div className="bg-white rounded-lg border border-gray-200 overflow-hidden">
<div className={`rounded-lg border overflow-hidden ${isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}`}>
{notifications.length === 0 ? (
<div className="p-8 sm:p-12 text-center text-gray-500">
<Bell className="w-12 h-12 mx-auto mb-2 text-gray-300" />
<div className={`p-8 sm:p-12 text-center ${isDark ? "text-gray-400" : "text-gray-500"}`}>
<Bell className={`w-12 h-12 mx-auto mb-2 ${isDark ? "text-gray-600" : "text-gray-300"}`} />
<p className="text-sm">No notifications</p>
</div>
) : (
<div className="divide-y">
<div className={`divide-y ${isDark ? "divide-gray-700" : ""}`}>
{notifications.map((notification) => {
return (
<div
key={notification.id}
className={`p-4 sm:p-6 hover:bg-gray-50 transition-colors cursor-pointer ${
!notification.read ? "bg-rose-50/50" : ""
className={`p-4 sm:p-6 transition-colors cursor-pointer ${
!notification.read
? isDark
? "bg-rose-500/10"
: "bg-rose-50/50"
: ""
}`}
>
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-2">
<p
className={`text-sm sm:text-base font-medium text-gray-900 ${
className={`text-sm sm:text-base font-medium ${isDark ? "text-white" : "text-gray-900"} ${
!notification.read ? "font-semibold" : ""
}`}
>
@ -101,10 +108,10 @@ export default function NotificationsPage() {
<span className="shrink-0 w-2 h-2 bg-green-500 rounded-full mt-1"></span>
)}
</div>
<p className="text-sm text-gray-600 mt-1">
<p className={`text-sm mt-1 ${isDark ? "text-gray-400" : "text-gray-600"}`}>
{notification.message}
</p>
<p className="text-xs text-gray-400 mt-1">
<p className={`text-xs mt-1 ${isDark ? "text-gray-500" : "text-gray-400"}`}>
{notification.time}
</p>
</div>

View File

@ -15,6 +15,7 @@ import {
EyeOff,
} from "lucide-react";
import Link from "next/link";
import { useAppTheme } from "@/components/ThemeProvider";
export default function AdminSettingsPage() {
const [loading, setLoading] = useState(false);
@ -33,6 +34,8 @@ export default function AdminSettingsPage() {
new: false,
confirm: false,
});
const { theme } = useAppTheme();
const isDark = theme === "dark";
const handleInputChange = (field: string, value: string) => {
setFormData((prev) => ({
@ -88,22 +91,22 @@ export default function AdminSettingsPage() {
};
return (
<div className="min-h-screen bg-gray-50">
<div className={`min-h-screen ${isDark ? "bg-gray-900" : "bg-gray-50"}`}>
{/* Main Content */}
<main className="p-4 sm:p-6 lg:p-8 space-y-6">
{/* Header */}
<div className="flex items-center justify-between mb-6">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
<div className="flex items-center gap-4">
<Link href="/admin/dashboard">
<Button variant="ghost" size="icon" className="hover:bg-gray-100">
<Button variant="ghost" size="icon" className={isDark ? "hover:bg-gray-800 text-gray-300" : "hover:bg-gray-100"}>
<ArrowLeft className="w-4 h-4" />
</Button>
</Link>
<div>
<h1 className="text-2xl font-semibold text-gray-900 mb-1">
<h1 className={`text-2xl font-semibold mb-1 ${isDark ? "text-white" : "text-gray-900"}`}>
Settings
</h1>
<p className="text-sm text-gray-600">
<p className={`text-sm ${isDark ? "text-gray-400" : "text-gray-600"}`}>
Manage your account settings and practice information
</p>
</div>
@ -111,7 +114,7 @@ export default function AdminSettingsPage() {
<Button
onClick={handleSave}
disabled={loading}
className="bg-linear-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white"
className="w-full sm:w-auto bg-linear-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white"
>
{loading ? (
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
@ -125,60 +128,60 @@ export default function AdminSettingsPage() {
<div className="max-w-4xl mx-auto">
<div className="space-y-6">
{/* Profile Information */}
<Card className="bg-white border-gray-200">
<Card className={isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}>
<CardHeader>
<div className="flex items-center gap-2">
<User className="w-5 h-5 text-gray-600" />
<CardTitle className="text-gray-900">Profile Information</CardTitle>
<User className={`w-5 h-5 ${isDark ? "text-gray-300" : "text-gray-600"}`} />
<CardTitle className={isDark ? "text-white" : "text-gray-900"}>Profile Information</CardTitle>
</div>
<CardDescription className="text-gray-600">
<CardDescription className={isDark ? "text-gray-400" : "text-gray-600"}>
Update your personal information and contact details
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">
<label className={`text-sm font-medium ${isDark ? "text-gray-300" : "text-gray-700"}`}>
Full Name
</label>
<div className="relative">
<User className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
<User className={`absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 ${isDark ? "text-gray-500" : "text-gray-400"}`} />
<Input
type="text"
value={formData.fullName}
onChange={(e) => handleInputChange("fullName", e.target.value)}
className="pl-10"
className={`pl-10 ${isDark ? "bg-gray-700 border-gray-600 text-white placeholder:text-gray-400" : ""}`}
placeholder="Enter your full name"
/>
</div>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">
<label className={`text-sm font-medium ${isDark ? "text-gray-300" : "text-gray-700"}`}>
Email Address
</label>
<div className="relative">
<Mail className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
<Mail className={`absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 ${isDark ? "text-gray-500" : "text-gray-400"}`} />
<Input
type="email"
value={formData.email}
onChange={(e) => handleInputChange("email", e.target.value)}
className="pl-10"
className={`pl-10 ${isDark ? "bg-gray-700 border-gray-600 text-white placeholder:text-gray-400" : ""}`}
placeholder="Enter your email"
/>
</div>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">
<label className={`text-sm font-medium ${isDark ? "text-gray-300" : "text-gray-700"}`}>
Phone Number
</label>
<div className="relative">
<Phone className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
<Phone className={`absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 ${isDark ? "text-gray-500" : "text-gray-400"}`} />
<Input
type="tel"
value={formData.phone}
onChange={(e) => handleInputChange("phone", e.target.value)}
className="pl-10"
className={`pl-10 ${isDark ? "bg-gray-700 border-gray-600 text-white placeholder:text-gray-400" : ""}`}
placeholder="Enter your phone number"
/>
</div>
@ -187,34 +190,34 @@ export default function AdminSettingsPage() {
</Card>
{/* Change Password */}
<Card className="bg-white border-gray-200">
<Card className={isDark ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"}>
<CardHeader>
<div className="flex items-center gap-2">
<Lock className="w-5 h-5 text-gray-600" />
<CardTitle className="text-gray-900">Change Password</CardTitle>
<Lock className={`w-5 h-5 ${isDark ? "text-gray-300" : "text-gray-600"}`} />
<CardTitle className={isDark ? "text-white" : "text-gray-900"}>Change Password</CardTitle>
</div>
<CardDescription className="text-gray-600">
<CardDescription className={isDark ? "text-gray-400" : "text-gray-600"}>
Update your password to keep your account secure
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">
<label className={`text-sm font-medium ${isDark ? "text-gray-300" : "text-gray-700"}`}>
Current Password
</label>
<div className="relative">
<Lock className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
<Lock className={`absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 ${isDark ? "text-gray-500" : "text-gray-400"}`} />
<Input
type={showPasswords.current ? "text" : "password"}
value={passwordData.currentPassword}
onChange={(e) => handlePasswordChange("currentPassword", e.target.value)}
className="pl-10 pr-10"
className={`pl-10 pr-10 ${isDark ? "bg-gray-700 border-gray-600 text-white placeholder:text-gray-400" : ""}`}
placeholder="Enter your current password"
/>
<button
type="button"
onClick={() => togglePasswordVisibility("current")}
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
className={`absolute right-3 top-1/2 transform -translate-y-1/2 ${isDark ? "text-gray-400 hover:text-gray-300" : "text-gray-400 hover:text-gray-600"}`}
>
{showPasswords.current ? (
<EyeOff className="w-4 h-4" />
@ -226,22 +229,22 @@ export default function AdminSettingsPage() {
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">
<label className={`text-sm font-medium ${isDark ? "text-gray-300" : "text-gray-700"}`}>
New Password
</label>
<div className="relative">
<Lock className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
<Lock className={`absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 ${isDark ? "text-gray-500" : "text-gray-400"}`} />
<Input
type={showPasswords.new ? "text" : "password"}
value={passwordData.newPassword}
onChange={(e) => handlePasswordChange("newPassword", e.target.value)}
className="pl-10 pr-10"
className={`pl-10 pr-10 ${isDark ? "bg-gray-700 border-gray-600 text-white placeholder:text-gray-400" : ""}`}
placeholder="Enter your new password"
/>
<button
type="button"
onClick={() => togglePasswordVisibility("new")}
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
className={`absolute right-3 top-1/2 transform -translate-y-1/2 ${isDark ? "text-gray-400 hover:text-gray-300" : "text-gray-400 hover:text-gray-600"}`}
>
{showPasswords.new ? (
<EyeOff className="w-4 h-4" />
@ -250,28 +253,28 @@ export default function AdminSettingsPage() {
)}
</button>
</div>
<p className="text-xs text-gray-500">
<p className={`text-xs ${isDark ? "text-gray-400" : "text-gray-500"}`}>
Password must be at least 8 characters long
</p>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-gray-700">
<label className={`text-sm font-medium ${isDark ? "text-gray-300" : "text-gray-700"}`}>
Confirm New Password
</label>
<div className="relative">
<Lock className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
<Lock className={`absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 ${isDark ? "text-gray-500" : "text-gray-400"}`} />
<Input
type={showPasswords.confirm ? "text" : "password"}
value={passwordData.confirmPassword}
onChange={(e) => handlePasswordChange("confirmPassword", e.target.value)}
className="pl-10 pr-10"
className={`pl-10 pr-10 ${isDark ? "bg-gray-700 border-gray-600 text-white placeholder:text-gray-400" : ""}`}
placeholder="Confirm your new password"
/>
<button
type="button"
onClick={() => togglePasswordVisibility("confirm")}
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
className={`absolute right-3 top-1/2 transform -translate-y-1/2 ${isDark ? "text-gray-400 hover:text-gray-300" : "text-gray-400 hover:text-gray-600"}`}
>
{showPasswords.confirm ? (
<EyeOff className="w-4 h-4" />

View File

@ -98,7 +98,7 @@ export default function SettingsPage() {
{/* Main Content */}
<main className="container mx-auto px-4 sm:px-6 lg:px-8 space-y-6 pt-20 sm:pt-24 pb-8">
{/* Header */}
<div className="flex items-center justify-between mb-6">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
<div className="flex items-center gap-4">
<Link href="/user/dashboard">
<Button variant="ghost" size="icon" className={isDark ? 'hover:bg-gray-800 text-gray-300' : 'hover:bg-gray-100'}>
@ -117,7 +117,7 @@ export default function SettingsPage() {
<Button
onClick={handleSave}
disabled={loading}
className="bg-gradient-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white"
className="w-full sm:w-auto bg-gradient-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white"
>
{loading ? (
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>