526 lines
23 KiB
TypeScript
526 lines
23 KiB
TypeScript
'use client';
|
|
|
|
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from '@/components/ui/dropdown-menu';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@/components/ui/dialog';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Button } from '@/components/ui/button';
|
|
import { User } from '@/lib/session';
|
|
import { fetchPreferences, fetchReminderSettings, saveReminderSettings, ReminderSettings, UserPreferences } from '@/lib/storage';
|
|
import { useNotifications } from '@/hooks/useNotifications';
|
|
import { useEffect, useState } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { Cigarette, Leaf, LogOut, Home, ChevronDown, Sun, Moon, Bell, BellOff, BellRing, Menu, Sparkles, Link as LinkIcon } from 'lucide-react';
|
|
import { useTheme } from '@/lib/theme-context';
|
|
import { InstallAppButton } from './InstallAppButton';
|
|
import { cn } from '@/lib/utils';
|
|
import { SideMenu } from './SideMenu';
|
|
|
|
interface UserHeaderProps {
|
|
user: User;
|
|
preferences?: UserPreferences | null;
|
|
}
|
|
|
|
interface HourlyTimePickerProps {
|
|
value: string;
|
|
onChange: (time: string) => void;
|
|
}
|
|
|
|
function HourlyTimePicker({ value, onChange }: HourlyTimePickerProps) {
|
|
const [parsedHours, parsedMinutes] = value.split(':').map(Number);
|
|
const currentAmpm = parsedHours >= 12 ? 'PM' : 'AM';
|
|
const currentHour12 = parsedHours % 12 || 12;
|
|
const hourString = currentHour12.toString().padStart(2, '0');
|
|
const minuteString = parsedMinutes.toString().padStart(2, '0');
|
|
|
|
const updateTime = (newHourStr: string, newMinuteStr: string, newAmpmStr: string) => {
|
|
let h = parseInt(newHourStr);
|
|
if (newAmpmStr === 'PM' && h !== 12) h += 12;
|
|
if (newAmpmStr === 'AM' && h === 12) h = 0;
|
|
|
|
onChange(`${h.toString().padStart(2, '0')}:${newMinuteStr}`);
|
|
};
|
|
|
|
const hoursOptions = Array.from({ length: 12 }, (_, i) => (i + 1).toString().padStart(2, '0'));
|
|
const minutesOptions = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0'));
|
|
|
|
return (
|
|
<div className="flex gap-2 w-full">
|
|
{/* Hour Select */}
|
|
<div className="flex-1">
|
|
<Select
|
|
value={hourString}
|
|
onValueChange={(val) => updateTime(val, minuteString, currentAmpm)}
|
|
>
|
|
<SelectTrigger className="w-full">
|
|
<SelectValue placeholder="Hour" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{hoursOptions.map((h) => (
|
|
<SelectItem key={h} value={h}>
|
|
{h}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* Minute Select */}
|
|
<div className="flex-1">
|
|
<Select
|
|
value={minuteString}
|
|
onValueChange={(val) => updateTime(hourString, val, currentAmpm)}
|
|
>
|
|
<SelectTrigger className="w-full">
|
|
<SelectValue placeholder="Min" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{minutesOptions.map((m) => (
|
|
<SelectItem key={m} value={m}>
|
|
{m}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* AM/PM Select */}
|
|
<div className="w-24">
|
|
<Select
|
|
value={currentAmpm}
|
|
onValueChange={(val) => updateTime(hourString, minuteString, val)}
|
|
>
|
|
<SelectTrigger className="w-full">
|
|
<SelectValue placeholder="AM/PM" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="AM">AM</SelectItem>
|
|
<SelectItem value="PM">PM</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function UserHeader({ user, preferences }: UserHeaderProps) {
|
|
const [userName, setUserName] = useState<string | null>(null);
|
|
const [reminderSettings, setReminderSettings] = useState<ReminderSettings>({ enabled: false, reminderTime: '09:00', frequency: 'daily' });
|
|
const [showReminderDialog, setShowReminderDialog] = useState(false);
|
|
const [isSideMenuOpen, setIsSideMenuOpen] = useState(false);
|
|
const [localTime, setLocalTime] = useState('09:00');
|
|
const [localFrequency, setLocalFrequency] = useState<'daily' | 'hourly'>('daily');
|
|
const router = useRouter();
|
|
const { theme, toggleTheme } = useTheme();
|
|
const { isSupported, permission, requestPermission } = useNotifications(reminderSettings);
|
|
|
|
// Helper to parse time string
|
|
const [parsedHours, parsedMinutes] = reminderSettings.reminderTime.split(':').map(Number);
|
|
const currentAmpm = parsedHours >= 12 ? 'PM' : 'AM';
|
|
const currentHour12 = parsedHours % 12 || 12;
|
|
const hourString = currentHour12.toString().padStart(2, '0');
|
|
const minuteString = parsedMinutes.toString().padStart(2, '0');
|
|
|
|
const updateTime = async (newHourStr: string, newMinuteStr: string, newAmpmStr: string) => {
|
|
let h = parseInt(newHourStr);
|
|
if (newAmpmStr === 'PM' && h !== 12) h += 12;
|
|
if (newAmpmStr === 'AM' && h === 12) h = 0;
|
|
|
|
const timeString = `${h.toString().padStart(2, '0')}:${newMinuteStr}`;
|
|
setLocalTime(timeString);
|
|
|
|
const newSettings = { ...reminderSettings, reminderTime: timeString };
|
|
setReminderSettings(newSettings);
|
|
await saveReminderSettings(newSettings);
|
|
};
|
|
|
|
// Generate options
|
|
const hoursOptions = Array.from({ length: 12 }, (_, i) => (i + 1).toString().padStart(2, '0'));
|
|
const minutesOptions = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0'));
|
|
|
|
useEffect(() => {
|
|
const loadData = async () => {
|
|
const [prefs, reminders] = await Promise.all([
|
|
preferences ? Promise.resolve(preferences) : fetchPreferences(),
|
|
fetchReminderSettings(),
|
|
]);
|
|
|
|
if (prefs) {
|
|
setUserName(prefs.userName);
|
|
}
|
|
|
|
const detectedTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
let settingsToUse = reminders;
|
|
|
|
if (reminders.timezone !== detectedTimezone) {
|
|
settingsToUse = { ...reminders, timezone: detectedTimezone };
|
|
await saveReminderSettings(settingsToUse);
|
|
}
|
|
|
|
setReminderSettings(settingsToUse);
|
|
setLocalTime(settingsToUse.reminderTime);
|
|
setLocalFrequency(settingsToUse.frequency || 'daily');
|
|
};
|
|
loadData();
|
|
}, [preferences]);
|
|
|
|
const handleToggleReminders = async () => {
|
|
if (!reminderSettings.enabled) {
|
|
const result = await requestPermission();
|
|
if (result !== 'granted') return;
|
|
}
|
|
const newSettings = { ...reminderSettings, enabled: !reminderSettings.enabled };
|
|
setReminderSettings(newSettings);
|
|
await saveReminderSettings(newSettings);
|
|
};
|
|
|
|
const handleFrequencyChange = async (newFrequency: 'daily' | 'hourly') => {
|
|
setLocalFrequency(newFrequency);
|
|
const newSettings = { ...reminderSettings, frequency: newFrequency };
|
|
setReminderSettings(newSettings);
|
|
await saveReminderSettings(newSettings);
|
|
};
|
|
|
|
const initials = [user.firstName?.[0], user.lastName?.[0]]
|
|
.filter(Boolean)
|
|
.join('')
|
|
.toUpperCase() || user.email[0].toUpperCase();
|
|
|
|
const handleNavigate = (path: string) => {
|
|
router.push(path);
|
|
setIsSideMenuOpen(false);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<header className="sticky top-0 z-50 transition-colors duration-300 relative" style={{
|
|
background: theme === 'light'
|
|
? 'rgba(255, 255, 255, 0.98)'
|
|
: 'rgba(10, 10, 20, 0.99)',
|
|
backdropFilter: 'blur(16px)',
|
|
borderBottom: theme === 'light' ? '1px solid rgba(0,0,0,0.05)' : '1px solid rgba(255,255,255,0.08)'
|
|
}}>
|
|
{/* Cloudy/Foggy effect overlay - removed mix-blend-overlay for visibility */}
|
|
<div className="absolute inset-0 pointer-events-none select-none overflow-hidden invert dark:invert-0 transition-all duration-300">
|
|
<div className="absolute inset-0 fog-layer-1 opacity-35 dark:opacity-25" />
|
|
<div className="absolute inset-0 fog-layer-2 opacity-25 dark:opacity-15" />
|
|
</div>
|
|
|
|
<div className="container mx-auto px-4 h-16 sm:h-20 flex items-center justify-between relative z-50">
|
|
{/* LEFT: User Profile / Side Menu Trigger */}
|
|
<div className="flex-1 flex justify-start">
|
|
<button
|
|
onClick={() => setIsSideMenuOpen(true)}
|
|
className="group relative flex items-center gap-2 p-1.5 pr-3 rounded-full transition-all hover:bg-black/5 dark:hover:bg-white/5 active:scale-95 border border-transparent hover:border-primary/10"
|
|
>
|
|
<div className="relative">
|
|
<Avatar className="h-9 w-9 sm:h-10 sm:w-10 ring-2 ring-primary/20 transition-all group-hover:ring-primary/50 shadow-sm">
|
|
<AvatarImage src={user.profilePictureUrl ?? undefined} alt={userName || 'User'} />
|
|
<AvatarFallback className="bg-gradient-to-br from-indigo-500 to-purple-500 text-white font-bold">{initials}</AvatarFallback>
|
|
</Avatar>
|
|
<div className="absolute -bottom-1 -right-1 bg-white dark:bg-slate-900 rounded-full p-0.5 shadow-sm border border-border">
|
|
<Menu className="h-3 w-3 text-primary" />
|
|
</div>
|
|
</div>
|
|
<div className="hidden sm:block text-left">
|
|
<div className="text-[10px] font-bold uppercase tracking-widest opacity-50 leading-none">Menu</div>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
{/* CENTER: Title and Welcome Message */}
|
|
<div className="flex-[2] flex flex-col items-center justify-center text-center">
|
|
<h1
|
|
className={cn(
|
|
"text-xl sm:text-2xl font-bold cursor-pointer transition-all duration-300 hover:scale-105 tracking-tight leading-tight bg-clip-text text-transparent w-fit mx-auto",
|
|
theme === 'light'
|
|
? 'bg-gradient-to-br from-[#4f46e5] to-[#7c3aed]'
|
|
: 'bg-gradient-to-br from-[#a78bfa] to-[#f472b6]'
|
|
)}
|
|
onClick={() => handleNavigate('/')}
|
|
style={{
|
|
filter: theme === 'dark' ? 'drop-shadow(0 0 10px rgba(167, 139, 250, 0.3))' : 'none'
|
|
}}
|
|
>
|
|
QuitTraq
|
|
</h1>
|
|
{userName && (
|
|
<p className="text-[10px] sm:text-xs font-medium text-foreground/60 tracking-wide mt-0.5 whitespace-nowrap overflow-hidden">
|
|
Welcome {userName}, you got this!
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
{/* RIGHT: Action Buttons */}
|
|
<div className="flex-1 flex items-center justify-end gap-1.5 sm:gap-3">
|
|
<button
|
|
onClick={() => setShowReminderDialog(true)}
|
|
className={cn(
|
|
"p-2 sm:p-2.5 rounded-full transition-all duration-300 active:scale-90 shadow-sm",
|
|
reminderSettings.enabled
|
|
? 'bg-indigo-500/15 text-indigo-400 border border-indigo-500/20'
|
|
: 'bg-muted border border-transparent text-muted-foreground'
|
|
)}
|
|
>
|
|
{reminderSettings.enabled ? (
|
|
<BellRing className="h-4.5 w-4.5 sm:h-5 sm:w-5" />
|
|
) : (
|
|
<Bell className="h-4.5 w-4.5 sm:h-5 sm:w-5" />
|
|
)}
|
|
</button>
|
|
<InstallAppButton />
|
|
<button
|
|
onClick={toggleTheme}
|
|
className="p-2 sm:p-2.5 rounded-full bg-muted border border-transparent hover:bg-muted/80 transition-all active:scale-90"
|
|
>
|
|
{theme === 'dark' ? (
|
|
<Moon className="h-4.5 w-4.5 sm:h-5 sm:w-5 text-blue-300" />
|
|
) : (
|
|
<Sun className="h-4.5 w-4.5 sm:h-5 sm:w-5 text-yellow-500" />
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Side Menu Integration */}
|
|
<SideMenu
|
|
isOpen={isSideMenuOpen}
|
|
onClose={() => setIsSideMenuOpen(false)}
|
|
user={user}
|
|
userName={userName}
|
|
/>
|
|
|
|
{/* Reminder Settings Dialog */}
|
|
<Dialog open={showReminderDialog} onOpenChange={setShowReminderDialog}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-2 font-bold tracking-tight">
|
|
<Bell className="h-5 w-5 text-indigo-400" />
|
|
Notification Settings
|
|
</DialogTitle>
|
|
</DialogHeader>
|
|
|
|
<div className="space-y-4 py-4 px-1">
|
|
{/* Enable/Disable Toggle */}
|
|
<div className={cn(
|
|
"flex items-center justify-between p-4 rounded-2xl border transition-all",
|
|
theme === 'light' ? "bg-slate-50 border-slate-100" : "bg-white/5 border-white/5"
|
|
)}>
|
|
<div className="flex items-center gap-3">
|
|
<div className={cn(
|
|
"p-2.5 rounded-xl",
|
|
reminderSettings.enabled ? "bg-indigo-500/20 text-indigo-400" : "bg-slate-500/20 text-slate-400"
|
|
)}>
|
|
{reminderSettings.enabled ? <BellRing className="h-5 w-5" /> : <BellOff className="h-5 w-5" />}
|
|
</div>
|
|
<div className="flex flex-col">
|
|
<span className="text-sm font-bold">
|
|
{reminderSettings.enabled ? 'Enabled' : 'Disabled'}
|
|
</span>
|
|
<span className="text-[10px] opacity-60">
|
|
{reminderSettings.enabled ? 'Reminders active' : 'Turn on to get alerts'}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<button
|
|
onClick={handleToggleReminders}
|
|
disabled={!isSupported || (permission === 'denied' && !reminderSettings.enabled)}
|
|
className={cn(
|
|
"relative w-12 h-6 rounded-full transition-all duration-300 shadow-inner",
|
|
reminderSettings.enabled ? "bg-indigo-500" : "bg-slate-400/30",
|
|
(!isSupported || (permission === 'denied' && !reminderSettings.enabled)) && "opacity-50 cursor-not-allowed"
|
|
)}
|
|
>
|
|
<div className={cn(
|
|
"absolute top-1 w-4 h-4 rounded-full bg-white shadow-md transition-all duration-300",
|
|
reminderSettings.enabled ? "left-7" : "left-1"
|
|
)} />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Frequency Selection */}
|
|
{reminderSettings.enabled && (
|
|
<div className="space-y-3">
|
|
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">Reminder Frequency</div>
|
|
<div className="grid grid-cols-2 gap-3">
|
|
<button
|
|
onClick={() => handleFrequencyChange('daily')}
|
|
className={cn(
|
|
"p-4 rounded-2xl border text-sm font-bold transition-all flex flex-col items-center gap-1",
|
|
localFrequency === 'daily'
|
|
? 'bg-indigo-500 border-indigo-500 text-white shadow-lg shadow-indigo-500/25 scale-[1.02]'
|
|
: 'bg-background border-border hover:border-indigo-500/50'
|
|
)}
|
|
>
|
|
<span>Daily</span>
|
|
<span className="text-[10px] font-normal opacity-70">Once a day</span>
|
|
</button>
|
|
<button
|
|
onClick={() => handleFrequencyChange('hourly')}
|
|
className={cn(
|
|
"p-4 rounded-2xl border text-sm font-bold transition-all flex flex-col items-center gap-1",
|
|
localFrequency === 'hourly'
|
|
? 'bg-indigo-500 border-indigo-500 text-white shadow-lg shadow-indigo-500/25 scale-[1.02]'
|
|
: 'bg-background border-border hover:border-indigo-500/50'
|
|
)}
|
|
>
|
|
<span>Hourly</span>
|
|
<span className="text-[10px] font-normal opacity-70">Window alerts</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Time Picker (Only for Daily) */}
|
|
{reminderSettings.enabled && localFrequency === 'daily' && (
|
|
<div className="space-y-3 animate-in fade-in slide-in-from-top-2 duration-300">
|
|
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">Preferred Time</div>
|
|
<div className="flex gap-2 p-1 bg-muted/30 rounded-2xl border border-border/50">
|
|
<div className="flex-1">
|
|
<Select
|
|
value={hourString}
|
|
onValueChange={(val) => updateTime(val, minuteString, currentAmpm)}
|
|
>
|
|
<SelectTrigger className="border-none bg-transparent shadow-none hover:bg-white/5 h-12 rounded-xl">
|
|
<SelectValue placeholder="Hour" />
|
|
</SelectTrigger>
|
|
<SelectContent className="rounded-xl">
|
|
{hoursOptions.map((h) => (
|
|
<SelectItem key={h} value={h} className="rounded-lg">{h}</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="flex-1">
|
|
<Select
|
|
value={minuteString}
|
|
onValueChange={(val) => updateTime(hourString, val, currentAmpm)}
|
|
>
|
|
<SelectTrigger className="border-none bg-transparent shadow-none hover:bg-white/5 h-12 rounded-xl">
|
|
<SelectValue placeholder="Min" />
|
|
</SelectTrigger>
|
|
<SelectContent className="rounded-xl">
|
|
{minutesOptions.map((m) => (
|
|
<SelectItem key={m} value={m} className="rounded-lg">{m}</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="w-24 px-1">
|
|
<Select
|
|
value={currentAmpm}
|
|
onValueChange={(val) => updateTime(hourString, minuteString, val)}
|
|
>
|
|
<SelectTrigger className="border-none bg-indigo-500/10 text-indigo-400 font-bold shadow-none hover:bg-indigo-500/20 h-10 mt-1 rounded-lg">
|
|
<SelectValue placeholder="AM/PM" />
|
|
</SelectTrigger>
|
|
<SelectContent className="rounded-xl">
|
|
<SelectItem value="AM" className="rounded-lg">AM</SelectItem>
|
|
<SelectItem value="PM" className="rounded-lg">PM</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Hourly Alerts Window */}
|
|
{reminderSettings.enabled && localFrequency === 'hourly' && (
|
|
<div className="space-y-4 animate-in fade-in slide-in-from-top-2 duration-300">
|
|
<div className="space-y-2">
|
|
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">Start Time</div>
|
|
<HourlyTimePicker
|
|
value={reminderSettings.hourlyStart || '09:00'}
|
|
onChange={async (newTime) => {
|
|
const [h, m] = newTime.split(':');
|
|
const end = (reminderSettings.hourlyEnd || '21:00').split(':');
|
|
const newSettings = { ...reminderSettings, hourlyStart: newTime, hourlyEnd: `${end[0]}:${m}` };
|
|
setReminderSettings(newSettings);
|
|
await saveReminderSettings(newSettings);
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<div className="text-[10px] font-bold uppercase tracking-widest opacity-40 px-1">End Time</div>
|
|
<HourlyTimePicker
|
|
value={reminderSettings.hourlyEnd || '21:00'}
|
|
onChange={async (newTime) => {
|
|
const [h, m] = newTime.split(':');
|
|
const start = (reminderSettings.hourlyStart || '09:00').split(':');
|
|
const newSettings = { ...reminderSettings, hourlyEnd: newTime, hourlyStart: `${start[0]}:${m}` };
|
|
setReminderSettings(newSettings);
|
|
await saveReminderSettings(newSettings);
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2 p-3 bg-indigo-500/5 rounded-2xl border border-indigo-500/10">
|
|
<Sparkles className="h-4 w-4 text-indigo-400" />
|
|
<p className="text-[10px] text-indigo-400 uppercase font-black tracking-widest">Reminders every 60 minutes</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Notification Permission Sync */}
|
|
{reminderSettings.enabled && isSupported && (
|
|
<div className="pt-2">
|
|
<Button
|
|
onClick={async () => {
|
|
const result = await requestPermission();
|
|
if (result === 'granted') {
|
|
try {
|
|
const res = await fetch('/api/notifications/test', { method: 'POST' });
|
|
if (res.ok) alert("Success! Push notifications active.");
|
|
} catch (err) { console.error(err); }
|
|
} else alert("Please enable notifications in settings.");
|
|
}}
|
|
className={cn(
|
|
"w-full h-12 rounded-2xl font-bold transition-all shadow-md group",
|
|
permission === 'granted'
|
|
? 'bg-emerald-500/10 text-emerald-500 hover:bg-emerald-500/20'
|
|
: 'bg-emerald-600 text-white hover:bg-emerald-500 hover:scale-[1.02]'
|
|
)}
|
|
>
|
|
<Bell className="mr-2 h-4 w-4 group-hover:animate-bounce" />
|
|
{permission === 'granted' ? 'Permissions Verified' : 'Enable Push Alerts'}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
|
|
{permission === 'denied' && (
|
|
<div className="p-4 bg-red-500/10 border border-red-500/20 rounded-2xl">
|
|
<p className="text-xs text-red-500 text-center font-medium leading-relaxed">
|
|
Browser notifications are currently blocked. To get reminders, please update your site settings.
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</header>
|
|
</>
|
|
);
|
|
}
|