Compare commits

..

16 Commits

Author SHA1 Message Date
github-actions
d1528fd63b chore: extract translations 2024-09-11 07:27:20 +00:00
Catalin Pit
85012ae991 Merge branch 'main' into feat/save-data-on-blur 2024-09-11 10:26:39 +03:00
Catalin Pit
ff4c9616fc Merge branch 'main' into feat/save-data-on-blur 2024-09-05 10:26:22 +03:00
Catalin Pit
fd004f5f24 chore: merge main 2024-08-29 12:37:19 +03:00
github-actions
bb222cc0fc chore: extract translations 2024-08-22 05:16:14 +00:00
Catalin Pit
f627cbc7db Delete packages/lib/translations/de/common.po 2024-08-22 08:15:24 +03:00
Catalin Pit
67be4fdb45 Delete packages/lib/translations/de/web.po 2024-08-22 08:15:15 +03:00
Catalin Pit
c8b7d13b4f Delete packages/lib/translations/de/marketing.po 2024-08-22 08:15:05 +03:00
Catalin Pit
2b4699bb61 Delete packages/lib/translations/de/marketing.js 2024-08-22 08:14:52 +03:00
github-actions
39603fc150 chore: extract translations 2024-08-21 10:59:09 +00:00
Catalin Pit
7f2a8deda3 Merge branch 'main' into feat/save-data-on-blur 2024-08-21 13:58:17 +03:00
Catalin Pit
f24a33c182 fix: fix err msg 2024-08-21 13:57:43 +03:00
Catalin Pit
4a8f32a44f fix: remove unnecessary code 2024-08-21 12:56:28 +03:00
Catalin Pit
bbf2ed7154 feat: fix code 2024-08-21 12:15:22 +03:00
Catalin Pit
5ce7f4adcc feat: ux improvements 2024-08-21 08:50:24 +03:00
Catalin Pit
d74aca2aa6 feat: save subject and message on blur 2024-08-20 14:19:16 +03:00
32 changed files with 357 additions and 493 deletions

View File

@@ -2,7 +2,7 @@ declare namespace NodeJS {
export interface ProcessEnv {
NEXT_PUBLIC_WEBAPP_URL?: string;
NEXT_PUBLIC_MARKETING_URL?: string;
NEXT_PRIVATE_INTERNAL_WEBAPP_URL?: string;
NEXT_PRIVATE_INTERNAL_WEBAPP_URL?:string;
NEXT_PRIVATE_DATABASE_URL: string;

View File

@@ -2,7 +2,7 @@ declare namespace NodeJS {
export interface ProcessEnv {
NEXT_PUBLIC_WEBAPP_URL?: string;
NEXT_PUBLIC_MARKETING_URL?: string;
NEXT_PRIVATE_INTERNAL_WEBAPP_URL?: string;
NEXT_PRIVATE_INTERNAL_WEBAPP_URL?:string;
NEXT_PRIVATE_DATABASE_URL: string;

View File

@@ -349,13 +349,11 @@ export const EditDocumentForm = ({
<AddSignersFormPartial
key={recipients.length}
documentFlow={documentFlow.signers}
document={document}
recipients={recipients}
fields={fields}
isDocumentEnterprise={isDocumentEnterprise}
onSubmit={onAddSignersFormSubmit}
isDocumentPdfLoaded={isDocumentPdfLoaded}
teamId={team?.id}
/>
<AddFieldsFormPartial

View File

@@ -266,7 +266,6 @@ export const EditTemplateForm = ({
onSubmit={onAddTemplatePlaceholderFormSubmit}
isEnterprise={isEnterprise}
isDocumentPdfLoaded={isDocumentPdfLoaded}
template={template}
/>
<AddTemplateFieldsFormPartial

View File

@@ -1,8 +1,5 @@
import { z } from 'zod';
export const ZBaseEmbedDataSchema = z.object({
css: z
.string()
.optional()
.transform((value) => value || undefined),
css: z.string().optional().transform(value => value || undefined),
});

View File

@@ -18,18 +18,15 @@ export const EmbedDocumentCompleted = ({ name, signature }: EmbedDocumentComplet
<div className="mt-8 w-full max-w-md">
<SigningCard3D
className="mx-auto w-full"
className='w-full mx-auto'
name={name || 'Documenso'}
signature={signature}
signingCelebrationImage={signingCelebration}
/>
</div>
<p className="text-muted-foreground mt-8 max-w-[50ch] text-center text-sm">
<Trans>
The document is now completed, please follow any instructions provided within the parent
application.
</Trans>
<p className="mt-8 max-w-[50ch] text-center text-muted-foreground text-sm">
<Trans>The document is now completed, please follow any instructions provided within the parent application.</Trans>
</p>
</div>
);

View File

@@ -6,7 +6,6 @@ import { useSearchParams } from 'next/navigation';
import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
import { DateTime } from 'luxon';
import { useThrottleFn } from '@documenso/lib/client-only/hooks/use-throttle-fn';
@@ -15,7 +14,7 @@ import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
import { validateFieldsInserted } from '@documenso/lib/utils/fields';
import type { DocumentMeta, Recipient, TemplateMeta } from '@documenso/prisma/client';
import { type DocumentData, type Field, FieldType } from '@documenso/prisma/client';
import { FieldType, type DocumentData, type Field } from '@documenso/prisma/client';
import { trpc } from '@documenso/trpc/react';
import type {
TRemovedSignedFieldWithTokenMutationSchema,
@@ -35,6 +34,7 @@ import type { DirectTemplateLocalField } from '~/app/(recipient)/d/[token]/sign-
import { useRequiredSigningContext } from '~/app/(signing)/sign/[token]/provider';
import { Logo } from '~/components/branding/logo';
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
import { EmbedClientLoading } from '../../client-loading';
import { EmbedDocumentCompleted } from '../../completed';
import { EmbedDocumentFields } from '../../document-fields';
@@ -307,7 +307,7 @@ export const EmbedDirectTemplateClientPage = ({
<div className="relative mx-auto flex min-h-[100dvh] max-w-screen-lg flex-col items-center justify-center p-6">
{(!hasFinishedInit || !hasDocumentLoaded) && <EmbedClientLoading />}
<div className="relative flex w-full flex-col gap-x-6 gap-y-12 md:flex-row">
<div className="relative flex flex-col md:flex-row w-full gap-x-6 gap-y-12">
{/* Viewer */}
<div className="flex-1">
<LazyPDFViewer
@@ -318,26 +318,26 @@ export const EmbedDirectTemplateClientPage = ({
{/* Widget */}
<div
className="group/document-widget fixed bottom-8 left-0 z-50 h-fit w-full flex-shrink-0 px-6 md:sticky md:top-4 md:z-auto md:w-[350px] md:px-0"
className="group/document-widget fixed md:sticky md:top-4 left-0 w-full bottom-8 px-6 md:px-0 z-50 md:z-auto md:w-[350px] flex-shrink-0 h-fit"
data-expanded={isExpanded || undefined}
>
<div className="border-border bg-widget flex h-fit w-full flex-col rounded-xl border px-4 py-4 md:min-h-[min(calc(100dvh-2rem),48rem)] md:py-6">
<div className="w-full border-border bg-widget flex md:min-h-[min(calc(100dvh-2rem),48rem)] h-fit flex-col rounded-xl border px-4 py-4 md:py-6">
{/* Header */}
<div>
<div className="flex items-center justify-between gap-x-2">
<h3 className="text-foreground text-xl font-semibold md:text-2xl">
<h3 className="text-foreground text-xl md:text-2xl font-semibold">
<Trans>Sign document</Trans>
</h3>
<Button variant="outline" className="h-8 w-8 p-0 md:hidden">
{isExpanded ? (
<LucideChevronDown
className="text-muted-foreground h-5 w-5"
className="h-5 w-5 text-muted-foreground"
onClick={() => setIsExpanded(false)}
/>
) : (
<LucideChevronUp
className="text-muted-foreground h-5 w-5"
className="h-5 w-5 text-muted-foreground"
onClick={() => setIsExpanded(true)}
/>
)}
@@ -354,7 +354,7 @@ export const EmbedDirectTemplateClientPage = ({
</div>
{/* Form */}
<div className="-mx-2 hidden px-2 group-data-[expanded]/document-widget:block md:block">
<div className="-mx-2 px-2 hidden group-data-[expanded]/document-widget:block md:block">
<div className="flex flex-1 flex-col gap-y-4">
<div>
<Label htmlFor="full-name">
@@ -408,9 +408,9 @@ export const EmbedDirectTemplateClientPage = ({
</div>
</div>
<div className="hidden flex-1 group-data-[expanded]/document-widget:block md:block" />
<div className="flex-1 hidden group-data-[expanded]/document-widget:block md:block" />
<div className="mt-4 hidden w-full grid-cols-2 items-center group-data-[expanded]/document-widget:grid md:grid">
<div className="w-full grid-cols-2 items-center mt-4 hidden group-data-[expanded]/document-widget:grid md:grid">
{pendingFields.length > 0 ? (
<Button className="col-start-2" onClick={() => onNextFieldClick()}>
<Trans>Next</Trans>

View File

@@ -1,3 +1,3 @@
export default function EmbedDirectTemplateNotFound() {
return <div>Not Found</div>;
return <div>Not Found</div>
}

View File

@@ -73,7 +73,11 @@ export default async function EmbedDirectTemplatePage({ params }: EmbedDirectTem
const fields = template.Field.filter((field) => field.recipientId === directTemplateRecipientId);
return (
<SigningProvider email={user?.email} fullName={user?.name} signature={user?.signature}>
<SigningProvider
email={user?.email}
fullName={user?.name}
signature={user?.signature}
>
<DocumentAuthProvider
documentAuthOptions={template.authOptions}
recipient={recipient}

View File

@@ -13,7 +13,7 @@ import {
ZTextFieldMeta,
} from '@documenso/lib/types/field-meta';
import type { DocumentMeta, Recipient, TemplateMeta } from '@documenso/prisma/client';
import { type Field, FieldType } from '@documenso/prisma/client';
import { FieldType, type Field } from '@documenso/prisma/client';
import type { FieldWithSignatureAndFieldMeta } from '@documenso/prisma/types/field-with-signature-and-fieldmeta';
import type {
TRemovedSignedFieldWithTokenMutationSchema,

View File

@@ -1,7 +1,5 @@
export const EmbedPaywall = () => {
return (
<div>
<h1>Paywall</h1>
</div>
);
};
return <div>
<h1>Paywall</h1>
</div>
}

View File

@@ -1,17 +1,15 @@
'use client';
import { useEffect, useState } from 'react';
import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
import { useThrottleFn } from '@documenso/lib/client-only/hooks/use-throttle-fn';
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
import { validateFieldsInserted } from '@documenso/lib/utils/fields';
import type { DocumentMeta, Recipient, TemplateMeta } from '@documenso/prisma/client';
import { type DocumentData, type Field } from '@documenso/prisma/client';
import { trpc } from '@documenso/trpc/react';
import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react';
import { useEffect, useState } from 'react';
import { FieldToolTip } from '@documenso/ui/components/field/field-tooltip';
import { Button } from '@documenso/ui/primitives/button';
import { Card, CardContent } from '@documenso/ui/primitives/card';
@@ -22,9 +20,9 @@ import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
import { SignaturePad } from '@documenso/ui/primitives/signature-pad';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
import { useRequiredSigningContext } from '~/app/(signing)/sign/[token]/provider';
import { Logo } from '~/components/branding/logo';
import { EmbedClientLoading } from '../../client-loading';
import { EmbedDocumentCompleted } from '../../completed';
import { EmbedDocumentFields } from '../../document-fields';
@@ -187,7 +185,7 @@ export const EmbedSignDocumentClientPage = ({
<div className="relative mx-auto flex min-h-[100dvh] max-w-screen-lg flex-col items-center justify-center p-6">
{(!hasFinishedInit || !hasDocumentLoaded) && <EmbedClientLoading />}
<div className="relative flex w-full flex-col gap-x-6 gap-y-12 md:flex-row">
<div className="relative flex flex-col md:flex-row w-full gap-x-6 gap-y-12">
{/* Viewer */}
<div className="flex-1">
<LazyPDFViewer
@@ -198,26 +196,26 @@ export const EmbedSignDocumentClientPage = ({
{/* Widget */}
<div
className="group/document-widget fixed bottom-8 left-0 z-50 h-fit w-full flex-shrink-0 px-6 md:sticky md:top-4 md:z-auto md:w-[350px] md:px-0"
className="group/document-widget fixed md:sticky md:top-4 left-0 w-full bottom-8 px-6 md:px-0 z-50 md:z-auto md:w-[350px] flex-shrink-0 h-fit"
data-expanded={isExpanded || undefined}
>
<div className="border-border bg-widget flex w-full flex-col rounded-xl border px-4 py-4 md:py-6">
<div className="w-full border-border bg-widget flex flex-col rounded-xl border px-4 py-4 md:py-6">
{/* Header */}
<div>
<div className="flex items-center justify-between gap-x-2">
<h3 className="text-foreground text-xl font-semibold md:text-2xl">
<h3 className="text-foreground text-xl md:text-2xl font-semibold">
<Trans>Sign document</Trans>
</h3>
<Button variant="outline" className="h-8 w-8 p-0 md:hidden">
{isExpanded ? (
<LucideChevronDown
className="text-muted-foreground h-5 w-5"
className="h-5 w-5 text-muted-foreground"
onClick={() => setIsExpanded(false)}
/>
) : (
<LucideChevronUp
className="text-muted-foreground h-5 w-5"
className="h-5 w-5 text-muted-foreground"
onClick={() => setIsExpanded(true)}
/>
)}
@@ -234,7 +232,7 @@ export const EmbedSignDocumentClientPage = ({
</div>
{/* Form */}
<div className="-mx-2 hidden px-2 group-data-[expanded]/document-widget:block md:block">
<div className="-mx-2 px-2 hidden group-data-[expanded]/document-widget:block md:block">
<div className="flex flex-1 flex-col gap-y-4">
<div>
<Label htmlFor="full-name">
@@ -287,9 +285,9 @@ export const EmbedSignDocumentClientPage = ({
</div>
</div>
<div className="hidden flex-1 group-data-[expanded]/document-widget:block md:block" />
<div className="flex-1 hidden group-data-[expanded]/document-widget:block md:block" />
<div className="mt-4 hidden w-full grid-cols-2 items-center group-data-[expanded]/document-widget:grid md:grid">
<div className="w-full grid-cols-2 items-center mt-4 hidden group-data-[expanded]/document-widget:grid md:grid">
{pendingFields.length > 0 ? (
<Button className="col-start-2" onClick={() => onNextFieldClick()}>
<Trans>Next</Trans>

View File

@@ -1,3 +1,3 @@
export default function EmbedDirectTemplateNotFound() {
return <div>Not Found</div>;
return <div>Not Found</div>
}

View File

@@ -4,12 +4,8 @@ import { match } from 'ts-pattern';
import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app';
import { getServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
import { DocumentAccessAuth } from '@documenso/lib/types/document-auth';
import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth';
import { DocumentStatus } from '@documenso/prisma/client';
import { DocumentAuthProvider } from '~/app/(signing)/sign/[token]/document-auth-provider';
import { SigningProvider } from '~/app/(signing)/sign/[token]/provider';
@@ -17,6 +13,10 @@ import { SigningProvider } from '~/app/(signing)/sign/[token]/provider';
import { EmbedAuthenticateView } from '../../authenticate';
import { EmbedPaywall } from '../../paywall';
import { EmbedSignDocumentClientPage } from './client';
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
import { DocumentStatus } from '@documenso/prisma/client';
export type EmbedSignDocumentPageProps = {
params: {
@@ -66,12 +66,7 @@ export default async function EmbedSignDocumentPage({ params }: EmbedSignDocumen
.exhaustive();
if (!isAccessAuthValid) {
return (
<EmbedAuthenticateView
email={user?.email || recipient.email}
returnTo={`/embed/direct/${token}`}
/>
);
return <EmbedAuthenticateView email={user?.email || recipient.email} returnTo={`/embed/direct/${token}`} />;
}
return (

View File

@@ -81,7 +81,7 @@ async function middleware(req: NextRequest): Promise<NextResponse> {
// Allow third parties to iframe the document.
res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.headers.set('Access-Control-Allow-Origin', '*');
res.headers.set('Content-Security-Policy', 'frame-ancestors *');
res.headers.set('Content-Security-Policy', "frame-ancestors *");
res.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
res.headers.set('X-Content-Type-Options', 'nosniff');
res.headers.set('X-Frame-Options', 'ALLOW-ALL');

View File

@@ -3,12 +3,12 @@ import { useCallback, useRef, useState } from 'react';
type ThrottleOptions = {
leading?: boolean;
trailing?: boolean;
};
}
export function useThrottleFn<T extends (...args: unknown[]) => unknown>(
fn: T,
ms = 500,
options: ThrottleOptions = {},
options: ThrottleOptions = {}
): [(...args: Parameters<T>) => void, boolean, () => void] {
const [isThrottling, setIsThrottling] = useState(false);
const $isThrottling = useRef(false);
@@ -44,7 +44,7 @@ export function useThrottleFn<T extends (...args: unknown[]) => unknown>(
$lastArgs.current = args;
}
},
[fn, ms, leading, trailing, $setIsThrottling],
[fn, ms, leading, trailing, $setIsThrottling]
);
const cancel = useCallback(() => {

View File

@@ -5,8 +5,7 @@ export const APP_DOCUMENT_UPLOAD_SIZE_LIMIT =
export const NEXT_PUBLIC_WEBAPP_URL = () => env('NEXT_PUBLIC_WEBAPP_URL');
export const NEXT_PUBLIC_MARKETING_URL = () => env('NEXT_PUBLIC_MARKETING_URL');
export const NEXT_PRIVATE_INTERNAL_WEBAPP_URL =
process.env.NEXT_PRIVATE_INTERNAL_WEBAPP_URL ?? NEXT_PUBLIC_WEBAPP_URL();
export const NEXT_PRIVATE_INTERNAL_WEBAPP_URL = process.env.NEXT_PRIVATE_INTERNAL_WEBAPP_URL ?? NEXT_PUBLIC_WEBAPP_URL();
export const IS_APP_MARKETING = process.env.NEXT_PUBLIC_PROJECT === 'marketing';
export const IS_APP_WEB = process.env.NEXT_PUBLIC_PROJECT === 'web';

View File

@@ -5,11 +5,7 @@ import { getToken } from 'next-auth/jwt';
import { LOCAL_FEATURE_FLAGS } from '@documenso/lib/constants/feature-flags';
import PostHogServerClient from '@documenso/lib/server-only/feature-flags/get-post-hog-server-client';
import {
NEXT_PRIVATE_INTERNAL_WEBAPP_URL,
NEXT_PUBLIC_MARKETING_URL,
NEXT_PUBLIC_WEBAPP_URL,
} from '../../constants/app';
import { NEXT_PUBLIC_MARKETING_URL, NEXT_PUBLIC_WEBAPP_URL, NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../constants/app';
import { extractDistinctUserId, mapJwtToFlagProperties } from './get';
/**

View File

@@ -7,11 +7,7 @@ import { getToken } from 'next-auth/jwt';
import { LOCAL_FEATURE_FLAGS, extractPostHogConfig } from '@documenso/lib/constants/feature-flags';
import PostHogServerClient from '@documenso/lib/server-only/feature-flags/get-post-hog-server-client';
import {
NEXT_PRIVATE_INTERNAL_WEBAPP_URL,
NEXT_PUBLIC_MARKETING_URL,
NEXT_PUBLIC_WEBAPP_URL,
} from '../../constants/app';
import { NEXT_PUBLIC_MARKETING_URL, NEXT_PUBLIC_WEBAPP_URL, NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../constants/app';
/**
* Evaluate a single feature flag based on the current user if possible.

View File

@@ -1,54 +0,0 @@
import { prisma } from '@documenso/prisma';
import { SendStatus } from '@documenso/prisma/client';
export type DeleteRecipientForTemplateOptions = {
templateId: number;
recipientId: number;
userId: number;
teamId?: number;
};
export const deleteRecipientFromTemplate = async ({
templateId,
recipientId,
userId,
teamId,
}: DeleteRecipientForTemplateOptions) => {
const recipient = await prisma.recipient.findFirst({
where: {
id: recipientId,
Template: {
id: templateId,
...(teamId
? {
team: {
id: teamId,
members: {
some: {
userId,
},
},
},
}
: {
userId,
teamId: null,
}),
},
},
});
if (!recipient) {
throw new Error('Recipient not found');
}
if (recipient.sendStatus !== SendStatus.NOT_SENT) {
throw new Error('Can not delete a recipient that has already been sent a document');
}
return await prisma.recipient.delete({
where: {
id: recipient.id,
},
});
};

View File

@@ -6,7 +6,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: de\n"
"Project-Id-Version: \n"
"Project-Id-Version: documenso-app\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-09-05 06:04\n"
"Last-Translator: \n"
@@ -82,19 +82,19 @@ msgstr "Weitere Option hinzufügen"
msgid "Add another value"
msgstr "Weiteren Wert hinzufügen"
#: packages/ui/primitives/document-flow/add-signers.tsx:459
#: packages/ui/primitives/document-flow/add-signers.tsx:359
msgid "Add myself"
msgstr "Mich selbst hinzufügen"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:450
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:369
msgid "Add Myself"
msgstr "Mich hinzufügen"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:436
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:355
msgid "Add Placeholder Recipient"
msgstr "Platzhalterempfänger hinzufügen"
#: packages/ui/primitives/document-flow/add-signers.tsx:448
#: packages/ui/primitives/document-flow/add-signers.tsx:348
msgid "Add Signer"
msgstr "Unterzeichner hinzufügen"
@@ -154,8 +154,8 @@ msgid "Cancel"
msgstr "Abbrechen"
#: packages/ui/primitives/document-flow/add-signers.tsx:164
#~ msgid "Cannot remove signer"
#~ msgstr "Unterzeichner kann nicht entfernt werden"
msgid "Cannot remove signer"
msgstr "Unterzeichner kann nicht entfernt werden"
#: packages/lib/constants/recipient-roles.ts:17
msgid "Cc"
@@ -230,7 +230,7 @@ msgstr "Datum"
msgid "Date Format"
msgstr "Datumsformat"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:393
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:312
msgid "Direct link receiver"
msgstr "Empfänger des direkten Links"
@@ -263,11 +263,11 @@ msgstr "Dropdown-Optionen"
#: packages/ui/primitives/document-flow/add-fields.tsx:776
#: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:330
#: packages/ui/primitives/document-flow/add-signers.tsx:337
#: packages/ui/primitives/document-flow/add-signers.tsx:232
#: packages/ui/primitives/document-flow/add-signers.tsx:239
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:296
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:303
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:210
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:217
msgid "Email"
msgstr "E-Mail"
@@ -367,7 +367,7 @@ msgstr "Max"
msgid "Member"
msgstr "Mitglied"
#: packages/ui/primitives/document-flow/add-subject.tsx:95
#: packages/ui/primitives/document-flow/add-subject.tsx:229
#: packages/ui/primitives/template-flow/add-template-settings.tsx:215
msgid "Message <0>(Optional)</0>"
msgstr "Nachricht <0>(Optional)</0>"
@@ -378,10 +378,10 @@ msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:802
#: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:364
#: packages/ui/primitives/document-flow/add-signers.tsx:265
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:327
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:333
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:245
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:251
msgid "Name"
msgstr "Name"
@@ -542,7 +542,7 @@ msgstr "Wählen Sie mindestens"
msgid "Select default option"
msgstr "Standardoption auswählen"
#: packages/ui/primitives/document-flow/add-subject.tsx:124
#: packages/ui/primitives/document-flow/add-subject.tsx:275
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:34
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:64
msgid "Send"
@@ -560,8 +560,8 @@ msgstr "Unterschriftenkarte teilen"
msgid "Share the Link"
msgstr "Link teilen"
#: packages/ui/primitives/document-flow/add-signers.tsx:477
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:468
#: packages/ui/primitives/document-flow/add-signers.tsx:377
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:387
msgid "Show advanced settings"
msgstr "Erweiterte Einstellungen anzeigen"
@@ -604,7 +604,7 @@ msgstr "Etwas ist schief gelaufen."
msgid "Step <0>{step} of {maxStep}</0>"
msgstr "Schritt <0>{step} von {maxStep}</0>"
#: packages/ui/primitives/document-flow/add-subject.tsx:78
#: packages/ui/primitives/document-flow/add-subject.tsx:194
#: packages/ui/primitives/template-flow/add-template-settings.tsx:195
msgid "Subject <0>(Optional)</0>"
msgstr "Betreff <0>(Optional)</0>"
@@ -686,13 +686,13 @@ msgstr "Dieses Dokument wurde bereits an diesen Empfänger gesendet. Sie können
msgid "This document is password protected. Please enter the password to view the document."
msgstr "Dieses Dokument ist durch ein Passwort geschützt. Bitte geben Sie das Passwort ein, um das Dokument anzusehen."
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:396
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:315
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
msgstr "Dieses Feld kann nicht geändert oder gelöscht werden. Wenn Sie den direkten Link dieser Vorlage teilen oder zu Ihrem öffentlichen Profil hinzufügen, kann jeder, der darauf zugreift, seinen Namen und seine E-Mail-Adresse eingeben und die ihm zugewiesenen Felder ausfüllen."
#: packages/ui/primitives/document-flow/add-signers.tsx:165
#~ msgid "This signer has already received the document."
#~ msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten."
msgid "This signer has already received the document."
msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten."
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings."
@@ -712,7 +712,7 @@ msgstr "Titel"
msgid "To proceed further, please set at least one value for the {0} field."
msgstr "Um fortzufahren, legen Sie bitte mindestens einen Wert für das Feld {0} fest."
#: packages/ui/primitives/document-flow/add-subject.tsx:124
#: packages/ui/primitives/document-flow/add-subject.tsx:275
msgid "Update"
msgstr "Aktualisieren"

View File

@@ -6,12 +6,17 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: de\n"
"Project-Id-Version: \n"
"Project-Id-Version: documenso-app\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-09-05 06:04\n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
"Language-Team: German\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Crowdin-Project: documenso-app\n"
"X-Crowdin-Project-ID: 694691\n"
"X-Crowdin-Language: de\n"
"X-Crowdin-File: marketing.po\n"
"X-Crowdin-File-ID: 6\n"
#: apps/marketing/src/app/(marketing)/blog/page.tsx:45
msgid "{0}"
@@ -417,7 +422,7 @@ msgid "Save $60 or $120"
msgstr ""
#~ msgid "Search languages..."
#~ msgstr "Sprachen suchen...>>>>>>> main"
#~ msgstr "Sprachen suchen..."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:109
msgid "Securely. Our data centers are located in Frankfurt (Germany), giving us the best local privacy laws. We are very aware of the sensitive nature of our data and follow best practices to ensure the security and integrity of the data entrusted to us."

View File

@@ -6,7 +6,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: de\n"
"Project-Id-Version: \n"
"Project-Id-Version: documenso-app\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-09-05 06:04\n"
"Last-Translator: \n"
@@ -754,7 +754,7 @@ msgstr "Klicken Sie, um den Signatur-Link zu kopieren, um ihn an den Empfänger
#: apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx:175
#: apps/web/src/app/(signing)/sign/[token]/form.tsx:107
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:435
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:314
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:312
msgid "Click to insert field"
msgstr "Klicken Sie, um das Feld einzufügen"
@@ -772,7 +772,7 @@ msgstr "Schließen"
#: apps/web/src/app/(signing)/sign/[token]/sign-dialog.tsx:58
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:425
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:304
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:302
#: apps/web/src/components/forms/v2/signup.tsx:522
msgid "Complete"
msgstr "Vollständig"
@@ -1405,7 +1405,7 @@ msgstr "Webhook bearbeiten"
#: apps/web/src/app/(recipient)/d/[token]/configure-direct-template.tsx:118
#: apps/web/src/app/(signing)/sign/[token]/email-field.tsx:126
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:376
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:256
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:254
#: apps/web/src/components/(teams)/dialogs/add-team-email-dialog.tsx:169
#: apps/web/src/components/(teams)/dialogs/update-team-email-dialog.tsx:153
#: apps/web/src/components/forms/forgot-password.tsx:81
@@ -1587,7 +1587,7 @@ msgstr "Haben Sie Ihr Passwort vergessen?"
#: apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx:326
#: apps/web/src/app/(signing)/sign/[token]/name-field.tsx:193
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:361
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:241
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:239
#: apps/web/src/components/forms/profile.tsx:110
#: apps/web/src/components/forms/v2/signup.tsx:300
msgid "Full Name"
@@ -2030,7 +2030,7 @@ msgid "New Template"
msgstr "Neue Vorlage"
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:416
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:295
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:293
#: apps/web/src/components/forms/v2/signup.tsx:509
msgid "Next"
msgstr "Nächster"
@@ -2733,7 +2733,7 @@ msgid "Sign as<0>{0} <1>({1})</1></0>"
msgstr "Unterzeichnen als<0>{0} <1>({1})</1></0>"
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:329
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:209
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:207
msgid "Sign document"
msgstr "Dokument unterschreiben"
@@ -2762,7 +2762,7 @@ msgid "Sign Out"
msgstr "Ausloggen"
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:350
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:230
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:228
msgid "Sign the document to complete the process."
msgstr "Unterschreiben Sie das Dokument, um den Vorgang abzuschließen."
@@ -2789,7 +2789,7 @@ msgstr "Registrieren mit OIDC"
#: apps/web/src/app/(signing)/sign/[token]/signature-field.tsx:197
#: apps/web/src/app/(signing)/sign/[token]/signature-field.tsx:227
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:391
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:270
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:268
#: apps/web/src/components/forms/profile.tsx:132
msgid "Signature"
msgstr "Unterschrift"
@@ -2857,7 +2857,7 @@ msgstr "Website Einstellungen"
#: apps/web/src/app/(teams)/t/[teamUrl]/settings/team-email-dropdown.tsx:39
#: apps/web/src/app/(unauthenticated)/verify-email/[token]/page.tsx:61
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:243
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:123
#: apps/web/src/components/(teams)/dialogs/create-team-checkout-dialog.tsx:50
#: apps/web/src/components/(teams)/dialogs/create-team-checkout-dialog.tsx:99
#: apps/web/src/components/(teams)/dialogs/invite-team-member-dialog.tsx:210
@@ -4023,7 +4023,7 @@ msgstr "Wir konnten die Zwei-Faktor-Authentifizierung für Ihr Konto nicht einri
#: apps/web/src/app/(recipient)/d/[token]/direct-template.tsx:119
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:245
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:127
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125
msgid "We were unable to submit this document at this time. Please try again later."
msgstr "Wir konnten dieses Dokument zurzeit nicht einreichen. Bitte versuchen Sie es später erneut."

View File

@@ -77,19 +77,19 @@ msgstr "Add another option"
msgid "Add another value"
msgstr "Add another value"
#: packages/ui/primitives/document-flow/add-signers.tsx:459
#: packages/ui/primitives/document-flow/add-signers.tsx:359
msgid "Add myself"
msgstr "Add myself"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:450
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:369
msgid "Add Myself"
msgstr "Add Myself"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:436
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:355
msgid "Add Placeholder Recipient"
msgstr "Add Placeholder Recipient"
#: packages/ui/primitives/document-flow/add-signers.tsx:448
#: packages/ui/primitives/document-flow/add-signers.tsx:348
msgid "Add Signer"
msgstr "Add Signer"
@@ -149,8 +149,8 @@ msgid "Cancel"
msgstr "Cancel"
#: packages/ui/primitives/document-flow/add-signers.tsx:164
#~ msgid "Cannot remove signer"
#~ msgstr "Cannot remove signer"
msgid "Cannot remove signer"
msgstr "Cannot remove signer"
#: packages/lib/constants/recipient-roles.ts:17
msgid "Cc"
@@ -225,7 +225,7 @@ msgstr "Date"
msgid "Date Format"
msgstr "Date Format"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:393
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:312
msgid "Direct link receiver"
msgstr "Direct link receiver"
@@ -258,11 +258,11 @@ msgstr "Dropdown options"
#: packages/ui/primitives/document-flow/add-fields.tsx:776
#: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:330
#: packages/ui/primitives/document-flow/add-signers.tsx:337
#: packages/ui/primitives/document-flow/add-signers.tsx:232
#: packages/ui/primitives/document-flow/add-signers.tsx:239
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:296
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:303
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:210
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:217
msgid "Email"
msgstr "Email"
@@ -362,7 +362,7 @@ msgstr "Max"
msgid "Member"
msgstr "Member"
#: packages/ui/primitives/document-flow/add-subject.tsx:95
#: packages/ui/primitives/document-flow/add-subject.tsx:229
#: packages/ui/primitives/template-flow/add-template-settings.tsx:215
msgid "Message <0>(Optional)</0>"
msgstr "Message <0>(Optional)</0>"
@@ -373,10 +373,10 @@ msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:802
#: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:364
#: packages/ui/primitives/document-flow/add-signers.tsx:265
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:327
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:333
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:245
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:251
msgid "Name"
msgstr "Name"
@@ -537,7 +537,7 @@ msgstr "Select at least"
msgid "Select default option"
msgstr "Select default option"
#: packages/ui/primitives/document-flow/add-subject.tsx:124
#: packages/ui/primitives/document-flow/add-subject.tsx:275
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:34
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:64
msgid "Send"
@@ -555,8 +555,8 @@ msgstr "Share Signature Card"
msgid "Share the Link"
msgstr "Share the Link"
#: packages/ui/primitives/document-flow/add-signers.tsx:477
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:468
#: packages/ui/primitives/document-flow/add-signers.tsx:377
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:387
msgid "Show advanced settings"
msgstr "Show advanced settings"
@@ -599,7 +599,7 @@ msgstr "Something went wrong."
msgid "Step <0>{step} of {maxStep}</0>"
msgstr "Step <0>{step} of {maxStep}</0>"
#: packages/ui/primitives/document-flow/add-subject.tsx:78
#: packages/ui/primitives/document-flow/add-subject.tsx:194
#: packages/ui/primitives/template-flow/add-template-settings.tsx:195
msgid "Subject <0>(Optional)</0>"
msgstr "Subject <0>(Optional)</0>"
@@ -681,13 +681,13 @@ msgstr "This document has already been sent to this recipient. You can no longer
msgid "This document is password protected. Please enter the password to view the document."
msgstr "This document is password protected. Please enter the password to view the document."
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:396
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:315
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
msgstr "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
#: packages/ui/primitives/document-flow/add-signers.tsx:165
#~ msgid "This signer has already received the document."
#~ msgstr "This signer has already received the document."
msgid "This signer has already received the document."
msgstr "This signer has already received the document."
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings."
@@ -707,7 +707,7 @@ msgstr "Title"
msgid "To proceed further, please set at least one value for the {0} field."
msgstr "To proceed further, please set at least one value for the {0} field."
#: packages/ui/primitives/document-flow/add-subject.tsx:124
#: packages/ui/primitives/document-flow/add-subject.tsx:275
msgid "Update"
msgstr "Update"

View File

@@ -749,7 +749,7 @@ msgstr "Click to copy signing link for sending to recipient"
#: apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx:175
#: apps/web/src/app/(signing)/sign/[token]/form.tsx:107
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:435
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:314
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:312
msgid "Click to insert field"
msgstr "Click to insert field"
@@ -767,7 +767,7 @@ msgstr "Close"
#: apps/web/src/app/(signing)/sign/[token]/sign-dialog.tsx:58
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:425
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:304
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:302
#: apps/web/src/components/forms/v2/signup.tsx:522
msgid "Complete"
msgstr "Complete"
@@ -1402,7 +1402,7 @@ msgstr "Edit webhook"
#: apps/web/src/app/(recipient)/d/[token]/configure-direct-template.tsx:118
#: apps/web/src/app/(signing)/sign/[token]/email-field.tsx:126
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:376
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:256
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:254
#: apps/web/src/components/(teams)/dialogs/add-team-email-dialog.tsx:169
#: apps/web/src/components/(teams)/dialogs/update-team-email-dialog.tsx:153
#: apps/web/src/components/forms/forgot-password.tsx:81
@@ -1586,7 +1586,7 @@ msgstr "Forgot your password?"
#: apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx:326
#: apps/web/src/app/(signing)/sign/[token]/name-field.tsx:193
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:361
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:241
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:239
#: apps/web/src/components/forms/profile.tsx:110
#: apps/web/src/components/forms/v2/signup.tsx:300
msgid "Full Name"
@@ -2029,7 +2029,7 @@ msgid "New Template"
msgstr "New Template"
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:416
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:295
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:293
#: apps/web/src/components/forms/v2/signup.tsx:509
msgid "Next"
msgstr "Next"
@@ -2732,7 +2732,7 @@ msgid "Sign as<0>{0} <1>({1})</1></0>"
msgstr "Sign as<0>{0} <1>({1})</1></0>"
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:329
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:209
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:207
msgid "Sign document"
msgstr "Sign document"
@@ -2761,7 +2761,7 @@ msgid "Sign Out"
msgstr "Sign Out"
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:350
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:230
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:228
msgid "Sign the document to complete the process."
msgstr "Sign the document to complete the process."
@@ -2788,7 +2788,7 @@ msgstr "Sign Up with OIDC"
#: apps/web/src/app/(signing)/sign/[token]/signature-field.tsx:197
#: apps/web/src/app/(signing)/sign/[token]/signature-field.tsx:227
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:391
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:270
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:268
#: apps/web/src/components/forms/profile.tsx:132
msgid "Signature"
msgstr "Signature"
@@ -2856,7 +2856,7 @@ msgstr "Site Settings"
#: apps/web/src/app/(teams)/t/[teamUrl]/settings/team-email-dropdown.tsx:39
#: apps/web/src/app/(unauthenticated)/verify-email/[token]/page.tsx:61
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:243
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:123
#: apps/web/src/components/(teams)/dialogs/create-team-checkout-dialog.tsx:50
#: apps/web/src/components/(teams)/dialogs/create-team-checkout-dialog.tsx:99
#: apps/web/src/components/(teams)/dialogs/invite-team-member-dialog.tsx:210
@@ -4022,7 +4022,7 @@ msgstr "We were unable to setup two-factor authentication for your account. Plea
#: apps/web/src/app/(recipient)/d/[token]/direct-template.tsx:119
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:245
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:127
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125
msgid "We were unable to submit this document at this time. Please try again later."
msgstr "We were unable to submit this document at this time. Please try again later."

View File

@@ -38,6 +38,7 @@ import {
ZResendDocumentMutationSchema,
ZSearchDocumentsMutationSchema,
ZSendDocumentMutationSchema,
ZSetDocumentEmailSettingsMutationSchema,
ZSetPasswordForDocumentMutationSchema,
ZSetSettingsForDocumentMutationSchema,
ZSetTitleForDocumentMutationSchema,
@@ -275,6 +276,32 @@ export const documentRouter = router({
}
}),
setDocumentEmailSettings: authenticatedProcedure
.input(ZSetDocumentEmailSettingsMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { documentId, subject, message } = input;
const userId = ctx.user.id;
return await upsertDocumentMeta({
documentId,
userId,
subject,
message,
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message:
'We were unable to update the email settings for this document. Please try again later.',
});
}
}),
setPasswordForDocument: authenticatedProcedure
.input(ZSetPasswordForDocumentMutationSchema)
.mutation(async ({ input, ctx }) => {

View File

@@ -139,6 +139,12 @@ export const ZSendDocumentMutationSchema = z.object({
}),
});
export const ZSetDocumentEmailSettingsMutationSchema = z.object({
documentId: z.number(),
subject: z.string().optional(),
message: z.string().optional(),
});
export const ZSetPasswordForDocumentMutationSchema = z.object({
documentId: z.number(),
password: z.string(),

View File

@@ -1,8 +1,6 @@
import { TRPCError } from '@trpc/server';
import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token';
import { deleteRecipient } from '@documenso/lib/server-only/recipient/delete-recipient';
import { deleteRecipientFromTemplate } from '@documenso/lib/server-only/recipient/delete-recipient-from-template';
import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/set-recipients-for-document';
import { setRecipientsForTemplate } from '@documenso/lib/server-only/recipient/set-recipients-for-template';
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
@@ -12,8 +10,6 @@ import {
ZAddSignersMutationSchema,
ZAddTemplateSignersMutationSchema,
ZCompleteDocumentWithTokenMutationSchema,
ZRemoveSignerMutationSchema,
ZRemoveTemplateSignerMutationSchema,
} from './schema';
export const recipientRouter = router({
@@ -74,51 +70,6 @@ export const recipientRouter = router({
}
}),
removeTemplateSigner: authenticatedProcedure
.input(ZRemoveTemplateSignerMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { templateId, recipientId, teamId } = input;
const userId = ctx.user.id;
return await deleteRecipientFromTemplate({
userId,
templateId,
teamId,
recipientId,
});
} catch (e) {
console.error(e);
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to remove the recipient. Please try again later.',
});
}
}),
removeSigner: authenticatedProcedure
.input(ZRemoveSignerMutationSchema)
.mutation(async ({ input, ctx }) => {
try {
const { documentId, teamId, recipientId } = input;
return await deleteRecipient({
userId: ctx.user.id,
documentId,
teamId,
recipientId,
requestMetadata: extractNextApiRequestMetadata(ctx.req),
});
} catch (err) {
console.error(err);
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'We were unable to set this field. Please try again later.',
});
}
}),
completeDocumentWithToken: procedure
.input(ZCompleteDocumentWithTokenMutationSchema)
.mutation(async ({ input, ctx }) => {

View File

@@ -58,14 +58,6 @@ export const ZAddTemplateSignersMutationSchema = z
export type TAddTemplateSignersMutationSchema = z.infer<typeof ZAddTemplateSignersMutationSchema>;
export const ZRemoveSignerMutationSchema = z.object({
documentId: z.number(),
teamId: z.number().optional(),
recipientId: z.number(),
});
export type TRemoveSignerMutationSchema = z.infer<typeof ZRemoveSignerMutationSchema>;
export const ZCompleteDocumentWithTokenMutationSchema = z.object({
token: z.string(),
documentId: z.number(),
@@ -75,13 +67,3 @@ export const ZCompleteDocumentWithTokenMutationSchema = z.object({
export type TCompleteDocumentWithTokenMutationSchema = z.infer<
typeof ZCompleteDocumentWithTokenMutationSchema
>;
export const ZRemoveTemplateSignerMutationSchema = z.object({
templateId: z.number(),
teamId: z.number().optional(),
recipientId: z.number(),
});
export type TRemoveTemplateSignerMutationSchema = z.infer<
typeof ZRemoveTemplateSignerMutationSchema
>;

View File

@@ -2,8 +2,6 @@
import React, { useId, useMemo, useState } from 'react';
import { useRouter } from 'next/navigation';
import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react';
@@ -13,13 +11,10 @@ import { useSession } from 'next-auth/react';
import { useFieldArray, useForm } from 'react-hook-form';
import { useLimits } from '@documenso/ee/server-only/limits/provider/client';
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
import { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';
import { nanoid } from '@documenso/lib/universal/id';
import type { Field, Recipient } from '@documenso/prisma/client';
import { RecipientRole, SendStatus } from '@documenso/prisma/client';
import type { DocumentWithDetails } from '@documenso/prisma/types/document';
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';
import { RecipientRoleSelect } from '@documenso/ui/components/recipient/recipient-role-select';
@@ -46,70 +41,32 @@ import type { DocumentFlowStep } from './types';
export type AddSignersFormProps = {
documentFlow: DocumentFlowStep;
document: DocumentWithDetails;
recipients: Recipient[];
fields: Field[];
isDocumentEnterprise: boolean;
onSubmit: (_data: TAddSignersFormSchema) => void;
isDocumentPdfLoaded: boolean;
teamId?: number;
};
export const AddSignersFormPartial = ({
documentFlow,
document,
recipients,
fields,
isDocumentEnterprise,
onSubmit,
isDocumentPdfLoaded,
teamId,
}: AddSignersFormProps) => {
const { _ } = useLingui();
const { toast } = useToast();
const { remaining } = useLimits();
const { data: session } = useSession();
const router = useRouter();
const user = session?.user;
const initialId = useId();
const utils = trpc.useUtils();
const { currentStep, totalSteps, previousStep } = useStep();
const { mutateAsync: addSigners } = trpc.recipient.addSigners.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (newRecipients) => {
utils.document.getDocumentWithDetailsById.setData(
{
id: document.id,
teamId,
},
(oldData) => ({ ...(oldData || document), Recipient: newRecipients }),
);
},
});
const { mutateAsync: deleteSigner } = trpc.recipient.removeSigner.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (deletedRecipient) => {
utils.document.getDocumentWithDetailsById.setData(
{
id: document.id,
teamId,
},
(oldData) => {
if (!oldData) return document;
return {
...oldData,
Recipient: oldData.Recipient.filter((r) => r.id !== deletedRecipient.id),
};
},
);
},
});
const form = useForm<TAddSignersFormSchema>({
resolver: zodResolver(ZAddSignersFormSchema),
defaultValues: {
@@ -199,11 +156,22 @@ export const AddSignersFormPartial = ({
});
};
/*
The self-signer is automatically saved on blur
since the email input is focused after adding the self-signer.
When the user clicks outside the input, the self-signer is saved in the db.
*/
const onRemoveSigner = (index: number) => {
const signer = signers[index];
if (hasBeenSentToRecipientId(signer.nativeId)) {
toast({
title: _(msg`Cannot remove signer`),
description: _(msg`This signer has already received the document.`),
variant: 'destructive',
});
return;
}
removeSigner(index);
};
const onAddSelfSigner = () => {
if (emptySignerIndex !== -1) {
setValue(`signers.${emptySignerIndex}.name`, user?.name ?? '');
@@ -225,72 +193,6 @@ export const AddSignersFormPartial = ({
}
};
const handleOnBlur = async (index: number) => {
try {
const currentSigner = form.getValues(`signers.${index}`);
if (!currentSigner.email) {
return;
}
await addSigners({
documentId: document.id,
teamId: teamId,
signers: form.getValues('signers').map((signer) => ({
...signer,
actionAuth: signer.actionAuth || null,
})),
});
const isNewSigner = !currentSigner.nativeId;
toast({
title: isNewSigner ? 'Signer added' : 'Signer updated',
description: isNewSigner
? 'The signer has been added to the document.'
: 'The signer information has been updated.',
});
router.refresh();
} catch (e) {
console.error(e);
toast({
title: 'Error',
description: 'An error occurred while updating the document recipient.',
variant: 'destructive',
});
}
};
const handleRemoveSigner = async (index: number) => {
const signer = signers[index];
if (hasBeenSentToRecipientId(signer.nativeId)) {
toast({
title: 'Cannot remove signer',
description: 'This signer has already received the document.',
variant: 'destructive',
});
return;
}
removeSigner(index);
if (signer.nativeId) {
await deleteSigner({
documentId: document.id,
teamId: teamId,
recipientId: signer.nativeId,
});
toast({
title: 'Signer removed',
description: 'The signer has been removed from the document.',
});
}
};
return (
<>
<DocumentFlowFormContainerHeader
@@ -338,7 +240,6 @@ export const AddSignersFormPartial = ({
{...field}
disabled={isSubmitting || hasBeenSentToRecipientId(signer.nativeId)}
onKeyDown={onKeyDown}
onBlur={() => void handleOnBlur(index)}
/>
</FormControl>
@@ -365,7 +266,6 @@ export const AddSignersFormPartial = ({
{...field}
disabled={isSubmitting || hasBeenSentToRecipientId(signer.nativeId)}
onKeyDown={onKeyDown}
onBlur={() => void handleOnBlur(index)}
/>
</FormControl>
@@ -419,7 +319,7 @@ export const AddSignersFormPartial = ({
hasBeenSentToRecipientId(signer.nativeId) ||
signers.length === 1
}
onClick={() => void handleRemoveSigner(index)}
onClick={() => onRemoveSigner(index)}
>
<Trash className="h-5 w-5" />
</button>

View File

@@ -1,14 +1,23 @@
'use client';
import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, msg } from '@lingui/macro';
import { Loader } from 'lucide-react';
import { useForm } from 'react-hook-form';
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
import type { Field, Recipient } from '@documenso/prisma/client';
import { DocumentStatus } from '@documenso/prisma/client';
import type { DocumentWithData } from '@documenso/prisma/types/document-with-data';
import { trpc } from '@documenso/trpc/react';
import { DocumentSendEmailMessageHelper } from '@documenso/ui/components/document/document-send-email-message-helper';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { Button } from '../button';
import { FormErrorMessage } from '../form/form-error-message';
import { Input } from '../input';
import { Label } from '../label';
@@ -45,6 +54,7 @@ export const AddSubjectFormPartial = ({
const {
register,
handleSubmit,
setValue,
formState: { errors, isSubmitting },
} = useForm<TAddSubjectFormSchema>({
defaultValues: {
@@ -56,6 +66,111 @@ export const AddSubjectFormPartial = ({
resolver: zodResolver(ZAddSubjectFormSchema),
});
const [oldEmailData, setOldEmailData] = useState<{ subject: string; message: string } | null>(
document.documentMeta
? {
subject: document.documentMeta.subject ?? '',
message: document.documentMeta.message ?? '',
}
: null,
);
const [changedFields, setChangedFields] = useState<{ subject: boolean; message: boolean }>({
subject: false,
message: false,
});
const { toast } = useToast();
const router = useRouter();
const utils = trpc.useUtils();
const { mutateAsync: setEmailSettingsForDocument } =
trpc.document.setDocumentEmailSettings.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: () => {
const data = utils.document.getDocumentWithDetailsById.getData({
id: document.id,
});
setOldEmailData({
subject: data?.documentMeta?.subject ?? '',
message: data?.documentMeta?.message ?? '',
});
},
});
const handleOnBlur = async (field: 'subject' | 'message', value: string) => {
if (value == oldEmailData?.[field]) return;
try {
await setEmailSettingsForDocument({
documentId: document.id,
[field]: value,
});
setChangedFields((prev) => ({ ...prev, [field]: true }));
router.refresh();
toast({
title: 'Email settings updated',
description: 'The email settings for the document have been updated.',
duration: 5000,
});
} catch (e) {
console.error(e);
toast({
title: 'Error',
description: 'An error occurred while updating the email settings.',
duration: 5000,
});
}
};
const handleUndoButton = async (field: 'subject' | 'message') => {
if (!oldEmailData) return;
try {
await setEmailSettingsForDocument({
documentId: document.id,
[field]: oldEmailData[field],
});
setValue(`meta.${field}`, oldEmailData[field]);
setOldEmailData((prev) => (prev ? { ...prev, [field]: undefined } : null));
setChangedFields((prev) => ({ ...prev, [field]: false }));
router.refresh();
toast({
title: 'Change reverted',
description: `The latest change to the ${field} has been reverted.`,
duration: 5000,
});
if (oldEmailData.subject === undefined && oldEmailData.message === undefined) {
setOldEmailData(null);
}
} catch (e) {
console.error(e);
toast({
title: 'Error',
description: 'An error occurred while undoing the latest change',
duration: 5000,
});
}
};
useEffect(() => {
const timeout = setTimeout(() => {
setChangedFields({ subject: false, message: false });
}, 5000);
return () => {
clearTimeout(timeout);
};
}, [oldEmailData]);
const onFormSubmit = handleSubmit(onSubmit);
const { currentStep, totalSteps, previousStep } = useStep();
@@ -65,6 +180,7 @@ export const AddSubjectFormPartial = ({
title={documentFlow.title}
description={documentFlow.description}
/>
<DocumentFlowFormContainerContent>
<div className="flex flex-col">
{isDocumentPdfLoaded &&
@@ -84,9 +200,27 @@ export const AddSubjectFormPartial = ({
id="subject"
className="bg-background mt-2"
disabled={isSubmitting}
{...register('meta.subject')}
{...register('meta.subject', {
onBlur: (event) => {
void handleOnBlur('subject', event.target.value);
},
})}
/>
{changedFields.subject && oldEmailData && (
<div className="mt-2 flex items-center">
<Button
className="-ml-2"
size="sm"
variant="link"
onClick={() => void handleUndoButton('subject')}
>
<span className="text-xs">Undo change</span>
<Loader className="ml-1 h-4 w-4 animate-spin text-gray-500" />
</Button>
</div>
)}
<FormErrorMessage className="mt-2" error={errors.meta?.subject} />
</div>
@@ -101,15 +235,32 @@ export const AddSubjectFormPartial = ({
id="message"
className="bg-background mt-2 h-32 resize-none"
disabled={isSubmitting}
{...register('meta.message')}
{...register('meta.message', {
onBlur: (event) => {
void handleOnBlur('message', event.target.value);
},
})}
/>
{changedFields.message && oldEmailData && (
<div className="mt-2 flex items-center">
<Button
className="-ml-2"
size="sm"
variant="link"
onClick={() => void handleUndoButton('message')}
>
<span className="text-xs">Undo change</span>
<Loader className="ml-1 h-4 w-4 animate-spin text-gray-500" />
</Button>
</div>
)}
<FormErrorMessage
className="mt-2"
error={typeof errors.meta?.message !== 'string' ? errors.meta?.message : undefined}
/>
</div>
<DocumentSendEmailMessageHelper />
</div>
</div>

View File

@@ -2,8 +2,6 @@
import React, { useEffect, useId, useMemo, useState } from 'react';
import { useRouter } from 'next/navigation';
import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react';
@@ -12,14 +10,11 @@ import { Link2Icon, Plus, Trash } from 'lucide-react';
import { useSession } from 'next-auth/react';
import { useFieldArray, useForm } from 'react-hook-form';
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
import { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';
import { nanoid } from '@documenso/lib/universal/id';
import { generateRecipientPlaceholder } from '@documenso/lib/utils/templates';
import type { TemplateDirectLink } from '@documenso/prisma/client';
import { type Field, type Recipient, RecipientRole } from '@documenso/prisma/client';
import type { TemplateWithDetails } from '@documenso/prisma/types/template';
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';
import { RecipientRoleSelect } from '@documenso/ui/components/recipient/recipient-role-select';
@@ -27,7 +22,6 @@ import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button';
import { FormErrorMessage } from '@documenso/ui/primitives/form/form-error-message';
import { Input } from '@documenso/ui/primitives/input';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { Checkbox } from '../checkbox';
import {
@@ -52,7 +46,6 @@ export type AddTemplatePlaceholderRecipientsFormProps = {
templateDirectLink: TemplateDirectLink | null;
isEnterprise: boolean;
isDocumentPdfLoaded: boolean;
template: TemplateWithDetails;
onSubmit: (_data: TAddTemplatePlacholderRecipientsFormSchema) => void;
};
@@ -64,10 +57,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
fields,
isDocumentPdfLoaded,
onSubmit,
template,
}: AddTemplatePlaceholderRecipientsFormProps) => {
const { toast } = useToast();
const router = useRouter();
const initialId = useId();
const { _ } = useLingui();
@@ -81,38 +71,6 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
const { currentStep, totalSteps, previousStep } = useStep();
const utils = trpc.useUtils();
const { mutateAsync: addTemplateSigners } = trpc.recipient.addTemplateSigners.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (newData) => {
utils.template.getTemplateWithDetailsById.setData(
{
id: template.id,
},
(oldData) => ({ ...(oldData || template), ...newData }),
);
},
});
const { mutateAsync: removeTemplateSigner } = trpc.recipient.removeTemplateSigner.useMutation({
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
onSuccess: (deletedRecipient) => {
utils.template.getTemplateWithDetailsById.setData(
{
id: template.id,
},
(oldData) => {
if (!oldData) return template;
return {
...oldData,
recipients: oldData.Recipient.filter((r) => r.id !== deletedRecipient.id),
};
},
);
},
});
const generateDefaultFormSigners = () => {
if (recipients.length === 0) {
return [
@@ -200,6 +158,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
setPlaceholderRecipientCount((count) => count + 1);
};
const onRemoveSigner = (index: number) => {
removeSigner(index);
};
const isSignerDirectRecipient = (
signer: TAddTemplatePlacholderRecipientsFormSchema['signers'][number],
): boolean => {
@@ -209,54 +171,6 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
);
};
const handleOnBlur = async (index: number) => {
try {
const currentSigner = form.getValues(`signers.${index}`);
if (!currentSigner.email) {
return;
}
await addTemplateSigners({
templateId: template.id,
teamId: template.teamId ?? undefined,
signers: form.getValues('signers'),
});
router.refresh();
} catch (e) {
console.error(e);
toast({
title: 'Error',
description: 'An error occurred while updating the template recipient.',
variant: 'destructive',
});
}
};
const handleRemoveSigner = async (index: number) => {
const signer = signers[index];
if (!signer) {
return;
}
removeSigner(index);
if (signer.nativeId) {
await removeTemplateSigner({
templateId: template.id,
teamId: template.teamId ?? undefined,
recipientId: signer.nativeId,
});
toast({
title: 'Signer removed',
description: 'The signer has been removed from the document.',
});
}
};
return (
<>
<DocumentFlowFormContainerHeader
@@ -302,8 +216,12 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
type="email"
placeholder={_(msg`Email`)}
{...field}
disabled={field.disabled || isSubmitting}
onBlur={() => void handleOnBlur(index)}
disabled={
field.disabled ||
isSubmitting ||
signers[index].email === user?.email ||
isSignerDirectRecipient(signer)
}
/>
</FormControl>
@@ -332,8 +250,12 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
<Input
placeholder={_(msg`Name`)}
{...field}
disabled={field.disabled || isSubmitting}
onBlur={() => void handleOnBlur(index)}
disabled={
field.disabled ||
isSubmitting ||
signers[index].email === user?.email ||
isSignerDirectRecipient(signer)
}
/>
</FormControl>
@@ -369,10 +291,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
<FormControl>
<RecipientRoleSelect
{...field}
onValueChange={(value) => {
field.onChange(value);
void handleOnBlur(index);
}}
onValueChange={field.onChange}
disabled={isSubmitting}
hideCCRecipients={isSignerDirectRecipient(signer)}
/>
@@ -406,7 +325,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
type="button"
className="col-span-1 mt-auto inline-flex h-10 w-10 items-center justify-center text-slate-500 hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50"
disabled={isSubmitting || signers.length === 1}
onClick={() => void handleRemoveSigner(index)}
onClick={() => onRemoveSigner(index)}
>
<Trash className="h-5 w-5" />
</button>