feat: tempcommit
This commit is contained in:
parent
b191090f90
commit
f508f26531
2 changed files with 74 additions and 24 deletions
|
@ -11,6 +11,7 @@ export default function LabeledInput({
|
||||||
subtext,
|
subtext,
|
||||||
placeholder,
|
placeholder,
|
||||||
value,
|
value,
|
||||||
|
defaultValue,
|
||||||
name,
|
name,
|
||||||
icon,
|
icon,
|
||||||
variantSize = 'default',
|
variantSize = 'default',
|
||||||
|
@ -31,7 +32,7 @@ export default function LabeledInput({
|
||||||
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 [inputValue, setInputValue] = React.useState(value || defaultValue || '');
|
||||||
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setInputValue(e.target.value);
|
setInputValue(e.target.value);
|
||||||
|
|
|
@ -22,7 +22,11 @@ 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 { useDeleteApiUserMe, useGetApiUserMe } from '@/generated/api/user/user';
|
import {
|
||||||
|
useDeleteApiUserMe,
|
||||||
|
useGetApiUserMe,
|
||||||
|
usePatchApiUserMePassword,
|
||||||
|
} from '@/generated/api/user/user';
|
||||||
import { ThemePicker } from './theme-picker';
|
import { ThemePicker } from './theme-picker';
|
||||||
import LabeledInput from '../custom-ui/labeled-input';
|
import LabeledInput from '../custom-ui/labeled-input';
|
||||||
import { GroupWrapper } from '../wrappers/group-wrapper';
|
import { GroupWrapper } from '../wrappers/group-wrapper';
|
||||||
|
@ -55,17 +59,55 @@ import {
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from '../ui/dialog';
|
} from '../ui/dialog';
|
||||||
|
import useZodForm from '@/lib/hooks/useZodForm';
|
||||||
|
import { updateUserPasswordServerSchema } from '@/app/api/user/me/validation';
|
||||||
|
|
||||||
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 { data } = useGetApiUserMe();
|
||||||
const deleteUser = useDeleteApiUserMe();
|
const deleteUser = useDeleteApiUserMe();
|
||||||
|
const updatePassword = usePatchApiUserMePassword();
|
||||||
|
|
||||||
// Move password state hooks here
|
const { handleSubmit, formState, register, setError } = useZodForm(
|
||||||
const [currentPassword, setCurrentPassword] = useState('');
|
updateUserPasswordServerSchema,
|
||||||
const [newPassword, setNewPassword] = useState('');
|
);
|
||||||
const [repeatPassword, setRepeatPassword] = useState('');
|
|
||||||
|
const onSubmit = handleSubmit(async (data) => {
|
||||||
|
await updatePassword.mutateAsync(
|
||||||
|
{
|
||||||
|
data: data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
router.refresh();
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
setError('root', {
|
||||||
|
message: error.response?.data.message,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setError('root', {
|
||||||
|
message: 'An unknown error occurred.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return (
|
||||||
|
<div className='fixed inset-0 flex items-center justify-center p-4 bg-background/50 backdrop-blur-sm'>
|
||||||
|
<div className='rounded-lg border bg-card text-card-foreground shadow-xl max-w-[700px] w-full h-auto max-h-[calc(100vh-2rem)] flex flex-col'>
|
||||||
|
<div className='p-6 border-b'>
|
||||||
|
<h1 className='text-2xl font-semibold'>Loading Settings...</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const renderSettingsContent = () => {
|
const renderSettingsContent = () => {
|
||||||
switch (currentSection) {
|
switch (currentSection) {
|
||||||
|
@ -85,7 +127,7 @@ export default function SettingsPage() {
|
||||||
type='text'
|
type='text'
|
||||||
label='First Name'
|
label='First Name'
|
||||||
placeholder='First Name'
|
placeholder='First Name'
|
||||||
defaultValue={data?.data.user.first_name ?? ''}
|
defaultValue={data.data.user.first_name ?? ''}
|
||||||
></LabeledInput>
|
></LabeledInput>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -93,7 +135,7 @@ export default function SettingsPage() {
|
||||||
type='text'
|
type='text'
|
||||||
label='Last Name'
|
label='Last Name'
|
||||||
placeholder='Last Name'
|
placeholder='Last Name'
|
||||||
defaultValue={data?.data.user.last_name ?? ''}
|
defaultValue={data.data.user.last_name ?? ''}
|
||||||
></LabeledInput>
|
></LabeledInput>
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
|
@ -102,7 +144,7 @@ export default function SettingsPage() {
|
||||||
label='Display Name'
|
label='Display Name'
|
||||||
icon={UserPen}
|
icon={UserPen}
|
||||||
placeholder='Display Name'
|
placeholder='Display Name'
|
||||||
defaultValue={data?.data.user.name}
|
defaultValue={data.data.user.name}
|
||||||
></LabeledInput>
|
></LabeledInput>
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-2 space-b-2'>
|
<div className='space-y-2 space-b-2'>
|
||||||
|
@ -111,7 +153,7 @@ export default function SettingsPage() {
|
||||||
label='Email Address'
|
label='Email Address'
|
||||||
icon={MailOpen}
|
icon={MailOpen}
|
||||||
placeholder='Your E-Mail'
|
placeholder='Your E-Mail'
|
||||||
defaultValue={data?.data.user.email ?? ''}
|
defaultValue={data.data.user.email ?? ''}
|
||||||
></LabeledInput>
|
></LabeledInput>
|
||||||
|
|
||||||
<span className='text-sm text-muted-foreground'>
|
<span className='text-sm text-muted-foreground'>
|
||||||
|
@ -123,16 +165,18 @@ export default function SettingsPage() {
|
||||||
{/*-------------------- General Settings --------------------*/}
|
{/*-------------------- General Settings --------------------*/}
|
||||||
{/*-------------------- Reset Password --------------------*/}
|
{/*-------------------- Reset Password --------------------*/}
|
||||||
<GroupWrapper title='Reset Password'>
|
<GroupWrapper title='Reset Password'>
|
||||||
<div className='flex flex-col sm:flex-row items-center gap-6'>
|
<div className='flex flex-col items-center gap-6'>
|
||||||
<div className='flex flex-col sm:flex-row gap-6 w-full'>
|
<form
|
||||||
{/* Use the state variables directly */}
|
onSubmit={onSubmit}
|
||||||
|
className='flex flex-col sm:flex-row gap-6 w-full'
|
||||||
|
>
|
||||||
<div className='flex-1'>
|
<div className='flex-1'>
|
||||||
<LabeledInput
|
<LabeledInput
|
||||||
type='password'
|
type='password'
|
||||||
label='Current Password'
|
label='Current Password'
|
||||||
icon={FileKey}
|
icon={FileKey}
|
||||||
value={currentPassword}
|
{...register('current_password')}
|
||||||
onChange={(e) => setCurrentPassword(e.target.value)}
|
error={formState.errors.current_password?.message}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex-1'>
|
<div className='flex-1'>
|
||||||
|
@ -140,8 +184,8 @@ export default function SettingsPage() {
|
||||||
type='password'
|
type='password'
|
||||||
label='New Password'
|
label='New Password'
|
||||||
icon={FileKey2}
|
icon={FileKey2}
|
||||||
value={newPassword}
|
{...register('new_password')}
|
||||||
onChange={(e) => setNewPassword(e.target.value)}
|
error={formState.errors.new_password?.message}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex-1'>
|
<div className='flex-1'>
|
||||||
|
@ -149,34 +193,39 @@ export default function SettingsPage() {
|
||||||
type='password'
|
type='password'
|
||||||
label='Repeat Password'
|
label='Repeat Password'
|
||||||
icon={RotateCcwKey}
|
icon={RotateCcwKey}
|
||||||
value={repeatPassword}
|
{...register('confirm_new_password')}
|
||||||
onChange={(e) => setRepeatPassword(e.target.value)}
|
error={formState.errors.confirm_new_password?.message}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-end'>
|
<div className='flex items-end'>
|
||||||
<Button
|
<Button
|
||||||
variant={
|
variant={
|
||||||
currentPassword || newPassword || repeatPassword
|
formState.isValid
|
||||||
? 'outline_secondary'
|
? 'outline_secondary'
|
||||||
: 'outline_muted'
|
: 'outline_muted'
|
||||||
}
|
}
|
||||||
size='icon'
|
size='icon'
|
||||||
className='w-full md:size-9'
|
className='w-full md:size-9'
|
||||||
disabled={
|
disabled={
|
||||||
!(currentPassword || newPassword || repeatPassword)
|
!formState.isValid || formState.isSubmitting
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<BookKey className='h-[1.2rem] w-[1.2rem]' />
|
<BookKey className='h-[1.2rem] w-[1.2rem]' />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
|
{formState.errors.root && (
|
||||||
|
<p className='text-red-500 text-sm mt-1'>
|
||||||
|
{formState.errors.root.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</GroupWrapper>
|
</GroupWrapper>
|
||||||
{/*-------------------- Reset Password --------------------*/}
|
{/*-------------------- Reset Password --------------------*/}
|
||||||
{/*-------------------- Profile Picture --------------------*/}
|
{/*-------------------- 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 />
|
||||||
</div>
|
</div>
|
||||||
</GroupWrapper>
|
</GroupWrapper>
|
||||||
{/*-------------------- Profile Picture --------------------*/}
|
{/*-------------------- Profile Picture --------------------*/}
|
||||||
|
@ -216,7 +265,7 @@ export default function SettingsPage() {
|
||||||
>
|
>
|
||||||
<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'>
|
||||||
<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger>
|
<DialogTrigger asChild>
|
||||||
<Button variant='destructive'>Delete Account</Button>
|
<Button variant='destructive'>Delete Account</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue