Compare commits

...

9 Commits

31 changed files with 628 additions and 313 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,8 +4,12 @@ import { match } from 'ts-pattern';
import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app'; import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app';
import { getServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session'; 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 { DocumentAccessAuth } from '@documenso/lib/types/document-auth';
import { extractDocumentAuthMethods } from '@documenso/lib/utils/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 { DocumentAuthProvider } from '~/app/(signing)/sign/[token]/document-auth-provider';
import { SigningProvider } from '~/app/(signing)/sign/[token]/provider'; import { SigningProvider } from '~/app/(signing)/sign/[token]/provider';
@ -13,10 +17,6 @@ import { SigningProvider } from '~/app/(signing)/sign/[token]/provider';
import { EmbedAuthenticateView } from '../../authenticate'; import { EmbedAuthenticateView } from '../../authenticate';
import { EmbedPaywall } from '../../paywall'; import { EmbedPaywall } from '../../paywall';
import { EmbedSignDocumentClientPage } from './client'; 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 = { export type EmbedSignDocumentPageProps = {
params: { params: {
@ -66,7 +66,12 @@ export default async function EmbedSignDocumentPage({ params }: EmbedSignDocumen
.exhaustive(); .exhaustive();
if (!isAccessAuthValid) { 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 ( return (

View File

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

View File

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

View File

@ -5,7 +5,8 @@ export const APP_DOCUMENT_UPLOAD_SIZE_LIMIT =
export const NEXT_PUBLIC_WEBAPP_URL = () => env('NEXT_PUBLIC_WEBAPP_URL'); 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_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_MARKETING = process.env.NEXT_PUBLIC_PROJECT === 'marketing';
export const IS_APP_WEB = process.env.NEXT_PUBLIC_PROJECT === 'web'; export const IS_APP_WEB = process.env.NEXT_PUBLIC_PROJECT === 'web';

View File

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

View File

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

View File

@ -0,0 +1,54 @@
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

@ -1,12 +1,12 @@
msgid "" msgid ""
msgstr "" msgstr ""
"POT-Creation-Date: 2024-07-24 13:01+1000\n" "POT-Creation-Date: 2024-08-22 05:16+0000\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n" "X-Generator: @lingui/cli\n"
"Language: de\n" "Language: de\n"
"Project-Id-Version: documenso-app\n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-09-05 06:04\n" "PO-Revision-Date: 2024-09-05 06:04\n"
"Last-Translator: \n" "Last-Translator: \n"
@ -82,19 +82,19 @@ msgstr "Weitere Option hinzufügen"
msgid "Add another value" msgid "Add another value"
msgstr "Weiteren Wert hinzufügen" msgstr "Weiteren Wert hinzufügen"
#: packages/ui/primitives/document-flow/add-signers.tsx:359 #: packages/ui/primitives/document-flow/add-signers.tsx:459
msgid "Add myself" msgid "Add myself"
msgstr "Mich selbst hinzufügen" msgstr "Mich selbst hinzufügen"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:369 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:450
msgid "Add Myself" msgid "Add Myself"
msgstr "Mich hinzufügen" msgstr "Mich hinzufügen"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:355 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:436
msgid "Add Placeholder Recipient" msgid "Add Placeholder Recipient"
msgstr "Platzhalterempfänger hinzufügen" msgstr "Platzhalterempfänger hinzufügen"
#: packages/ui/primitives/document-flow/add-signers.tsx:348 #: packages/ui/primitives/document-flow/add-signers.tsx:448
msgid "Add Signer" msgid "Add Signer"
msgstr "Unterzeichner hinzufügen" msgstr "Unterzeichner hinzufügen"
@ -154,8 +154,8 @@ msgid "Cancel"
msgstr "Abbrechen" msgstr "Abbrechen"
#: packages/ui/primitives/document-flow/add-signers.tsx:164 #: packages/ui/primitives/document-flow/add-signers.tsx:164
msgid "Cannot remove signer" #~ msgid "Cannot remove signer"
msgstr "Unterzeichner kann nicht entfernt werden" #~ msgstr "Unterzeichner kann nicht entfernt werden"
#: packages/lib/constants/recipient-roles.ts:17 #: packages/lib/constants/recipient-roles.ts:17
msgid "Cc" msgid "Cc"
@ -230,7 +230,7 @@ msgstr "Datum"
msgid "Date Format" msgid "Date Format"
msgstr "Datumsformat" msgstr "Datumsformat"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:312 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:393
msgid "Direct link receiver" msgid "Direct link receiver"
msgstr "Empfänger des direkten Links" 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-fields.tsx:776
#: packages/ui/primitives/document-flow/add-signature.tsx:272 #: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:232 #: packages/ui/primitives/document-flow/add-signers.tsx:330
#: packages/ui/primitives/document-flow/add-signers.tsx:239 #: packages/ui/primitives/document-flow/add-signers.tsx:337
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632 #: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:210 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:296
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:217 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:303
msgid "Email" msgid "Email"
msgstr "E-Mail" msgstr "E-Mail"
@ -378,10 +378,10 @@ msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:802 #: packages/ui/primitives/document-flow/add-fields.tsx:802
#: packages/ui/primitives/document-flow/add-signature.tsx:298 #: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:265 #: packages/ui/primitives/document-flow/add-signers.tsx:364
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658 #: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:245 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:327
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:251 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:333
msgid "Name" msgid "Name"
msgstr "Name" msgstr "Name"
@ -560,8 +560,8 @@ msgstr "Unterschriftenkarte teilen"
msgid "Share the Link" msgid "Share the Link"
msgstr "Link teilen" msgstr "Link teilen"
#: packages/ui/primitives/document-flow/add-signers.tsx:377 #: packages/ui/primitives/document-flow/add-signers.tsx:477
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:387 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:468
msgid "Show advanced settings" msgid "Show advanced settings"
msgstr "Erweiterte Einstellungen anzeigen" msgstr "Erweiterte Einstellungen anzeigen"
@ -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." 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." 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:315 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:396
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." 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." 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 #: packages/ui/primitives/document-flow/add-signers.tsx:165
msgid "This signer has already received the document." #~ msgid "This signer has already received the document."
msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten." #~ msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten."
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48 #: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings." msgid "This will override any global settings."

File diff suppressed because one or more lines are too long

View File

@ -1,38 +1,33 @@
msgid "" msgid ""
msgstr "" msgstr ""
"POT-Creation-Date: 2024-07-24 13:01+1000\n" "POT-Creation-Date: 2024-08-22 05:16+0000\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n" "X-Generator: @lingui/cli\n"
"Language: de\n" "Language: de\n"
"Project-Id-Version: documenso-app\n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-09-05 06:04\n" "PO-Revision-Date: 2024-09-05 06:04\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: German\n" "Language-Team: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: \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 #: apps/marketing/src/app/(marketing)/blog/page.tsx:45
msgid "{0}" msgid "{0}"
msgstr "{0}" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:100 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:100
msgid "5 standard documents per month" msgid "5 standard documents per month"
msgstr "5 Standarddokumente pro Monat" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:198 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:198
msgid "5 Users Included" msgid "5 Users Included"
msgstr "5 Benutzer inbegriffen" msgstr ""
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:34 #: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:34
msgid "A 10x better signing experience." msgid "A 10x better signing experience."
msgstr "Eine 10x bessere Signaturerfahrung." msgstr ""
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:51 #: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:51
msgid "Add document" msgid "Add document"
@ -40,142 +35,138 @@ msgstr "Dokument hinzufügen"
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:201 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:201
msgid "Add More Users for {0}" msgid "Add More Users for {0}"
msgstr "Mehr Benutzer hinzufügen für {0}" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:165 #: apps/marketing/src/app/(marketing)/open/page.tsx:165
msgid "All our metrics, finances, and learnings are public. We believe in transparency and want to share our journey with you. You can read more about why here: <0>Announcing Open Metrics</0>" msgid "All our metrics, finances, and learnings are public. We believe in transparency and want to share our journey with you. You can read more about why here: <0>Announcing Open Metrics</0>"
msgstr "Alle unsere Kennzahlen, Finanzen und Erkenntnisse sind öffentlich. Wir glauben an Transparenz und möchten unsere Reise mit Ihnen teilen. Mehr erfahren Sie hier: <0>Ankündigung Offene Kennzahlen</0>" msgstr ""
#: apps/marketing/src/app/(marketing)/open/funding-raised.tsx:58 #: apps/marketing/src/app/(marketing)/open/funding-raised.tsx:58
#: apps/marketing/src/app/(marketing)/open/funding-raised.tsx:65 #: apps/marketing/src/app/(marketing)/open/funding-raised.tsx:65
msgid "Amount Raised" msgid "Amount Raised"
msgstr "Erhobener Betrag" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:145 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:145
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:189 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:189
msgid "API Access" msgid "API Access"
msgstr "API-Zugriff" msgstr ""
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:67 #: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:67
msgid "Beautiful." msgid "Beautiful."
msgstr "Schön." msgstr ""
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:69 #: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:69
msgid "Because signing should be celebrated. Thats why we care about the smallest detail in our product." msgid "Because signing should be celebrated. Thats why we care about the smallest detail in our product."
msgstr "Weil Unterschriften gefeiert werden sollten. Deshalb kümmern wir uns um jedes kleinste Detail in unserem Produkt." msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:35 #: apps/marketing/src/components/(marketing)/footer.tsx:35
#: apps/marketing/src/components/(marketing)/header.tsx:57 #: apps/marketing/src/components/(marketing)/header.tsx:57
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:36 #: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:36
msgid "Blog" msgid "Blog"
msgstr "Blog" msgstr ""
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:64 #: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:64
msgid "Build on top." msgid "Build on top."
msgstr "Aufbauen oben drauf." msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:163 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:163
msgid "Can I use Documenso commercially?" msgid "Can I use Documenso commercially?"
msgstr "Kann ich Documenso kommerziell nutzen?" msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:42 #: apps/marketing/src/components/(marketing)/footer.tsx:42
msgid "Careers" msgid "Careers"
msgstr "Karrieren" msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:36 #: apps/marketing/src/components/(marketing)/footer.tsx:36
msgid "Changelog" msgid "Changelog"
msgstr "Änderungsprotokoll" msgstr ""
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:85 #: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:85
msgid "Choose a template from the community app store. Or submit your own template for others to use." msgid "Choose a template from the community app store. Or submit your own template for others to use."
msgstr "Wählen Sie eine Vorlage aus dem Community-App-Store. Oder reichen Sie Ihre eigene Vorlage ein, damit andere sie benutzen können." msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:219 #: apps/marketing/src/app/(marketing)/open/page.tsx:219
msgid "Community" msgid "Community"
msgstr "Gemeinschaft" msgstr ""
#: apps/marketing/src/app/(marketing)/open/monthly-completed-documents-chart.tsx:55 #: apps/marketing/src/app/(marketing)/open/monthly-completed-documents-chart.tsx:55
msgid "Completed Documents" msgid "Completed Documents"
msgstr "Fertige Dokumente" msgstr ""
#: apps/marketing/src/app/(marketing)/open/monthly-completed-documents-chart.tsx:33 #: apps/marketing/src/app/(marketing)/open/monthly-completed-documents-chart.tsx:33
msgid "Completed Documents per Month" msgid "Completed Documents per Month"
msgstr "Fertige Dokumente pro Monat" msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:65 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:65
msgid "Connections" msgid "Connections"
msgstr "Verbindungen" msgstr ""
#: apps/marketing/src/components/(marketing)/enterprise.tsx:35 #: apps/marketing/src/components/(marketing)/enterprise.tsx:35
msgid "Contact Us" msgid "Contact Us"
msgstr "Kontaktiere uns" msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:67 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:67
msgid "Create connections and automations with Zapier and more to integrate with your favorite tools." msgid "Create connections and automations with Zapier and more to integrate with your favorite tools."
msgstr "Erstellen Sie Verbindungen und Automatisierungen mit Zapier und mehr, um sich mit Ihren Lieblingstools zu integrieren." msgstr ""
#: apps/marketing/src/components/(marketing)/call-to-action.tsx:23 #: apps/marketing/src/components/(marketing)/call-to-action.tsx:23
msgid "Create your account and start using state-of-the-art document signing. Open and beautiful signing is within your grasp." msgid "Create your account and start using state-of-the-art document signing. Open and beautiful signing is within your grasp."
msgstr "Erstellen Sie Ihr Konto und beginnen Sie mit der Nutzung modernster Dokumentensignaturen. Offene und schöne Signaturen sind zum Greifen nah." msgstr ""
#: apps/marketing/src/app/(marketing)/open/tooltip.tsx:35 #: apps/marketing/src/app/(marketing)/open/tooltip.tsx:35
msgid "Customers with an Active Subscriptions." msgid "Customers with an Active Subscriptions."
msgstr "Kunden mit einer aktiven Abonnements." msgstr ""
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:33 #: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:33
msgid "Customise and expand." msgid "Customise and expand."
msgstr "Anpassen und erweitern." msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:38 #: apps/marketing/src/components/(marketing)/footer.tsx:38
msgid "Design" msgid "Design"
msgstr "Design" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:44 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:44
msgid "Designed for every stage of your journey." msgid "Designed for every stage of your journey."
msgstr "Entwickelt für jede Phase Ihrer Reise." msgstr ""
#: apps/marketing/src/components/(marketing)/carousel.tsx:40 #: apps/marketing/src/components/(marketing)/carousel.tsx:40
msgid "Direct Link" msgid "Direct Link"
msgstr "Direktlink" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:181 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:181
msgid "Documenso is a community effort to create an open and vibrant ecosystem around a tool, everybody is free to use and adapt. By being truly open we want to create trusted infrastructure for the future of the internet." msgid "Documenso is a community effort to create an open and vibrant ecosystem around a tool, everybody is free to use and adapt. By being truly open we want to create trusted infrastructure for the future of the internet."
msgstr "Documenso ist eine Gemeinschaftsanstrengung, um ein offenes und lebendiges Ökosystem um ein Werkzeug zu schaffen, das jeder frei nutzen und anpassen kann. Indem wir wirklich offen sind, wollen wir vertrauenswürdige Infrastruktur für die Zukunft des Internets schaffen." msgstr ""
#: apps/marketing/src/app/(marketing)/open/typefully.tsx:28 #: apps/marketing/src/app/(marketing)/open/typefully.tsx:28
msgid "Documenso on X" msgid "Documenso on X"
msgstr "Documenso auf X" msgstr ""
#: apps/marketing/src/components/(marketing)/hero.tsx:104 #: apps/marketing/src/components/(marketing)/hero.tsx:104
msgid "Document signing,<0/>finally open source." msgid "Document signing,<0/>finally open source."
msgstr "Unterschriften,<0/>endlich Open Source." msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:33 #: apps/marketing/src/components/(marketing)/footer.tsx:33
#: apps/marketing/src/components/(marketing)/header.tsx:50 #: apps/marketing/src/components/(marketing)/header.tsx:50
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:28 #: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:28
msgid "Documentation" msgid "Documentation"
msgstr "Dokumentation" msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:110 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:110
msgid "Easily embed Documenso into your product. Simply copy and paste our react widget into your application." msgid "Easily embed Documenso into your product. Simply copy and paste our react widget into your application."
msgstr "Betten Sie Documenso ganz einfach in Ihr Produkt ein. Kopieren und fügen Sie einfach unser React-Widget in Ihre Anwendung ein." msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:42
#~ msgid "Easy Sharing (Soon)."
#~ msgstr "Easy Sharing (Soon)."
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:46 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:46
msgid "Easy Sharing." msgid "Easy Sharing."
msgstr "Einfaches Teilen." msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:148 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:148
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:192 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:192
msgid "Email and Discord Support" msgid "Email and Discord Support"
msgstr "E-Mail- und Discord-Support" msgstr ""
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:43 #: apps/marketing/src/app/(marketing)/open/team-members.tsx:43
msgid "Engagement" msgid "Engagement"
msgstr "Beteiligung" msgstr ""
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:64 #: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:64
msgid "Enter your details." msgid "Enter your details."
@ -183,43 +174,43 @@ msgstr "Geben Sie Ihre Details ein."
#: apps/marketing/src/components/(marketing)/enterprise.tsx:16 #: apps/marketing/src/components/(marketing)/enterprise.tsx:16
msgid "Enterprise Compliance, License or Technical Needs?" msgid "Enterprise Compliance, License or Technical Needs?"
msgstr "Enterprise-Konformität, Lizenz- oder technische Bedürfnisse?" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:128 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:128
msgid "Everything you need for a great signing experience." msgid "Everything you need for a great signing experience."
msgstr "Alles, was Sie für ein großartiges Signaturerlebnis benötigen." msgstr ""
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:45 #: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:45
msgid "Fast." msgid "Fast."
msgstr "Schnell." msgstr ""
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:36 #: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:36
msgid "Faster, smarter and more beautiful." msgid "Faster, smarter and more beautiful."
msgstr "Schneller, intelligenter und schöner." msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:210 #: apps/marketing/src/app/(marketing)/open/page.tsx:210
msgid "Finances" msgid "Finances"
msgstr "Finanzen" msgstr ""
#: apps/marketing/src/app/(marketing)/open/typefully.tsx:38 #: apps/marketing/src/app/(marketing)/open/typefully.tsx:38
msgid "Follow us on X" msgid "Follow us on X"
msgstr "Folgen Sie uns auf X" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:172 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:172
msgid "For companies looking to scale across multiple teams." msgid "For companies looking to scale across multiple teams."
msgstr "Für Unternehmen, die über mehrere Teams skalieren möchten." msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:85 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:85
msgid "For small teams and individuals with basic needs." msgid "For small teams and individuals with basic needs."
msgstr "Für kleine Teams und Einzelpersonen mit grundlegenden Bedürfnissen." msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:80 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:80
msgid "Free" msgid "Free"
msgstr "Kostenlos" msgstr ""
#: apps/marketing/src/app/(marketing)/blog/page.tsx:26 #: apps/marketing/src/app/(marketing)/blog/page.tsx:26
msgid "From the blog" msgid "From the blog"
msgstr "Aus dem Blog" msgstr ""
#: apps/marketing/src/app/(marketing)/open/data.ts:9 #: apps/marketing/src/app/(marketing)/open/data.ts:9
#: apps/marketing/src/app/(marketing)/open/data.ts:17 #: apps/marketing/src/app/(marketing)/open/data.ts:17
@ -227,227 +218,222 @@ msgstr "Aus dem Blog"
#: apps/marketing/src/app/(marketing)/open/data.ts:41 #: apps/marketing/src/app/(marketing)/open/data.ts:41
#: apps/marketing/src/app/(marketing)/open/data.ts:49 #: apps/marketing/src/app/(marketing)/open/data.ts:49
msgid "Full-Time" msgid "Full-Time"
msgstr "Vollzeit" msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:87 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:87
msgid "Get paid (Soon)." msgid "Get paid (Soon)."
msgstr "Lassen Sie sich bezahlen (Bald)." msgstr ""
#: apps/marketing/src/components/(marketing)/call-to-action.tsx:31 #: apps/marketing/src/components/(marketing)/call-to-action.tsx:31
msgid "Get started" msgid "Get started"
msgstr "Loslegen" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:75 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:75
msgid "Get Started" msgid "Get Started"
msgstr "Loslegen" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:47 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:47
msgid "Get started today." msgid "Get started today."
msgstr "Fangen Sie heute an." msgstr ""
#: apps/marketing/src/app/(marketing)/blog/page.tsx:30 #: apps/marketing/src/app/(marketing)/blog/page.tsx:30
msgid "Get the latest news from Documenso, including product updates, team announcements and more!" msgid "Get the latest news from Documenso, including product updates, team announcements and more!"
msgstr "Erhalten Sie die neuesten Nachrichten von Documenso, einschließlich Produkt-Updates, Team-Ankündigungen und mehr!" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:233 #: apps/marketing/src/app/(marketing)/open/page.tsx:233
msgid "GitHub: Total Merged PRs" msgid "GitHub: Total Merged PRs"
msgstr "GitHub: Gesamte PRs zusammengeführt" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:251 #: apps/marketing/src/app/(marketing)/open/page.tsx:251
msgid "GitHub: Total Open Issues" msgid "GitHub: Total Open Issues"
msgstr "GitHub: Gesamte offene Issues" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:225 #: apps/marketing/src/app/(marketing)/open/page.tsx:225
msgid "GitHub: Total Stars" msgid "GitHub: Total Stars"
msgstr "GitHub: Gesamtanzahl Sterne" msgstr ""
#: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:23 #: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:23
msgid "Global Salary Bands" msgid "Global Salary Bands"
msgstr "Globale Gehaltsbänder" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:261 #: apps/marketing/src/app/(marketing)/open/page.tsx:261
msgid "Growth" msgid "Growth"
msgstr "Wachstum" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:134 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:134
msgid "How can I contribute?" msgid "How can I contribute?"
msgstr "Wie kann ich beitragen?" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:105 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:105
msgid "How do you handle my data?" msgid "How do you handle my data?"
msgstr "Wie gehen Sie mit meinen Daten um?" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:118 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:118
msgid "Individual" msgid "Individual"
msgstr "Einzelperson" msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:89 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:89
msgid "Integrated payments with Stripe so you dont have to worry about getting paid." msgid "Integrated payments with Stripe so you dont have to worry about getting paid."
msgstr "Integrierte Zahlungen mit Stripe, sodass Sie sich keine Sorgen ums Bezahlen machen müssen." msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:35 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:35
msgid "Integrates with all your favourite tools." msgid "Integrates with all your favourite tools."
msgstr "Integriert sich mit all Ihren Lieblingstools." msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:289 #: apps/marketing/src/app/(marketing)/open/page.tsx:289
msgid "Is there more?" msgid "Is there more?"
msgstr "Gibt es mehr?" msgstr ""
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:44 #: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:44
msgid "Its up to you. Either clone our repository or rely on our easy to use hosting solution." msgid "Its up to you. Either clone our repository or rely on our easy to use hosting solution."
msgstr "Es liegt an Ihnen. Entweder klonen Sie unser Repository oder nutzen unsere einfach zu bedienende Hosting-Lösung." msgstr ""
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:49 #: apps/marketing/src/app/(marketing)/open/team-members.tsx:49
msgid "Join Date" msgid "Join Date"
msgstr "Eintrittsdatum" msgstr ""
#: apps/marketing/src/components/(marketing)/call-to-action.tsx:19 #: apps/marketing/src/components/(marketing)/call-to-action.tsx:19
msgid "Join the Open Signing Movement" msgid "Join the Open Signing Movement"
msgstr "Treten Sie der Open Signing-Bewegung bei" msgstr ""
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:46 #: apps/marketing/src/app/(marketing)/open/team-members.tsx:46
msgid "Location" msgid "Location"
msgstr "Standort" msgstr ""
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:66 #: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:66
msgid "Make it your own through advanced customization and adjustability." msgid "Make it your own through advanced customization and adjustability."
msgstr "Machen Sie es zu Ihrem eigenen durch erweiterte Anpassung und Einstellbarkeit." msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:199 #: apps/marketing/src/app/(marketing)/open/page.tsx:199
msgid "Merged PR's" msgid "Merged PR's"
msgstr "Zusammengeführte PRs" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:234 #: apps/marketing/src/app/(marketing)/open/page.tsx:234
msgid "Merged PRs" msgid "Merged PRs"
msgstr "Zusammengeführte PRs" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:40 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:40
msgid "Monthly" msgid "Monthly"
msgstr "Monatlich" msgstr ""
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:34 #: apps/marketing/src/app/(marketing)/open/team-members.tsx:34
msgid "Name" msgid "Name"
msgstr "Name" msgstr ""
#: apps/marketing/src/app/(marketing)/open/monthly-new-users-chart.tsx:30 #: apps/marketing/src/app/(marketing)/open/monthly-new-users-chart.tsx:30
#: apps/marketing/src/app/(marketing)/open/monthly-new-users-chart.tsx:43 #: apps/marketing/src/app/(marketing)/open/monthly-new-users-chart.tsx:43
#: apps/marketing/src/app/(marketing)/open/monthly-new-users-chart.tsx:52 #: apps/marketing/src/app/(marketing)/open/monthly-new-users-chart.tsx:52
msgid "New Users" msgid "New Users"
msgstr "Neue Benutzer" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:106 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:106
msgid "No credit card required" msgid "No credit card required"
msgstr "Keine Kreditkarte erforderlich" msgstr ""
#: apps/marketing/src/components/(marketing)/callout.tsx:29 #: apps/marketing/src/components/(marketing)/callout.tsx:29
#: apps/marketing/src/components/(marketing)/hero.tsx:125 #: apps/marketing/src/components/(marketing)/hero.tsx:125
msgid "No Credit Card required" msgid "No Credit Card required"
msgstr "Keine Kreditkarte erforderlich" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:61 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:61
msgid "None of these work for you? Try self-hosting!" msgid "None of these work for you? Try self-hosting!"
msgstr "Keines dieser Angebote passt zu Ihnen? Versuchen Sie das Selbst-Hosting!" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:194 #: apps/marketing/src/app/(marketing)/open/page.tsx:194
#: apps/marketing/src/app/(marketing)/open/page.tsx:252 #: apps/marketing/src/app/(marketing)/open/page.tsx:252
msgid "Open Issues" msgid "Open Issues"
msgstr "Offene Issues" msgstr ""
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:42 #: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:42
msgid "Open Source or Hosted." msgid "Open Source or Hosted."
msgstr "Open Source oder Hosted." msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:161 #: apps/marketing/src/app/(marketing)/open/page.tsx:161
#: apps/marketing/src/components/(marketing)/footer.tsx:37 #: apps/marketing/src/components/(marketing)/footer.tsx:37
#: apps/marketing/src/components/(marketing)/header.tsx:64 #: apps/marketing/src/components/(marketing)/header.tsx:64
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:40 #: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:40
msgid "Open Startup" msgid "Open Startup"
msgstr "Offenes Startup" msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:41 #: apps/marketing/src/components/(marketing)/footer.tsx:41
msgid "OSS Friends" msgid "OSS Friends"
msgstr "OSS-Freunde" msgstr ""
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:91 #: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:91
msgid "Our custom templates come with smart rules that can help you save time and energy." msgid "Our custom templates come with smart rules that can help you save time and energy."
msgstr "Unsere benutzerdefinierten Vorlagen verfügen über intelligente Regeln, die Ihnen Zeit und Energie sparen können." msgstr ""
#: apps/marketing/src/components/(marketing)/enterprise.tsx:20 #: apps/marketing/src/components/(marketing)/enterprise.tsx:20
msgid "Our Enterprise License is great for large organizations looking to switch to Documenso for all their signing needs. It's available for our cloud offering as well as self-hosted setups and offers a wide range of compliance and Adminstration Features." msgid "Our Enterprise License is great for large organizations looking to switch to Documenso for all their signing needs. It's available for our cloud offering as well as self-hosted setups and offers a wide range of compliance and Adminstration Features."
msgstr "Unsere Enterprise-Lizenz ist ideal für große Organisationen, die auf Documenso für all ihre Signaturanforderungen umsteigen möchten. Sie ist sowohl für unser Cloud-Angebot als auch für selbstgehostete Setups verfügbar und bietet eine breite Palette an Compliance- und Verwaltungsfunktionen." msgstr ""
#: apps/marketing/src/components/(marketing)/enterprise.tsx:20
#~ msgid "Our Enterprise License is great large organizations looking to switch to Documenso for all their signing needs. It's availible for our cloud offering as well as self-hosted setups and offer a wide range of compliance and Adminstration Features."
#~ msgstr "Our Enterprise License is great large organizations looking to switch to Documenso for all their signing needs. It's availible for our cloud offering as well as self-hosted setups and offer a wide range of compliance and Adminstration Features."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:65 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:65
msgid "Our self-hosted option is great for small teams and individuals who need a simple solution. You can use our docker based setup to get started in minutes. Take control with full customizability and data ownership." msgid "Our self-hosted option is great for small teams and individuals who need a simple solution. You can use our docker based setup to get started in minutes. Take control with full customizability and data ownership."
msgstr "Unsere selbstgehostete Option ist ideal für kleine Teams und Einzelpersonen, die eine einfache Lösung benötigen. Sie können unser docker-basiertes Setup verwenden, um in wenigen Minuten loszulegen. Übernehmen Sie die Kontrolle mit vollständiger Anpassbarkeit und Datenhoheit." msgstr ""
#: apps/marketing/src/app/(marketing)/open/data.ts:25 #: apps/marketing/src/app/(marketing)/open/data.ts:25
msgid "Part-Time" msgid "Part-Time"
msgstr "Teilzeit" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:151 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:151
msgid "Premium Profile Name" msgid "Premium Profile Name"
msgstr "Premium Profilname" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:40 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:40
#: apps/marketing/src/components/(marketing)/footer.tsx:31 #: apps/marketing/src/components/(marketing)/footer.tsx:31
#: apps/marketing/src/components/(marketing)/header.tsx:42 #: apps/marketing/src/components/(marketing)/header.tsx:42
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:24 #: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:24
msgid "Pricing" msgid "Pricing"
msgstr "Preise" msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:43 #: apps/marketing/src/components/(marketing)/footer.tsx:43
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:53 #: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:53
msgid "Privacy" msgid "Privacy"
msgstr "Datenschutz" msgstr ""
#: apps/marketing/src/components/(marketing)/carousel.tsx:58 #: apps/marketing/src/components/(marketing)/carousel.tsx:58
msgid "Profile" msgid "Profile"
msgstr "Profil" msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:108 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:108
msgid "React Widget (Soon)." msgid "React Widget (Soon)."
msgstr "React Widget (Demnächst)." msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:48 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:48
msgid "Receive your personal link to share with everyone you care about." msgid "Receive your personal link to share with everyone you care about."
msgstr "Erhalten Sie Ihren persönlichen Link zum Teilen mit allen, die Ihnen wichtig sind." msgstr ""
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:37 #: apps/marketing/src/app/(marketing)/open/team-members.tsx:37
msgid "Role" msgid "Role"
msgstr "Rolle" msgstr ""
#: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:37 #: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:37
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:40 #: apps/marketing/src/app/(marketing)/open/team-members.tsx:40
msgid "Salary" msgid "Salary"
msgstr "Gehalt" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:62 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:62
msgid "Save $60 or $120" msgid "Save $60 or $120"
msgstr "Sparen Sie $60 oder $120" msgstr ""
#: apps/marketing/src/components/(marketing)/i18n-switcher.tsx:47
#~ msgid "Search languages..." #~ msgid "Search languages..."
#~ msgstr "Sprachen suchen..." #~ msgstr "Sprachen suchen...>>>>>>> main"
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:109 #: 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." 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."
msgstr "Sicher. Unsere Rechenzentren befinden sich in Frankfurt (Deutschland) und bieten uns die besten lokalen Datenschutzgesetze. Uns ist die sensible Natur unserer Daten sehr bewusst und wir folgen bewährten Praktiken, um die Sicherheit und Integrität der uns anvertrauten Daten zu gewährleisten." msgstr ""
#: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:37 #: apps/marketing/src/components/(marketing)/share-connect-paid-widget-bento.tsx:37
msgid "Send, connect, receive and embed everywhere." msgid "Send, connect, receive and embed everywhere."
msgstr "Überall senden, verbinden, empfangen und einbetten." msgstr ""
#: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:34 #: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:34
msgid "Seniority" msgid "Seniority"
msgstr "Dienstalter" msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:39 #: apps/marketing/src/components/(marketing)/footer.tsx:39
msgid "Shop" msgid "Shop"
msgstr "Shop" msgstr ""
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:63 #: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:63
msgid "Sign" msgid "Sign"
@ -456,115 +442,115 @@ msgstr "Signieren"
#: apps/marketing/src/components/(marketing)/header.tsx:72 #: apps/marketing/src/components/(marketing)/header.tsx:72
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:61 #: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:61
msgid "Sign in" msgid "Sign in"
msgstr "Anmelden" msgstr ""
#: apps/marketing/src/components/(marketing)/header.tsx:77 #: apps/marketing/src/components/(marketing)/header.tsx:77
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:57 #: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:57
msgid "Sign up" msgid "Sign up"
msgstr "Registrieren" msgstr ""
#: apps/marketing/src/components/(marketing)/carousel.tsx:22 #: apps/marketing/src/components/(marketing)/carousel.tsx:22
msgid "Signing Process" msgid "Signing Process"
msgstr "Signaturprozess" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:94 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:94
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:136 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:136
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:180 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:180
msgid "Signup Now" msgid "Signup Now"
msgstr "Jetzt registrieren" msgstr ""
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:89 #: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:89
msgid "Smart." msgid "Smart."
msgstr "Intelligent." msgstr ""
#: apps/marketing/src/components/(marketing)/hero.tsx:132 #: apps/marketing/src/components/(marketing)/hero.tsx:132
msgid "Star on GitHub" msgid "Star on GitHub"
msgstr "Auf GitHub favorisieren" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:226 #: apps/marketing/src/app/(marketing)/open/page.tsx:226
msgid "Stars" msgid "Stars"
msgstr "Favoriten" msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:40 #: apps/marketing/src/components/(marketing)/footer.tsx:40
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:44 #: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:44
msgid "Status" msgid "Status"
msgstr "Status" msgstr ""
#: apps/marketing/src/components/(marketing)/footer.tsx:34 #: apps/marketing/src/components/(marketing)/footer.tsx:34
#: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:48 #: apps/marketing/src/components/(marketing)/mobile-navigation.tsx:48
msgid "Support" msgid "Support"
msgstr "Support" msgstr ""
#: apps/marketing/src/app/(marketing)/open/team-members.tsx:26 #: apps/marketing/src/app/(marketing)/open/team-members.tsx:26
msgid "Team" msgid "Team"
msgstr "Team" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:195 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:195
msgid "Team Inbox" msgid "Team Inbox"
msgstr "Team-Posteingang" msgstr ""
#: apps/marketing/src/components/(marketing)/carousel.tsx:28 #: apps/marketing/src/components/(marketing)/carousel.tsx:28
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:162 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:162
msgid "Teams" msgid "Teams"
msgstr "Teams" msgstr ""
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:83 #: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:83
msgid "Template Store (Soon)." msgid "Template Store (Soon)."
msgstr "Vorlagen-Shop (Demnächst)." msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:138 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:138
msgid "That's awesome. You can take a look at the current <0>Issues</0> and join our <1>Discord Community</1> to keep up to date, on what the current priorities are. In any case, we are an open community and welcome all input, technical and non-technical ❤️" msgid "That's awesome. You can take a look at the current <0>Issues</0> and join our <1>Discord Community</1> to keep up to date, on what the current priorities are. In any case, we are an open community and welcome all input, technical and non-technical ❤️"
msgstr "Das ist großartig. Sie können sich die aktuellen <0>Issues</0> ansehen und unserer <1>Discord-Community</1> beitreten, um auf dem neuesten Stand zu bleiben, was die aktuellen Prioritäten sind. In jedem Fall sind wir eine offene Gemeinschaft und begrüßen jegliche Beiträge, technische und nicht-technische ❤️" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:293 #: apps/marketing/src/app/(marketing)/open/page.tsx:293
msgid "This page is evolving as we learn what makes a great signing company. We'll update it when we have more to share." msgid "This page is evolving as we learn what makes a great signing company. We'll update it when we have more to share."
msgstr "Diese Seite entwickelt sich weiter, während wir lernen, was ein großartiges Signing-Unternehmen ausmacht. Wir werden sie aktualisieren, wenn wir mehr zu teilen haben." msgstr ""
#: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:31 #: apps/marketing/src/app/(marketing)/open/salary-bands.tsx:31
msgid "Title" msgid "Title"
msgstr "Titel" msgstr ""
#: apps/marketing/src/app/(marketing)/open/total-signed-documents-chart.tsx:30 #: apps/marketing/src/app/(marketing)/open/total-signed-documents-chart.tsx:30
#: apps/marketing/src/app/(marketing)/open/total-signed-documents-chart.tsx:55 #: apps/marketing/src/app/(marketing)/open/total-signed-documents-chart.tsx:55
msgid "Total Completed Documents" msgid "Total Completed Documents"
msgstr "Insgesamt Abgeschlossene Dokumente" msgstr ""
#: apps/marketing/src/app/(marketing)/open/page.tsx:267 #: apps/marketing/src/app/(marketing)/open/page.tsx:267
#: apps/marketing/src/app/(marketing)/open/page.tsx:268 #: apps/marketing/src/app/(marketing)/open/page.tsx:268
msgid "Total Customers" msgid "Total Customers"
msgstr "Insgesamt Kunden" msgstr ""
#: apps/marketing/src/app/(marketing)/open/funding-raised.tsx:29 #: apps/marketing/src/app/(marketing)/open/funding-raised.tsx:29
msgid "Total Funding Raised" msgid "Total Funding Raised"
msgstr "Insgesamt Finanzierungsvolumen" msgstr ""
#: apps/marketing/src/app/(marketing)/open/monthly-total-users-chart.tsx:30 #: apps/marketing/src/app/(marketing)/open/monthly-total-users-chart.tsx:30
#: apps/marketing/src/app/(marketing)/open/monthly-total-users-chart.tsx:43 #: apps/marketing/src/app/(marketing)/open/monthly-total-users-chart.tsx:43
#: apps/marketing/src/app/(marketing)/open/monthly-total-users-chart.tsx:52 #: apps/marketing/src/app/(marketing)/open/monthly-total-users-chart.tsx:52
msgid "Total Users" msgid "Total Users"
msgstr "Gesamtanzahl der Benutzer" msgstr ""
#: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:31 #: apps/marketing/src/components/(marketing)/open-build-template-bento.tsx:31
msgid "Truly your own." msgid "Truly your own."
msgstr "Wirklich Ihr Eigenes." msgstr ""
#: apps/marketing/src/components/(marketing)/callout.tsx:27 #: apps/marketing/src/components/(marketing)/callout.tsx:27
#: apps/marketing/src/components/(marketing)/hero.tsx:123 #: apps/marketing/src/components/(marketing)/hero.tsx:123
msgid "Try our Free Plan" msgid "Try our Free Plan"
msgstr "Probieren Sie unseren Gratisplan aus" msgstr ""
#: apps/marketing/src/app/(marketing)/open/typefully.tsx:20 #: apps/marketing/src/app/(marketing)/open/typefully.tsx:20
msgid "Twitter Stats" msgid "Twitter Stats"
msgstr "Twitter-Statistiken" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:142 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:142
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:186 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:186
msgid "Unlimited Documents per Month" msgid "Unlimited Documents per Month"
msgstr "Unbegrenzte Dokumente pro Monat" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:103 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:103
msgid "Up to 10 recipients per document" msgid "Up to 10 recipients per document"
msgstr "Bis zu 10 Empfänger pro Dokument" msgstr ""
#: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:52 #: apps/marketing/src/app/(marketing)/singleplayer/client.tsx:52
msgid "Upload a document and add fields." msgid "Upload a document and add fields."
@ -572,48 +558,52 @@ msgstr "Laden Sie ein Dokument hoch und fügen Sie Felder hinzu."
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:123 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:123
msgid "Using our hosted version is the easiest way to get started, you can simply subscribe and start signing your documents. We take care of the infrastructure, so you can focus on your business. Additionally, when using our hosted version you benefit from our trusted signing certificates which helps you to build trust with your customers." msgid "Using our hosted version is the easiest way to get started, you can simply subscribe and start signing your documents. We take care of the infrastructure, so you can focus on your business. Additionally, when using our hosted version you benefit from our trusted signing certificates which helps you to build trust with your customers."
msgstr "Die Nutzung unserer gehosteten Version ist der einfachste Weg, um zu starten. Sie können einfach abonnieren und mit der Unterzeichnung Ihrer Dokumente beginnen. Wir kümmern uns um die Infrastruktur, damit Sie sich auf Ihr Geschäft konzentrieren können. Zudem profitieren Sie bei der Nutzung unserer gehosteten Version von unseren vertrauenswürdigen Signaturzertifikaten, die Ihnen helfen, Vertrauen bei Ihren Kunden aufzubauen." msgstr ""
#: apps/marketing/src/app/(marketing)/open/typefully.tsx:33 #: apps/marketing/src/app/(marketing)/open/typefully.tsx:33
msgid "View all stats" msgid "View all stats"
msgstr "Alle Statistiken anzeigen" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:195 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:195
msgid "We are happy to assist you at <0>support@documenso.com</0> or <1>in our Discord-Support-Channel</1> please message either Lucas or Timur to get added to the channel if you are not already a member." msgid "We are happy to assist you at <0>support@documenso.com</0> or <1>in our Discord-Support-Channel</1> please message either Lucas or Timur to get added to the channel if you are not already a member."
msgstr "Wir helfen Ihnen gerne unter <0>support@documenso.com</0> oder <1>in unserem Discord-Support-Kanal</1>. Bitte senden Sie Lucas oder Timur eine Nachricht, um dem Kanal beizutreten, falls Sie noch kein Mitglied sind." msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:89 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:89
msgid "What is the difference between the plans?" msgid "What is the difference between the plans?"
msgstr "Was ist der Unterschied zwischen den Plänen?" msgstr ""
#: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:47 #: apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx:47
msgid "When it comes to sending or receiving a contract, you can count on lightning-fast speeds." msgid "When it comes to sending or receiving a contract, you can count on lightning-fast speeds."
msgstr "Wenn es um das Senden oder Empfangen eines Vertrags geht, können Sie auf blitzschnelle Geschwindigkeiten zählen." msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:191 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:191
msgid "Where can I get support?" msgid "Where can I get support?"
msgstr "Wo kann ich Unterstützung bekommen?" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:177 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:177
msgid "Why should I prefer Documenso over DocuSign or some other signing tool?" msgid "Why should I prefer Documenso over DocuSign or some other signing tool?"
msgstr "Warum sollte ich Documenso gegenüber DocuSign oder einem anderen Signatur-Tool bevorzugen?" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:119 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:119
msgid "Why should I use your hosting service?" msgid "Why should I use your hosting service?"
msgstr "Warum sollte ich Ihren Hosting-Service nutzen?" msgstr ""
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:60 #: apps/marketing/src/components/(marketing)/pricing-table.tsx:60
msgid "Yearly" msgid "Yearly"
msgstr "Jährlich" msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:167 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:167
msgid "Yes! Documenso is offered under the GNU AGPL V3 open source license. This means you can use it for free and even modify it to fit your needs, as long as you publish your changes under the same license." msgid "Yes! Documenso is offered under the GNU AGPL V3 open source license. This means you can use it for free and even modify it to fit your needs, as long as you publish your changes under the same license."
msgstr "Ja! Documenso wird unter der GNU AGPL V3 Open-Source-Lizenz angeboten. Das bedeutet, dass Sie es kostenlos nutzen und sogar an Ihre Bedürfnisse anpassen können, solange Sie Ihre Änderungen unter derselben Lizenz veröffentlichen." msgstr ""
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:93 #: apps/marketing/src/app/(marketing)/pricing/page.tsx:93
msgid "You can self-host Documenso for free or use our ready-to-use hosted version. The hosted version comes with additional support, painless scalability and more. Early adopters will get access to all features we build this year, for no additional cost! Forever! Yes, that includes multiple users per account later. If you want Documenso for your enterprise, we are happy to talk about your needs." msgid "You can self-host Documenso for free or use our ready-to-use hosted version. The hosted version comes with additional support, painless scalability and more. Early adopters will get access to all features we build this year, for no additional cost! Forever! Yes, that includes multiple users per account later. If you want Documenso for your enterprise, we are happy to talk about your needs."
msgstr "Sie können Documenso kostenlos selbst hosten oder unsere sofort einsatzbereite gehostete Version nutzen. Die gehostete Version bietet zusätzlichen Support, schmerzfreie Skalierbarkeit und mehr. Frühzeitige Anwender erhalten in diesem Jahr Zugriff auf alle Funktionen, die wir entwickeln, ohne zusätzliche Kosten! Für immer! Ja, das beinhaltet später mehrere Benutzer pro Konto. Wenn Sie Documenso für Ihr Unternehmen möchten, sprechen wir gerne über Ihre Bedürfnisse." msgstr ""
#: apps/marketing/src/components/(marketing)/carousel.tsx:265 #: apps/marketing/src/components/(marketing)/carousel.tsx:265
msgid "Your browser does not support the video tag." msgid "Your browser does not support the video tag."
msgstr "Ihr Browser unterstützt das Video-Tag nicht." msgstr ""
#: apps/marketing/src/components/(marketing)/carousel.tsx:265
#~ msgid "Your browser does not support the video tag.<<<<<<< HEAD"
#~ msgstr "Ihr Browser unterstützt das Video-Tag nicht.>>>>>>> main"

View File

@ -1,12 +1,12 @@
msgid "" msgid ""
msgstr "" msgstr ""
"POT-Creation-Date: 2024-07-24 13:01+1000\n" "POT-Creation-Date: 2024-08-22 05:16+0000\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n" "X-Generator: @lingui/cli\n"
"Language: de\n" "Language: de\n"
"Project-Id-Version: documenso-app\n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-09-05 06:04\n" "PO-Revision-Date: 2024-09-05 06:04\n"
"Last-Translator: \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/(recipient)/d/[token]/sign-direct-template.tsx:175
#: apps/web/src/app/(signing)/sign/[token]/form.tsx:107 #: 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/direct/[[...url]]/client.tsx:435
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:312 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:314
msgid "Click to insert field" msgid "Click to insert field"
msgstr "Klicken Sie, um das Feld einzufügen" 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/(signing)/sign/[token]/sign-dialog.tsx:58
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:425 #: apps/web/src/app/embed/direct/[[...url]]/client.tsx:425
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:302 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:304
#: apps/web/src/components/forms/v2/signup.tsx:522 #: apps/web/src/components/forms/v2/signup.tsx:522
msgid "Complete" msgid "Complete"
msgstr "Vollständig" 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/(recipient)/d/[token]/configure-direct-template.tsx:118
#: apps/web/src/app/(signing)/sign/[token]/email-field.tsx:126 #: 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/direct/[[...url]]/client.tsx:376
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:254 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:256
#: apps/web/src/components/(teams)/dialogs/add-team-email-dialog.tsx:169 #: 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/(teams)/dialogs/update-team-email-dialog.tsx:153
#: apps/web/src/components/forms/forgot-password.tsx:81 #: 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/(recipient)/d/[token]/sign-direct-template.tsx:326
#: apps/web/src/app/(signing)/sign/[token]/name-field.tsx:193 #: 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/direct/[[...url]]/client.tsx:361
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:239 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:241
#: apps/web/src/components/forms/profile.tsx:110 #: apps/web/src/components/forms/profile.tsx:110
#: apps/web/src/components/forms/v2/signup.tsx:300 #: apps/web/src/components/forms/v2/signup.tsx:300
msgid "Full Name" msgid "Full Name"
@ -2030,7 +2030,7 @@ msgid "New Template"
msgstr "Neue Vorlage" msgstr "Neue Vorlage"
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:416 #: apps/web/src/app/embed/direct/[[...url]]/client.tsx:416
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:293 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:295
#: apps/web/src/components/forms/v2/signup.tsx:509 #: apps/web/src/components/forms/v2/signup.tsx:509
msgid "Next" msgid "Next"
msgstr "Nächster" 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>" msgstr "Unterzeichnen als<0>{0} <1>({1})</1></0>"
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:329 #: apps/web/src/app/embed/direct/[[...url]]/client.tsx:329
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:207 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:209
msgid "Sign document" msgid "Sign document"
msgstr "Dokument unterschreiben" msgstr "Dokument unterschreiben"
@ -2762,7 +2762,7 @@ msgid "Sign Out"
msgstr "Ausloggen" msgstr "Ausloggen"
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:350 #: apps/web/src/app/embed/direct/[[...url]]/client.tsx:350
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:228 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:230
msgid "Sign the document to complete the process." msgid "Sign the document to complete the process."
msgstr "Unterschreiben Sie das Dokument, um den Vorgang abzuschließen." 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:197
#: apps/web/src/app/(signing)/sign/[token]/signature-field.tsx:227 #: 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/direct/[[...url]]/client.tsx:391
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:268 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:270
#: apps/web/src/components/forms/profile.tsx:132 #: apps/web/src/components/forms/profile.tsx:132
msgid "Signature" msgid "Signature"
msgstr "Unterschrift" 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/(teams)/t/[teamUrl]/settings/team-email-dropdown.tsx:39
#: apps/web/src/app/(unauthenticated)/verify-email/[token]/page.tsx:61 #: 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/direct/[[...url]]/client.tsx:243
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:123 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125
#: apps/web/src/components/(teams)/dialogs/create-team-checkout-dialog.tsx:50 #: 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/create-team-checkout-dialog.tsx:99
#: apps/web/src/components/(teams)/dialogs/invite-team-member-dialog.tsx:210 #: 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/(recipient)/d/[token]/direct-template.tsx:119
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:245 #: apps/web/src/app/embed/direct/[[...url]]/client.tsx:245
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125 #: apps/web/src/app/embed/sign/[[...url]]/client.tsx:127
msgid "We were unable to submit this document at this time. Please try again later." 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." 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" msgid "Add another value"
msgstr "Add another value" msgstr "Add another value"
#: packages/ui/primitives/document-flow/add-signers.tsx:359 #: packages/ui/primitives/document-flow/add-signers.tsx:459
msgid "Add myself" msgid "Add myself"
msgstr "Add myself" msgstr "Add myself"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:369 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:450
msgid "Add Myself" msgid "Add Myself"
msgstr "Add Myself" msgstr "Add Myself"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:355 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:436
msgid "Add Placeholder Recipient" msgid "Add Placeholder Recipient"
msgstr "Add Placeholder Recipient" msgstr "Add Placeholder Recipient"
#: packages/ui/primitives/document-flow/add-signers.tsx:348 #: packages/ui/primitives/document-flow/add-signers.tsx:448
msgid "Add Signer" msgid "Add Signer"
msgstr "Add Signer" msgstr "Add Signer"
@ -149,8 +149,8 @@ msgid "Cancel"
msgstr "Cancel" msgstr "Cancel"
#: packages/ui/primitives/document-flow/add-signers.tsx:164 #: packages/ui/primitives/document-flow/add-signers.tsx:164
msgid "Cannot remove signer" #~ msgid "Cannot remove signer"
msgstr "Cannot remove signer" #~ msgstr "Cannot remove signer"
#: packages/lib/constants/recipient-roles.ts:17 #: packages/lib/constants/recipient-roles.ts:17
msgid "Cc" msgid "Cc"
@ -225,7 +225,7 @@ msgstr "Date"
msgid "Date Format" msgid "Date Format"
msgstr "Date Format" msgstr "Date Format"
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:312 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:393
msgid "Direct link receiver" msgid "Direct link receiver"
msgstr "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-fields.tsx:776
#: packages/ui/primitives/document-flow/add-signature.tsx:272 #: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:232 #: packages/ui/primitives/document-flow/add-signers.tsx:330
#: packages/ui/primitives/document-flow/add-signers.tsx:239 #: packages/ui/primitives/document-flow/add-signers.tsx:337
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632 #: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:210 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:296
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:217 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:303
msgid "Email" msgid "Email"
msgstr "Email" msgstr "Email"
@ -373,10 +373,10 @@ msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:802 #: packages/ui/primitives/document-flow/add-fields.tsx:802
#: packages/ui/primitives/document-flow/add-signature.tsx:298 #: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:265 #: packages/ui/primitives/document-flow/add-signers.tsx:364
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658 #: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:245 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:327
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:251 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:333
msgid "Name" msgid "Name"
msgstr "Name" msgstr "Name"
@ -555,8 +555,8 @@ msgstr "Share Signature Card"
msgid "Share the Link" msgid "Share the Link"
msgstr "Share the Link" msgstr "Share the Link"
#: packages/ui/primitives/document-flow/add-signers.tsx:377 #: packages/ui/primitives/document-flow/add-signers.tsx:477
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:387 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:468
msgid "Show advanced settings" msgid "Show advanced settings"
msgstr "Show advanced settings" msgstr "Show advanced settings"
@ -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." 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." msgstr "This document is password protected. Please enter the password to view the document."
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:315 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:396
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." 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." 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 #: packages/ui/primitives/document-flow/add-signers.tsx:165
msgid "This signer has already received the document." #~ msgid "This signer has already received the document."
msgstr "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 #: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings." msgid "This will override any global settings."

File diff suppressed because one or more lines are too long

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

View File

@ -1,6 +1,8 @@
import { TRPCError } from '@trpc/server'; import { TRPCError } from '@trpc/server';
import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token'; 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 { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/set-recipients-for-document';
import { setRecipientsForTemplate } from '@documenso/lib/server-only/recipient/set-recipients-for-template'; import { setRecipientsForTemplate } from '@documenso/lib/server-only/recipient/set-recipients-for-template';
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata'; import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
@ -10,6 +12,8 @@ import {
ZAddSignersMutationSchema, ZAddSignersMutationSchema,
ZAddTemplateSignersMutationSchema, ZAddTemplateSignersMutationSchema,
ZCompleteDocumentWithTokenMutationSchema, ZCompleteDocumentWithTokenMutationSchema,
ZRemoveSignerMutationSchema,
ZRemoveTemplateSignerMutationSchema,
} from './schema'; } from './schema';
export const recipientRouter = router({ export const recipientRouter = router({
@ -70,6 +74,51 @@ 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 completeDocumentWithToken: procedure
.input(ZCompleteDocumentWithTokenMutationSchema) .input(ZCompleteDocumentWithTokenMutationSchema)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {

View File

@ -58,6 +58,14 @@ export const ZAddTemplateSignersMutationSchema = z
export type TAddTemplateSignersMutationSchema = z.infer<typeof ZAddTemplateSignersMutationSchema>; 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({ export const ZCompleteDocumentWithTokenMutationSchema = z.object({
token: z.string(), token: z.string(),
documentId: z.number(), documentId: z.number(),
@ -67,3 +75,13 @@ export const ZCompleteDocumentWithTokenMutationSchema = z.object({
export type TCompleteDocumentWithTokenMutationSchema = z.infer< export type TCompleteDocumentWithTokenMutationSchema = z.infer<
typeof ZCompleteDocumentWithTokenMutationSchema 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,6 +2,8 @@
import React, { useId, useMemo, useState } from 'react'; import React, { useId, useMemo, useState } from 'react';
import { useRouter } from 'next/navigation';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, msg } from '@lingui/macro'; import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
@ -11,10 +13,13 @@ import { useSession } from 'next-auth/react';
import { useFieldArray, useForm } from 'react-hook-form'; import { useFieldArray, useForm } from 'react-hook-form';
import { useLimits } from '@documenso/ee/server-only/limits/provider/client'; 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 { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';
import { nanoid } from '@documenso/lib/universal/id'; import { nanoid } from '@documenso/lib/universal/id';
import type { Field, Recipient } from '@documenso/prisma/client'; import type { Field, Recipient } from '@documenso/prisma/client';
import { RecipientRole, SendStatus } 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 { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out';
import { RecipientActionAuthSelect } from '@documenso/ui/components/recipient/recipient-action-auth-select'; import { RecipientActionAuthSelect } from '@documenso/ui/components/recipient/recipient-action-auth-select';
import { RecipientRoleSelect } from '@documenso/ui/components/recipient/recipient-role-select'; import { RecipientRoleSelect } from '@documenso/ui/components/recipient/recipient-role-select';
@ -41,32 +46,70 @@ import type { DocumentFlowStep } from './types';
export type AddSignersFormProps = { export type AddSignersFormProps = {
documentFlow: DocumentFlowStep; documentFlow: DocumentFlowStep;
document: DocumentWithDetails;
recipients: Recipient[]; recipients: Recipient[];
fields: Field[]; fields: Field[];
isDocumentEnterprise: boolean; isDocumentEnterprise: boolean;
onSubmit: (_data: TAddSignersFormSchema) => void; onSubmit: (_data: TAddSignersFormSchema) => void;
isDocumentPdfLoaded: boolean; isDocumentPdfLoaded: boolean;
teamId?: number;
}; };
export const AddSignersFormPartial = ({ export const AddSignersFormPartial = ({
documentFlow, documentFlow,
document,
recipients, recipients,
fields, fields,
isDocumentEnterprise, isDocumentEnterprise,
onSubmit, onSubmit,
isDocumentPdfLoaded, isDocumentPdfLoaded,
teamId,
}: AddSignersFormProps) => { }: AddSignersFormProps) => {
const { _ } = useLingui(); const { _ } = useLingui();
const { toast } = useToast(); const { toast } = useToast();
const { remaining } = useLimits(); const { remaining } = useLimits();
const { data: session } = useSession(); const { data: session } = useSession();
const router = useRouter();
const user = session?.user; const user = session?.user;
const initialId = useId(); const initialId = useId();
const utils = trpc.useUtils();
const { currentStep, totalSteps, previousStep } = useStep(); 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>({ const form = useForm<TAddSignersFormSchema>({
resolver: zodResolver(ZAddSignersFormSchema), resolver: zodResolver(ZAddSignersFormSchema),
defaultValues: { defaultValues: {
@ -156,22 +199,11 @@ export const AddSignersFormPartial = ({
}); });
}; };
const onRemoveSigner = (index: number) => { /*
const signer = signers[index]; The self-signer is automatically saved on blur
since the email input is focused after adding the self-signer.
if (hasBeenSentToRecipientId(signer.nativeId)) { When the user clicks outside the input, the self-signer is saved in the db.
toast({ */
title: _(msg`Cannot remove signer`),
description: _(msg`This signer has already received the document.`),
variant: 'destructive',
});
return;
}
removeSigner(index);
};
const onAddSelfSigner = () => { const onAddSelfSigner = () => {
if (emptySignerIndex !== -1) { if (emptySignerIndex !== -1) {
setValue(`signers.${emptySignerIndex}.name`, user?.name ?? ''); setValue(`signers.${emptySignerIndex}.name`, user?.name ?? '');
@ -193,6 +225,72 @@ 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 ( return (
<> <>
<DocumentFlowFormContainerHeader <DocumentFlowFormContainerHeader
@ -240,6 +338,7 @@ export const AddSignersFormPartial = ({
{...field} {...field}
disabled={isSubmitting || hasBeenSentToRecipientId(signer.nativeId)} disabled={isSubmitting || hasBeenSentToRecipientId(signer.nativeId)}
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
onBlur={() => void handleOnBlur(index)}
/> />
</FormControl> </FormControl>
@ -266,6 +365,7 @@ export const AddSignersFormPartial = ({
{...field} {...field}
disabled={isSubmitting || hasBeenSentToRecipientId(signer.nativeId)} disabled={isSubmitting || hasBeenSentToRecipientId(signer.nativeId)}
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
onBlur={() => void handleOnBlur(index)}
/> />
</FormControl> </FormControl>
@ -319,7 +419,7 @@ export const AddSignersFormPartial = ({
hasBeenSentToRecipientId(signer.nativeId) || hasBeenSentToRecipientId(signer.nativeId) ||
signers.length === 1 signers.length === 1
} }
onClick={() => onRemoveSigner(index)} onClick={() => void handleRemoveSigner(index)}
> >
<Trash className="h-5 w-5" /> <Trash className="h-5 w-5" />
</button> </button>

View File

@ -2,6 +2,8 @@
import React, { useEffect, useId, useMemo, useState } from 'react'; import React, { useEffect, useId, useMemo, useState } from 'react';
import { useRouter } from 'next/navigation';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, msg } from '@lingui/macro'; import { Trans, msg } from '@lingui/macro';
import { useLingui } from '@lingui/react'; import { useLingui } from '@lingui/react';
@ -10,11 +12,14 @@ import { Link2Icon, Plus, Trash } from 'lucide-react';
import { useSession } from 'next-auth/react'; import { useSession } from 'next-auth/react';
import { useFieldArray, useForm } from 'react-hook-form'; 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 { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';
import { nanoid } from '@documenso/lib/universal/id'; import { nanoid } from '@documenso/lib/universal/id';
import { generateRecipientPlaceholder } from '@documenso/lib/utils/templates'; import { generateRecipientPlaceholder } from '@documenso/lib/utils/templates';
import type { TemplateDirectLink } from '@documenso/prisma/client'; import type { TemplateDirectLink } from '@documenso/prisma/client';
import { type Field, type Recipient, RecipientRole } 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 { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out';
import { RecipientActionAuthSelect } from '@documenso/ui/components/recipient/recipient-action-auth-select'; import { RecipientActionAuthSelect } from '@documenso/ui/components/recipient/recipient-action-auth-select';
import { RecipientRoleSelect } from '@documenso/ui/components/recipient/recipient-role-select'; import { RecipientRoleSelect } from '@documenso/ui/components/recipient/recipient-role-select';
@ -22,6 +27,7 @@ import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button'; import { Button } from '@documenso/ui/primitives/button';
import { FormErrorMessage } from '@documenso/ui/primitives/form/form-error-message'; import { FormErrorMessage } from '@documenso/ui/primitives/form/form-error-message';
import { Input } from '@documenso/ui/primitives/input'; import { Input } from '@documenso/ui/primitives/input';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { Checkbox } from '../checkbox'; import { Checkbox } from '../checkbox';
import { import {
@ -46,6 +52,7 @@ export type AddTemplatePlaceholderRecipientsFormProps = {
templateDirectLink: TemplateDirectLink | null; templateDirectLink: TemplateDirectLink | null;
isEnterprise: boolean; isEnterprise: boolean;
isDocumentPdfLoaded: boolean; isDocumentPdfLoaded: boolean;
template: TemplateWithDetails;
onSubmit: (_data: TAddTemplatePlacholderRecipientsFormSchema) => void; onSubmit: (_data: TAddTemplatePlacholderRecipientsFormSchema) => void;
}; };
@ -57,7 +64,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
fields, fields,
isDocumentPdfLoaded, isDocumentPdfLoaded,
onSubmit, onSubmit,
template,
}: AddTemplatePlaceholderRecipientsFormProps) => { }: AddTemplatePlaceholderRecipientsFormProps) => {
const { toast } = useToast();
const router = useRouter();
const initialId = useId(); const initialId = useId();
const { _ } = useLingui(); const { _ } = useLingui();
@ -71,6 +81,38 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
const { currentStep, totalSteps, previousStep } = useStep(); 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 = () => { const generateDefaultFormSigners = () => {
if (recipients.length === 0) { if (recipients.length === 0) {
return [ return [
@ -158,10 +200,6 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
setPlaceholderRecipientCount((count) => count + 1); setPlaceholderRecipientCount((count) => count + 1);
}; };
const onRemoveSigner = (index: number) => {
removeSigner(index);
};
const isSignerDirectRecipient = ( const isSignerDirectRecipient = (
signer: TAddTemplatePlacholderRecipientsFormSchema['signers'][number], signer: TAddTemplatePlacholderRecipientsFormSchema['signers'][number],
): boolean => { ): boolean => {
@ -171,6 +209,54 @@ 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 ( return (
<> <>
<DocumentFlowFormContainerHeader <DocumentFlowFormContainerHeader
@ -216,12 +302,8 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
type="email" type="email"
placeholder={_(msg`Email`)} placeholder={_(msg`Email`)}
{...field} {...field}
disabled={ disabled={field.disabled || isSubmitting}
field.disabled || onBlur={() => void handleOnBlur(index)}
isSubmitting ||
signers[index].email === user?.email ||
isSignerDirectRecipient(signer)
}
/> />
</FormControl> </FormControl>
@ -250,12 +332,8 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
<Input <Input
placeholder={_(msg`Name`)} placeholder={_(msg`Name`)}
{...field} {...field}
disabled={ disabled={field.disabled || isSubmitting}
field.disabled || onBlur={() => void handleOnBlur(index)}
isSubmitting ||
signers[index].email === user?.email ||
isSignerDirectRecipient(signer)
}
/> />
</FormControl> </FormControl>
@ -291,7 +369,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
<FormControl> <FormControl>
<RecipientRoleSelect <RecipientRoleSelect
{...field} {...field}
onValueChange={field.onChange} onValueChange={(value) => {
field.onChange(value);
void handleOnBlur(index);
}}
disabled={isSubmitting} disabled={isSubmitting}
hideCCRecipients={isSignerDirectRecipient(signer)} hideCCRecipients={isSignerDirectRecipient(signer)}
/> />
@ -325,7 +406,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
type="button" 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" 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} disabled={isSubmitting || signers.length === 1}
onClick={() => onRemoveSigner(index)} onClick={() => void handleRemoveSigner(index)}
> >
<Trash className="h-5 w-5" /> <Trash className="h-5 w-5" />
</button> </button>