Compare commits

..

2 Commits

Author SHA1 Message Date
a75e71700f fix: cleanup 2025-11-18 13:12:09 +11:00
d121392f74 fix: envelope template recipient placeholders 2025-11-18 13:08:44 +11:00
8 changed files with 43 additions and 100 deletions

View File

@ -5,7 +5,7 @@ import { msg } from '@lingui/core/macro';
import { Trans, useLingui } from '@lingui/react/macro';
import { FieldType, RecipientRole } from '@prisma/client';
import { FileTextIcon } from 'lucide-react';
import { Link, useSearchParams } from 'react-router';
import { Link } from 'react-router';
import { isDeepEqual } from 'remeda';
import { match } from 'ts-pattern';
@ -65,8 +65,6 @@ const FieldSettingsTypeTranslations: Record<FieldType, MessageDescriptor> = {
};
export const EnvelopeEditorFieldsPage = () => {
const [searchParams] = useSearchParams();
const { envelope, editorFields, relativePath } = useCurrentEnvelopeEditor();
const { currentEnvelopeItem } = useCurrentEnvelopeRender();
@ -210,37 +208,6 @@ export const EnvelopeEditorFieldsPage = () => {
<section>
<Separator className="my-4" />
{searchParams.get('devmode') && (
<>
<div className="px-4">
<h3 className="text-foreground mb-3 text-sm font-semibold">
<Trans>Developer Mode</Trans>
</h3>
<div className="bg-muted/50 border-border text-foreground space-y-2 rounded-md border p-3 text-sm">
<p>
<span className="text-muted-foreground min-w-12">Pos X:&nbsp;</span>
{selectedField.positionX.toFixed(2)}
</p>
<p>
<span className="text-muted-foreground min-w-12">Pos Y:&nbsp;</span>
{selectedField.positionY.toFixed(2)}
</p>
<p>
<span className="text-muted-foreground min-w-12">Width:&nbsp;</span>
{selectedField.width.toFixed(2)}
</p>
<p>
<span className="text-muted-foreground min-w-12">Height:&nbsp;</span>
{selectedField.height.toFixed(2)}
</p>
</div>
</div>
<Separator className="my-4" />
</>
)}
<div className="[&_label]:text-foreground/70 px-4 [&_label]:text-xs">
<h3 className="text-sm font-semibold">
{t(FieldSettingsTypeTranslations[selectedField.type])}

View File

@ -44,7 +44,7 @@ export default function EnvelopeEditorHeader() {
<nav className="bg-background border-border w-full border-b px-4 py-3 md:px-6">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<Link to="/">
<Link to={relativePath.basePath}>
<BrandingLogo className="h-6 w-auto" />
</Link>
<Separator orientation="vertical" className="h-6" />

View File

@ -22,12 +22,14 @@ import { useDebouncedValue } from '@documenso/lib/client-only/hooks/use-debounce
import { useCurrentEnvelopeEditor } from '@documenso/lib/client-only/providers/envelope-editor-provider';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
import { useSession } from '@documenso/lib/client-only/providers/session';
import { isTemplateRecipientEmailPlaceholder } from '@documenso/lib/constants/template';
import {
ZRecipientActionAuthTypesSchema,
ZRecipientAuthOptionsSchema,
} from '@documenso/lib/types/document-auth';
import { nanoid } from '@documenso/lib/universal/id';
import { canRecipientBeModified as utilCanRecipientBeModified } from '@documenso/lib/utils/recipients';
import { generateRecipientPlaceholder } from '@documenso/lib/utils/templates';
import { trpc } from '@documenso/trpc/react';
import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out';
import { RecipientActionAuthSelect } from '@documenso/ui/components/recipient/recipient-action-auth-select';
@ -82,7 +84,8 @@ const ZEnvelopeRecipientsForm = z.object({
type TEnvelopeRecipientsForm = z.infer<typeof ZEnvelopeRecipientsForm>;
export const EnvelopeEditorRecipientForm = () => {
const { envelope, setRecipientsDebounced, updateEnvelope } = useCurrentEnvelopeEditor();
const { envelope, setRecipientsDebounced, updateEnvelope, isTemplate } =
useCurrentEnvelopeEditor();
const organisation = useCurrentOrganisation();
@ -119,6 +122,7 @@ export const EnvelopeEditorRecipientForm = () => {
role: RecipientRole.SIGNER,
signingOrder: 1,
actionAuth: [],
...(isTemplate ? generateRecipientPlaceholder(1) : {}),
},
];
@ -234,6 +238,8 @@ export const EnvelopeEditorRecipientForm = () => {
};
const onAddSigner = () => {
const placeholderRecipientCount = signers.length > 1 ? signers.length + 1 : 2;
appendSigner({
formId: nanoid(12),
name: '',
@ -241,7 +247,10 @@ export const EnvelopeEditorRecipientForm = () => {
role: RecipientRole.SIGNER,
actionAuth: [],
signingOrder: signers.length > 0 ? (signers[signers.length - 1]?.signingOrder ?? 0) + 1 : 1,
...(isTemplate ? generateRecipientPlaceholder(placeholderRecipientCount) : {}),
});
void form.trigger('signers');
};
const onRemoveSigner = (index: number) => {
@ -806,7 +815,7 @@ export const EnvelopeEditorRecipientForm = () => {
})}
>
{!showAdvancedSettings && index === 0 && (
<FormLabel required>
<FormLabel required={!isTemplate}>
<Trans>Email</Trans>
</FormLabel>
)}
@ -815,7 +824,12 @@ export const EnvelopeEditorRecipientForm = () => {
<RecipientAutoCompleteInput
type="email"
placeholder={t`Email`}
value={field.value}
value={
isTemplate &&
isTemplateRecipientEmailPlaceholder(field.value)
? ''
: field.value
}
disabled={
snapshot.isDragging ||
isSubmitting ||

View File

@ -84,13 +84,6 @@ export async function loader({ params, request }: Route.LoaderArgs) {
const canSignUp = !isExistingUser && env('NEXT_PUBLIC_DISABLE_SIGNUP') !== 'true';
const redirectToFolder =
user && document.userId === user.id && document.folderId && document.team?.url;
const homePath = redirectToFolder
? `/t/${document.team.url}/documents/f/${document.folderId}`
: '/';
return {
isDocumentAccessValid: true,
canSignUp,
@ -99,7 +92,6 @@ export async function loader({ params, request }: Route.LoaderArgs) {
signatures,
document,
recipient,
homePath,
};
}
@ -117,7 +109,6 @@ export default function CompletedSigningPage({ loaderData }: Route.ComponentProp
document,
recipient,
recipientEmail,
homePath,
} = loaderData;
if (!isDocumentAccessValid) {
@ -211,12 +202,8 @@ export default function CompletedSigningPage({ loaderData }: Route.ComponentProp
</p>
))}
<div className="mt-8 flex w-full max-w-xs flex-col items-stretch gap-4 md:w-auto md:max-w-none md:flex-row md:items-center">
<DocumentShareButton
documentId={document.id}
token={recipient.token}
className="w-full max-w-none md:flex-1"
/>
<div className="mt-8 flex w-full max-w-sm items-center justify-center gap-4">
<DocumentShareButton documentId={document.id} token={recipient.token} />
{isDocumentCompleted(document.status) && (
<EnvelopeDownloadDialog
@ -225,21 +212,13 @@ export default function CompletedSigningPage({ loaderData }: Route.ComponentProp
envelopeItems={document.envelopeItems}
token={recipient?.token}
trigger={
<Button type="button" variant="outline" className="flex-1 md:flex-initial">
<Button type="button" variant="outline" className="flex-1">
<DownloadIcon className="mr-2 h-5 w-5" />
<Trans>Download</Trans>
</Button>
}
/>
)}
{user && (
<Button asChild>
<Link to={homePath}>
<Trans>Go Back Home</Trans>
</Link>
</Button>
)}
</div>
</div>
@ -259,6 +238,12 @@ export default function CompletedSigningPage({ loaderData }: Route.ComponentProp
<ClaimAccount defaultName={recipientName} defaultEmail={recipient.email} />
</div>
)}
{user && (
<Link to="/" className="text-documenso-700 hover:text-documenso-600 mt-2">
<Trans>Go Back Home</Trans>
</Link>
)}
</div>
</div>

View File

@ -1,16 +1,6 @@
import { z } from 'zod';
export const SUPPORTED_LANGUAGE_CODES = [
'de',
'en',
'fr',
'es',
'it',
'pl',
'ja',
'ko',
'zh',
] as const;
export const SUPPORTED_LANGUAGE_CODES = ['de', 'en', 'fr', 'es', 'it', 'pl'] as const;
export const ZSupportedLanguageCodeSchema = z.enum(SUPPORTED_LANGUAGE_CODES).catch('en');
@ -64,18 +54,6 @@ export const SUPPORTED_LANGUAGES: Record<string, SupportedLanguage> = {
short: 'pl',
full: 'Polish',
},
ja: {
short: 'ja',
full: 'Japanese',
},
ko: {
short: 'ko',
full: 'Korean',
},
zh: {
short: 'zh',
full: 'Chinese',
},
} satisfies Record<SupportedLanguageCodes, SupportedLanguage>;
export const isValidLanguageCode = (code: unknown): code is SupportedLanguageCodes =>

View File

@ -103,7 +103,6 @@ export const getDocumentAndSenderByToken = async ({
select: {
name: true,
teamEmail: true,
url: true,
teamGlobalSettings: {
select: {
brandingEnabled: true,

View File

@ -31,16 +31,26 @@ export const viewedDocument = async ({
type: EnvelopeType.DOCUMENT,
},
},
include: {
envelope: {
include: {
documentMeta: true,
recipients: true,
},
},
},
});
if (!recipient) {
return;
}
const { envelope } = recipient;
await prisma.documentAuditLog.create({
data: createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_VIEWED,
envelopeId: recipient.envelopeId,
envelopeId: envelope.id,
user: {
name: recipient.name,
email: recipient.email,
@ -76,7 +86,7 @@ export const viewedDocument = async ({
await tx.documentAuditLog.create({
data: createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_OPENED,
envelopeId: recipient.envelopeId,
envelopeId: envelope.id,
user: {
name: recipient.name,
email: recipient.email,
@ -93,16 +103,6 @@ export const viewedDocument = async ({
});
});
const envelope = await prisma.envelope.findUniqueOrThrow({
where: {
id: recipient.envelopeId,
},
include: {
documentMeta: true,
recipients: true,
},
});
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_OPENED,
data: ZWebhookDocumentSchema.parse(mapEnvelopeToWebhookDocumentPayload(envelope)),

View File

@ -127,11 +127,11 @@ export const DocumentShareButton = ({
<Button
variant="outline"
disabled={!token || !documentId}
className={cn('h-11 w-full max-w-lg flex-1', className)}
className={cn('flex-1 text-[11px]', className)}
loading={isLoading}
>
{!isLoading && <Sparkles className="mr-2 h-5 w-5" />}
<Trans>Share</Trans>
<Trans>Share Signature Card</Trans>
</Button>
)}
</DialogTrigger>