This commit is contained in:
David Nguyen
2025-01-31 14:09:02 +11:00
parent f7a98180d7
commit d7d0fca501
146 changed files with 1250 additions and 1263 deletions

View File

@ -8,7 +8,6 @@ import { z } from 'zod';
import { downloadFile } from '@documenso/lib/client-only/download-file';
import { AppError } from '@documenso/lib/errors/app-error';
import { ErrorCode } from '@documenso/lib/next-auth/error-codes';
import { trpc } from '@documenso/trpc/react';
import { Alert, AlertDescription } from '@documenso/ui/primitives/alert';
import { Button } from '@documenso/ui/primitives/button';
@ -145,7 +144,7 @@ export const ViewRecoveryCodesDialog = () => {
<Alert variant="destructive">
<AlertDescription>
{match(AppError.parseError(error).message)
.with(ErrorCode.INCORRECT_TWO_FACTOR_CODE, () => (
.with('INCORRECT_TWO_FACTOR_CODE', () => (
<Trans>Invalid code. Please try again.</Trans>
))
.otherwise(() => (

View File

@ -3,14 +3,14 @@ import { useMemo } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react';
// Todo
// import { ErrorCode, useDropzone } from 'react-dropzone';
import { ErrorCode, useDropzone } from 'react-dropzone';
import { useForm } from 'react-hook-form';
import { match } from 'ts-pattern';
import { z } from 'zod';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { AppError } from '@documenso/lib/errors/app-error';
import { formatAvatarUrl } from '@documenso/lib/utils/avatars';
import { base64 } from '@documenso/lib/universal/base64';
import { extractInitials } from '@documenso/lib/utils/recipient-formatter';
import { trpc } from '@documenso/trpc/react';
import { cn } from '@documenso/ui/lib/utils';
@ -40,9 +40,9 @@ export type AvatarImageFormProps = {
};
export const AvatarImageForm = ({ className }: AvatarImageFormProps) => {
const { user } = useAuth();
const { _ } = useLingui();
const { toast } = useToast();
const { user } = useAuth();
const team = useOptionalCurrentTeam();
@ -67,31 +67,31 @@ export const AvatarImageForm = ({ className }: AvatarImageFormProps) => {
resolver: zodResolver(ZAvatarImageFormSchema),
});
// const { getRootProps, getInputProps } = useDropzone({
// maxSize: 1024 * 1024,
// accept: {
// 'image/*': ['.png', '.jpg', '.jpeg'],
// },
// multiple: false,
// onDropAccepted: ([file]) => {
// void file.arrayBuffer().then((buffer) => {
// const contents = base64.encode(new Uint8Array(buffer));
const { getRootProps, getInputProps } = useDropzone({
maxSize: 1024 * 1024,
accept: {
'image/*': ['.png', '.jpg', '.jpeg'],
},
multiple: false,
onDropAccepted: ([file]) => {
void file.arrayBuffer().then((buffer) => {
const contents = base64.encode(new Uint8Array(buffer));
// form.setValue('bytes', contents);
// void form.handleSubmit(onFormSubmit)();
// });
// },
// onDropRejected: ([file]) => {
// form.setError('bytes', {
// type: 'onChange',
// message: match(file.errors[0].code)
// .with(ErrorCode.FileTooLarge, () => _(msg`Uploaded file is too large`))
// .with(ErrorCode.FileTooSmall, () => _(msg`Uploaded file is too small`))
// .with(ErrorCode.FileInvalidType, () => _(msg`Uploaded file not an allowed file type`))
// .otherwise(() => _(msg`An unknown error occurred`)),
// });
// },
// });
form.setValue('bytes', contents);
void form.handleSubmit(onFormSubmit)();
});
},
onDropRejected: ([file]) => {
form.setError('bytes', {
type: 'onChange',
message: match(file.errors[0].code)
.with(ErrorCode.FileTooLarge, () => _(msg`Uploaded file is too large`))
.with(ErrorCode.FileTooSmall, () => _(msg`Uploaded file is too small`))
.with(ErrorCode.FileInvalidType, () => _(msg`Uploaded file not an allowed file type`))
.otherwise(() => _(msg`An unknown error occurred`)),
});
},
});
const onFormSubmit = async (data: TAvatarImageFormSchema) => {
try {
@ -106,7 +106,8 @@ export const AvatarImageForm = ({ className }: AvatarImageFormProps) => {
duration: 5000,
});
// router.refresh(); // Todo
// Todo
// router.refresh();
} catch (err) {
const error = AppError.parseError(err);
@ -143,7 +144,11 @@ export const AvatarImageForm = ({ className }: AvatarImageFormProps) => {
<div className="flex items-center gap-8">
<div className="relative">
<Avatar className="h-16 w-16 border-2 border-solid">
{avatarImageId && <AvatarImage src={formatAvatarUrl(avatarImageId)} />}
{avatarImageId && (
<AvatarImage
src={`${NEXT_PUBLIC_WEBAPP_URL()}/api/avatar/${avatarImageId}`}
/>
)}
<AvatarFallback className="text-sm text-gray-400">
{initials}
</AvatarFallback>
@ -165,12 +170,12 @@ export const AvatarImageForm = ({ className }: AvatarImageFormProps) => {
type="button"
variant="secondary"
size="sm"
// {...getRootProps()}
{...getRootProps()}
loading={form.formState.isSubmitting}
disabled={form.formState.isSubmitting}
>
<Trans>Upload Avatar</Trans>
{/* <input {...getInputProps()} /> */}
<input {...getInputProps()} />
</Button>
</div>
</FormControl>

View File

@ -6,8 +6,8 @@ import { useForm } from 'react-hook-form';
import { match } from 'ts-pattern';
import { z } from 'zod';
import { authClient } from '@documenso/auth/client';
import { AppError } from '@documenso/lib/errors/app-error';
import { trpc } from '@documenso/trpc/react';
import { ZCurrentPasswordSchema, ZPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button';
@ -55,11 +55,9 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
const isSubmitting = form.formState.isSubmitting;
const { mutateAsync: updatePassword } = trpc.profile.updatePassword.useMutation();
const onFormSubmit = async ({ currentPassword, password }: TPasswordFormSchema) => {
try {
await updatePassword({
await authClient.updatePassword({
currentPassword,
password,
});

View File

@ -88,12 +88,12 @@ export const ClaimPublicProfileDialogForm = ({
} catch (err) {
const error = AppError.parseError(err);
if (error.code === AppErrorCode.PROFILE_URL_TAKEN) {
if (error.code === 'PROFILE_URL_TAKEN') {
form.setError('url', {
type: 'manual',
message: _(msg`This username is already taken`),
});
} else if (error.code === AppErrorCode.PREMIUM_PROFILE_URL) {
} else if (error.code === 'PREMIUM_PROFILE_URL') {
form.setError('url', {
type: 'manual',
message: error.message,

View File

@ -11,7 +11,7 @@ import { useForm } from 'react-hook-form';
import type { z } from 'zod';
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { AppError } from '@documenso/lib/errors/app-error';
import { formatUserProfilePath } from '@documenso/lib/utils/public-profiles';
import {
MAX_PROFILE_BIO_LENGTH,
@ -88,8 +88,8 @@ export const PublicProfileForm = ({
const error = AppError.parseError(err);
switch (error.code) {
case AppErrorCode.PREMIUM_PROFILE_URL:
case AppErrorCode.PROFILE_URL_TAKEN:
case 'PREMIUM_PROFILE_URL':
case 'PROFILE_URL_TAKEN':
form.setError('url', {
type: 'manual',
message: error.message,

View File

@ -15,7 +15,6 @@ import { z } from 'zod';
import { authClient } from '@documenso/auth/client';
import { AuthenticationErrorCode } from '@documenso/auth/server/lib/errors/error-codes';
import { AppError } from '@documenso/lib/errors/app-error';
import { ErrorCode } from '@documenso/lib/next-auth/error-codes';
import { trpc } from '@documenso/trpc/react';
import { ZCurrentPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
import { cn } from '@documenso/ui/lib/utils';
@ -46,8 +45,6 @@ const CommonErrorMessages = {
[AuthenticationErrorCode.AccountDisabled]: msg`This account has been disabled. Please contact support.`,
};
const TwoFactorEnabledErrorCode = ErrorCode.TWO_FACTOR_MISSING_CREDENTIALS;
const LOGIN_REDIRECT_PATH = '/documents';
export const ZSignInFormSchema = z.object({
@ -90,7 +87,7 @@ export const SignInForm = ({
const [isPasskeyLoading, setIsPasskeyLoading] = useState(false);
const callbackUrl = useMemo(() => {
const redirectUrl = useMemo(() => {
// Handle SSR
if (typeof window === 'undefined') {
return LOGIN_REDIRECT_PATH;
@ -161,15 +158,16 @@ export const SignInForm = ({
const credential = await startAuthentication(options);
const result = await authClient.passkey.signIn({
await authClient.passkey.signIn({
credential: JSON.stringify(credential),
csrfToken: sessionId,
redirectUrl,
// callbackUrl,
// redirect: false,
});
// Todo: Can't use navigate because of embed?
window.location.href = callbackUrl;
// window.location.href = callbackUrl;
} catch (err) {
setIsPasskeyLoading(false);
@ -208,17 +206,18 @@ export const SignInForm = ({
password,
totpCode,
backupCode,
redirectUrl,
// callbackUrl,
// redirect: false,
});
window.location.href = callbackUrl;
// window.location.href = callbackUrl; // Todo: Handle redirect.
} catch (err) {
console.log(err);
const error = AppError.parseError(err);
if (error.code === TwoFactorEnabledErrorCode) {
if (error.code === 'TWO_FACTOR_MISSING_CREDENTIALS') {
setIsTwoFactorAuthenticationDialogOpen(true);
return;
}
@ -257,12 +256,7 @@ export const SignInForm = ({
const onSignInWithGoogleClick = async () => {
try {
// await signIn('google', {
// callbackUrl,
// });
const result = await authClient.google.signIn();
console.log(result);
await authClient.google.signIn(); // Todo: Handle redirect.
} catch (err) {
toast({
title: _(msg`An unknown error occurred`),

View File

@ -12,9 +12,9 @@ import { Link, useNavigate, useSearchParams } from 'react-router';
import { z } from 'zod';
import communityCardsImage from '@documenso/assets/images/community-cards.png';
import { authClient } from '@documenso/auth/client';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { trpc } from '@documenso/trpc/react';
import { ZPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button';
@ -71,8 +71,8 @@ export const signupErrorMessages: Record<string, MessageDescriptor> = {
SIGNUP_DISABLED: msg`Signups are disabled.`,
[AppErrorCode.ALREADY_EXISTS]: msg`User with this email already exists. Please use a different email address.`,
[AppErrorCode.INVALID_REQUEST]: msg`We were unable to create your account. Please review the information you provided and try again.`,
[AppErrorCode.PROFILE_URL_TAKEN]: msg`This username has already been taken`,
[AppErrorCode.PREMIUM_PROFILE_URL]: msg`Only subscribers can have a username shorter than 6 characters`,
PROFILE_URL_TAKEN: msg`This username has already been taken`,
PREMIUM_PROFILE_URL: msg`Only subscribers can have a username shorter than 6 characters`,
};
export type TSignUpFormSchema = z.infer<typeof ZSignUpFormSchema>;
@ -93,7 +93,7 @@ export const SignUpForm = ({
const { _ } = useLingui();
const { toast } = useToast();
// const analytics = useAnalytics();
// const analytics = useAnalytics(); // Todo
const navigate = useNavigate();
const [searchParams] = useSearchParams();
@ -120,11 +120,9 @@ export const SignUpForm = ({
const name = form.watch('name');
const url = form.watch('url');
const { mutateAsync: signup } = trpc.auth.signup.useMutation();
const onFormSubmit = async ({ name, email, password, signature, url }: TSignUpFormSchema) => {
try {
await signup({ name, email, password, signature, url });
await authClient.emailPassword.signUp({ name, email, password, signature, url });
void navigate(`/unverified-account`);
@ -146,10 +144,7 @@ export const SignUpForm = ({
const errorMessage = signupErrorMessages[error.code] ?? signupErrorMessages.INVALID_REQUEST;
if (
error.code === AppErrorCode.PROFILE_URL_TAKEN ||
error.code === AppErrorCode.PREMIUM_PROFILE_URL
) {
if (error.code === 'PROFILE_URL_TAKEN' || error.code === 'PREMIUM_PROFILE_URL') {
form.setError('url', {
type: 'manual',
message: _(errorMessage),
@ -175,8 +170,7 @@ export const SignUpForm = ({
const onSignUpWithGoogleClick = async () => {
try {
await new Promise((resolve) => setTimeout(resolve, 2000));
// await signIn('google', { callbackUrl: SIGN_UP_REDIRECT_PATH });
await authClient.google.signIn();
} catch (err) {
toast({
title: _(msg`An unknown error occurred`),