feat: tempcommit

This commit is contained in:
Maximilian Liebmann 2025-06-30 11:08:56 +02:00
parent f813f2351a
commit b191090f90
4 changed files with 124 additions and 62 deletions

View file

@ -10,7 +10,7 @@ export function IconButton({
icon?: ForwardRefExoticComponent< icon?: ForwardRefExoticComponent<
Omit<LucideProps, 'ref'> & RefAttributes<SVGSVGElement> 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}>

View file

@ -69,7 +69,7 @@ export default function LabeledInput({
)} )}
type={passwordVisible ? 'text' : type} type={passwordVisible ? 'text' : type}
placeholder={placeholder} placeholder={placeholder}
value={inputValue} defaultValue={inputValue}
id={name} id={name}
name={name} name={name}
autoComplete={autocomplete} autoComplete={autocomplete}

View file

@ -29,6 +29,7 @@ import { GroupWrapper } from '../wrappers/group-wrapper';
import ProfilePictureUpload from './profile-picture-upload'; import ProfilePictureUpload from './profile-picture-upload';
import { import {
BookKey,
CalendarArrowDown, CalendarArrowDown,
CalendarArrowUp, CalendarArrowUp,
CalendarCheck, CalendarCheck,
@ -46,6 +47,14 @@ import {
UserPen, UserPen,
} from 'lucide-react'; } from 'lucide-react';
import { IconButton } from '../buttons/icon-button'; import { IconButton } from '../buttons/icon-button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '../ui/dialog';
export default function SettingsPage() { export default function SettingsPage() {
const router = useRouter(); const router = useRouter();
@ -53,6 +62,11 @@ export default function SettingsPage() {
const { data } = useGetApiUserMe(); const { data } = useGetApiUserMe();
const deleteUser = useDeleteApiUserMe(); const deleteUser = useDeleteApiUserMe();
// Move password state hooks here
const [currentPassword, setCurrentPassword] = useState('');
const [newPassword, setNewPassword] = useState('');
const [repeatPassword, setRepeatPassword] = useState('');
const renderSettingsContent = () => { const renderSettingsContent = () => {
switch (currentSection) { switch (currentSection) {
case 'general': case 'general':
@ -109,27 +123,52 @@ export default function SettingsPage() {
{/*-------------------- General Settings --------------------*/} {/*-------------------- General Settings --------------------*/}
{/*-------------------- Reset Password --------------------*/} {/*-------------------- 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 flex-col sm:flex-row items-center gap-6'>
<div> <div className='flex flex-col sm:flex-row gap-6 w-full'>
<LabeledInput {/* Use the state variables directly */}
type='password' <div className='flex-1'>
label='Current Password' <LabeledInput
icon={FileKey} type='password'
></LabeledInput> label='Current Password'
</div> icon={FileKey}
<div> value={currentPassword}
<LabeledInput onChange={(e) => setCurrentPassword(e.target.value)}
type='password' />
label='New Password' </div>
icon={FileKey2} <div className='flex-1'>
></LabeledInput> <LabeledInput
</div> type='password'
<div> label='New Password'
<LabeledInput icon={FileKey2}
type='password' value={newPassword}
label='Repeat Password' onChange={(e) => setNewPassword(e.target.value)}
icon={RotateCcwKey} />
></LabeledInput> </div>
<div className='flex-1'>
<LabeledInput
type='password'
label='Repeat Password'
icon={RotateCcwKey}
value={repeatPassword}
onChange={(e) => setRepeatPassword(e.target.value)}
/>
</div>
<div className='flex items-end'>
<Button
variant={
currentPassword || newPassword || repeatPassword
? 'outline_secondary'
: 'outline_muted'
}
size='icon'
className='w-full md:size-9'
disabled={
!(currentPassword || newPassword || repeatPassword)
}
>
<BookKey className='h-[1.2rem] w-[1.2rem]' />
</Button>
</div>
</div> </div>
</div> </div>
</GroupWrapper> </GroupWrapper>
@ -170,25 +209,49 @@ export default function SettingsPage() {
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- Regional Settings --------------------*/} {/*-------------------- Regional Settings --------------------*/}
<GroupWrapper title='DANGER ZONE - INSTANT DELETE - NO CONFIRMATION'> {/*-------------------- DANGER ZONE --------------------*/}
<GroupWrapper
title='DANGER ZONE'
className='border-destructive'
>
<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 <Dialog>
onClick={() => { <DialogTrigger>
deleteUser.mutate(undefined, { <Button variant='destructive'>Delete Account</Button>
onSuccess: () => { </DialogTrigger>
router.push('/api/logout'); <DialogContent>
}, <DialogHeader>
}); <div className='space-y-4'>
}} <DialogTitle>Are you absolutely sure?</DialogTitle>
variant='destructive' <div className='space-y-4'>
> <DialogDescription>
Delete Account This action cannot be undone. This will
</Button> permanently delete your account and remove your
data from our servers.
</DialogDescription>
<Button
variant='destructive'
onClick={() => {
deleteUser.mutate(undefined, {
onSuccess: () => {
router.push('/api/logout');
},
});
}}
>
Confirm Delete
</Button>
</div>
</div>
</DialogHeader>
</DialogContent>
</Dialog>
<span className='text-sm text-muted-foreground pt-1'> <span className='text-sm text-muted-foreground pt-1'>
Permanently delete your account and all associated data. Permanently delete your account and all associated data.
</span> </span>
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- DANGER ZONE --------------------*/}
</CardContent> </CardContent>
</ScrollableSettingsWrapper> </ScrollableSettingsWrapper>
</Card> </Card>
@ -236,35 +299,34 @@ export default function SettingsPage() {
</Label> </Label>
<Switch id='meetingConfirmations' /> <Switch id='meetingConfirmations' />
</div> </div>
<div className='space-y-4 grid grid-cols-[1fr_1fr_auto] items-center'> <div className='flex items-center justify-between space-x-2'>
<div className='flex items-center justify-between space-x-2'> <Label
<Label htmlFor='enableMeetingReminders'
htmlFor='enableMeetingReminders' className='font-normal'
className='font-normal' >
> Meeting Reminders
Meeting Reminders </Label>
</Label>
</div>
<div>
<Label className='text-sm' htmlFor='remindBefore'>
Remind me before
</Label>
<Select>
<SelectTrigger id='remindBefore'>
<SelectValue placeholder='Select reminder time' />
</SelectTrigger>
<SelectContent>
<SelectItem value='15m'>15 minutes</SelectItem>
<SelectItem value='30m'>30 minutes</SelectItem>
<SelectItem value='1h'>1 hour</SelectItem>
<SelectItem value='1d'>1 day</SelectItem>
</SelectContent>
</Select>
</div>
<div> <div>
<Switch id='enableMeetingReminders' /> <Switch id='enableMeetingReminders' />
</div> </div>
</div> </div>
<div className='flex items-center justify-between space-x-2'>
<Label className='font-normal' htmlFor='remindBefore'>
Remind me before
</Label>
<Select>
<SelectTrigger id='remindBefore'>
<SelectValue placeholder='Select reminder time' />
</SelectTrigger>
<SelectContent>
<SelectItem value='15m'>15 minutes</SelectItem>
<SelectItem value='30m'>30 minutes</SelectItem>
<SelectItem value='1h'>1 hour</SelectItem>
<SelectItem value='1d'>1 day</SelectItem>
</SelectContent>
</Select>
</div>
</div> </div>
</GroupWrapper> </GroupWrapper>
{/*-------------------- Meetings --------------------*/} {/*-------------------- Meetings --------------------*/}

View file

@ -69,7 +69,7 @@ function DialogContent({
{showCloseButton && ( {showCloseButton && (
<DialogPrimitive.Close <DialogPrimitive.Close
data-slot='dialog-close' data-slot='dialog-close'
className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4" className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-2 right-2 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
> >
<XIcon /> <XIcon />
<span className='sr-only'>Close</span> <span className='sr-only'>Close</span>