feat: tempcommit

This commit is contained in:
Maximilian Liebmann 2025-06-24 11:45:50 +02:00
parent 5d81288479
commit 13a99e9dc4
6 changed files with 113 additions and 174 deletions

View file

@ -52,7 +52,7 @@ const items = [
},
{
title: 'Events',
url: '#',
url: '/events',
icon: CalendarClock,
},
];
@ -114,7 +114,7 @@ export function AppSidebar() {
<SidebarFooter>
<SidebarMenuItem className='pl-[8px]'>
<Link
href='/event/new'
href='/events/new'
className='flex items-center gap-2 text-xl font-label'
>
<CalendarPlus className='size-8' />

View file

@ -57,19 +57,19 @@ const settingsSections: SettingsSection[] = [
{
label: 'Calendar',
value: 'calendarAvailability',
description: 'Manage calendar display and availability',
description: 'Manage calendar display, availability and iCal integration',
icon: Calendar,
},
{
label: 'Privacy',
value: 'sharingPrivacy',
description: 'Control who can see your calendar',
description: 'Control who can see your calendar and book time with you',
icon: Shield,
},
{
label: 'Appearance',
value: 'appearance',
description: 'Customize the look and feel',
description: 'Customize the look and feel of the application',
icon: Palette,
},
];
@ -99,7 +99,7 @@ export function SettingsDropdown({
variant='outline_muted'
role='combobox'
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'>
<CurrentIcon className='h-4 w-4 text-muted-foreground' />

View file

@ -23,10 +23,15 @@ import {
} from '@/components/ui/select';
import { SettingsDropdown } from '@/components/misc/settings-dropdown';
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() {
const router = useRouter();
const [currentSection, setCurrentSection] = useState('general');
const { data } = useGetApiUserMe();
const renderSettingsContent = () => {
switch (currentSection) {
@ -36,28 +41,79 @@ export default function SettingsPage() {
<ScrollableSettingsWrapper>
<CardHeader>
<CardTitle>Account Settings</CardTitle>
<CardDescription>
Manage your account details and preferences.
</CardDescription>
</CardHeader>
<CardContent className='space-y-6'>
<div className='space-y-2'>
<Label htmlFor='displayName'>Display Name</Label>
<Input id='displayName' placeholder='Your Name' />
</div>
<div className='space-y-2'>
<Label htmlFor='email'>Email Address</Label>
<Input
id='email'
type='email'
placeholder='your.email@example.com'
readOnly
value='user-email@example.com'
/>
<p className='text-sm text-muted-foreground'>
Email is managed by your SSO provider.
</p>
</div>
<CardContent className='space-y-6 mt-2'>
<GroupWrapper legend='General Settings'>
<div className='space-y-4'>
<div className='flex items-center justify-evenly'>
<div>
<Label htmlFor='displayName'>First Name</Label>
<Input
id='displayName'
placeholder='Your Name'
defaultValue={data?.data.user.first_name ?? ''}
/>
</div>
<div>
<Label htmlFor='displayName'>Last Name</Label>
<Input
id='displayName'
placeholder='Your Name'
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'>
<Label htmlFor='profilePicture'>Profile Picture</Label>
<Input id='profilePicture' type='file' />
@ -67,7 +123,11 @@ export default function SettingsPage() {
</div>
<div className='space-y-2'>
<Label htmlFor='timezone'>Timezone</Label>
<Input id='displayName' placeholder='Europe/Berlin' />
<Input
id='displayName'
placeholder='Europe/Berlin'
defaultValue={data?.data.user.timezone}
/>
</div>
<div className='space-y-2'>
<Label htmlFor='language'>Language</Label>
@ -98,9 +158,6 @@ export default function SettingsPage() {
<ScrollableSettingsWrapper>
<CardHeader>
<CardTitle>Notification Preferences</CardTitle>
<CardDescription>
Choose how you want to be notified.
</CardDescription>
</CardHeader>
<CardContent className='space-y-6'>
<div className='flex items-center justify-between space-x-2 p-3 rounded-md border'>
@ -175,10 +232,6 @@ export default function SettingsPage() {
<ScrollableSettingsWrapper>
<CardHeader>
<CardTitle>Calendar & Availability</CardTitle>
<CardDescription>
Manage your calendar display, default availability, and iCal
integrations.
</CardDescription>
</CardHeader>
<CardContent className='space-y-6'>
<fieldset className='space-y-4 p-4 border rounded-md'>
@ -298,9 +351,6 @@ export default function SettingsPage() {
<ScrollableSettingsWrapper>
<CardHeader>
<CardTitle>Sharing & Privacy</CardTitle>
<CardDescription>
Control who can see your calendar and book time with you.
</CardDescription>
</CardHeader>
<CardContent className='space-y-6'>
<div className='space-y-2'>
@ -386,23 +436,11 @@ export default function SettingsPage() {
<ScrollableSettingsWrapper>
<CardHeader>
<CardTitle>Appearance</CardTitle>
<CardDescription>
Customize the look and feel of the application.
</CardDescription>
</CardHeader>
<CardContent className='space-y-6'>
<div className='space-y-2'>
<Label htmlFor='theme'>Theme</Label>
<Select>
<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>
<ThemePicker />
</div>
<div className='space-y-2'>
<Label htmlFor='dateFormat'>Date Format</Label>

View file

@ -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>
);
}

View file

@ -17,6 +17,7 @@ import UserCard from '@/components/misc/user-card';
export default function UserDropdown() {
const { data } = useGetApiUserMe();
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>

View 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>
);
}