feat: avoid sending document if the owner is the only recipient

This commit is contained in:
Ephraim Atta-Duncan
2024-10-16 17:10:01 +00:00
parent e0c948c2ac
commit f9e3993519
4 changed files with 73 additions and 3 deletions

View File

@ -6,6 +6,7 @@ import { useRouter, useSearchParams } from 'next/navigation';
import { msg } from '@lingui/macro'; import { msg } from '@lingui/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
import { useSession } from 'next-auth/react';
import { import {
DO_NOT_INVALIDATE_QUERY_ON_MUTATION, DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
@ -53,6 +54,7 @@ export const EditDocumentForm = ({
const router = useRouter(); const router = useRouter();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const team = useOptionalCurrentTeam(); const team = useOptionalCurrentTeam();
const { data: session } = useSession();
const [isDocumentPdfLoaded, setIsDocumentPdfLoaded] = useState(false); const [isDocumentPdfLoaded, setIsDocumentPdfLoaded] = useState(false);
@ -138,6 +140,19 @@ export const EditDocumentForm = ({
}, },
}); });
const { mutateAsync: selfSignDocument } = trpc.document.selfSignDocument.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (newData) => {
utils.document.getDocumentWithDetailsById.setData(
{
id: initialDocument.id,
teamId: team?.id,
},
(oldData) => ({ ...(oldData || initialDocument), ...newData }),
);
},
});
const { mutateAsync: setPasswordForDocument } = const { mutateAsync: setPasswordForDocument } =
trpc.document.setPasswordForDocument.useMutation(); trpc.document.setPasswordForDocument.useMutation();
@ -266,10 +281,22 @@ export const EditDocumentForm = ({
} }
} }
const hasSameOwnerAsRecipient =
recipients.length === 1 && recipients[0].email === session?.user?.email;
if (hasSameOwnerAsRecipient) {
await selfSignDocument({
documentId: document.id,
teamId: team?.id,
});
router.push(`/sign/${recipients[0].token}`);
} else {
// Router refresh is here to clear the router cache for when navigating to /documents. // Router refresh is here to clear the router cache for when navigating to /documents.
router.refresh(); router.refresh();
setStep('subject'); setStep('subject');
}
} catch (err) { } catch (err) {
console.error(err); console.error(err);

View File

@ -37,6 +37,7 @@ import {
ZMoveDocumentsToTeamSchema, ZMoveDocumentsToTeamSchema,
ZResendDocumentMutationSchema, ZResendDocumentMutationSchema,
ZSearchDocumentsMutationSchema, ZSearchDocumentsMutationSchema,
ZSelfSignDocumentMutationSchema,
ZSendDocumentMutationSchema, ZSendDocumentMutationSchema,
ZSetPasswordForDocumentMutationSchema, ZSetPasswordForDocumentMutationSchema,
ZSetSettingsForDocumentMutationSchema, ZSetSettingsForDocumentMutationSchema,
@ -367,6 +368,29 @@ export const documentRouter = router({
} }
}), }),
selfSignDocument: authenticatedProcedure
.input(ZSelfSignDocumentMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { documentId, teamId } = input;
return await sendDocument({
userId: ctx.user.id,
documentId,
teamId,
sendEmail: false,
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to self sign this document. Please try again later.',
});
}
}),
resendDocument: authenticatedProcedure resendDocument: authenticatedProcedure
.input(ZResendDocumentMutationSchema) .input(ZResendDocumentMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {

View File

@ -140,6 +140,11 @@ export const ZSendDocumentMutationSchema = z.object({
}), }),
}); });
export const ZSelfSignDocumentMutationSchema = z.object({
documentId: z.number(),
teamId: z.number().optional(),
});
export const ZSetPasswordForDocumentMutationSchema = z.object({ export const ZSetPasswordForDocumentMutationSchema = z.object({
documentId: z.number(), documentId: z.number(),
password: z.string(), password: z.string(),

View File

@ -20,6 +20,7 @@ import {
Type, Type,
User, User,
} from 'lucide-react'; } from 'lucide-react';
import { useSession } from 'next-auth/react';
import { useFieldArray, useForm } from 'react-hook-form'; import { useFieldArray, useForm } from 'react-hook-form';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { prop, sortBy } from 'remeda'; import { prop, sortBy } from 'remeda';
@ -99,6 +100,13 @@ export type AddFieldsFormProps = {
teamId?: number; teamId?: number;
}; };
// Self Sign
// If the recipient is the user and it is the only recipient,
// dont send the document, after adding the fields, skip the next step and go straight to the point
// no need for the sending section
// it will create the document
// and redirect you to the signing page.
export const AddFieldsFormPartial = ({ export const AddFieldsFormPartial = ({
documentFlow, documentFlow,
hideRecipients = false, hideRecipients = false,
@ -110,6 +118,7 @@ export const AddFieldsFormPartial = ({
teamId, teamId,
}: AddFieldsFormProps) => { }: AddFieldsFormProps) => {
const { toast } = useToast(); const { toast } = useToast();
const { data: session } = useSession();
const [isMissingSignatureDialogVisible, setIsMissingSignatureDialogVisible] = useState(false); const [isMissingSignatureDialogVisible, setIsMissingSignatureDialogVisible] = useState(false);
@ -530,6 +539,10 @@ export const AddFieldsFormPartial = ({
); );
}, [recipientsByRole]); }, [recipientsByRole]);
const hasSameOwnerAsRecipient =
recipientsByRole.SIGNER.length === 1 &&
recipientsByRole.SIGNER[0].email === session?.user?.email;
const handleAdvancedSettings = () => { const handleAdvancedSettings = () => {
setShowAdvancedSettings((prev) => !prev); setShowAdvancedSettings((prev) => !prev);
}; };
@ -1067,6 +1080,7 @@ export const AddFieldsFormPartial = ({
documentFlow.onBackStep?.(); documentFlow.onBackStep?.();
}} }}
goBackLabel={canRenderBackButtonAsRemove ? msg`Remove` : undefined} goBackLabel={canRenderBackButtonAsRemove ? msg`Remove` : undefined}
goNextLabel={hasSameOwnerAsRecipient ? msg`Self Sign` : undefined}
onGoNextClick={handleGoNextClick} onGoNextClick={handleGoNextClick}
/> />
</DocumentFlowFormContainerFooter> </DocumentFlowFormContainerFooter>