Compare commits
16 Commits
feat/save-
...
feat/save-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1528fd63b | ||
|
|
85012ae991 | ||
|
|
ff4c9616fc | ||
|
|
fd004f5f24 | ||
|
|
bb222cc0fc | ||
|
|
f627cbc7db | ||
|
|
67be4fdb45 | ||
|
|
c8b7d13b4f | ||
|
|
2b4699bb61 | ||
|
|
39603fc150 | ||
|
|
7f2a8deda3 | ||
|
|
f24a33c182 | ||
|
|
4a8f32a44f | ||
|
|
bbf2ed7154 | ||
|
|
5ce7f4adcc | ||
|
|
d74aca2aa6 |
4
apps/marketing/process-env.d.ts
vendored
4
apps/marketing/process-env.d.ts
vendored
@@ -2,8 +2,8 @@ declare namespace NodeJS {
|
||||
export interface ProcessEnv {
|
||||
NEXT_PUBLIC_WEBAPP_URL?: string;
|
||||
NEXT_PUBLIC_MARKETING_URL?: string;
|
||||
NEXT_PRIVATE_INTERNAL_WEBAPP_URL?: string;
|
||||
|
||||
NEXT_PRIVATE_INTERNAL_WEBAPP_URL?:string;
|
||||
|
||||
NEXT_PRIVATE_DATABASE_URL: string;
|
||||
|
||||
NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID: string;
|
||||
|
||||
2
apps/web/process-env.d.ts
vendored
2
apps/web/process-env.d.ts
vendored
@@ -2,7 +2,7 @@ declare namespace NodeJS {
|
||||
export interface ProcessEnv {
|
||||
NEXT_PUBLIC_WEBAPP_URL?: string;
|
||||
NEXT_PUBLIC_MARKETING_URL?: string;
|
||||
NEXT_PRIVATE_INTERNAL_WEBAPP_URL?: string;
|
||||
NEXT_PRIVATE_INTERNAL_WEBAPP_URL?:string;
|
||||
|
||||
NEXT_PRIVATE_DATABASE_URL: string;
|
||||
|
||||
|
||||
@@ -349,13 +349,11 @@ export const EditDocumentForm = ({
|
||||
<AddSignersFormPartial
|
||||
key={recipients.length}
|
||||
documentFlow={documentFlow.signers}
|
||||
document={document}
|
||||
recipients={recipients}
|
||||
fields={fields}
|
||||
isDocumentEnterprise={isDocumentEnterprise}
|
||||
onSubmit={onAddSignersFormSubmit}
|
||||
isDocumentPdfLoaded={isDocumentPdfLoaded}
|
||||
teamId={team?.id}
|
||||
/>
|
||||
|
||||
<AddFieldsFormPartial
|
||||
|
||||
@@ -266,7 +266,6 @@ export const EditTemplateForm = ({
|
||||
onSubmit={onAddTemplatePlaceholderFormSubmit}
|
||||
isEnterprise={isEnterprise}
|
||||
isDocumentPdfLoaded={isDocumentPdfLoaded}
|
||||
template={template}
|
||||
/>
|
||||
|
||||
<AddTemplateFieldsFormPartial
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZBaseEmbedDataSchema = z.object({
|
||||
css: z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((value) => value || undefined),
|
||||
css: z.string().optional().transform(value => value || undefined),
|
||||
});
|
||||
|
||||
@@ -18,18 +18,15 @@ export const EmbedDocumentCompleted = ({ name, signature }: EmbedDocumentComplet
|
||||
|
||||
<div className="mt-8 w-full max-w-md">
|
||||
<SigningCard3D
|
||||
className="mx-auto w-full"
|
||||
className='w-full mx-auto'
|
||||
name={name || 'Documenso'}
|
||||
signature={signature}
|
||||
signingCelebrationImage={signingCelebration}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p className="text-muted-foreground mt-8 max-w-[50ch] text-center text-sm">
|
||||
<Trans>
|
||||
The document is now completed, please follow any instructions provided within the parent
|
||||
application.
|
||||
</Trans>
|
||||
<p className="mt-8 max-w-[50ch] text-center text-muted-foreground text-sm">
|
||||
<Trans>The document is now completed, please follow any instructions provided within the parent application.</Trans>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -6,7 +6,6 @@ import { useSearchParams } from 'next/navigation';
|
||||
|
||||
import { Trans, msg } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { useThrottleFn } from '@documenso/lib/client-only/hooks/use-throttle-fn';
|
||||
@@ -15,7 +14,7 @@ import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
|
||||
import { validateFieldsInserted } from '@documenso/lib/utils/fields';
|
||||
import type { DocumentMeta, Recipient, TemplateMeta } from '@documenso/prisma/client';
|
||||
import { type DocumentData, type Field, FieldType } from '@documenso/prisma/client';
|
||||
import { FieldType, type DocumentData, type Field } from '@documenso/prisma/client';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import type {
|
||||
TRemovedSignedFieldWithTokenMutationSchema,
|
||||
@@ -35,6 +34,7 @@ import type { DirectTemplateLocalField } from '~/app/(recipient)/d/[token]/sign-
|
||||
import { useRequiredSigningContext } from '~/app/(signing)/sign/[token]/provider';
|
||||
import { Logo } from '~/components/branding/logo';
|
||||
|
||||
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
|
||||
import { EmbedClientLoading } from '../../client-loading';
|
||||
import { EmbedDocumentCompleted } from '../../completed';
|
||||
import { EmbedDocumentFields } from '../../document-fields';
|
||||
@@ -307,7 +307,7 @@ export const EmbedDirectTemplateClientPage = ({
|
||||
<div className="relative mx-auto flex min-h-[100dvh] max-w-screen-lg flex-col items-center justify-center p-6">
|
||||
{(!hasFinishedInit || !hasDocumentLoaded) && <EmbedClientLoading />}
|
||||
|
||||
<div className="relative flex w-full flex-col gap-x-6 gap-y-12 md:flex-row">
|
||||
<div className="relative flex flex-col md:flex-row w-full gap-x-6 gap-y-12">
|
||||
{/* Viewer */}
|
||||
<div className="flex-1">
|
||||
<LazyPDFViewer
|
||||
@@ -318,26 +318,26 @@ export const EmbedDirectTemplateClientPage = ({
|
||||
|
||||
{/* Widget */}
|
||||
<div
|
||||
className="group/document-widget fixed bottom-8 left-0 z-50 h-fit w-full flex-shrink-0 px-6 md:sticky md:top-4 md:z-auto md:w-[350px] md:px-0"
|
||||
className="group/document-widget fixed md:sticky md:top-4 left-0 w-full bottom-8 px-6 md:px-0 z-50 md:z-auto md:w-[350px] flex-shrink-0 h-fit"
|
||||
data-expanded={isExpanded || undefined}
|
||||
>
|
||||
<div className="border-border bg-widget flex h-fit w-full flex-col rounded-xl border px-4 py-4 md:min-h-[min(calc(100dvh-2rem),48rem)] md:py-6">
|
||||
<div className="w-full border-border bg-widget flex md:min-h-[min(calc(100dvh-2rem),48rem)] h-fit flex-col rounded-xl border px-4 py-4 md:py-6">
|
||||
{/* Header */}
|
||||
<div>
|
||||
<div className="flex items-center justify-between gap-x-2">
|
||||
<h3 className="text-foreground text-xl font-semibold md:text-2xl">
|
||||
<h3 className="text-foreground text-xl md:text-2xl font-semibold">
|
||||
<Trans>Sign document</Trans>
|
||||
</h3>
|
||||
|
||||
<Button variant="outline" className="h-8 w-8 p-0 md:hidden">
|
||||
{isExpanded ? (
|
||||
<LucideChevronDown
|
||||
className="text-muted-foreground h-5 w-5"
|
||||
className="h-5 w-5 text-muted-foreground"
|
||||
onClick={() => setIsExpanded(false)}
|
||||
/>
|
||||
) : (
|
||||
<LucideChevronUp
|
||||
className="text-muted-foreground h-5 w-5"
|
||||
className="h-5 w-5 text-muted-foreground"
|
||||
onClick={() => setIsExpanded(true)}
|
||||
/>
|
||||
)}
|
||||
@@ -354,7 +354,7 @@ export const EmbedDirectTemplateClientPage = ({
|
||||
</div>
|
||||
|
||||
{/* Form */}
|
||||
<div className="-mx-2 hidden px-2 group-data-[expanded]/document-widget:block md:block">
|
||||
<div className="-mx-2 px-2 hidden group-data-[expanded]/document-widget:block md:block">
|
||||
<div className="flex flex-1 flex-col gap-y-4">
|
||||
<div>
|
||||
<Label htmlFor="full-name">
|
||||
@@ -408,9 +408,9 @@ export const EmbedDirectTemplateClientPage = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="hidden flex-1 group-data-[expanded]/document-widget:block md:block" />
|
||||
<div className="flex-1 hidden group-data-[expanded]/document-widget:block md:block" />
|
||||
|
||||
<div className="mt-4 hidden w-full grid-cols-2 items-center group-data-[expanded]/document-widget:grid md:grid">
|
||||
<div className="w-full grid-cols-2 items-center mt-4 hidden group-data-[expanded]/document-widget:grid md:grid">
|
||||
{pendingFields.length > 0 ? (
|
||||
<Button className="col-start-2" onClick={() => onNextFieldClick()}>
|
||||
<Trans>Next</Trans>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export default function EmbedDirectTemplateNotFound() {
|
||||
return <div>Not Found</div>;
|
||||
return <div>Not Found</div>
|
||||
}
|
||||
|
||||
@@ -73,7 +73,11 @@ export default async function EmbedDirectTemplatePage({ params }: EmbedDirectTem
|
||||
const fields = template.Field.filter((field) => field.recipientId === directTemplateRecipientId);
|
||||
|
||||
return (
|
||||
<SigningProvider email={user?.email} fullName={user?.name} signature={user?.signature}>
|
||||
<SigningProvider
|
||||
email={user?.email}
|
||||
fullName={user?.name}
|
||||
signature={user?.signature}
|
||||
>
|
||||
<DocumentAuthProvider
|
||||
documentAuthOptions={template.authOptions}
|
||||
recipient={recipient}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
ZTextFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import type { DocumentMeta, Recipient, TemplateMeta } from '@documenso/prisma/client';
|
||||
import { type Field, FieldType } from '@documenso/prisma/client';
|
||||
import { FieldType, type Field } from '@documenso/prisma/client';
|
||||
import type { FieldWithSignatureAndFieldMeta } from '@documenso/prisma/types/field-with-signature-and-fieldmeta';
|
||||
import type {
|
||||
TRemovedSignedFieldWithTokenMutationSchema,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
export const EmbedPaywall = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Paywall</h1>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
return <div>
|
||||
<h1>Paywall</h1>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { Trans, msg } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
|
||||
|
||||
import { useThrottleFn } from '@documenso/lib/client-only/hooks/use-throttle-fn';
|
||||
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||
import { validateFieldsInserted } from '@documenso/lib/utils/fields';
|
||||
import type { DocumentMeta, Recipient, TemplateMeta } from '@documenso/prisma/client';
|
||||
import { type DocumentData, type Field } from '@documenso/prisma/client';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { Trans, msg } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { FieldToolTip } from '@documenso/ui/components/field/field-tooltip';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
||||
@@ -22,9 +20,9 @@ import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
||||
import { SignaturePad } from '@documenso/ui/primitives/signature-pad';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
|
||||
import { useRequiredSigningContext } from '~/app/(signing)/sign/[token]/provider';
|
||||
import { Logo } from '~/components/branding/logo';
|
||||
|
||||
import { EmbedClientLoading } from '../../client-loading';
|
||||
import { EmbedDocumentCompleted } from '../../completed';
|
||||
import { EmbedDocumentFields } from '../../document-fields';
|
||||
@@ -187,7 +185,7 @@ export const EmbedSignDocumentClientPage = ({
|
||||
<div className="relative mx-auto flex min-h-[100dvh] max-w-screen-lg flex-col items-center justify-center p-6">
|
||||
{(!hasFinishedInit || !hasDocumentLoaded) && <EmbedClientLoading />}
|
||||
|
||||
<div className="relative flex w-full flex-col gap-x-6 gap-y-12 md:flex-row">
|
||||
<div className="relative flex flex-col md:flex-row w-full gap-x-6 gap-y-12">
|
||||
{/* Viewer */}
|
||||
<div className="flex-1">
|
||||
<LazyPDFViewer
|
||||
@@ -198,26 +196,26 @@ export const EmbedSignDocumentClientPage = ({
|
||||
|
||||
{/* Widget */}
|
||||
<div
|
||||
className="group/document-widget fixed bottom-8 left-0 z-50 h-fit w-full flex-shrink-0 px-6 md:sticky md:top-4 md:z-auto md:w-[350px] md:px-0"
|
||||
className="group/document-widget fixed md:sticky md:top-4 left-0 w-full bottom-8 px-6 md:px-0 z-50 md:z-auto md:w-[350px] flex-shrink-0 h-fit"
|
||||
data-expanded={isExpanded || undefined}
|
||||
>
|
||||
<div className="border-border bg-widget flex w-full flex-col rounded-xl border px-4 py-4 md:py-6">
|
||||
<div className="w-full border-border bg-widget flex flex-col rounded-xl border px-4 py-4 md:py-6">
|
||||
{/* Header */}
|
||||
<div>
|
||||
<div className="flex items-center justify-between gap-x-2">
|
||||
<h3 className="text-foreground text-xl font-semibold md:text-2xl">
|
||||
<h3 className="text-foreground text-xl md:text-2xl font-semibold">
|
||||
<Trans>Sign document</Trans>
|
||||
</h3>
|
||||
|
||||
<Button variant="outline" className="h-8 w-8 p-0 md:hidden">
|
||||
{isExpanded ? (
|
||||
<LucideChevronDown
|
||||
className="text-muted-foreground h-5 w-5"
|
||||
className="h-5 w-5 text-muted-foreground"
|
||||
onClick={() => setIsExpanded(false)}
|
||||
/>
|
||||
) : (
|
||||
<LucideChevronUp
|
||||
className="text-muted-foreground h-5 w-5"
|
||||
className="h-5 w-5 text-muted-foreground"
|
||||
onClick={() => setIsExpanded(true)}
|
||||
/>
|
||||
)}
|
||||
@@ -234,7 +232,7 @@ export const EmbedSignDocumentClientPage = ({
|
||||
</div>
|
||||
|
||||
{/* Form */}
|
||||
<div className="-mx-2 hidden px-2 group-data-[expanded]/document-widget:block md:block">
|
||||
<div className="-mx-2 px-2 hidden group-data-[expanded]/document-widget:block md:block">
|
||||
<div className="flex flex-1 flex-col gap-y-4">
|
||||
<div>
|
||||
<Label htmlFor="full-name">
|
||||
@@ -287,9 +285,9 @@ export const EmbedSignDocumentClientPage = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="hidden flex-1 group-data-[expanded]/document-widget:block md:block" />
|
||||
<div className="flex-1 hidden group-data-[expanded]/document-widget:block md:block" />
|
||||
|
||||
<div className="mt-4 hidden w-full grid-cols-2 items-center group-data-[expanded]/document-widget:grid md:grid">
|
||||
<div className="w-full grid-cols-2 items-center mt-4 hidden group-data-[expanded]/document-widget:grid md:grid">
|
||||
{pendingFields.length > 0 ? (
|
||||
<Button className="col-start-2" onClick={() => onNextFieldClick()}>
|
||||
<Trans>Next</Trans>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export default function EmbedDirectTemplateNotFound() {
|
||||
return <div>Not Found</div>;
|
||||
return <div>Not Found</div>
|
||||
}
|
||||
|
||||
@@ -4,12 +4,8 @@ import { match } from 'ts-pattern';
|
||||
|
||||
import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app';
|
||||
import { getServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
|
||||
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
||||
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
|
||||
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
|
||||
import { DocumentAccessAuth } from '@documenso/lib/types/document-auth';
|
||||
import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth';
|
||||
import { DocumentStatus } from '@documenso/prisma/client';
|
||||
|
||||
import { DocumentAuthProvider } from '~/app/(signing)/sign/[token]/document-auth-provider';
|
||||
import { SigningProvider } from '~/app/(signing)/sign/[token]/provider';
|
||||
@@ -17,6 +13,10 @@ import { SigningProvider } from '~/app/(signing)/sign/[token]/provider';
|
||||
import { EmbedAuthenticateView } from '../../authenticate';
|
||||
import { EmbedPaywall } from '../../paywall';
|
||||
import { EmbedSignDocumentClientPage } from './client';
|
||||
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
|
||||
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
|
||||
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
||||
import { DocumentStatus } from '@documenso/prisma/client';
|
||||
|
||||
export type EmbedSignDocumentPageProps = {
|
||||
params: {
|
||||
@@ -66,12 +66,7 @@ export default async function EmbedSignDocumentPage({ params }: EmbedSignDocumen
|
||||
.exhaustive();
|
||||
|
||||
if (!isAccessAuthValid) {
|
||||
return (
|
||||
<EmbedAuthenticateView
|
||||
email={user?.email || recipient.email}
|
||||
returnTo={`/embed/direct/${token}`}
|
||||
/>
|
||||
);
|
||||
return <EmbedAuthenticateView email={user?.email || recipient.email} returnTo={`/embed/direct/${token}`} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -81,7 +81,7 @@ async function middleware(req: NextRequest): Promise<NextResponse> {
|
||||
// Allow third parties to iframe the document.
|
||||
res.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
||||
res.headers.set('Access-Control-Allow-Origin', '*');
|
||||
res.headers.set('Content-Security-Policy', 'frame-ancestors *');
|
||||
res.headers.set('Content-Security-Policy', "frame-ancestors *");
|
||||
res.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
|
||||
res.headers.set('X-Content-Type-Options', 'nosniff');
|
||||
res.headers.set('X-Frame-Options', 'ALLOW-ALL');
|
||||
|
||||
@@ -3,19 +3,19 @@ import { useCallback, useRef, useState } from 'react';
|
||||
type ThrottleOptions = {
|
||||
leading?: boolean;
|
||||
trailing?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export function useThrottleFn<T extends (...args: unknown[]) => unknown>(
|
||||
fn: T,
|
||||
ms = 500,
|
||||
options: ThrottleOptions = {},
|
||||
options: ThrottleOptions = {}
|
||||
): [(...args: Parameters<T>) => void, boolean, () => void] {
|
||||
const [isThrottling, setIsThrottling] = useState(false);
|
||||
const $isThrottling = useRef(false);
|
||||
|
||||
const $timeout = useRef<NodeJS.Timeout | null>(null);
|
||||
const $lastArgs = useRef<Parameters<T> | null>(null);
|
||||
|
||||
|
||||
const { leading = true, trailing = true } = options;
|
||||
|
||||
const $setIsThrottling = useCallback((value: boolean) => {
|
||||
@@ -44,7 +44,7 @@ export function useThrottleFn<T extends (...args: unknown[]) => unknown>(
|
||||
$lastArgs.current = args;
|
||||
}
|
||||
},
|
||||
[fn, ms, leading, trailing, $setIsThrottling],
|
||||
[fn, ms, leading, trailing, $setIsThrottling]
|
||||
);
|
||||
|
||||
const cancel = useCallback(() => {
|
||||
|
||||
@@ -5,8 +5,7 @@ export const APP_DOCUMENT_UPLOAD_SIZE_LIMIT =
|
||||
|
||||
export const NEXT_PUBLIC_WEBAPP_URL = () => env('NEXT_PUBLIC_WEBAPP_URL');
|
||||
export const NEXT_PUBLIC_MARKETING_URL = () => env('NEXT_PUBLIC_MARKETING_URL');
|
||||
export const NEXT_PRIVATE_INTERNAL_WEBAPP_URL =
|
||||
process.env.NEXT_PRIVATE_INTERNAL_WEBAPP_URL ?? NEXT_PUBLIC_WEBAPP_URL();
|
||||
export const NEXT_PRIVATE_INTERNAL_WEBAPP_URL = process.env.NEXT_PRIVATE_INTERNAL_WEBAPP_URL ?? NEXT_PUBLIC_WEBAPP_URL();
|
||||
|
||||
export const IS_APP_MARKETING = process.env.NEXT_PUBLIC_PROJECT === 'marketing';
|
||||
export const IS_APP_WEB = process.env.NEXT_PUBLIC_PROJECT === 'web';
|
||||
|
||||
@@ -5,11 +5,7 @@ import { getToken } from 'next-auth/jwt';
|
||||
import { LOCAL_FEATURE_FLAGS } from '@documenso/lib/constants/feature-flags';
|
||||
import PostHogServerClient from '@documenso/lib/server-only/feature-flags/get-post-hog-server-client';
|
||||
|
||||
import {
|
||||
NEXT_PRIVATE_INTERNAL_WEBAPP_URL,
|
||||
NEXT_PUBLIC_MARKETING_URL,
|
||||
NEXT_PUBLIC_WEBAPP_URL,
|
||||
} from '../../constants/app';
|
||||
import { NEXT_PUBLIC_MARKETING_URL, NEXT_PUBLIC_WEBAPP_URL, NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../constants/app';
|
||||
import { extractDistinctUserId, mapJwtToFlagProperties } from './get';
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,11 +7,7 @@ import { getToken } from 'next-auth/jwt';
|
||||
import { LOCAL_FEATURE_FLAGS, extractPostHogConfig } from '@documenso/lib/constants/feature-flags';
|
||||
import PostHogServerClient from '@documenso/lib/server-only/feature-flags/get-post-hog-server-client';
|
||||
|
||||
import {
|
||||
NEXT_PRIVATE_INTERNAL_WEBAPP_URL,
|
||||
NEXT_PUBLIC_MARKETING_URL,
|
||||
NEXT_PUBLIC_WEBAPP_URL,
|
||||
} from '../../constants/app';
|
||||
import { NEXT_PUBLIC_MARKETING_URL, NEXT_PUBLIC_WEBAPP_URL, NEXT_PRIVATE_INTERNAL_WEBAPP_URL } from '../../constants/app';
|
||||
|
||||
/**
|
||||
* Evaluate a single feature flag based on the current user if possible.
|
||||
@@ -71,7 +67,7 @@ export default async function handleFeatureFlagGet(req: Request) {
|
||||
if (origin.startsWith(NEXT_PUBLIC_MARKETING_URL() ?? 'http://localhost:3001')) {
|
||||
res.headers.set('Access-Control-Allow-Origin', origin);
|
||||
}
|
||||
|
||||
|
||||
if (origin.startsWith(NEXT_PRIVATE_INTERNAL_WEBAPP_URL ?? 'http://localhost:3000')) {
|
||||
res.headers.set('Access-Control-Allow-Origin', origin);
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { SendStatus } from '@documenso/prisma/client';
|
||||
|
||||
export type DeleteRecipientForTemplateOptions = {
|
||||
templateId: number;
|
||||
recipientId: number;
|
||||
userId: number;
|
||||
teamId?: number;
|
||||
};
|
||||
|
||||
export const deleteRecipientFromTemplate = async ({
|
||||
templateId,
|
||||
recipientId,
|
||||
userId,
|
||||
teamId,
|
||||
}: DeleteRecipientForTemplateOptions) => {
|
||||
const recipient = await prisma.recipient.findFirst({
|
||||
where: {
|
||||
id: recipientId,
|
||||
Template: {
|
||||
id: templateId,
|
||||
...(teamId
|
||||
? {
|
||||
team: {
|
||||
id: teamId,
|
||||
members: {
|
||||
some: {
|
||||
userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
: {
|
||||
userId,
|
||||
teamId: null,
|
||||
}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!recipient) {
|
||||
throw new Error('Recipient not found');
|
||||
}
|
||||
|
||||
if (recipient.sendStatus !== SendStatus.NOT_SENT) {
|
||||
throw new Error('Can not delete a recipient that has already been sent a document');
|
||||
}
|
||||
|
||||
return await prisma.recipient.delete({
|
||||
where: {
|
||||
id: recipient.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -6,7 +6,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: \n"
|
||||
"Project-Id-Version: documenso-app\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-09-05 06:04\n"
|
||||
"Last-Translator: \n"
|
||||
@@ -82,19 +82,19 @@ msgstr "Weitere Option hinzufügen"
|
||||
msgid "Add another value"
|
||||
msgstr "Weiteren Wert hinzufügen"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:459
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:359
|
||||
msgid "Add myself"
|
||||
msgstr "Mich selbst hinzufügen"
|
||||
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:450
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:369
|
||||
msgid "Add Myself"
|
||||
msgstr "Mich hinzufügen"
|
||||
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:436
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:355
|
||||
msgid "Add Placeholder Recipient"
|
||||
msgstr "Platzhalterempfänger hinzufügen"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:448
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:348
|
||||
msgid "Add Signer"
|
||||
msgstr "Unterzeichner hinzufügen"
|
||||
|
||||
@@ -154,8 +154,8 @@ msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:164
|
||||
#~ msgid "Cannot remove signer"
|
||||
#~ msgstr "Unterzeichner kann nicht entfernt werden"
|
||||
msgid "Cannot remove signer"
|
||||
msgstr "Unterzeichner kann nicht entfernt werden"
|
||||
|
||||
#: packages/lib/constants/recipient-roles.ts:17
|
||||
msgid "Cc"
|
||||
@@ -230,7 +230,7 @@ msgstr "Datum"
|
||||
msgid "Date Format"
|
||||
msgstr "Datumsformat"
|
||||
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:393
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:312
|
||||
msgid "Direct link receiver"
|
||||
msgstr "Empfänger des direkten Links"
|
||||
|
||||
@@ -263,11 +263,11 @@ msgstr "Dropdown-Optionen"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-fields.tsx:776
|
||||
#: packages/ui/primitives/document-flow/add-signature.tsx:272
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:330
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:337
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:232
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:239
|
||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:296
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:303
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:210
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:217
|
||||
msgid "Email"
|
||||
msgstr "E-Mail"
|
||||
|
||||
@@ -367,7 +367,7 @@ msgstr "Max"
|
||||
msgid "Member"
|
||||
msgstr "Mitglied"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:95
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:229
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:215
|
||||
msgid "Message <0>(Optional)</0>"
|
||||
msgstr "Nachricht <0>(Optional)</0>"
|
||||
@@ -378,10 +378,10 @@ msgstr "Min"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-fields.tsx:802
|
||||
#: packages/ui/primitives/document-flow/add-signature.tsx:298
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:364
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:265
|
||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:327
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:333
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:245
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:251
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@@ -542,7 +542,7 @@ msgstr "Wählen Sie mindestens"
|
||||
msgid "Select default option"
|
||||
msgstr "Standardoption auswählen"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:124
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:275
|
||||
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:34
|
||||
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:64
|
||||
msgid "Send"
|
||||
@@ -560,8 +560,8 @@ msgstr "Unterschriftenkarte teilen"
|
||||
msgid "Share the Link"
|
||||
msgstr "Link teilen"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:477
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:468
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:377
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:387
|
||||
msgid "Show advanced settings"
|
||||
msgstr "Erweiterte Einstellungen anzeigen"
|
||||
|
||||
@@ -604,7 +604,7 @@ msgstr "Etwas ist schief gelaufen."
|
||||
msgid "Step <0>{step} of {maxStep}</0>"
|
||||
msgstr "Schritt <0>{step} von {maxStep}</0>"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:78
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:194
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:195
|
||||
msgid "Subject <0>(Optional)</0>"
|
||||
msgstr "Betreff <0>(Optional)</0>"
|
||||
@@ -686,13 +686,13 @@ msgstr "Dieses Dokument wurde bereits an diesen Empfänger gesendet. Sie können
|
||||
msgid "This document is password protected. Please enter the password to view the document."
|
||||
msgstr "Dieses Dokument ist durch ein Passwort geschützt. Bitte geben Sie das Passwort ein, um das Dokument anzusehen."
|
||||
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:396
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:315
|
||||
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
|
||||
msgstr "Dieses Feld kann nicht geändert oder gelöscht werden. Wenn Sie den direkten Link dieser Vorlage teilen oder zu Ihrem öffentlichen Profil hinzufügen, kann jeder, der darauf zugreift, seinen Namen und seine E-Mail-Adresse eingeben und die ihm zugewiesenen Felder ausfüllen."
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:165
|
||||
#~ msgid "This signer has already received the document."
|
||||
#~ msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten."
|
||||
msgid "This signer has already received the document."
|
||||
msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten."
|
||||
|
||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
|
||||
msgid "This will override any global settings."
|
||||
@@ -712,7 +712,7 @@ msgstr "Titel"
|
||||
msgid "To proceed further, please set at least one value for the {0} field."
|
||||
msgstr "Um fortzufahren, legen Sie bitte mindestens einen Wert für das Feld {0} fest."
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:124
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:275
|
||||
msgid "Update"
|
||||
msgstr "Aktualisieren"
|
||||
|
||||
|
||||
@@ -6,12 +6,17 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: \n"
|
||||
"Project-Id-Version: documenso-app\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-09-05 06:04\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
"Language-Team: German\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Crowdin-Project: documenso-app\n"
|
||||
"X-Crowdin-Project-ID: 694691\n"
|
||||
"X-Crowdin-Language: de\n"
|
||||
"X-Crowdin-File: marketing.po\n"
|
||||
"X-Crowdin-File-ID: 6\n"
|
||||
|
||||
#: apps/marketing/src/app/(marketing)/blog/page.tsx:45
|
||||
msgid "{0}"
|
||||
@@ -417,7 +422,7 @@ msgid "Save $60 or $120"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Search languages..."
|
||||
#~ msgstr "Sprachen suchen...>>>>>>> main"
|
||||
#~ msgstr "Sprachen suchen..."
|
||||
|
||||
#: apps/marketing/src/app/(marketing)/pricing/page.tsx:109
|
||||
msgid "Securely. Our data centers are located in Frankfurt (Germany), giving us the best local privacy laws. We are very aware of the sensitive nature of our data and follow best practices to ensure the security and integrity of the data entrusted to us."
|
||||
|
||||
@@ -6,7 +6,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: @lingui/cli\n"
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: \n"
|
||||
"Project-Id-Version: documenso-app\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-09-05 06:04\n"
|
||||
"Last-Translator: \n"
|
||||
@@ -754,7 +754,7 @@ msgstr "Klicken Sie, um den Signatur-Link zu kopieren, um ihn an den Empfänger
|
||||
#: apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx:175
|
||||
#: apps/web/src/app/(signing)/sign/[token]/form.tsx:107
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:435
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:314
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:312
|
||||
msgid "Click to insert field"
|
||||
msgstr "Klicken Sie, um das Feld einzufügen"
|
||||
|
||||
@@ -772,7 +772,7 @@ msgstr "Schließen"
|
||||
|
||||
#: apps/web/src/app/(signing)/sign/[token]/sign-dialog.tsx:58
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:425
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:304
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:302
|
||||
#: apps/web/src/components/forms/v2/signup.tsx:522
|
||||
msgid "Complete"
|
||||
msgstr "Vollständig"
|
||||
@@ -1405,7 +1405,7 @@ msgstr "Webhook bearbeiten"
|
||||
#: apps/web/src/app/(recipient)/d/[token]/configure-direct-template.tsx:118
|
||||
#: apps/web/src/app/(signing)/sign/[token]/email-field.tsx:126
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:376
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:256
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:254
|
||||
#: apps/web/src/components/(teams)/dialogs/add-team-email-dialog.tsx:169
|
||||
#: apps/web/src/components/(teams)/dialogs/update-team-email-dialog.tsx:153
|
||||
#: apps/web/src/components/forms/forgot-password.tsx:81
|
||||
@@ -1587,7 +1587,7 @@ msgstr "Haben Sie Ihr Passwort vergessen?"
|
||||
#: apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx:326
|
||||
#: apps/web/src/app/(signing)/sign/[token]/name-field.tsx:193
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:361
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:241
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:239
|
||||
#: apps/web/src/components/forms/profile.tsx:110
|
||||
#: apps/web/src/components/forms/v2/signup.tsx:300
|
||||
msgid "Full Name"
|
||||
@@ -2030,7 +2030,7 @@ msgid "New Template"
|
||||
msgstr "Neue Vorlage"
|
||||
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:416
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:295
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:293
|
||||
#: apps/web/src/components/forms/v2/signup.tsx:509
|
||||
msgid "Next"
|
||||
msgstr "Nächster"
|
||||
@@ -2733,7 +2733,7 @@ msgid "Sign as<0>{0} <1>({1})</1></0>"
|
||||
msgstr "Unterzeichnen als<0>{0} <1>({1})</1></0>"
|
||||
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:329
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:209
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:207
|
||||
msgid "Sign document"
|
||||
msgstr "Dokument unterschreiben"
|
||||
|
||||
@@ -2762,7 +2762,7 @@ msgid "Sign Out"
|
||||
msgstr "Ausloggen"
|
||||
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:350
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:230
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:228
|
||||
msgid "Sign the document to complete the process."
|
||||
msgstr "Unterschreiben Sie das Dokument, um den Vorgang abzuschließen."
|
||||
|
||||
@@ -2789,7 +2789,7 @@ msgstr "Registrieren mit OIDC"
|
||||
#: apps/web/src/app/(signing)/sign/[token]/signature-field.tsx:197
|
||||
#: apps/web/src/app/(signing)/sign/[token]/signature-field.tsx:227
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:391
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:270
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:268
|
||||
#: apps/web/src/components/forms/profile.tsx:132
|
||||
msgid "Signature"
|
||||
msgstr "Unterschrift"
|
||||
@@ -2857,7 +2857,7 @@ msgstr "Website Einstellungen"
|
||||
#: apps/web/src/app/(teams)/t/[teamUrl]/settings/team-email-dropdown.tsx:39
|
||||
#: apps/web/src/app/(unauthenticated)/verify-email/[token]/page.tsx:61
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:243
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:123
|
||||
#: apps/web/src/components/(teams)/dialogs/create-team-checkout-dialog.tsx:50
|
||||
#: apps/web/src/components/(teams)/dialogs/create-team-checkout-dialog.tsx:99
|
||||
#: apps/web/src/components/(teams)/dialogs/invite-team-member-dialog.tsx:210
|
||||
@@ -4023,7 +4023,7 @@ msgstr "Wir konnten die Zwei-Faktor-Authentifizierung für Ihr Konto nicht einri
|
||||
|
||||
#: apps/web/src/app/(recipient)/d/[token]/direct-template.tsx:119
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:245
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:127
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125
|
||||
msgid "We were unable to submit this document at this time. Please try again later."
|
||||
msgstr "Wir konnten dieses Dokument zurzeit nicht einreichen. Bitte versuchen Sie es später erneut."
|
||||
|
||||
|
||||
@@ -77,19 +77,19 @@ msgstr "Add another option"
|
||||
msgid "Add another value"
|
||||
msgstr "Add another value"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:459
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:359
|
||||
msgid "Add myself"
|
||||
msgstr "Add myself"
|
||||
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:450
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:369
|
||||
msgid "Add Myself"
|
||||
msgstr "Add Myself"
|
||||
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:436
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:355
|
||||
msgid "Add Placeholder Recipient"
|
||||
msgstr "Add Placeholder Recipient"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:448
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:348
|
||||
msgid "Add Signer"
|
||||
msgstr "Add Signer"
|
||||
|
||||
@@ -149,8 +149,8 @@ msgid "Cancel"
|
||||
msgstr "Cancel"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:164
|
||||
#~ msgid "Cannot remove signer"
|
||||
#~ msgstr "Cannot remove signer"
|
||||
msgid "Cannot remove signer"
|
||||
msgstr "Cannot remove signer"
|
||||
|
||||
#: packages/lib/constants/recipient-roles.ts:17
|
||||
msgid "Cc"
|
||||
@@ -225,7 +225,7 @@ msgstr "Date"
|
||||
msgid "Date Format"
|
||||
msgstr "Date Format"
|
||||
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:393
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:312
|
||||
msgid "Direct link receiver"
|
||||
msgstr "Direct link receiver"
|
||||
|
||||
@@ -258,11 +258,11 @@ msgstr "Dropdown options"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-fields.tsx:776
|
||||
#: packages/ui/primitives/document-flow/add-signature.tsx:272
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:330
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:337
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:232
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:239
|
||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:296
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:303
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:210
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:217
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
@@ -362,7 +362,7 @@ msgstr "Max"
|
||||
msgid "Member"
|
||||
msgstr "Member"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:95
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:229
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:215
|
||||
msgid "Message <0>(Optional)</0>"
|
||||
msgstr "Message <0>(Optional)</0>"
|
||||
@@ -373,10 +373,10 @@ msgstr "Min"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-fields.tsx:802
|
||||
#: packages/ui/primitives/document-flow/add-signature.tsx:298
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:364
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:265
|
||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:327
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:333
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:245
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:251
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@@ -537,7 +537,7 @@ msgstr "Select at least"
|
||||
msgid "Select default option"
|
||||
msgstr "Select default option"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:124
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:275
|
||||
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:34
|
||||
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:64
|
||||
msgid "Send"
|
||||
@@ -555,8 +555,8 @@ msgstr "Share Signature Card"
|
||||
msgid "Share the Link"
|
||||
msgstr "Share the Link"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:477
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:468
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:377
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:387
|
||||
msgid "Show advanced settings"
|
||||
msgstr "Show advanced settings"
|
||||
|
||||
@@ -599,7 +599,7 @@ msgstr "Something went wrong."
|
||||
msgid "Step <0>{step} of {maxStep}</0>"
|
||||
msgstr "Step <0>{step} of {maxStep}</0>"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:78
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:194
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:195
|
||||
msgid "Subject <0>(Optional)</0>"
|
||||
msgstr "Subject <0>(Optional)</0>"
|
||||
@@ -681,13 +681,13 @@ msgstr "This document has already been sent to this recipient. You can no longer
|
||||
msgid "This document is password protected. Please enter the password to view the document."
|
||||
msgstr "This document is password protected. Please enter the password to view the document."
|
||||
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:396
|
||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:315
|
||||
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
|
||||
msgstr "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:165
|
||||
#~ msgid "This signer has already received the document."
|
||||
#~ msgstr "This signer has already received the document."
|
||||
msgid "This signer has already received the document."
|
||||
msgstr "This signer has already received the document."
|
||||
|
||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
|
||||
msgid "This will override any global settings."
|
||||
@@ -707,7 +707,7 @@ msgstr "Title"
|
||||
msgid "To proceed further, please set at least one value for the {0} field."
|
||||
msgstr "To proceed further, please set at least one value for the {0} field."
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:124
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx:275
|
||||
msgid "Update"
|
||||
msgstr "Update"
|
||||
|
||||
|
||||
@@ -749,7 +749,7 @@ msgstr "Click to copy signing link for sending to recipient"
|
||||
#: apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx:175
|
||||
#: apps/web/src/app/(signing)/sign/[token]/form.tsx:107
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:435
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:314
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:312
|
||||
msgid "Click to insert field"
|
||||
msgstr "Click to insert field"
|
||||
|
||||
@@ -767,7 +767,7 @@ msgstr "Close"
|
||||
|
||||
#: apps/web/src/app/(signing)/sign/[token]/sign-dialog.tsx:58
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:425
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:304
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:302
|
||||
#: apps/web/src/components/forms/v2/signup.tsx:522
|
||||
msgid "Complete"
|
||||
msgstr "Complete"
|
||||
@@ -1402,7 +1402,7 @@ msgstr "Edit webhook"
|
||||
#: apps/web/src/app/(recipient)/d/[token]/configure-direct-template.tsx:118
|
||||
#: apps/web/src/app/(signing)/sign/[token]/email-field.tsx:126
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:376
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:256
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:254
|
||||
#: apps/web/src/components/(teams)/dialogs/add-team-email-dialog.tsx:169
|
||||
#: apps/web/src/components/(teams)/dialogs/update-team-email-dialog.tsx:153
|
||||
#: apps/web/src/components/forms/forgot-password.tsx:81
|
||||
@@ -1586,7 +1586,7 @@ msgstr "Forgot your password?"
|
||||
#: apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx:326
|
||||
#: apps/web/src/app/(signing)/sign/[token]/name-field.tsx:193
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:361
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:241
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:239
|
||||
#: apps/web/src/components/forms/profile.tsx:110
|
||||
#: apps/web/src/components/forms/v2/signup.tsx:300
|
||||
msgid "Full Name"
|
||||
@@ -2029,7 +2029,7 @@ msgid "New Template"
|
||||
msgstr "New Template"
|
||||
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:416
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:295
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:293
|
||||
#: apps/web/src/components/forms/v2/signup.tsx:509
|
||||
msgid "Next"
|
||||
msgstr "Next"
|
||||
@@ -2732,7 +2732,7 @@ msgid "Sign as<0>{0} <1>({1})</1></0>"
|
||||
msgstr "Sign as<0>{0} <1>({1})</1></0>"
|
||||
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:329
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:209
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:207
|
||||
msgid "Sign document"
|
||||
msgstr "Sign document"
|
||||
|
||||
@@ -2761,7 +2761,7 @@ msgid "Sign Out"
|
||||
msgstr "Sign Out"
|
||||
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:350
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:230
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:228
|
||||
msgid "Sign the document to complete the process."
|
||||
msgstr "Sign the document to complete the process."
|
||||
|
||||
@@ -2788,7 +2788,7 @@ msgstr "Sign Up with OIDC"
|
||||
#: apps/web/src/app/(signing)/sign/[token]/signature-field.tsx:197
|
||||
#: apps/web/src/app/(signing)/sign/[token]/signature-field.tsx:227
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:391
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:270
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:268
|
||||
#: apps/web/src/components/forms/profile.tsx:132
|
||||
msgid "Signature"
|
||||
msgstr "Signature"
|
||||
@@ -2856,7 +2856,7 @@ msgstr "Site Settings"
|
||||
#: apps/web/src/app/(teams)/t/[teamUrl]/settings/team-email-dropdown.tsx:39
|
||||
#: apps/web/src/app/(unauthenticated)/verify-email/[token]/page.tsx:61
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:243
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:123
|
||||
#: apps/web/src/components/(teams)/dialogs/create-team-checkout-dialog.tsx:50
|
||||
#: apps/web/src/components/(teams)/dialogs/create-team-checkout-dialog.tsx:99
|
||||
#: apps/web/src/components/(teams)/dialogs/invite-team-member-dialog.tsx:210
|
||||
@@ -4022,7 +4022,7 @@ msgstr "We were unable to setup two-factor authentication for your account. Plea
|
||||
|
||||
#: apps/web/src/app/(recipient)/d/[token]/direct-template.tsx:119
|
||||
#: apps/web/src/app/embed/direct/[[...url]]/client.tsx:245
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:127
|
||||
#: apps/web/src/app/embed/sign/[[...url]]/client.tsx:125
|
||||
msgid "We were unable to submit this document at this time. Please try again later."
|
||||
msgstr "We were unable to submit this document at this time. Please try again later."
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
ZResendDocumentMutationSchema,
|
||||
ZSearchDocumentsMutationSchema,
|
||||
ZSendDocumentMutationSchema,
|
||||
ZSetDocumentEmailSettingsMutationSchema,
|
||||
ZSetPasswordForDocumentMutationSchema,
|
||||
ZSetSettingsForDocumentMutationSchema,
|
||||
ZSetTitleForDocumentMutationSchema,
|
||||
@@ -275,6 +276,32 @@ export const documentRouter = router({
|
||||
}
|
||||
}),
|
||||
|
||||
setDocumentEmailSettings: authenticatedProcedure
|
||||
.input(ZSetDocumentEmailSettingsMutationSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
const { documentId, subject, message } = input;
|
||||
|
||||
const userId = ctx.user.id;
|
||||
|
||||
return await upsertDocumentMeta({
|
||||
documentId,
|
||||
userId,
|
||||
subject,
|
||||
message,
|
||||
requestMetadata: extractNextApiRequestMetadata(ctx.req),
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message:
|
||||
'We were unable to update the email settings for this document. Please try again later.',
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
setPasswordForDocument: authenticatedProcedure
|
||||
.input(ZSetPasswordForDocumentMutationSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
|
||||
@@ -139,6 +139,12 @@ export const ZSendDocumentMutationSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
export const ZSetDocumentEmailSettingsMutationSchema = z.object({
|
||||
documentId: z.number(),
|
||||
subject: z.string().optional(),
|
||||
message: z.string().optional(),
|
||||
});
|
||||
|
||||
export const ZSetPasswordForDocumentMutationSchema = z.object({
|
||||
documentId: z.number(),
|
||||
password: z.string(),
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
|
||||
import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token';
|
||||
import { deleteRecipient } from '@documenso/lib/server-only/recipient/delete-recipient';
|
||||
import { deleteRecipientFromTemplate } from '@documenso/lib/server-only/recipient/delete-recipient-from-template';
|
||||
import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/set-recipients-for-document';
|
||||
import { setRecipientsForTemplate } from '@documenso/lib/server-only/recipient/set-recipients-for-template';
|
||||
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||
@@ -12,8 +10,6 @@ import {
|
||||
ZAddSignersMutationSchema,
|
||||
ZAddTemplateSignersMutationSchema,
|
||||
ZCompleteDocumentWithTokenMutationSchema,
|
||||
ZRemoveSignerMutationSchema,
|
||||
ZRemoveTemplateSignerMutationSchema,
|
||||
} from './schema';
|
||||
|
||||
export const recipientRouter = router({
|
||||
@@ -74,51 +70,6 @@ export const recipientRouter = router({
|
||||
}
|
||||
}),
|
||||
|
||||
removeTemplateSigner: authenticatedProcedure
|
||||
.input(ZRemoveTemplateSignerMutationSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
const { templateId, recipientId, teamId } = input;
|
||||
const userId = ctx.user.id;
|
||||
|
||||
return await deleteRecipientFromTemplate({
|
||||
userId,
|
||||
templateId,
|
||||
teamId,
|
||||
recipientId,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: 'We were unable to remove the recipient. Please try again later.',
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
removeSigner: authenticatedProcedure
|
||||
.input(ZRemoveSignerMutationSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
try {
|
||||
const { documentId, teamId, recipientId } = input;
|
||||
|
||||
return await deleteRecipient({
|
||||
userId: ctx.user.id,
|
||||
documentId,
|
||||
teamId,
|
||||
recipientId,
|
||||
requestMetadata: extractNextApiRequestMetadata(ctx.req),
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: 'We were unable to set this field. Please try again later.',
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
completeDocumentWithToken: procedure
|
||||
.input(ZCompleteDocumentWithTokenMutationSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
|
||||
@@ -58,14 +58,6 @@ export const ZAddTemplateSignersMutationSchema = z
|
||||
|
||||
export type TAddTemplateSignersMutationSchema = z.infer<typeof ZAddTemplateSignersMutationSchema>;
|
||||
|
||||
export const ZRemoveSignerMutationSchema = z.object({
|
||||
documentId: z.number(),
|
||||
teamId: z.number().optional(),
|
||||
recipientId: z.number(),
|
||||
});
|
||||
|
||||
export type TRemoveSignerMutationSchema = z.infer<typeof ZRemoveSignerMutationSchema>;
|
||||
|
||||
export const ZCompleteDocumentWithTokenMutationSchema = z.object({
|
||||
token: z.string(),
|
||||
documentId: z.number(),
|
||||
@@ -75,13 +67,3 @@ export const ZCompleteDocumentWithTokenMutationSchema = z.object({
|
||||
export type TCompleteDocumentWithTokenMutationSchema = z.infer<
|
||||
typeof ZCompleteDocumentWithTokenMutationSchema
|
||||
>;
|
||||
|
||||
export const ZRemoveTemplateSignerMutationSchema = z.object({
|
||||
templateId: z.number(),
|
||||
teamId: z.number().optional(),
|
||||
recipientId: z.number(),
|
||||
});
|
||||
|
||||
export type TRemoveTemplateSignerMutationSchema = z.infer<
|
||||
typeof ZRemoveTemplateSignerMutationSchema
|
||||
>;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
import React, { useId, useMemo, useState } from 'react';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, msg } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
@@ -13,13 +11,10 @@ import { useSession } from 'next-auth/react';
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
|
||||
import { useLimits } from '@documenso/ee/server-only/limits/provider/client';
|
||||
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
|
||||
import { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';
|
||||
import { nanoid } from '@documenso/lib/universal/id';
|
||||
import type { Field, Recipient } from '@documenso/prisma/client';
|
||||
import { RecipientRole, SendStatus } from '@documenso/prisma/client';
|
||||
import type { DocumentWithDetails } from '@documenso/prisma/types/document';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out';
|
||||
import { RecipientActionAuthSelect } from '@documenso/ui/components/recipient/recipient-action-auth-select';
|
||||
import { RecipientRoleSelect } from '@documenso/ui/components/recipient/recipient-role-select';
|
||||
@@ -46,70 +41,32 @@ import type { DocumentFlowStep } from './types';
|
||||
|
||||
export type AddSignersFormProps = {
|
||||
documentFlow: DocumentFlowStep;
|
||||
document: DocumentWithDetails;
|
||||
recipients: Recipient[];
|
||||
fields: Field[];
|
||||
isDocumentEnterprise: boolean;
|
||||
onSubmit: (_data: TAddSignersFormSchema) => void;
|
||||
isDocumentPdfLoaded: boolean;
|
||||
teamId?: number;
|
||||
};
|
||||
|
||||
export const AddSignersFormPartial = ({
|
||||
documentFlow,
|
||||
document,
|
||||
recipients,
|
||||
fields,
|
||||
isDocumentEnterprise,
|
||||
onSubmit,
|
||||
isDocumentPdfLoaded,
|
||||
teamId,
|
||||
}: AddSignersFormProps) => {
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
const { remaining } = useLimits();
|
||||
const { data: session } = useSession();
|
||||
const router = useRouter();
|
||||
|
||||
const user = session?.user;
|
||||
|
||||
const initialId = useId();
|
||||
const utils = trpc.useUtils();
|
||||
|
||||
const { currentStep, totalSteps, previousStep } = useStep();
|
||||
|
||||
const { mutateAsync: addSigners } = trpc.recipient.addSigners.useMutation({
|
||||
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
||||
onSuccess: (newRecipients) => {
|
||||
utils.document.getDocumentWithDetailsById.setData(
|
||||
{
|
||||
id: document.id,
|
||||
teamId,
|
||||
},
|
||||
(oldData) => ({ ...(oldData || document), Recipient: newRecipients }),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const { mutateAsync: deleteSigner } = trpc.recipient.removeSigner.useMutation({
|
||||
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
||||
onSuccess: (deletedRecipient) => {
|
||||
utils.document.getDocumentWithDetailsById.setData(
|
||||
{
|
||||
id: document.id,
|
||||
teamId,
|
||||
},
|
||||
(oldData) => {
|
||||
if (!oldData) return document;
|
||||
return {
|
||||
...oldData,
|
||||
Recipient: oldData.Recipient.filter((r) => r.id !== deletedRecipient.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const form = useForm<TAddSignersFormSchema>({
|
||||
resolver: zodResolver(ZAddSignersFormSchema),
|
||||
defaultValues: {
|
||||
@@ -199,11 +156,22 @@ export const AddSignersFormPartial = ({
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
The self-signer is automatically saved on blur
|
||||
since the email input is focused after adding the self-signer.
|
||||
When the user clicks outside the input, the self-signer is saved in the db.
|
||||
*/
|
||||
const onRemoveSigner = (index: number) => {
|
||||
const signer = signers[index];
|
||||
|
||||
if (hasBeenSentToRecipientId(signer.nativeId)) {
|
||||
toast({
|
||||
title: _(msg`Cannot remove signer`),
|
||||
description: _(msg`This signer has already received the document.`),
|
||||
variant: 'destructive',
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
removeSigner(index);
|
||||
};
|
||||
|
||||
const onAddSelfSigner = () => {
|
||||
if (emptySignerIndex !== -1) {
|
||||
setValue(`signers.${emptySignerIndex}.name`, user?.name ?? '');
|
||||
@@ -225,72 +193,6 @@ export const AddSignersFormPartial = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleOnBlur = async (index: number) => {
|
||||
try {
|
||||
const currentSigner = form.getValues(`signers.${index}`);
|
||||
|
||||
if (!currentSigner.email) {
|
||||
return;
|
||||
}
|
||||
|
||||
await addSigners({
|
||||
documentId: document.id,
|
||||
teamId: teamId,
|
||||
signers: form.getValues('signers').map((signer) => ({
|
||||
...signer,
|
||||
actionAuth: signer.actionAuth || null,
|
||||
})),
|
||||
});
|
||||
|
||||
const isNewSigner = !currentSigner.nativeId;
|
||||
|
||||
toast({
|
||||
title: isNewSigner ? 'Signer added' : 'Signer updated',
|
||||
description: isNewSigner
|
||||
? 'The signer has been added to the document.'
|
||||
: 'The signer information has been updated.',
|
||||
});
|
||||
|
||||
router.refresh();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'An error occurred while updating the document recipient.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveSigner = async (index: number) => {
|
||||
const signer = signers[index];
|
||||
|
||||
if (hasBeenSentToRecipientId(signer.nativeId)) {
|
||||
toast({
|
||||
title: 'Cannot remove signer',
|
||||
description: 'This signer has already received the document.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
removeSigner(index);
|
||||
|
||||
if (signer.nativeId) {
|
||||
await deleteSigner({
|
||||
documentId: document.id,
|
||||
teamId: teamId,
|
||||
recipientId: signer.nativeId,
|
||||
});
|
||||
|
||||
toast({
|
||||
title: 'Signer removed',
|
||||
description: 'The signer has been removed from the document.',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DocumentFlowFormContainerHeader
|
||||
@@ -338,7 +240,6 @@ export const AddSignersFormPartial = ({
|
||||
{...field}
|
||||
disabled={isSubmitting || hasBeenSentToRecipientId(signer.nativeId)}
|
||||
onKeyDown={onKeyDown}
|
||||
onBlur={() => void handleOnBlur(index)}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@@ -365,7 +266,6 @@ export const AddSignersFormPartial = ({
|
||||
{...field}
|
||||
disabled={isSubmitting || hasBeenSentToRecipientId(signer.nativeId)}
|
||||
onKeyDown={onKeyDown}
|
||||
onBlur={() => void handleOnBlur(index)}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@@ -419,7 +319,7 @@ export const AddSignersFormPartial = ({
|
||||
hasBeenSentToRecipientId(signer.nativeId) ||
|
||||
signers.length === 1
|
||||
}
|
||||
onClick={() => void handleRemoveSigner(index)}
|
||||
onClick={() => onRemoveSigner(index)}
|
||||
>
|
||||
<Trash className="h-5 w-5" />
|
||||
</button>
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, msg } from '@lingui/macro';
|
||||
import { Loader } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
|
||||
import type { Field, Recipient } from '@documenso/prisma/client';
|
||||
import { DocumentStatus } from '@documenso/prisma/client';
|
||||
import type { DocumentWithData } from '@documenso/prisma/types/document-with-data';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { DocumentSendEmailMessageHelper } from '@documenso/ui/components/document/document-send-email-message-helper';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
import { Button } from '../button';
|
||||
import { FormErrorMessage } from '../form/form-error-message';
|
||||
import { Input } from '../input';
|
||||
import { Label } from '../label';
|
||||
@@ -45,6 +54,7 @@ export const AddSubjectFormPartial = ({
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<TAddSubjectFormSchema>({
|
||||
defaultValues: {
|
||||
@@ -56,6 +66,111 @@ export const AddSubjectFormPartial = ({
|
||||
resolver: zodResolver(ZAddSubjectFormSchema),
|
||||
});
|
||||
|
||||
const [oldEmailData, setOldEmailData] = useState<{ subject: string; message: string } | null>(
|
||||
document.documentMeta
|
||||
? {
|
||||
subject: document.documentMeta.subject ?? '',
|
||||
message: document.documentMeta.message ?? '',
|
||||
}
|
||||
: null,
|
||||
);
|
||||
|
||||
const [changedFields, setChangedFields] = useState<{ subject: boolean; message: boolean }>({
|
||||
subject: false,
|
||||
message: false,
|
||||
});
|
||||
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
const utils = trpc.useUtils();
|
||||
|
||||
const { mutateAsync: setEmailSettingsForDocument } =
|
||||
trpc.document.setDocumentEmailSettings.useMutation({
|
||||
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
||||
onSuccess: () => {
|
||||
const data = utils.document.getDocumentWithDetailsById.getData({
|
||||
id: document.id,
|
||||
});
|
||||
|
||||
setOldEmailData({
|
||||
subject: data?.documentMeta?.subject ?? '',
|
||||
message: data?.documentMeta?.message ?? '',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const handleOnBlur = async (field: 'subject' | 'message', value: string) => {
|
||||
if (value == oldEmailData?.[field]) return;
|
||||
|
||||
try {
|
||||
await setEmailSettingsForDocument({
|
||||
documentId: document.id,
|
||||
[field]: value,
|
||||
});
|
||||
|
||||
setChangedFields((prev) => ({ ...prev, [field]: true }));
|
||||
router.refresh();
|
||||
|
||||
toast({
|
||||
title: 'Email settings updated',
|
||||
description: 'The email settings for the document have been updated.',
|
||||
duration: 5000,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'An error occurred while updating the email settings.',
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleUndoButton = async (field: 'subject' | 'message') => {
|
||||
if (!oldEmailData) return;
|
||||
|
||||
try {
|
||||
await setEmailSettingsForDocument({
|
||||
documentId: document.id,
|
||||
[field]: oldEmailData[field],
|
||||
});
|
||||
|
||||
setValue(`meta.${field}`, oldEmailData[field]);
|
||||
|
||||
setOldEmailData((prev) => (prev ? { ...prev, [field]: undefined } : null));
|
||||
setChangedFields((prev) => ({ ...prev, [field]: false }));
|
||||
router.refresh();
|
||||
|
||||
toast({
|
||||
title: 'Change reverted',
|
||||
description: `The latest change to the ${field} has been reverted.`,
|
||||
duration: 5000,
|
||||
});
|
||||
|
||||
if (oldEmailData.subject === undefined && oldEmailData.message === undefined) {
|
||||
setOldEmailData(null);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'An error occurred while undoing the latest change',
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
setChangedFields({ subject: false, message: false });
|
||||
}, 5000);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
}, [oldEmailData]);
|
||||
|
||||
const onFormSubmit = handleSubmit(onSubmit);
|
||||
const { currentStep, totalSteps, previousStep } = useStep();
|
||||
|
||||
@@ -65,6 +180,7 @@ export const AddSubjectFormPartial = ({
|
||||
title={documentFlow.title}
|
||||
description={documentFlow.description}
|
||||
/>
|
||||
|
||||
<DocumentFlowFormContainerContent>
|
||||
<div className="flex flex-col">
|
||||
{isDocumentPdfLoaded &&
|
||||
@@ -84,9 +200,27 @@ export const AddSubjectFormPartial = ({
|
||||
id="subject"
|
||||
className="bg-background mt-2"
|
||||
disabled={isSubmitting}
|
||||
{...register('meta.subject')}
|
||||
{...register('meta.subject', {
|
||||
onBlur: (event) => {
|
||||
void handleOnBlur('subject', event.target.value);
|
||||
},
|
||||
})}
|
||||
/>
|
||||
|
||||
{changedFields.subject && oldEmailData && (
|
||||
<div className="mt-2 flex items-center">
|
||||
<Button
|
||||
className="-ml-2"
|
||||
size="sm"
|
||||
variant="link"
|
||||
onClick={() => void handleUndoButton('subject')}
|
||||
>
|
||||
<span className="text-xs">Undo change</span>
|
||||
<Loader className="ml-1 h-4 w-4 animate-spin text-gray-500" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<FormErrorMessage className="mt-2" error={errors.meta?.subject} />
|
||||
</div>
|
||||
|
||||
@@ -101,15 +235,32 @@ export const AddSubjectFormPartial = ({
|
||||
id="message"
|
||||
className="bg-background mt-2 h-32 resize-none"
|
||||
disabled={isSubmitting}
|
||||
{...register('meta.message')}
|
||||
{...register('meta.message', {
|
||||
onBlur: (event) => {
|
||||
void handleOnBlur('message', event.target.value);
|
||||
},
|
||||
})}
|
||||
/>
|
||||
|
||||
{changedFields.message && oldEmailData && (
|
||||
<div className="mt-2 flex items-center">
|
||||
<Button
|
||||
className="-ml-2"
|
||||
size="sm"
|
||||
variant="link"
|
||||
onClick={() => void handleUndoButton('message')}
|
||||
>
|
||||
<span className="text-xs">Undo change</span>
|
||||
<Loader className="ml-1 h-4 w-4 animate-spin text-gray-500" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<FormErrorMessage
|
||||
className="mt-2"
|
||||
error={typeof errors.meta?.message !== 'string' ? errors.meta?.message : undefined}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DocumentSendEmailMessageHelper />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
import React, { useEffect, useId, useMemo, useState } from 'react';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, msg } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
@@ -12,14 +10,11 @@ import { Link2Icon, Plus, Trash } from 'lucide-react';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
|
||||
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
|
||||
import { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';
|
||||
import { nanoid } from '@documenso/lib/universal/id';
|
||||
import { generateRecipientPlaceholder } from '@documenso/lib/utils/templates';
|
||||
import type { TemplateDirectLink } from '@documenso/prisma/client';
|
||||
import { type Field, type Recipient, RecipientRole } from '@documenso/prisma/client';
|
||||
import type { TemplateWithDetails } from '@documenso/prisma/types/template';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out';
|
||||
import { RecipientActionAuthSelect } from '@documenso/ui/components/recipient/recipient-action-auth-select';
|
||||
import { RecipientRoleSelect } from '@documenso/ui/components/recipient/recipient-role-select';
|
||||
@@ -27,7 +22,6 @@ import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { FormErrorMessage } from '@documenso/ui/primitives/form/form-error-message';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
import { Checkbox } from '../checkbox';
|
||||
import {
|
||||
@@ -52,7 +46,6 @@ export type AddTemplatePlaceholderRecipientsFormProps = {
|
||||
templateDirectLink: TemplateDirectLink | null;
|
||||
isEnterprise: boolean;
|
||||
isDocumentPdfLoaded: boolean;
|
||||
template: TemplateWithDetails;
|
||||
onSubmit: (_data: TAddTemplatePlacholderRecipientsFormSchema) => void;
|
||||
};
|
||||
|
||||
@@ -64,10 +57,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
fields,
|
||||
isDocumentPdfLoaded,
|
||||
onSubmit,
|
||||
template,
|
||||
}: AddTemplatePlaceholderRecipientsFormProps) => {
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
const initialId = useId();
|
||||
|
||||
const { _ } = useLingui();
|
||||
@@ -81,38 +71,6 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
|
||||
const { currentStep, totalSteps, previousStep } = useStep();
|
||||
|
||||
const utils = trpc.useUtils();
|
||||
|
||||
const { mutateAsync: addTemplateSigners } = trpc.recipient.addTemplateSigners.useMutation({
|
||||
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
||||
onSuccess: (newData) => {
|
||||
utils.template.getTemplateWithDetailsById.setData(
|
||||
{
|
||||
id: template.id,
|
||||
},
|
||||
(oldData) => ({ ...(oldData || template), ...newData }),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const { mutateAsync: removeTemplateSigner } = trpc.recipient.removeTemplateSigner.useMutation({
|
||||
...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
||||
onSuccess: (deletedRecipient) => {
|
||||
utils.template.getTemplateWithDetailsById.setData(
|
||||
{
|
||||
id: template.id,
|
||||
},
|
||||
(oldData) => {
|
||||
if (!oldData) return template;
|
||||
return {
|
||||
...oldData,
|
||||
recipients: oldData.Recipient.filter((r) => r.id !== deletedRecipient.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const generateDefaultFormSigners = () => {
|
||||
if (recipients.length === 0) {
|
||||
return [
|
||||
@@ -200,6 +158,10 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
setPlaceholderRecipientCount((count) => count + 1);
|
||||
};
|
||||
|
||||
const onRemoveSigner = (index: number) => {
|
||||
removeSigner(index);
|
||||
};
|
||||
|
||||
const isSignerDirectRecipient = (
|
||||
signer: TAddTemplatePlacholderRecipientsFormSchema['signers'][number],
|
||||
): boolean => {
|
||||
@@ -209,54 +171,6 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
);
|
||||
};
|
||||
|
||||
const handleOnBlur = async (index: number) => {
|
||||
try {
|
||||
const currentSigner = form.getValues(`signers.${index}`);
|
||||
|
||||
if (!currentSigner.email) {
|
||||
return;
|
||||
}
|
||||
|
||||
await addTemplateSigners({
|
||||
templateId: template.id,
|
||||
teamId: template.teamId ?? undefined,
|
||||
signers: form.getValues('signers'),
|
||||
});
|
||||
|
||||
router.refresh();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'An error occurred while updating the template recipient.',
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveSigner = async (index: number) => {
|
||||
const signer = signers[index];
|
||||
|
||||
if (!signer) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeSigner(index);
|
||||
|
||||
if (signer.nativeId) {
|
||||
await removeTemplateSigner({
|
||||
templateId: template.id,
|
||||
teamId: template.teamId ?? undefined,
|
||||
recipientId: signer.nativeId,
|
||||
});
|
||||
|
||||
toast({
|
||||
title: 'Signer removed',
|
||||
description: 'The signer has been removed from the document.',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DocumentFlowFormContainerHeader
|
||||
@@ -302,8 +216,12 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
type="email"
|
||||
placeholder={_(msg`Email`)}
|
||||
{...field}
|
||||
disabled={field.disabled || isSubmitting}
|
||||
onBlur={() => void handleOnBlur(index)}
|
||||
disabled={
|
||||
field.disabled ||
|
||||
isSubmitting ||
|
||||
signers[index].email === user?.email ||
|
||||
isSignerDirectRecipient(signer)
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@@ -332,8 +250,12 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
<Input
|
||||
placeholder={_(msg`Name`)}
|
||||
{...field}
|
||||
disabled={field.disabled || isSubmitting}
|
||||
onBlur={() => void handleOnBlur(index)}
|
||||
disabled={
|
||||
field.disabled ||
|
||||
isSubmitting ||
|
||||
signers[index].email === user?.email ||
|
||||
isSignerDirectRecipient(signer)
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@@ -369,10 +291,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
<FormControl>
|
||||
<RecipientRoleSelect
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
void handleOnBlur(index);
|
||||
}}
|
||||
onValueChange={field.onChange}
|
||||
disabled={isSubmitting}
|
||||
hideCCRecipients={isSignerDirectRecipient(signer)}
|
||||
/>
|
||||
@@ -406,7 +325,7 @@ export const AddTemplatePlaceholderRecipientsFormPartial = ({
|
||||
type="button"
|
||||
className="col-span-1 mt-auto inline-flex h-10 w-10 items-center justify-center text-slate-500 hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
disabled={isSubmitting || signers.length === 1}
|
||||
onClick={() => void handleRemoveSigner(index)}
|
||||
onClick={() => onRemoveSigner(index)}
|
||||
>
|
||||
<Trash className="h-5 w-5" />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user