From 5b395fc9adff47d65f599b395f54db0b2d27ac77 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Sun, 9 Feb 2025 21:57:26 +1100 Subject: [PATCH] fix: wip --- .eslintrc.cjs | 1 + .../dialogs/team-email-add-dialog.tsx | 4 +- .../dialogs/team-email-delete-dialog.tsx | 4 +- .../dialogs/team-email-update-dialog.tsx | 4 +- .../dialogs/team-member-invite-dialog.tsx | 29 ++++++----- .../dialogs/team-transfer-dialog.tsx | 4 +- .../dialogs/template-direct-link-dialog.tsx | 15 ++++-- .../2fa/disable-authenticator-app-dialog.tsx | 5 +- .../2fa/enable-authenticator-app-dialog.tsx | 5 +- apps/remix/app/components/forms/profile.tsx | 4 +- apps/remix/app/components/forms/signup.tsx | 1 - .../app/components/forms/team-update-form.tsx | 2 +- .../document-signing-auto-sign.tsx | 14 ++---- .../document-signing-checkbox-field.tsx | 17 +++---- .../document-signing-date-field.tsx | 16 +++--- .../document-signing-dropdown-field.tsx | 14 +++--- .../document-signing-email-field.tsx | 14 ++---- .../document-signing-form.tsx | 6 ++- .../document-signing-initials-field.tsx | 13 ++--- .../document-signing-name-field.tsx | 12 ++--- .../document-signing-number-field.tsx | 13 +++-- .../document-signing-radio-field.tsx | 14 +++--- .../document-signing-signature-field.tsx | 23 ++++----- .../document-signing-text-field.tsx | 14 +++--- .../general/document/document-search.tsx | 11 ++--- .../general/teams/team-transfer-status.tsx | 7 +-- .../admin-document-recipient-item-table.tsx | 5 +- .../tables/user-settings-teams-page-table.tsx | 12 ++--- .../_authenticated+/admin+/site-settings.tsx | 5 +- .../_authenticated+/admin+/users.$id.tsx | 5 +- .../_authenticated+/documents+/_index.tsx | 7 ++- .../settings+/webhooks+/$id.tsx | 6 +-- .../t.$teamUrl+/settings+/members.tsx | 26 ++++------ .../t.$teamUrl+/settings+/webhooks.$id.tsx | 5 +- .../routes/_recipient+/d.$token+/_index.tsx | 2 +- .../_recipient+/sign.$token+/complete.tsx | 49 +++++++++---------- ...password.tsx => reset-password._index.tsx} | 0 .../_unauthenticated+/verify-email.$token.tsx | 2 +- ...rify-email.tsx => verify-email._index.tsx} | 0 apps/remix/package.json | 1 + apps/remix/server/context.ts | 2 +- apps/remix/server/router.ts | 4 +- apps/remix/vite.config.ts | 10 +++- package-lock.json | 11 +++++ .../e2e/document-auth/action-auth.spec.ts | 41 ++-------------- .../document-flow/stepper-component.spec.ts | 22 ++------- .../include-document-certificate.spec.ts | 28 ++--------- .../app-tests/e2e/fixtures/authentication.ts | 18 ++----- packages/app-tests/e2e/fixtures/signature.ts | 40 +++++++++++++++ .../e2e/teams/search-documents.spec.ts | 12 ++--- .../e2e/teams/team-documents.spec.ts | 2 +- .../app-tests/e2e/teams/team-members.spec.ts | 1 - .../e2e/templates/direct-templates.spec.ts | 4 +- .../e2e/templates/manage-templates.spec.ts | 17 +++---- packages/app-tests/e2e/user/auth-flow.spec.ts | 13 ++--- packages/auth/server/index.ts | 4 +- .../server/lib/session/session-cookies.ts | 32 +++++++----- packages/auth/server/lib/session/session.ts | 27 ++++++++-- packages/auth/server/lib/utils/authorizer.ts | 8 +++ packages/auth/server/routes/email-password.ts | 6 +-- packages/auth/server/routes/google.ts | 28 +++++------ packages/auth/server/routes/sign-out.ts | 7 ++- packages/lib/constants/auth.ts | 2 + packages/lib/constants/email.ts | 7 +++ packages/lib/jobs/client/local.ts | 35 +++++-------- .../server-only/document/resend-document.tsx | 26 +++++----- packages/lib/server-only/user/verify-email.ts | 8 +-- .../signature-pad/signature-pad.tsx | 1 + 68 files changed, 400 insertions(+), 407 deletions(-) rename apps/remix/app/routes/_unauthenticated+/{reset-password.tsx => reset-password._index.tsx} (100%) rename apps/remix/app/routes/_unauthenticated+/{verify-email.tsx => verify-email._index.tsx} (100%) create mode 100644 packages/app-tests/e2e/fixtures/signature.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index ed6ecc0ac..455860ea1 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -5,6 +5,7 @@ module.exports = { rules: { '@next/next/no-img-element': 'off', 'no-unreachable': 'error', + 'react-hooks/exhaustive-deps': 'off', }, settings: { next: { diff --git a/apps/remix/app/components/dialogs/team-email-add-dialog.tsx b/apps/remix/app/components/dialogs/team-email-add-dialog.tsx index 2aee969ca..161c2c0eb 100644 --- a/apps/remix/app/components/dialogs/team-email-add-dialog.tsx +++ b/apps/remix/app/components/dialogs/team-email-add-dialog.tsx @@ -7,6 +7,7 @@ import { Trans } from '@lingui/react/macro'; import type * as DialogPrimitive from '@radix-ui/react-dialog'; import { Plus } from 'lucide-react'; import { useForm } from 'react-hook-form'; +import { useRevalidator } from 'react-router'; import type { z } from 'zod'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; @@ -50,6 +51,7 @@ export const TeamEmailAddDialog = ({ teamId, trigger, ...props }: TeamEmailAddDi const { _ } = useLingui(); const { toast } = useToast(); + const { revalidate } = useRevalidator(); const form = useForm({ resolver: zodResolver(ZCreateTeamEmailFormSchema), @@ -76,7 +78,7 @@ export const TeamEmailAddDialog = ({ teamId, trigger, ...props }: TeamEmailAddDi duration: 5000, }); - // router.refresh(); // Todo + await revalidate(); setOpen(false); } catch (err) { diff --git a/apps/remix/app/components/dialogs/team-email-delete-dialog.tsx b/apps/remix/app/components/dialogs/team-email-delete-dialog.tsx index b9675f4a5..ec050961c 100644 --- a/apps/remix/app/components/dialogs/team-email-delete-dialog.tsx +++ b/apps/remix/app/components/dialogs/team-email-delete-dialog.tsx @@ -4,6 +4,7 @@ import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import type { Prisma } from '@prisma/client'; +import { useRevalidator } from 'react-router'; import { formatAvatarUrl } from '@documenso/lib/utils/avatars'; import { extractInitials } from '@documenso/lib/utils/recipient-formatter'; @@ -44,6 +45,7 @@ export const TeamEmailDeleteDialog = ({ trigger, teamName, team }: TeamEmailDele const { _ } = useLingui(); const { toast } = useToast(); + const { revalidate } = useRevalidator(); const { mutateAsync: deleteTeamEmail, isPending: isDeletingTeamEmail } = trpc.team.deleteTeamEmail.useMutation({ @@ -92,7 +94,7 @@ export const TeamEmailDeleteDialog = ({ trigger, teamName, team }: TeamEmailDele await deleteTeamEmailVerification({ teamId: team.id }); } - // router.refresh(); // Todo + await revalidate(); }; return ( diff --git a/apps/remix/app/components/dialogs/team-email-update-dialog.tsx b/apps/remix/app/components/dialogs/team-email-update-dialog.tsx index 6958dc64d..bde700949 100644 --- a/apps/remix/app/components/dialogs/team-email-update-dialog.tsx +++ b/apps/remix/app/components/dialogs/team-email-update-dialog.tsx @@ -7,6 +7,7 @@ import { Trans } from '@lingui/react/macro'; import type { TeamEmail } from '@prisma/client'; import type * as DialogPrimitive from '@radix-ui/react-dialog'; import { useForm } from 'react-hook-form'; +import { useRevalidator } from 'react-router'; import { z } from 'zod'; import { trpc } from '@documenso/trpc/react'; @@ -51,6 +52,7 @@ export const TeamEmailUpdateDialog = ({ const { _ } = useLingui(); const { toast } = useToast(); + const { revalidate } = useRevalidator(); const form = useForm({ resolver: zodResolver(ZUpdateTeamEmailFormSchema), @@ -76,7 +78,7 @@ export const TeamEmailUpdateDialog = ({ duration: 5000, }); - // router.refresh(); // Todo + await revalidate(); setOpen(false); } catch (err) { diff --git a/apps/remix/app/components/dialogs/team-member-invite-dialog.tsx b/apps/remix/app/components/dialogs/team-member-invite-dialog.tsx index d7986b199..dac4f8fce 100644 --- a/apps/remix/app/components/dialogs/team-member-invite-dialog.tsx +++ b/apps/remix/app/components/dialogs/team-member-invite-dialog.tsx @@ -46,9 +46,9 @@ import { import { Tabs, TabsContent, TabsList, TabsTrigger } from '@documenso/ui/primitives/tabs'; import { useToast } from '@documenso/ui/primitives/use-toast'; +import { useCurrentTeam } from '~/providers/team'; + export type TeamMemberInviteDialogProps = { - currentUserTeamRole: TeamMemberRole; - teamId: number; trigger?: React.ReactNode; } & Omit; @@ -95,12 +95,7 @@ const ZImportTeamMemberSchema = z.array( }), ); -export const TeamMemberInviteDialog = ({ - currentUserTeamRole, - teamId, - trigger, - ...props -}: TeamMemberInviteDialogProps) => { +export const TeamMemberInviteDialog = ({ trigger, ...props }: TeamMemberInviteDialogProps) => { const [open, setOpen] = useState(false); const fileInputRef = useRef(null); const [invitationType, setInvitationType] = useState('INDIVIDUAL'); @@ -108,6 +103,8 @@ export const TeamMemberInviteDialog = ({ const { _ } = useLingui(); const { toast } = useToast(); + const team = useCurrentTeam(); + const form = useForm({ resolver: zodResolver(ZInviteTeamMembersFormSchema), defaultValues: { @@ -141,7 +138,7 @@ export const TeamMemberInviteDialog = ({ const onFormSubmit = async ({ invitations }: TInviteTeamMembersFormSchema) => { try { await createTeamMemberInvites({ - teamId, + teamId: team.id, invitations, }); @@ -203,7 +200,7 @@ export const TeamMemberInviteDialog = ({ setInvitationType('INDIVIDUAL'); } catch (err) { - console.error(err.message); + console.error(err); toast({ title: _(msg`Something went wrong`), @@ -324,11 +321,13 @@ export const TeamMemberInviteDialog = ({ - {TEAM_MEMBER_ROLE_HIERARCHY[currentUserTeamRole].map((role) => ( - - {_(TEAM_MEMBER_ROLE_MAP[role]) ?? role} - - ))} + {TEAM_MEMBER_ROLE_HIERARCHY[team.currentTeamMember.role].map( + (role) => ( + + {_(TEAM_MEMBER_ROLE_MAP[role]) ?? role} + + ), + )} diff --git a/apps/remix/app/components/dialogs/team-transfer-dialog.tsx b/apps/remix/app/components/dialogs/team-transfer-dialog.tsx index 6205edcb1..8cc5cf1f1 100644 --- a/apps/remix/app/components/dialogs/team-transfer-dialog.tsx +++ b/apps/remix/app/components/dialogs/team-transfer-dialog.tsx @@ -6,6 +6,7 @@ import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { Loader } from 'lucide-react'; import { useForm } from 'react-hook-form'; +import { useRevalidator } from 'react-router'; import { z } from 'zod'; import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app'; @@ -56,6 +57,7 @@ export const TeamTransferDialog = ({ const { _ } = useLingui(); const { toast } = useToast(); + const { revalidate } = useRevalidator(); const { mutateAsync: requestTeamOwnershipTransfer } = trpc.team.requestTeamOwnershipTransfer.useMutation(); @@ -98,7 +100,7 @@ export const TeamTransferDialog = ({ clearPaymentMethods, }); - // router.refresh(); // Todo + await revalidate(); toast({ title: _(msg`Success`), diff --git a/apps/remix/app/components/dialogs/template-direct-link-dialog.tsx b/apps/remix/app/components/dialogs/template-direct-link-dialog.tsx index 2c05cb338..3c1bd9c8a 100644 --- a/apps/remix/app/components/dialogs/template-direct-link-dialog.tsx +++ b/apps/remix/app/components/dialogs/template-direct-link-dialog.tsx @@ -10,7 +10,7 @@ import { type TemplateDirectLink, } from '@prisma/client'; import { CircleDotIcon, CircleIcon, ClipboardCopyIcon, InfoIcon, LoaderIcon } from 'lucide-react'; -import { Link } from 'react-router'; +import { Link, useRevalidator } from 'react-router'; import { P, match } from 'ts-pattern'; import { useLimits } from '@documenso/ee/server-only/limits/provider/client'; @@ -64,6 +64,7 @@ export const TemplateDirectLinkDialog = ({ const { toast } = useToast(); const { quota, remaining } = useLimits(); const { _ } = useLingui(); + const { revalidate } = useRevalidator(); const [, copy] = useCopyToClipboard(); @@ -84,7 +85,9 @@ export const TemplateDirectLinkDialog = ({ isPending: isCreatingTemplateDirectLink, reset: resetCreateTemplateDirectLink, } = trpcReact.template.createTemplateDirectLink.useMutation({ - onSuccess: (data) => { + onSuccess: async (data) => { + await revalidate(); + setToken(data.token); setIsEnabled(data.enabled); setCurrentStep('MANAGE'); @@ -102,7 +105,9 @@ export const TemplateDirectLinkDialog = ({ const { mutateAsync: toggleTemplateDirectLink, isPending: isTogglingTemplateAccess } = trpcReact.template.toggleTemplateDirectLink.useMutation({ - onSuccess: (data) => { + onSuccess: async (data) => { + await revalidate(); + const enabledDescription = msg`Direct link signing has been enabled`; const disabledDescription = msg`Direct link signing has been disabled`; @@ -125,7 +130,9 @@ export const TemplateDirectLinkDialog = ({ const { mutateAsync: deleteTemplateDirectLink, isPending: isDeletingTemplateDirectLink } = trpcReact.template.deleteTemplateDirectLink.useMutation({ - onSuccess: () => { + onSuccess: async () => { + await revalidate(); + onOpenChange(false); setToken(null); diff --git a/apps/remix/app/components/forms/2fa/disable-authenticator-app-dialog.tsx b/apps/remix/app/components/forms/2fa/disable-authenticator-app-dialog.tsx index b4d623c0c..406d4c229 100644 --- a/apps/remix/app/components/forms/2fa/disable-authenticator-app-dialog.tsx +++ b/apps/remix/app/components/forms/2fa/disable-authenticator-app-dialog.tsx @@ -6,6 +6,7 @@ import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { flushSync } from 'react-dom'; import { useForm } from 'react-hook-form'; +import { useRevalidator } from 'react-router'; import { z } from 'zod'; import { trpc } from '@documenso/trpc/react'; @@ -41,6 +42,7 @@ export type TDisable2FAForm = z.infer; export const DisableAuthenticatorAppDialog = () => { const { _ } = useLingui(); const { toast } = useToast(); + const { revalidate } = useRevalidator(); const [isOpen, setIsOpen] = useState(false); const [twoFactorDisableMethod, setTwoFactorDisableMethod] = useState<'totp' | 'backup'>('totp'); @@ -92,8 +94,7 @@ export const DisableAuthenticatorAppDialog = () => { onCloseTwoFactorDisableDialog(); }); - // Todo - // router.refresh(); + await revalidate(); } catch (_err) { toast({ title: _(msg`Unable to disable two-factor authentication`), diff --git a/apps/remix/app/components/forms/2fa/enable-authenticator-app-dialog.tsx b/apps/remix/app/components/forms/2fa/enable-authenticator-app-dialog.tsx index 6d7ffb345..5fdd2c3b7 100644 --- a/apps/remix/app/components/forms/2fa/enable-authenticator-app-dialog.tsx +++ b/apps/remix/app/components/forms/2fa/enable-authenticator-app-dialog.tsx @@ -5,6 +5,7 @@ import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { useForm } from 'react-hook-form'; +import { useRevalidator } from 'react-router'; import { renderSVG } from 'uqr'; import { z } from 'zod'; @@ -47,6 +48,7 @@ export type EnableAuthenticatorAppDialogProps = { export const EnableAuthenticatorAppDialog = ({ onSuccess }: EnableAuthenticatorAppDialogProps) => { const { _ } = useLingui(); const { toast } = useToast(); + const { revalidate } = useRevalidator(); const [isOpen, setIsOpen] = useState(false); const [recoveryCodes, setRecoveryCodes] = useState(null); @@ -128,8 +130,7 @@ export const EnableAuthenticatorAppDialog = ({ onSuccess }: EnableAuthenticatorA if (!isOpen && recoveryCodes && recoveryCodes.length > 0) { setRecoveryCodes(null); - // Todo - // router.refresh(); + void revalidate(); } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/apps/remix/app/components/forms/profile.tsx b/apps/remix/app/components/forms/profile.tsx index cd1a0af73..c5e179e15 100644 --- a/apps/remix/app/components/forms/profile.tsx +++ b/apps/remix/app/components/forms/profile.tsx @@ -3,6 +3,7 @@ import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { useForm } from 'react-hook-form'; +import { useRevalidator } from 'react-router'; import { z } from 'zod'; import { useSession } from '@documenso/lib/client-only/providers/session'; @@ -42,6 +43,7 @@ export const ProfileForm = ({ className }: ProfileFormProps) => { const { _ } = useLingui(); const { toast } = useToast(); const { user } = useSession(); + const { revalidate } = useRevalidator(); const form = useForm({ values: { @@ -68,7 +70,7 @@ export const ProfileForm = ({ className }: ProfileFormProps) => { duration: 5000, }); - // router.refresh(); // Todo + await revalidate(); } catch (err) { toast({ title: _(msg`An unknown error occurred`), diff --git a/apps/remix/app/components/forms/signup.tsx b/apps/remix/app/components/forms/signup.tsx index 3dc86cf6e..ae00931a3 100644 --- a/apps/remix/app/components/forms/signup.tsx +++ b/apps/remix/app/components/forms/signup.tsx @@ -168,7 +168,6 @@ export const SignUpForm = ({ }; const onNextClick = async () => { - console.log('hello-world'); const valid = await form.trigger(['name', 'email', 'password', 'signature']); if (valid) { diff --git a/apps/remix/app/components/forms/team-update-form.tsx b/apps/remix/app/components/forms/team-update-form.tsx index 2eaf5d30b..a5165e30f 100644 --- a/apps/remix/app/components/forms/team-update-form.tsx +++ b/apps/remix/app/components/forms/team-update-form.tsx @@ -73,7 +73,7 @@ export const TeamUpdateForm = ({ teamId, teamName, teamUrl }: UpdateTeamDialogPr }); if (url !== teamUrl) { - await navigate(`${NEXT_PUBLIC_WEBAPP_URL()}/t/${url}/settings`); + await navigate(`/t/${url}/settings`); } } catch (err) { const error = AppError.parseError(err); diff --git a/apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx b/apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx index 495d62ffd..cb90525a7 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx @@ -1,4 +1,4 @@ -import { useState, useTransition } from 'react'; +import { useState } from 'react'; import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; @@ -6,6 +6,7 @@ import { Plural, Trans } from '@lingui/react/macro'; import type { Field, Recipient } from '@prisma/client'; import { FieldType } from '@prisma/client'; import { useForm } from 'react-hook-form'; +import { useRevalidator } from 'react-router'; import { P, match } from 'ts-pattern'; import { unsafe_useEffectOnce } from '@documenso/lib/client-only/hooks/use-effect-once'; @@ -60,12 +61,12 @@ export type DocumentSigningAutoSignProps = { export const DocumentSigningAutoSign = ({ recipient, fields }: DocumentSigningAutoSignProps) => { const { _ } = useLingui(); const { toast } = useToast(); + const { revalidate } = useRevalidator(); const { email, fullName } = useRequiredDocumentSigningContext(); const { derivedRecipientActionAuth } = useRequiredDocumentSigningAuthContext(); const [open, setOpen] = useState(false); - const [isPending, startTransition] = useTransition(); const form = useForm(); @@ -153,12 +154,7 @@ export const DocumentSigningAutoSign = ({ recipient, fields }: DocumentSigningAu }); } - startTransition(() => { - // Todo - // router.refresh(); - - setOpen(false); - }); + await revalidate(); }; unsafe_useEffectOnce(() => { @@ -219,7 +215,7 @@ export const DocumentSigningAutoSign = ({ recipient, fields }: DocumentSigningAu