This change actually makes the authoring flow work for the most part by tying in emailing and more. We have also done a number of quality of life updates to simplify the codebase overall making it easier to continue work on the refresh.
126 lines
3.4 KiB
TypeScript
126 lines
3.4 KiB
TypeScript
'use client';
|
|
|
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
import { Loader } from 'lucide-react';
|
|
import { useForm } from 'react-hook-form';
|
|
import { z } from 'zod';
|
|
|
|
import { User } from '@documenso/prisma/client';
|
|
import { TRPCClientError } from '@documenso/trpc/client';
|
|
import { trpc } from '@documenso/trpc/react';
|
|
import { cn } from '@documenso/ui/lib/utils';
|
|
import { Button } from '@documenso/ui/primitives/button';
|
|
import { Input } from '@documenso/ui/primitives/input';
|
|
import { Label } from '@documenso/ui/primitives/label';
|
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
|
|
|
import { FormErrorMessage } from '../form/form-error-message';
|
|
|
|
export const ZPasswordFormSchema = z
|
|
.object({
|
|
password: z.string().min(6),
|
|
repeatedPassword: z.string().min(6),
|
|
})
|
|
.refine((data) => data.password === data.repeatedPassword, {
|
|
message: 'Passwords do not match',
|
|
path: ['repeatedPassword'],
|
|
});
|
|
|
|
export type TPasswordFormSchema = z.infer<typeof ZPasswordFormSchema>;
|
|
|
|
export type PasswordFormProps = {
|
|
className?: string;
|
|
user: User;
|
|
};
|
|
|
|
export const PasswordForm = ({ className }: PasswordFormProps) => {
|
|
const { toast } = useToast();
|
|
|
|
const {
|
|
register,
|
|
handleSubmit,
|
|
formState: { errors, isSubmitting },
|
|
} = useForm<TPasswordFormSchema>({
|
|
values: {
|
|
password: '',
|
|
repeatedPassword: '',
|
|
},
|
|
resolver: zodResolver(ZPasswordFormSchema),
|
|
});
|
|
|
|
const { mutateAsync: updatePassword } = trpc.profile.updatePassword.useMutation();
|
|
|
|
const onFormSubmit = async ({ password }: TPasswordFormSchema) => {
|
|
try {
|
|
await updatePassword({
|
|
password,
|
|
});
|
|
|
|
toast({
|
|
title: 'Password updated',
|
|
description: 'Your password has been updated successfully.',
|
|
duration: 5000,
|
|
});
|
|
} catch (err) {
|
|
if (err instanceof TRPCClientError && err.data?.code === 'BAD_REQUEST') {
|
|
toast({
|
|
title: 'An error occurred',
|
|
description: err.message,
|
|
variant: 'destructive',
|
|
});
|
|
} else {
|
|
toast({
|
|
title: 'An unknown error occurred',
|
|
variant: 'destructive',
|
|
description:
|
|
'We encountered an unknown error while attempting to sign you In. Please try again later.',
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<form
|
|
className={cn('flex-col flex w-full gap-y-4', className)}
|
|
onSubmit={handleSubmit(onFormSubmit)}
|
|
>
|
|
<div>
|
|
<Label htmlFor="password" className="text-slate-500">
|
|
Password
|
|
</Label>
|
|
|
|
<Input
|
|
id="password"
|
|
type="password"
|
|
className="bg-background mt-2"
|
|
{...register('password')}
|
|
/>
|
|
|
|
<FormErrorMessage className="mt-1.5" error={errors.password} />
|
|
</div>
|
|
|
|
<div>
|
|
<Label htmlFor="repeated-password" className="text-slate-500">
|
|
Repeat Password
|
|
</Label>
|
|
|
|
<Input
|
|
id="repeated-password"
|
|
type="password"
|
|
className="bg-background mt-2"
|
|
{...register('repeatedPassword')}
|
|
/>
|
|
|
|
<FormErrorMessage className="mt-1.5" error={errors.repeatedPassword} />
|
|
</div>
|
|
|
|
<div className="mt-4">
|
|
<Button type="submit" disabled={isSubmitting}>
|
|
{isSubmitting && <Loader className="mr-2 h-5 w-5 animate-spin" />}
|
|
Update password
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
);
|
|
};
|