Files
sign/apps/remix/app/routes/_authenticated+/documents.$id.edit.tsx

139 lines
4.7 KiB
TypeScript
Raw Normal View History

2025-01-02 15:33:37 +11:00
import { Plural, Trans } from '@lingui/react/macro';
import { TeamMemberRole } from '@prisma/client';
2024-02-12 17:30:23 +11:00
import { ChevronLeft, Users2 } from 'lucide-react';
2025-01-02 15:33:37 +11:00
import { Link, redirect } from 'react-router';
import { match } from 'ts-pattern';
2024-02-12 17:30:23 +11:00
2025-02-17 22:46:36 +11:00
import { getSession } from '@documenso/auth/server/lib/utils/get-session';
2024-03-28 13:13:29 +08:00
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
fix: update document flow fetch logic (#1039) ## Description **Fixes issues with mismatching state between document steps.** For example, editing a recipient and proceeding to the next step may not display the updated recipient. And going back will display the old recipient instead of the updated values. **This PR also improves mutation and query speeds by adding logic to bypass query invalidation.** ```ts export const trpc = createTRPCReact<AppRouter>({ unstable_overrides: { useMutation: { async onSuccess(opts) { await opts.originalFn(); // This forces mutations to wait for all the queries on the page to reload, and in // this case one of the queries is `searchDocument` for the command overlay, which // on average takes ~500ms. This means that every single mutation must wait for this. await opts.queryClient.invalidateQueries(); }, }, }, }); ``` I've added workarounds to allow us to bypass things such as batching and invalidating queries. But I think we should instead remove this and update all the mutations where a query is required for a more optimised system. ## Example benchmarks Using stg-app vs this preview there's an average 50% speed increase across mutations. **Set signer step:** Average old speed: ~1100ms Average new speed: ~550ms **Set recipient step:** Average old speed: ~1200ms Average new speed: ~600ms **Set fields step:** Average old speed: ~1200ms Average new speed: ~600ms ## Related Issue This will resolve #470 ## Changes Made - Added ability to skip batch queries - Added a state to store the required document data. - Refetch the data between steps if/when required - Optimise mutations and queries ## Checklist - [X] I have tested these changes locally and they work as expected. - [X] I have followed the project's coding style guidelines. --------- Co-authored-by: Lucas Smith <me@lucasjamessmith.me>
2024-03-26 21:12:41 +08:00
import { getDocumentWithDetailsById } from '@documenso/lib/server-only/document/get-document-with-details-by-id';
2025-02-17 22:46:36 +11:00
import { type TGetTeamByUrlResponse, getTeamByUrl } from '@documenso/lib/server-only/team/get-team';
import { DocumentVisibility } from '@documenso/lib/types/document-visibility';
import { isDocumentCompleted } from '@documenso/lib/utils/document';
2024-02-12 17:30:23 +11:00
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
2025-01-02 15:33:37 +11:00
import { DocumentEditForm } from '~/components/general/document/document-edit-form';
import { DocumentStatus } from '~/components/general/document/document-status';
import { StackAvatarsWithTooltip } from '~/components/general/stack-avatars-with-tooltip';
import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
2025-02-21 15:53:23 +11:00
import type { Route } from './+types/documents.$id.edit';
2025-01-02 15:33:37 +11:00
2025-02-17 22:46:36 +11:00
export async function loader({ params, request }: Route.LoaderArgs) {
const { user } = await getSession(request);
let team: TGetTeamByUrlResponse | null = null;
if (params.teamUrl) {
team = await getTeamByUrl({ userId: user.id, teamUrl: params.teamUrl });
}
2025-01-02 15:33:37 +11:00
2024-02-12 17:30:23 +11:00
const { id } = params;
const documentId = Number(id);
const documentRootPath = formatDocumentsPath(team?.url);
if (!documentId || Number.isNaN(documentId)) {
2025-01-02 15:33:37 +11:00
throw redirect(documentRootPath);
2024-02-12 17:30:23 +11:00
}
fix: update document flow fetch logic (#1039) ## Description **Fixes issues with mismatching state between document steps.** For example, editing a recipient and proceeding to the next step may not display the updated recipient. And going back will display the old recipient instead of the updated values. **This PR also improves mutation and query speeds by adding logic to bypass query invalidation.** ```ts export const trpc = createTRPCReact<AppRouter>({ unstable_overrides: { useMutation: { async onSuccess(opts) { await opts.originalFn(); // This forces mutations to wait for all the queries on the page to reload, and in // this case one of the queries is `searchDocument` for the command overlay, which // on average takes ~500ms. This means that every single mutation must wait for this. await opts.queryClient.invalidateQueries(); }, }, }, }); ``` I've added workarounds to allow us to bypass things such as batching and invalidating queries. But I think we should instead remove this and update all the mutations where a query is required for a more optimised system. ## Example benchmarks Using stg-app vs this preview there's an average 50% speed increase across mutations. **Set signer step:** Average old speed: ~1100ms Average new speed: ~550ms **Set recipient step:** Average old speed: ~1200ms Average new speed: ~600ms **Set fields step:** Average old speed: ~1200ms Average new speed: ~600ms ## Related Issue This will resolve #470 ## Changes Made - Added ability to skip batch queries - Added a state to store the required document data. - Refetch the data between steps if/when required - Optimise mutations and queries ## Checklist - [X] I have tested these changes locally and they work as expected. - [X] I have followed the project's coding style guidelines. --------- Co-authored-by: Lucas Smith <me@lucasjamessmith.me>
2024-03-26 21:12:41 +08:00
const document = await getDocumentWithDetailsById({
2024-12-10 16:11:20 +09:00
documentId,
2024-02-12 17:30:23 +11:00
userId: user.id,
teamId: team?.id,
}).catch(() => null);
if (document?.teamId && !team?.url) {
2025-01-02 15:33:37 +11:00
throw redirect(documentRootPath);
}
const documentVisibility = document?.visibility;
const currentTeamMemberRole = team?.currentTeamMember?.role;
2025-01-13 13:41:53 +11:00
const isRecipient = document?.recipients.find((recipient) => recipient.email === user.email);
let canAccessDocument = true;
feat: add global settings for teams (#1391) ## Description This PR introduces global settings for teams. At the moment, it allows team admins to configure the following: * The default visibility of the documents uploaded to the team account * Whether to include the document owner (sender) details when sending emails to the recipients. ### Include Sender Details If the Sender Details setting is enabled, the emails sent by the team will include the sender's name: > "Example User" on behalf of "Example Team" has invited you to sign "document.pdf" Otherwise, the email will say: > "Example Team" has invited you to sign "document.pdf" ### Default Document Visibility This new option allows users to set the default visibility for the documents uploaded to the team account. It can have the following values: * Everyone * Manager and above * Admins only If the default document visibility isn't set, the document will be set to the role of the user who created the document: * If a user with the "User" role creates a document, the document's visibility is set to "Everyone". * Manager role -> "Manager and above" * Admin role -> "Admins only" Otherwise, if there is a default document visibility value, it uses that value. #### Gotcha To avoid issues, the `document owner` and the `recipient` can access the document irrespective of their role. For example: * If a team member with the role "Member" uploads a document and the default document visibility is "Admins", only the document owner and admins can access the document. * Similar to the other scenarios. * If an admin uploads a document and the default document visibility is "Admins", the recipient can access the document. * The admins have access to all the documents. * Managers have access to documents with the visibility set to "Everyone" and "Manager and above" * Members have access only to the documents with the visibility set to "Everyone". ## Testing Performed Tested it locally.
2024-11-08 13:50:49 +02:00
if (!isRecipient && document?.userId !== user.id) {
canAccessDocument = match([documentVisibility, currentTeamMemberRole])
.with([DocumentVisibility.EVERYONE, TeamMemberRole.ADMIN], () => true)
.with([DocumentVisibility.EVERYONE, TeamMemberRole.MANAGER], () => true)
.with([DocumentVisibility.EVERYONE, TeamMemberRole.MEMBER], () => true)
.with([DocumentVisibility.MANAGER_AND_ABOVE, TeamMemberRole.ADMIN], () => true)
.with([DocumentVisibility.MANAGER_AND_ABOVE, TeamMemberRole.MANAGER], () => true)
.with([DocumentVisibility.ADMIN, TeamMemberRole.ADMIN], () => true)
.otherwise(() => false);
}
fix: update document flow fetch logic (#1039) ## Description **Fixes issues with mismatching state between document steps.** For example, editing a recipient and proceeding to the next step may not display the updated recipient. And going back will display the old recipient instead of the updated values. **This PR also improves mutation and query speeds by adding logic to bypass query invalidation.** ```ts export const trpc = createTRPCReact<AppRouter>({ unstable_overrides: { useMutation: { async onSuccess(opts) { await opts.originalFn(); // This forces mutations to wait for all the queries on the page to reload, and in // this case one of the queries is `searchDocument` for the command overlay, which // on average takes ~500ms. This means that every single mutation must wait for this. await opts.queryClient.invalidateQueries(); }, }, }, }); ``` I've added workarounds to allow us to bypass things such as batching and invalidating queries. But I think we should instead remove this and update all the mutations where a query is required for a more optimised system. ## Example benchmarks Using stg-app vs this preview there's an average 50% speed increase across mutations. **Set signer step:** Average old speed: ~1100ms Average new speed: ~550ms **Set recipient step:** Average old speed: ~1200ms Average new speed: ~600ms **Set fields step:** Average old speed: ~1200ms Average new speed: ~600ms ## Related Issue This will resolve #470 ## Changes Made - Added ability to skip batch queries - Added a state to store the required document data. - Refetch the data between steps if/when required - Optimise mutations and queries ## Checklist - [X] I have tested these changes locally and they work as expected. - [X] I have followed the project's coding style guidelines. --------- Co-authored-by: Lucas Smith <me@lucasjamessmith.me>
2024-03-26 21:12:41 +08:00
if (!document) {
2025-01-02 15:33:37 +11:00
throw redirect(documentRootPath);
2024-02-12 17:30:23 +11:00
}
if (team && !canAccessDocument) {
2025-01-02 15:33:37 +11:00
throw redirect(documentRootPath);
}
if (isDocumentCompleted(document.status)) {
2025-01-02 15:33:37 +11:00
throw redirect(`${documentRootPath}/${documentId}`);
2024-02-12 17:30:23 +11:00
}
const isDocumentEnterprise = await isUserEnterprise({
userId: user.id,
teamId: team?.id,
});
2025-01-02 15:33:37 +11:00
return superLoaderJson({
document,
documentRootPath,
isDocumentEnterprise,
});
}
export default function DocumentEditPage() {
const { document, documentRootPath, isDocumentEnterprise } = useSuperLoaderData<typeof loader>();
const { recipients } = document;
2024-02-12 17:30:23 +11:00
return (
<div className="mx-auto -mt-4 w-full max-w-screen-xl px-4 md:px-8">
2025-01-02 15:33:37 +11:00
<Link to={documentRootPath} className="flex items-center text-[#7AC455] hover:opacity-80">
2024-02-12 17:30:23 +11:00
<ChevronLeft className="mr-2 inline-block h-5 w-5" />
2024-08-27 20:34:39 +09:00
<Trans>Documents</Trans>
2024-02-12 17:30:23 +11:00
</Link>
<h1
className="mt-4 block max-w-[20rem] truncate text-2xl font-semibold md:max-w-[30rem] md:text-3xl"
title={document.title}
>
2024-02-12 17:30:23 +11:00
{document.title}
</h1>
<div className="mt-2.5 flex items-center gap-x-6">
<DocumentStatus inheritColor status={document.status} className="text-muted-foreground" />
{recipients.length > 0 && (
<div className="text-muted-foreground flex items-center">
<Users2 className="mr-2 h-5 w-5" />
<StackAvatarsWithTooltip
recipients={recipients}
documentStatus={document.status}
position="bottom"
>
2024-08-27 20:34:39 +09:00
<span>
<Plural one="1 Recipient" other="# Recipients" value={recipients.length} />
</span>
2024-02-12 17:30:23 +11:00
</StackAvatarsWithTooltip>
</div>
)}
</div>
2025-01-02 15:33:37 +11:00
<DocumentEditForm
className="mt-6"
fix: update document flow fetch logic (#1039) ## Description **Fixes issues with mismatching state between document steps.** For example, editing a recipient and proceeding to the next step may not display the updated recipient. And going back will display the old recipient instead of the updated values. **This PR also improves mutation and query speeds by adding logic to bypass query invalidation.** ```ts export const trpc = createTRPCReact<AppRouter>({ unstable_overrides: { useMutation: { async onSuccess(opts) { await opts.originalFn(); // This forces mutations to wait for all the queries on the page to reload, and in // this case one of the queries is `searchDocument` for the command overlay, which // on average takes ~500ms. This means that every single mutation must wait for this. await opts.queryClient.invalidateQueries(); }, }, }, }); ``` I've added workarounds to allow us to bypass things such as batching and invalidating queries. But I think we should instead remove this and update all the mutations where a query is required for a more optimised system. ## Example benchmarks Using stg-app vs this preview there's an average 50% speed increase across mutations. **Set signer step:** Average old speed: ~1100ms Average new speed: ~550ms **Set recipient step:** Average old speed: ~1200ms Average new speed: ~600ms **Set fields step:** Average old speed: ~1200ms Average new speed: ~600ms ## Related Issue This will resolve #470 ## Changes Made - Added ability to skip batch queries - Added a state to store the required document data. - Refetch the data between steps if/when required - Optimise mutations and queries ## Checklist - [X] I have tested these changes locally and they work as expected. - [X] I have followed the project's coding style guidelines. --------- Co-authored-by: Lucas Smith <me@lucasjamessmith.me>
2024-03-26 21:12:41 +08:00
initialDocument={document}
2024-02-12 17:30:23 +11:00
documentRootPath={documentRootPath}
2024-03-28 13:13:29 +08:00
isDocumentEnterprise={isDocumentEnterprise}
2024-02-12 17:30:23 +11:00
/>
</div>
);
2025-01-02 15:33:37 +11:00
}