feat: tempcommit (broken input)

This commit is contained in:
Maximilian Liebmann 2025-06-29 22:09:18 +02:00
parent 7d2d5c55e8
commit ba6d21eec5
6 changed files with 335 additions and 203 deletions

View file

@ -1,19 +1,20 @@
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { LucideProps } from 'lucide-react';
import { IconProp } from '@fortawesome/fontawesome-svg-core'; import React, { ForwardRefExoticComponent, RefAttributes } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
export function IconButton({ export function IconButton({
icon, icon,
children, children,
...props ...props
}: { }: {
icon: IconProp; icon?: ForwardRefExoticComponent<
Omit<LucideProps, 'ref'> & RefAttributes<SVGSVGElement>
>;
children: React.ReactNode; children: React.ReactNode;
} & React.ComponentProps<typeof Button>) { } & React.ComponentProps<typeof Button>) {
return ( return (
<Button type='button' variant='secondary' {...props}> <Button type='button' variant='secondary' {...props}>
<FontAwesomeIcon icon={icon} className='mr-2' /> {icon && React.createElement(icon, { className: 'mr-2' })}
{children} {children}
</Button> </Button>
); );

View file

@ -1,6 +1,6 @@
import { signIn } from '@/auth'; import { signIn } from '@/auth';
import { IconButton } from '@/components/buttons/icon-button'; import { IconButton } from '@/components/buttons/icon-button';
import { faOpenid } from '@fortawesome/free-brands-svg-icons'; import { Fingerprint, ScanEye } from 'lucide-react';
export default function SSOLogin({ export default function SSOLogin({
provider, provider,
@ -22,7 +22,7 @@ export default function SSOLogin({
className='w-full' className='w-full'
type='submit' type='submit'
variant='secondary' variant='secondary'
icon={faOpenid} icon={Fingerprint}
{...props} {...props}
> >
Login with {providerDisplayName} Login with {providerDisplayName}

View file

@ -62,6 +62,7 @@ export function AppSidebar() {
<> <>
<Sidebar collapsible='icon' variant='sidebar'> <Sidebar collapsible='icon' variant='sidebar'>
<SidebarHeader className='overflow-hidden'> <SidebarHeader className='overflow-hidden'>
<Link href='/home'>
<Logo <Logo
colorType='colored' colorType='colored'
logoType='combo' logoType='combo'
@ -74,6 +75,7 @@ export function AppSidebar() {
height={50} height={50}
className='group-data-[collapsible=]:hidden group-data-[mobile=true]/mobile:hidden' className='group-data-[collapsible=]:hidden group-data-[mobile=true]/mobile:hidden'
></Logo> ></Logo>
</Link>
</SidebarHeader> </SidebarHeader>
<SidebarContent className='grid grid-rows-[auto_1fr_auto]'> <SidebarContent className='grid grid-rows-[auto_1fr_auto]'>
<Collapsible defaultOpen className='group/collapsible'> <Collapsible defaultOpen className='group/collapsible'>

View file

@ -1,8 +1,8 @@
import { Input, Textarea } from '@/components/ui/input'; import { Input, Textarea } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import React from 'react'; import React, { ForwardRefExoticComponent, RefAttributes } from 'react';
import { Button } from '../ui/button'; import { Button } from '../ui/button';
import { Eye, EyeOff } from 'lucide-react'; import { Eye, EyeOff, LucideProps } from 'lucide-react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
export default function LabeledInput({ export default function LabeledInput({
@ -12,6 +12,7 @@ export default function LabeledInput({
placeholder, placeholder,
value, value,
name, name,
icon,
variantSize = 'default', variantSize = 'default',
autocomplete, autocomplete,
error, error,
@ -22,11 +23,22 @@ export default function LabeledInput({
placeholder?: string; placeholder?: string;
value?: string; value?: string;
name?: string; name?: string;
icon?: ForwardRefExoticComponent<
Omit<LucideProps, 'ref'> & RefAttributes<SVGSVGElement>
>;
variantSize?: 'default' | 'big' | 'textarea'; variantSize?: 'default' | 'big' | 'textarea';
autocomplete?: string; autocomplete?: string;
error?: string; error?: string;
} & React.InputHTMLAttributes<HTMLInputElement>) { } & React.InputHTMLAttributes<HTMLInputElement>) {
const [passwordVisible, setPasswordVisible] = React.useState(false); const [passwordVisible, setPasswordVisible] = React.useState(false);
const [inputValue, setInputValue] = React.useState(value || '');
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
if (rest.onChange) {
rest.onChange(e);
}
};
return ( return (
<div className='grid grid-cols-1 gap-1'> <div className='grid grid-cols-1 gap-1'>
@ -50,18 +62,32 @@ export default function LabeledInput({
className={cn( className={cn(
type === 'password' ? 'pr-[50px]' : '', type === 'password' ? 'pr-[50px]' : '',
variantSize === 'big' variantSize === 'big'
? 'h-12 file:h-10 text-lg gplaceholder:text-lg sm:text-2xl sm:placeholder:text-2xl' ? 'h-12 file:h-10 text-lg placeholder:text-lg sm:text-2xl sm:placeholder:text-2xl'
: '', : '',
icon && inputValue === '' ? 'pl-10' : '',
'transition-all duration-300 ease-in-out',
)} )}
type={passwordVisible ? 'text' : type} type={passwordVisible ? 'text' : type}
placeholder={placeholder} placeholder={placeholder}
defaultValue={value} value={inputValue}
id={name} id={name}
name={name} name={name}
autoComplete={autocomplete} autoComplete={autocomplete}
onChange={handleInputChange}
{...rest} {...rest}
/> />
{icon && (
<span
className={cn(
'absolute left-3 top-1/2 -translate-y-1/2 text-muted-input transition-all duration-300 ease-in-out',
inputValue === ''
? 'opacity-100 scale-100'
: 'opacity-0 scale-75 pointer-events-none',
)}
>
{React.createElement(icon)}
</span>
)}
{type === 'password' && ( {type === 'password' && (
<Button <Button
className='absolute right-0 top-0 w-[36px] h-[36px]' className='absolute right-0 top-0 w-[36px] h-[36px]'
@ -74,7 +100,6 @@ export default function LabeledInput({
)} )}
</span> </span>
)} )}
{error && <p className='text-red-500 text-sm mt-1'>{error}</p>} {error && <p className='text-red-500 text-sm mt-1'>{error}</p>}
</div> </div>
); );

View file

@ -4,11 +4,21 @@ import React, { useState, useRef } from 'react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import LabeledInput from '@/components/custom-ui/labeled-input'; import LabeledInput from '@/components/custom-ui/labeled-input';
import { Button } from '@/components/ui/button';
import useZodForm from '@/lib/hooks/useZodForm'; import useZodForm from '@/lib/hooks/useZodForm';
import { loginSchema, registerSchema } from '@/lib/auth/validation'; import { loginSchema, registerSchema } from '@/lib/auth/validation';
import { loginAction } from '@/lib/auth/login'; import { loginAction } from '@/lib/auth/login';
import { registerAction } from '@/lib/auth/register'; import { registerAction } from '@/lib/auth/register';
import { IconButton } from '../buttons/icon-button';
import {
FileKey,
FileKey2,
LogIn,
MailOpen,
RotateCcwKey,
UserCheck,
UserPen,
UserPlus,
} from 'lucide-react';
function LoginFormElement({ function LoginFormElement({
setIsSignUp, setIsSignUp,
@ -56,6 +66,7 @@ function LoginFormElement({
<LabeledInput <LabeledInput
type='text' type='text'
label='E-Mail or Username' label='E-Mail or Username'
icon={UserCheck}
placeholder='What you are known as' placeholder='What you are known as'
error={formState.errors.email?.message} error={formState.errors.email?.message}
{...register('email')} {...register('email')}
@ -64,16 +75,22 @@ function LoginFormElement({
<LabeledInput <LabeledInput
type='password' type='password'
label='Password' label='Password'
icon={FileKey}
placeholder="Let's hope you remember it" placeholder="Let's hope you remember it"
error={formState.errors.password?.message} error={formState.errors.password?.message}
{...register('password')} {...register('password')}
data-cy='password-input' data-cy='password-input'
/> />
<div className='grid grid-rows-2 gap-2'> <div className='grid grid-rows-2 gap-2'>
<Button type='submit' variant='primary' data-cy='login-button'> <IconButton
type='submit'
variant='primary'
data-cy='login-button'
icon={LogIn}
>
Login Login
</Button> </IconButton>
<Button <IconButton
type='button' type='button'
variant='outline_primary' variant='outline_primary'
onClick={() => { onClick={() => {
@ -81,9 +98,10 @@ function LoginFormElement({
setIsSignUp((v) => !v); setIsSignUp((v) => !v);
}} }}
data-cy='register-switch' data-cy='register-switch'
icon={UserPlus}
> >
Sign Up Sign Up
</Button> </IconButton>
</div> </div>
<div> <div>
{formState.errors.root?.message && ( {formState.errors.root?.message && (
@ -159,6 +177,7 @@ function RegisterFormElement({
<LabeledInput <LabeledInput
type='email' type='email'
label='E-Mail' label='E-Mail'
icon={MailOpen}
placeholder='Your email address' placeholder='Your email address'
autocomplete='email' autocomplete='email'
error={formState.errors.email?.message} error={formState.errors.email?.message}
@ -168,6 +187,7 @@ function RegisterFormElement({
<LabeledInput <LabeledInput
type='text' type='text'
label='Username' label='Username'
icon={UserPen}
placeholder='Your username' placeholder='Your username'
autocomplete='username' autocomplete='username'
error={formState.errors.username?.message} error={formState.errors.username?.message}
@ -177,6 +197,7 @@ function RegisterFormElement({
<LabeledInput <LabeledInput
type='password' type='password'
label='Password' label='Password'
icon={FileKey2}
placeholder='Create a password' placeholder='Create a password'
autocomplete='new-password' autocomplete='new-password'
error={formState.errors.password?.message} error={formState.errors.password?.message}
@ -186,6 +207,7 @@ function RegisterFormElement({
<LabeledInput <LabeledInput
type='password' type='password'
label='Confirm Password' label='Confirm Password'
icon={RotateCcwKey}
placeholder='Repeat your password' placeholder='Repeat your password'
autocomplete='new-password' autocomplete='new-password'
error={formState.errors.confirmPassword?.message} error={formState.errors.confirmPassword?.message}
@ -193,19 +215,25 @@ function RegisterFormElement({
data-cy='confirm-password-input' data-cy='confirm-password-input'
/> />
<div className='grid grid-rows-2 gap-2'> <div className='grid grid-rows-2 gap-2'>
<Button type='submit' variant='primary' data-cy='register-button'> <IconButton
type='submit'
variant='primary'
data-cy='register-button'
icon={UserPlus}
>
Sign Up Sign Up
</Button> </IconButton>
<Button <IconButton
type='button' type='button'
variant='outline_primary' variant='outline_primary'
onClick={() => { onClick={() => {
formRef?.current?.reset(); formRef?.current?.reset();
setIsSignUp((v) => !v); setIsSignUp((v) => !v);
}} }}
icon={LogIn}
> >
Back to Login Back to Login
</Button> </IconButton>
</div> </div>
<div> <div>
{formState.errors.root?.message && ( {formState.errors.root?.message && (

View file

@ -9,7 +9,7 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from '@/components/ui/card'; } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { ScrollableSettingsWrapper } from '@/components/wrappers/settings-scroll'; import { ScrollableSettingsWrapper } from '@/components/wrappers/settings-scroll';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
@ -28,8 +28,23 @@ import LabeledInput from '../custom-ui/labeled-input';
import { GroupWrapper } from '../wrappers/group-wrapper'; import { GroupWrapper } from '../wrappers/group-wrapper';
import ProfilePictureUpload from './profile-picture-upload'; import ProfilePictureUpload from './profile-picture-upload';
import { LogOut } from 'lucide-react'; import {
import { signOut } from '@/auth'; CalendarArrowDown,
CalendarArrowUp,
CalendarCheck,
CalendarClock,
CalendarCog,
CalendarPlus,
CalendarPlus2,
ClockAlert,
ClockFading,
FileKey,
FileKey2,
MailOpen,
RotateCcwKey,
UserLock,
} from 'lucide-react';
import { IconButton } from '../buttons/icon-button';
export default function SettingsPage() { export default function SettingsPage() {
const router = useRouter(); const router = useRouter();
@ -46,7 +61,8 @@ export default function SettingsPage() {
<CardHeader> <CardHeader>
<CardTitle>Account Settings</CardTitle> <CardTitle>Account Settings</CardTitle>
</CardHeader> </CardHeader>
<CardContent className='space-y-6 mt-2'> <CardContent className='space-y-6 my-2'>
{/*-------------------- General Settings --------------------*/}
<GroupWrapper title='General Settings'> <GroupWrapper title='General Settings'>
<div className='space-y-4'> <div className='space-y-4'>
<div> <div>
@ -77,6 +93,7 @@ export default function SettingsPage() {
<LabeledInput <LabeledInput
type='email' type='email'
label='Email Address' label='Email Address'
icon={MailOpen}
placeholder='Your E-Mail' placeholder='Your E-Mail'
defaultValue={data?.data.user.email ?? ''} defaultValue={data?.data.user.email ?? ''}
></LabeledInput> ></LabeledInput>
@ -87,39 +104,42 @@ export default function SettingsPage() {
</div> </div>
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- General Settings --------------------*/}
{/*-------------------- Reset Password --------------------*/}
<GroupWrapper title='Reset Password'> <GroupWrapper title='Reset Password'>
<div className='flex items-center justify-evenly sm:flex-row flex-col gap-6'> <div className='flex items-center justify-evenly sm:flex-row flex-col gap-6'>
<div> <div>
<LabeledInput <LabeledInput
type='password' type='password'
label='Current Password' label='Current Password'
placeholder='Current Password' icon={FileKey}
defaultValue={data?.data.user.first_name ?? ''}
></LabeledInput> ></LabeledInput>
</div> </div>
<div> <div>
<LabeledInput <LabeledInput
type='password' type='password'
label='New Password' label='New Password'
placeholder='New Password' icon={FileKey2}
defaultValue={data?.data.user.first_name ?? ''}
></LabeledInput> ></LabeledInput>
</div> </div>
<div> <div>
<LabeledInput <LabeledInput
type='password' type='password'
label='Repeat Password' label='Repeat Password'
placeholder='Repeat Password' icon={RotateCcwKey}
defaultValue={data?.data.user.first_name ?? ''}
></LabeledInput> ></LabeledInput>
</div> </div>
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- Reset Password --------------------*/}
{/*-------------------- Profile Picture --------------------*/}
<GroupWrapper title='Profile Picture'> <GroupWrapper title='Profile Picture'>
<div className='space-y-2 grid grid-cols-[1fr_auto]'> <div className='space-y-2 grid grid-cols-[1fr_auto]'>
<ProfilePictureUpload className='file:border file:rounded-md file:hover:bg-disabled-destructive' /> <ProfilePictureUpload className='file:border file:rounded-md file:hover:bg-disabled-destructive' />
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- Profile Picture --------------------*/}
{/*-------------------- Regional Settings --------------------*/}
<GroupWrapper title='Regional Settings'> <GroupWrapper title='Regional Settings'>
<div className='space-y-2 grid sm:grid-cols-[1fr_auto] sm:flex-row gap-4'> <div className='space-y-2 grid sm:grid-cols-[1fr_auto] sm:flex-row gap-4'>
<div className='grid gap-1'> <div className='grid gap-1'>
@ -127,6 +147,7 @@ export default function SettingsPage() {
type='text' type='text'
label='Timezone' label='Timezone'
placeholder='Europe/Berlin' placeholder='Europe/Berlin'
icon={CalendarClock}
defaultValue={data?.data.user.timezone ?? ''} defaultValue={data?.data.user.timezone ?? ''}
></LabeledInput> ></LabeledInput>
</div> </div>
@ -146,6 +167,8 @@ export default function SettingsPage() {
</div> </div>
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- Regional Settings --------------------*/}
<GroupWrapper title='DANGER ZONE - INSTANT DELETE - NO CONFIRMATION'>
<div className='flex items-center justify-evenly sm:flex-row flex-col gap-6'> <div className='flex items-center justify-evenly sm:flex-row flex-col gap-6'>
<Button <Button
onClick={() => { onClick={() => {
@ -163,6 +186,7 @@ export default function SettingsPage() {
Permanently delete your account and all associated data. Permanently delete your account and all associated data.
</span> </span>
</div> </div>
</GroupWrapper>
</CardContent> </CardContent>
</ScrollableSettingsWrapper> </ScrollableSettingsWrapper>
</Card> </Card>
@ -175,8 +199,9 @@ export default function SettingsPage() {
<CardHeader> <CardHeader>
<CardTitle>Notification Preferences</CardTitle> <CardTitle>Notification Preferences</CardTitle>
</CardHeader> </CardHeader>
<CardContent className='space-y-6'> <CardContent className='space-y-6 my-2'>
<GroupWrapper> {/*-------------------- All --------------------*/}
<GroupWrapper title='All'>
<div className='flex items-center justify-between'> <div className='flex items-center justify-between'>
<Label <Label
htmlFor='masterEmailNotifications' htmlFor='masterEmailNotifications'
@ -187,7 +212,8 @@ export default function SettingsPage() {
<Switch id='masterEmailNotifications' /> <Switch id='masterEmailNotifications' />
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- All --------------------*/}
{/*-------------------- Meetings --------------------*/}
<GroupWrapper title='Meetings'> <GroupWrapper title='Meetings'>
<div className='space-y-4'> <div className='space-y-4'>
<div className='flex items-center justify-between space-x-2'> <div className='flex items-center justify-between space-x-2'>
@ -239,6 +265,8 @@ export default function SettingsPage() {
</div> </div>
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- Meetings --------------------*/}
{/*-------------------- Social --------------------*/}
<GroupWrapper title='Social'> <GroupWrapper title='Social'>
<div className='space-y-4'> <div className='space-y-4'>
<div className='flex items-center justify-between space-x-2'> <div className='flex items-center justify-between space-x-2'>
@ -255,6 +283,7 @@ export default function SettingsPage() {
</div> </div>
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- Social --------------------*/}
</CardContent> </CardContent>
</ScrollableSettingsWrapper> </ScrollableSettingsWrapper>
</Card> </Card>
@ -267,8 +296,39 @@ export default function SettingsPage() {
<CardHeader> <CardHeader>
<CardTitle>Calendar & Availability</CardTitle> <CardTitle>Calendar & Availability</CardTitle>
</CardHeader> </CardHeader>
<CardContent className='space-y-6'> <CardContent className='space-y-6 my-2'>
{/*--------------------* Calendar --------------------*/} {/*-------------------- Date & Time Format --------------------*/}
<GroupWrapper title='Date & Time Format'>
<div className='flex flex-col space-y-4'>
<div className='grid grid-cols-1 gap-1'>
<Label htmlFor='dateFormat'>Date Format</Label>
<Select>
<SelectTrigger id='dateFormat'>
<SelectValue placeholder='Select date format' />
</SelectTrigger>
<SelectContent>
<SelectItem value='ddmmyyyy'>DD/MM/YYYY</SelectItem>
<SelectItem value='mmddyyyy'>MM/DD/YYYY</SelectItem>
<SelectItem value='yyyymmdd'>YYYY-MM-DD</SelectItem>
</SelectContent>
</Select>
</div>
<div className='grid grid-cols-1 gap-1'>
<Label htmlFor='timeFormat'>Time Format</Label>
<Select>
<SelectTrigger id='timeFormat'>
<SelectValue placeholder='Select time format' />
</SelectTrigger>
<SelectContent>
<SelectItem value='24h'>24-hour</SelectItem>
<SelectItem value='12h'>12-hour</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</GroupWrapper>
{/*-------------------- Date & Time Format --------------------*/}
{/*-------------------- Calendar --------------------*/}
<GroupWrapper title='Calendar'> <GroupWrapper title='Calendar'>
<div className='space-y-4'> <div className='space-y-4'>
<div className='grid grid-cols-1 gap-1'> <div className='grid grid-cols-1 gap-1'>
@ -306,9 +366,8 @@ export default function SettingsPage() {
</div> </div>
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*--------------------* Calendar --------------------*/} {/*-------------------- Calendar --------------------*/}
{/*-------------------- Availability --------------------*/}
{/*--------------------* Availability --------------------*/}
<GroupWrapper title='Availability'> <GroupWrapper title='Availability'>
<div className='space-y-4'> <div className='space-y-4'>
<div className='space-y-2'> <div className='space-y-2'>
@ -325,8 +384,9 @@ export default function SettingsPage() {
<LabeledInput <LabeledInput
type='text' type='text'
label='Minimum Notice for Bookings' label='Minimum Notice for Bookings'
icon={ClockAlert}
subtext='Min time before a booking can be made.' subtext='Min time before a booking can be made.'
placeholder='e.g., 1h' placeholder='e.g. 1h'
defaultValue={''} defaultValue={''}
></LabeledInput> ></LabeledInput>
</div> </div>
@ -334,43 +394,65 @@ export default function SettingsPage() {
<LabeledInput <LabeledInput
type='text' type='text'
label='Booking Window (days in advance)' label='Booking Window (days in advance)'
icon={ClockFading}
subtext='Max time in advance a booking can be made.' subtext='Max time in advance a booking can be made.'
placeholder='e.g., 30d' placeholder='e.g. 30d'
defaultValue={''} defaultValue={''}
></LabeledInput> ></LabeledInput>
</div> </div>
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*--------------------* Availability --------------------*/} {/*-------------------- Availability --------------------*/}
{/*-------------------- iCalendar Integration --------------------*/}
{/*--------------------* iCalendar Integration --------------------*/} <GroupWrapper title='iCalendar Integration'>
<fieldset className='space-y-4 p-4 border rounded-md'> <div className='space-y-4'>
<legend className='text-sm font-medium px-1'> <form
iCalendar Integration onSubmit={(e) => {
</legend> e.preventDefault();
<div className='space-y-2'> }}
className='space-y-2'
>
<LabeledInput <LabeledInput
type='url' type='url'
label='Import iCal Feed URL' label='Import iCal Feed URL'
subtext='Max time in advance a booking can be made.' icon={CalendarCheck}
placeholder='https://calendar.example.com/feed.ics' placeholder='https://calendar.example.com/feed.ics'
defaultValue={''} defaultValue={''}
name='icalUrl'
required
></LabeledInput> ></LabeledInput>
<Button size='sm' className='mt-1'> <IconButton
type='submit'
size='sm'
className='mt-1'
variant={'secondary'}
icon={CalendarPlus}
title='Submit iCal URL'
>
Add Feed Add Feed
</Button> </IconButton>
</div> </form>
<div className='space-y-2'> <div className='space-y-2'>
<Label>Export Your Calendar</Label> <Label>Export Your Calendar</Label>
<Button variant='outline_muted' size='sm'> <IconButton
variant='outline_muted'
size='sm'
icon={CalendarArrowUp}
>
Get iCal Export URL Get iCal Export URL
</Button> </IconButton>
<Button variant='outline_muted' size='sm' className='ml-2'> <IconButton
variant='outline_muted'
size='sm'
className='ml-2'
icon={CalendarArrowDown}
>
Download .ics File Download .ics File
</Button> </IconButton>
</div> </div>
</fieldset> </div>
{/*--------------------* iCalendar Integration --------------------*/} </GroupWrapper>
{/*-------------------- iCalendar Integration --------------------*/}
</CardContent> </CardContent>
</ScrollableSettingsWrapper> </ScrollableSettingsWrapper>
</Card> </Card>
@ -383,11 +465,17 @@ export default function SettingsPage() {
<CardHeader> <CardHeader>
<CardTitle>Sharing & Privacy</CardTitle> <CardTitle>Sharing & Privacy</CardTitle>
</CardHeader> </CardHeader>
<CardContent className='space-y-6'> <CardContent className='space-y-6 my-2'>
<div className='space-y-2'> {/*-------------------- Privacy Settigs --------------------*/}
<GroupWrapper title='Privacy Settings'>
<div className='flex flex-col space-y-4'>
<div className='grid grid-cols-1 gap-1'>
<Label htmlFor='defaultVisibility'> <Label htmlFor='defaultVisibility'>
Default Calendar Visibility Default Calendar Visibility
</Label> </Label>
<span className='text-sm text-muted-foreground'>
Default setting for new friends.
</span>
<Select> <Select>
<SelectTrigger id='defaultVisibility'> <SelectTrigger id='defaultVisibility'>
<SelectValue placeholder='Select visibility' /> <SelectValue placeholder='Select visibility' />
@ -396,16 +484,14 @@ export default function SettingsPage() {
<SelectItem value='private'> <SelectItem value='private'>
Private (Only You) Private (Only You)
</SelectItem> </SelectItem>
<SelectItem value='freebusy'> <SelectItem value='freebusy'>Free/Busy</SelectItem>
Free/Busy for Friends
</SelectItem>
<SelectItem value='fulldetails'> <SelectItem value='fulldetails'>
Full Details for Friends Full Details
</SelectItem> </SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<div className='space-y-2'> <div className='grid grid-cols-1 gap-1'>
<Label htmlFor='whoCanSeeFull'> <Label htmlFor='whoCanSeeFull'>
Who Can See Your Full Calendar Details? Who Can See Your Full Calendar Details?
</Label> </Label>
@ -413,9 +499,9 @@ export default function SettingsPage() {
(Override for Default Visibility) (Override for Default Visibility)
<br /> <br />
<span className='text-sm text-muted-foreground'> <span className='text-sm text-muted-foreground'>
This setting will override the default visibility for your This setting will override the default visibility for
calendar. You can set specific friends or groups to see your calendar. You can set specific friends or groups
your full calendar details. to see your full calendar details.
</span> </span>
</span> </span>
<Select> <Select>
@ -431,7 +517,7 @@ export default function SettingsPage() {
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<div className='space-y-2'> <div className='grid grid-cols-1 gap-1'>
<Label htmlFor='whoCanBook'> <Label htmlFor='whoCanBook'>
Who Can Book Time With You? Who Can Book Time With You?
</Label> </Label>
@ -448,14 +534,25 @@ export default function SettingsPage() {
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<div className='space-y-2'> <div className='space-y-4'>
<div className='grid grid-cols-1 gap-1'>
<Label>Blocked Users</Label> <Label>Blocked Users</Label>
<Button variant='outline_muted'>Manage Blocked Users</Button>
<span className='text-sm text-muted-foreground'> <span className='text-sm text-muted-foreground'>
Prevent specific users from seeing your calendar or booking Prevent specific users from seeing your calendar or
time. booking time.
</span> </span>
<IconButton
variant='outline_muted'
size='sm'
icon={UserLock}
>
Manage Blocked Users
</IconButton>
</div> </div>
</div>
</div>
</GroupWrapper>
{/*-------------------- Privacy Settigs --------------------*/}
</CardContent> </CardContent>
</ScrollableSettingsWrapper> </ScrollableSettingsWrapper>
</Card> </Card>
@ -468,36 +565,15 @@ export default function SettingsPage() {
<CardHeader> <CardHeader>
<CardTitle>Appearance</CardTitle> <CardTitle>Appearance</CardTitle>
</CardHeader> </CardHeader>
<CardContent className='space-y-6'> <CardContent className='space-y-6 my-2'>
{/*-------------------- Change Theme --------------------*/}
<GroupWrapper title='Change Theme'>
<div className='space-y-2'> <div className='space-y-2'>
<Label htmlFor='theme'>Theme</Label> <Label htmlFor='theme'>Theme</Label>
<ThemePicker /> <ThemePicker />
</div> </div>
<div className='space-y-2'> </GroupWrapper>
<Label htmlFor='dateFormat'>Date Format</Label> {/*-------------------- Change Theme --------------------*/}
<Select>
<SelectTrigger id='dateFormat'>
<SelectValue placeholder='Select date format' />
</SelectTrigger>
<SelectContent>
<SelectItem value='ddmmyyyy'>DD/MM/YYYY</SelectItem>
<SelectItem value='mmddyyyy'>MM/DD/YYYY</SelectItem>
<SelectItem value='yyyymmdd'>YYYY-MM-DD</SelectItem>
</SelectContent>
</Select>
</div>
<div className='space-y-2'>
<Label htmlFor='timeFormat'>Time Format</Label>
<Select>
<SelectTrigger id='timeFormat'>
<SelectValue placeholder='Select time format' />
</SelectTrigger>
<SelectContent>
<SelectItem value='24h'>24-hour</SelectItem>
<SelectItem value='12h'>12-hour</SelectItem>
</SelectContent>
</Select>
</div>
</CardContent> </CardContent>
</ScrollableSettingsWrapper> </ScrollableSettingsWrapper>
</Card> </Card>