feat: tempcommit
This commit is contained in:
parent
5d81288479
commit
13a99e9dc4
6 changed files with 113 additions and 174 deletions
|
@ -52,7 +52,7 @@ const items = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Events',
|
title: 'Events',
|
||||||
url: '#',
|
url: '/events',
|
||||||
icon: CalendarClock,
|
icon: CalendarClock,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -114,7 +114,7 @@ export function AppSidebar() {
|
||||||
<SidebarFooter>
|
<SidebarFooter>
|
||||||
<SidebarMenuItem className='pl-[8px]'>
|
<SidebarMenuItem className='pl-[8px]'>
|
||||||
<Link
|
<Link
|
||||||
href='/event/new'
|
href='/events/new'
|
||||||
className='flex items-center gap-2 text-xl font-label'
|
className='flex items-center gap-2 text-xl font-label'
|
||||||
>
|
>
|
||||||
<CalendarPlus className='size-8' />
|
<CalendarPlus className='size-8' />
|
||||||
|
|
|
@ -57,19 +57,19 @@ const settingsSections: SettingsSection[] = [
|
||||||
{
|
{
|
||||||
label: 'Calendar',
|
label: 'Calendar',
|
||||||
value: 'calendarAvailability',
|
value: 'calendarAvailability',
|
||||||
description: 'Manage calendar display and availability',
|
description: 'Manage calendar display, availability and iCal integration',
|
||||||
icon: Calendar,
|
icon: Calendar,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Privacy',
|
label: 'Privacy',
|
||||||
value: 'sharingPrivacy',
|
value: 'sharingPrivacy',
|
||||||
description: 'Control who can see your calendar',
|
description: 'Control who can see your calendar and book time with you',
|
||||||
icon: Shield,
|
icon: Shield,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Appearance',
|
label: 'Appearance',
|
||||||
value: 'appearance',
|
value: 'appearance',
|
||||||
description: 'Customize the look and feel',
|
description: 'Customize the look and feel of the application',
|
||||||
icon: Palette,
|
icon: Palette,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -99,7 +99,7 @@ export function SettingsDropdown({
|
||||||
variant='outline_muted'
|
variant='outline_muted'
|
||||||
role='combobox'
|
role='combobox'
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
className='w-full justify-between bg-white text-black h-auto py-3'
|
className='w-full justify-between bg-popover text-text h-auto py-3'
|
||||||
>
|
>
|
||||||
<div className='flex items-center gap-3'>
|
<div className='flex items-center gap-3'>
|
||||||
<CurrentIcon className='h-4 w-4 text-muted-foreground' />
|
<CurrentIcon className='h-4 w-4 text-muted-foreground' />
|
||||||
|
|
|
@ -23,10 +23,15 @@ import {
|
||||||
} from '@/components/ui/select';
|
} from '@/components/ui/select';
|
||||||
import { SettingsDropdown } from '@/components/misc/settings-dropdown';
|
import { SettingsDropdown } from '@/components/misc/settings-dropdown';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { useGetApiUserMe } from '@/generated/api/user/user';
|
||||||
|
import { ThemePicker } from './theme-picker';
|
||||||
|
import LabeledInput from '../custom-ui/labeled-input';
|
||||||
|
import { GroupWrapper } from '../wrappers/group-wrapper';
|
||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [currentSection, setCurrentSection] = useState('general');
|
const [currentSection, setCurrentSection] = useState('general');
|
||||||
|
const { data } = useGetApiUserMe();
|
||||||
|
|
||||||
const renderSettingsContent = () => {
|
const renderSettingsContent = () => {
|
||||||
switch (currentSection) {
|
switch (currentSection) {
|
||||||
|
@ -36,28 +41,79 @@ export default function SettingsPage() {
|
||||||
<ScrollableSettingsWrapper>
|
<ScrollableSettingsWrapper>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Account Settings</CardTitle>
|
<CardTitle>Account Settings</CardTitle>
|
||||||
<CardDescription>
|
|
||||||
Manage your account details and preferences.
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className='space-y-6'>
|
<CardContent className='space-y-6 mt-2'>
|
||||||
<div className='space-y-2'>
|
<GroupWrapper legend='General Settings'>
|
||||||
<Label htmlFor='displayName'>Display Name</Label>
|
<div className='space-y-4'>
|
||||||
<Input id='displayName' placeholder='Your Name' />
|
<div className='flex items-center justify-evenly'>
|
||||||
</div>
|
<div>
|
||||||
<div className='space-y-2'>
|
<Label htmlFor='displayName'>First Name</Label>
|
||||||
<Label htmlFor='email'>Email Address</Label>
|
<Input
|
||||||
<Input
|
id='displayName'
|
||||||
id='email'
|
placeholder='Your Name'
|
||||||
type='email'
|
defaultValue={data?.data.user.first_name ?? ''}
|
||||||
placeholder='your.email@example.com'
|
/>
|
||||||
readOnly
|
</div>
|
||||||
value='user-email@example.com'
|
<div>
|
||||||
/>
|
<Label htmlFor='displayName'>Last Name</Label>
|
||||||
<p className='text-sm text-muted-foreground'>
|
<Input
|
||||||
Email is managed by your SSO provider.
|
id='displayName'
|
||||||
</p>
|
placeholder='Your Name'
|
||||||
</div>
|
defaultValue={data?.data.user.last_name ?? ''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='space-y-2'>
|
||||||
|
<Label htmlFor='displayName'>Display Name</Label>
|
||||||
|
<Input
|
||||||
|
id='displayName'
|
||||||
|
placeholder='Your Name'
|
||||||
|
defaultValue={data?.data.user.name}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='space-y-2'>
|
||||||
|
<Label htmlFor='email'>Email Address</Label>
|
||||||
|
<Input
|
||||||
|
id='email'
|
||||||
|
type='email'
|
||||||
|
placeholder='your.email@example.com'
|
||||||
|
readOnly
|
||||||
|
defaultValue={data?.data.user.email}
|
||||||
|
/>
|
||||||
|
<p className='text-sm text-muted-foreground'>
|
||||||
|
Email might be managed by your SSO provider.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</GroupWrapper>
|
||||||
|
<GroupWrapper legend='Reset Password'>
|
||||||
|
<div className='flex items-center justify-evenly'>
|
||||||
|
<div>
|
||||||
|
<LabeledInput
|
||||||
|
type='password'
|
||||||
|
label='Current Password'
|
||||||
|
placeholder='Current Password'
|
||||||
|
defaultValue={data?.data.user.first_name ?? ''}
|
||||||
|
></LabeledInput>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<LabeledInput
|
||||||
|
type='password'
|
||||||
|
label='New Password'
|
||||||
|
placeholder='New Password'
|
||||||
|
defaultValue={data?.data.user.first_name ?? ''}
|
||||||
|
></LabeledInput>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<LabeledInput
|
||||||
|
type='password'
|
||||||
|
label='Repeat Password'
|
||||||
|
placeholder='Repeat Password'
|
||||||
|
defaultValue={data?.data.user.first_name ?? ''}
|
||||||
|
></LabeledInput>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</GroupWrapper>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
<Label htmlFor='profilePicture'>Profile Picture</Label>
|
<Label htmlFor='profilePicture'>Profile Picture</Label>
|
||||||
<Input id='profilePicture' type='file' />
|
<Input id='profilePicture' type='file' />
|
||||||
|
@ -67,7 +123,11 @@ export default function SettingsPage() {
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
<Label htmlFor='timezone'>Timezone</Label>
|
<Label htmlFor='timezone'>Timezone</Label>
|
||||||
<Input id='displayName' placeholder='Europe/Berlin' />
|
<Input
|
||||||
|
id='displayName'
|
||||||
|
placeholder='Europe/Berlin'
|
||||||
|
defaultValue={data?.data.user.timezone}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
<Label htmlFor='language'>Language</Label>
|
<Label htmlFor='language'>Language</Label>
|
||||||
|
@ -98,9 +158,6 @@ export default function SettingsPage() {
|
||||||
<ScrollableSettingsWrapper>
|
<ScrollableSettingsWrapper>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Notification Preferences</CardTitle>
|
<CardTitle>Notification Preferences</CardTitle>
|
||||||
<CardDescription>
|
|
||||||
Choose how you want to be notified.
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className='space-y-6'>
|
<CardContent className='space-y-6'>
|
||||||
<div className='flex items-center justify-between space-x-2 p-3 rounded-md border'>
|
<div className='flex items-center justify-between space-x-2 p-3 rounded-md border'>
|
||||||
|
@ -175,10 +232,6 @@ export default function SettingsPage() {
|
||||||
<ScrollableSettingsWrapper>
|
<ScrollableSettingsWrapper>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Calendar & Availability</CardTitle>
|
<CardTitle>Calendar & Availability</CardTitle>
|
||||||
<CardDescription>
|
|
||||||
Manage your calendar display, default availability, and iCal
|
|
||||||
integrations.
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className='space-y-6'>
|
<CardContent className='space-y-6'>
|
||||||
<fieldset className='space-y-4 p-4 border rounded-md'>
|
<fieldset className='space-y-4 p-4 border rounded-md'>
|
||||||
|
@ -298,9 +351,6 @@ export default function SettingsPage() {
|
||||||
<ScrollableSettingsWrapper>
|
<ScrollableSettingsWrapper>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Sharing & Privacy</CardTitle>
|
<CardTitle>Sharing & Privacy</CardTitle>
|
||||||
<CardDescription>
|
|
||||||
Control who can see your calendar and book time with you.
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className='space-y-6'>
|
<CardContent className='space-y-6'>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
|
@ -386,23 +436,11 @@ export default function SettingsPage() {
|
||||||
<ScrollableSettingsWrapper>
|
<ScrollableSettingsWrapper>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Appearance</CardTitle>
|
<CardTitle>Appearance</CardTitle>
|
||||||
<CardDescription>
|
|
||||||
Customize the look and feel of the application.
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className='space-y-6'>
|
<CardContent className='space-y-6'>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
<Label htmlFor='theme'>Theme</Label>
|
<Label htmlFor='theme'>Theme</Label>
|
||||||
<Select>
|
<ThemePicker />
|
||||||
<SelectTrigger id='theme'>
|
|
||||||
<SelectValue placeholder='Select theme' />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value='light'>Light</SelectItem>
|
|
||||||
<SelectItem value='dark'>Dark</SelectItem>
|
|
||||||
<SelectItem value='system'>System Default</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
<Label htmlFor='dateFormat'>Date Format</Label>
|
<Label htmlFor='dateFormat'>Date Format</Label>
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
'use client';
|
|
||||||
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import {
|
|
||||||
Command,
|
|
||||||
CommandEmpty,
|
|
||||||
CommandGroup,
|
|
||||||
CommandInput,
|
|
||||||
CommandItem,
|
|
||||||
CommandList,
|
|
||||||
} from '@/components/ui/command';
|
|
||||||
import {
|
|
||||||
Popover,
|
|
||||||
PopoverContent,
|
|
||||||
PopoverTrigger,
|
|
||||||
} from '@/components/ui/popover';
|
|
||||||
import { cn } from '@/lib/utils';
|
|
||||||
import { Check, ChevronDown } from 'lucide-react';
|
|
||||||
|
|
||||||
interface SettingsOption {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SettingsSwitcherProps {
|
|
||||||
title: string;
|
|
||||||
options: SettingsOption[];
|
|
||||||
defaultValue?: string;
|
|
||||||
onValueChange?: (value: string) => void;
|
|
||||||
placeholder?: string;
|
|
||||||
searchPlaceholder?: string;
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SettingsSwitcher({
|
|
||||||
title,
|
|
||||||
options,
|
|
||||||
defaultValue,
|
|
||||||
onValueChange,
|
|
||||||
placeholder = 'Select option...',
|
|
||||||
searchPlaceholder = 'Search options...',
|
|
||||||
className,
|
|
||||||
}: SettingsSwitcherProps) {
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
const [selectedValue, setSelectedValue] = useState(
|
|
||||||
defaultValue || options[0]?.value || '',
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedOption = options.find(
|
|
||||||
(option) => option.value === selectedValue,
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelect = (value: string) => {
|
|
||||||
setSelectedValue(value);
|
|
||||||
setOpen(false);
|
|
||||||
onValueChange?.(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={cn('space-y-2', className)}>
|
|
||||||
<label className='text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'>
|
|
||||||
{title}
|
|
||||||
</label>
|
|
||||||
<Popover open={open} onOpenChange={setOpen}>
|
|
||||||
<PopoverTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant='outline_muted'
|
|
||||||
role='combobox'
|
|
||||||
aria-expanded={open}
|
|
||||||
className='w-full justify-between bg-white text-black'
|
|
||||||
>
|
|
||||||
<div className='flex flex-col items-start'>
|
|
||||||
<span>{selectedOption?.label || placeholder}</span>
|
|
||||||
{selectedOption?.description && (
|
|
||||||
<span className='text-xs text-muted-foreground'>
|
|
||||||
{selectedOption.description}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<ChevronDown className='ml-2 h-4 w-4 shrink-0 opacity-50' />
|
|
||||||
</Button>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className='w-full p-0' align='start'>
|
|
||||||
<Command>
|
|
||||||
<CommandInput placeholder={searchPlaceholder} />
|
|
||||||
<CommandList>
|
|
||||||
<CommandEmpty>No option found.</CommandEmpty>
|
|
||||||
<CommandGroup>
|
|
||||||
{options.map((option) => (
|
|
||||||
<CommandItem
|
|
||||||
key={option.value}
|
|
||||||
value={option.value}
|
|
||||||
onSelect={() => handleSelect(option.value)}
|
|
||||||
className='flex items-center justify-between'
|
|
||||||
>
|
|
||||||
<div className='flex flex-col'>
|
|
||||||
<span>{option.label}</span>
|
|
||||||
{option.description && (
|
|
||||||
<span className='text-xs text-muted-foreground'>
|
|
||||||
{option.description}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<Check
|
|
||||||
className={cn(
|
|
||||||
'ml-2 h-4 w-4',
|
|
||||||
selectedValue === option.value
|
|
||||||
? 'opacity-100'
|
|
||||||
: 'opacity-0',
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</CommandItem>
|
|
||||||
))}
|
|
||||||
</CommandGroup>
|
|
||||||
</CommandList>
|
|
||||||
</Command>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -17,6 +17,7 @@ import UserCard from '@/components/misc/user-card';
|
||||||
|
|
||||||
export default function UserDropdown() {
|
export default function UserDropdown() {
|
||||||
const { data } = useGetApiUserMe();
|
const { data } = useGetApiUserMe();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
|
|
23
src/components/wrappers/group-wrapper.tsx
Normal file
23
src/components/wrappers/group-wrapper.tsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import type * as React from 'react';
|
||||||
|
|
||||||
|
interface ScrollableSettingsWrapperProps {
|
||||||
|
className?: string;
|
||||||
|
legend?: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GroupWrapper({
|
||||||
|
className,
|
||||||
|
legend,
|
||||||
|
children,
|
||||||
|
}: ScrollableSettingsWrapperProps) {
|
||||||
|
return (
|
||||||
|
<fieldset
|
||||||
|
className={cn('space-t-4 p-4 border rounded-md shadow-md', className)}
|
||||||
|
>
|
||||||
|
<legend className='text-sm font-medium px-1'>{legend}</legend>
|
||||||
|
{children}
|
||||||
|
</fieldset>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue