mirror of
https://github.com/documenso/documenso.git
synced 2025-11-24 13:41:30 +10:00
## Description Direct templates links is a feature that provides template owners the ability to allow users to create documents based of their templates. ## General outline This works by allowing the template owner to configure a "direct recipient" in the template. When a user opens the direct link to the template, it will create a flow where they sign the fields configured by the template owner for the direct recipient. After these fields are signed the following will occur: - A document will be created where the owner is the template owner - The direct recipient fields will be signed - The document will be sent to any other recipients configured in the template - If there are none the document will be immediately completed ## Notes There's a custom prisma migration to migrate all documents to have 'DOCUMENT' as the source, then sets the column to required. --------- Co-authored-by: Lucas Smith <me@lucasjamessmith.me>
122 lines
3.4 KiB
TypeScript
122 lines
3.4 KiB
TypeScript
import { useState } from 'react';
|
|
|
|
import type { Field } from '@documenso/prisma/client';
|
|
import { RecipientRole } from '@documenso/prisma/client';
|
|
import { Button } from '@documenso/ui/primitives/button';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogFooter,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from '@documenso/ui/primitives/dialog';
|
|
|
|
import { SigningDisclosure } from '~/components/general/signing-disclosure';
|
|
import { truncateTitle } from '~/helpers/truncate-title';
|
|
|
|
export type SignDialogProps = {
|
|
isSubmitting: boolean;
|
|
documentTitle: string;
|
|
fields: Field[];
|
|
fieldsValidated: () => void | Promise<void>;
|
|
onSignatureComplete: () => void | Promise<void>;
|
|
role: RecipientRole;
|
|
};
|
|
|
|
export const SignDialog = ({
|
|
isSubmitting,
|
|
documentTitle,
|
|
fields,
|
|
fieldsValidated,
|
|
onSignatureComplete,
|
|
role,
|
|
}: SignDialogProps) => {
|
|
const [showDialog, setShowDialog] = useState(false);
|
|
const truncatedTitle = truncateTitle(documentTitle);
|
|
const isComplete = fields.every((field) => field.inserted);
|
|
|
|
const handleOpenChange = (open: boolean) => {
|
|
if (isSubmitting || !isComplete) {
|
|
return;
|
|
}
|
|
|
|
setShowDialog(open);
|
|
};
|
|
|
|
return (
|
|
<Dialog open={showDialog} onOpenChange={handleOpenChange}>
|
|
<DialogTrigger asChild>
|
|
<Button
|
|
className="w-full"
|
|
type="button"
|
|
size="lg"
|
|
onClick={fieldsValidated}
|
|
loading={isSubmitting}
|
|
>
|
|
{isComplete ? 'Complete' : 'Next field'}
|
|
</Button>
|
|
</DialogTrigger>
|
|
|
|
<DialogContent>
|
|
<DialogTitle>
|
|
<div className="text-foreground text-xl font-semibold">
|
|
{role === RecipientRole.VIEWER && 'Complete Viewing'}
|
|
{role === RecipientRole.SIGNER && 'Complete Signing'}
|
|
{role === RecipientRole.APPROVER && 'Complete Approval'}
|
|
</div>
|
|
</DialogTitle>
|
|
|
|
<div className="text-muted-foreground max-w-[50ch]">
|
|
{role === RecipientRole.VIEWER && (
|
|
<span>
|
|
You are about to complete viewing "{truncatedTitle}".
|
|
<br /> Are you sure?
|
|
</span>
|
|
)}
|
|
{role === RecipientRole.SIGNER && (
|
|
<span>
|
|
You are about to complete signing "{truncatedTitle}".
|
|
<br /> Are you sure?
|
|
</span>
|
|
)}
|
|
{role === RecipientRole.APPROVER && (
|
|
<span>
|
|
You are about to complete approving "{truncatedTitle}".
|
|
<br /> Are you sure?
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
<SigningDisclosure className="mt-4" />
|
|
|
|
<DialogFooter>
|
|
<div className="flex w-full flex-1 flex-nowrap gap-4">
|
|
<Button
|
|
type="button"
|
|
className="dark:bg-muted dark:hover:bg-muted/80 flex-1 bg-black/5 hover:bg-black/10"
|
|
variant="secondary"
|
|
onClick={() => {
|
|
setShowDialog(false);
|
|
}}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
|
|
<Button
|
|
type="button"
|
|
className="flex-1"
|
|
disabled={!isComplete}
|
|
loading={isSubmitting}
|
|
onClick={onSignatureComplete}
|
|
>
|
|
{role === RecipientRole.VIEWER && 'Mark as Viewed'}
|
|
{role === RecipientRole.SIGNER && 'Sign'}
|
|
{role === RecipientRole.APPROVER && 'Approve'}
|
|
</Button>
|
|
</div>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|