mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 00:03:33 +10:00
fix: duplicate webhook calls on document complete (#1721)
Fix webhooks being sent twice due to duplicate frontend calls Updated the assistant confirmation dialog so the next signer is always visible (if dictate is enabled). Because if the form is invalid (due to no name) there is no visual queue that the form is invalid (since it's hidden) ## Notes Didn't bother to remove the weird assistants form since it currently works for now  ## Tests - Currently running locally - Tested webhooks via network tab and via webhook.site
This commit is contained in:
@ -1,5 +1,3 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
@ -57,8 +55,6 @@ export function AssistantConfirmationDialog({
|
|||||||
allowDictateNextSigner = false,
|
allowDictateNextSigner = false,
|
||||||
defaultNextSigner,
|
defaultNextSigner,
|
||||||
}: ConfirmationDialogProps) {
|
}: ConfirmationDialogProps) {
|
||||||
const [isEditingNextSigner, setIsEditingNextSigner] = useState(false);
|
|
||||||
|
|
||||||
const form = useForm<TNextSignerFormSchema>({
|
const form = useForm<TNextSignerFormSchema>({
|
||||||
resolver: zodResolver(ZNextSignerFormSchema),
|
resolver: zodResolver(ZNextSignerFormSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@ -68,7 +64,7 @@ export function AssistantConfirmationDialog({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onOpenChange = () => {
|
const onOpenChange = () => {
|
||||||
if (form.formState.isSubmitting) {
|
if (isSubmitting) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,32 +73,25 @@ export function AssistantConfirmationDialog({
|
|||||||
email: defaultNextSigner?.email ?? '',
|
email: defaultNextSigner?.email ?? '',
|
||||||
});
|
});
|
||||||
|
|
||||||
setIsEditingNextSigner(false);
|
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFormSubmit = async (data: TNextSignerFormSchema) => {
|
const handleSubmit = () => {
|
||||||
if (allowDictateNextSigner && data.name && data.email) {
|
// Validate the form and submit it if dictate signer is enabled.
|
||||||
await onConfirm({
|
if (allowDictateNextSigner) {
|
||||||
name: data.name,
|
void form.handleSubmit(onConfirm)();
|
||||||
email: data.email,
|
return;
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await onConfirm();
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const isNextSignerValid = !allowDictateNextSigner || (form.watch('name') && form.watch('email'));
|
onConfirm();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={isOpen} onOpenChange={onOpenChange}>
|
<Dialog open={isOpen} onOpenChange={onOpenChange}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(onFormSubmit)}>
|
<form>
|
||||||
<fieldset
|
<fieldset disabled={isSubmitting} className="border-none p-0">
|
||||||
disabled={form.formState.isSubmitting || isSubmitting}
|
|
||||||
className="border-none p-0"
|
|
||||||
>
|
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
<Trans>Complete Document</Trans>
|
<Trans>Complete Document</Trans>
|
||||||
@ -118,71 +107,53 @@ export function AssistantConfirmationDialog({
|
|||||||
|
|
||||||
<div className="mt-4 flex flex-col gap-4">
|
<div className="mt-4 flex flex-col gap-4">
|
||||||
{allowDictateNextSigner && (
|
{allowDictateNextSigner && (
|
||||||
<div className="space-y-4">
|
<div className="my-2">
|
||||||
{!isEditingNextSigner && (
|
<p className="text-muted-foreground mb-1 text-sm font-semibold">
|
||||||
<div>
|
The next recipient to sign this document will be{' '}
|
||||||
<p className="text-muted-foreground text-sm">
|
</p>
|
||||||
The next recipient to sign this document will be{' '}
|
|
||||||
<span className="font-semibold">{form.watch('name')}</span> (
|
|
||||||
<span className="font-semibold">{form.watch('email')}</span>).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<Button
|
<div className="flex flex-col gap-4 rounded-xl border p-4 md:flex-row">
|
||||||
type="button"
|
<FormField
|
||||||
className="mt-2"
|
control={form.control}
|
||||||
variant="outline"
|
name="name"
|
||||||
size="sm"
|
render={({ field }) => (
|
||||||
onClick={() => setIsEditingNextSigner((prev) => !prev)}
|
<FormItem className="flex-1">
|
||||||
>
|
<FormLabel>
|
||||||
<Trans>Update Recipient</Trans>
|
<Trans>Name</Trans>
|
||||||
</Button>
|
</FormLabel>
|
||||||
</div>
|
<FormControl>
|
||||||
)}
|
<Input
|
||||||
|
{...field}
|
||||||
|
className="mt-2"
|
||||||
|
placeholder="Enter the next signer's name"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
{isEditingNextSigner && (
|
<FormField
|
||||||
<div className="flex flex-col gap-4 md:flex-row">
|
control={form.control}
|
||||||
<FormField
|
name="email"
|
||||||
control={form.control}
|
render={({ field }) => (
|
||||||
name="name"
|
<FormItem className="flex-1">
|
||||||
render={({ field }) => (
|
<FormLabel>
|
||||||
<FormItem className="flex-1">
|
<Trans>Email</Trans>
|
||||||
<FormLabel>
|
</FormLabel>
|
||||||
<Trans>Name</Trans>
|
<FormControl>
|
||||||
</FormLabel>
|
<Input
|
||||||
<FormControl>
|
{...field}
|
||||||
<Input
|
type="email"
|
||||||
{...field}
|
className="mt-2"
|
||||||
className="mt-2"
|
placeholder="Enter the next signer's email"
|
||||||
placeholder="Enter the next signer's name"
|
/>
|
||||||
/>
|
</FormControl>
|
||||||
</FormControl>
|
<FormMessage />
|
||||||
<FormMessage />
|
</FormItem>
|
||||||
</FormItem>
|
)}
|
||||||
)}
|
/>
|
||||||
/>
|
</div>
|
||||||
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="email"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="flex-1">
|
|
||||||
<FormLabel>
|
|
||||||
<Trans>Email</Trans>
|
|
||||||
</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
type="email"
|
|
||||||
className="mt-2"
|
|
||||||
placeholder="Enter the next signer's email"
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -190,27 +161,17 @@ export function AssistantConfirmationDialog({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogFooter className="mt-4">
|
<DialogFooter className="mt-4">
|
||||||
<Button
|
<Button type="button" variant="secondary" onClick={onClose} disabled={isSubmitting}>
|
||||||
type="button"
|
|
||||||
variant="secondary"
|
|
||||||
onClick={onClose}
|
|
||||||
disabled={form.formState.isSubmitting}
|
|
||||||
>
|
|
||||||
<Trans>Cancel</Trans>
|
<Trans>Cancel</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="button"
|
||||||
variant={hasUninsertedFields ? 'destructive' : 'default'}
|
variant={hasUninsertedFields ? 'destructive' : 'default'}
|
||||||
disabled={form.formState.isSubmitting || !isNextSignerValid}
|
disabled={isSubmitting}
|
||||||
loading={form.formState.isSubmitting}
|
onClick={handleSubmit}
|
||||||
|
loading={isSubmitting}
|
||||||
>
|
>
|
||||||
{form.formState.isSubmitting ? (
|
{hasUninsertedFields ? <Trans>Proceed</Trans> : <Trans>Continue</Trans>}
|
||||||
<Trans>Submitting...</Trans>
|
|
||||||
) : hasUninsertedFields ? (
|
|
||||||
<Trans>Proceed</Trans>
|
|
||||||
) : (
|
|
||||||
<Trans>Continue</Trans>
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
import { useId, useMemo, useState } from 'react';
|
import { useId, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
|
||||||
import { msg } from '@lingui/core/macro';
|
import { msg } from '@lingui/core/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
import { type Field, FieldType, type Recipient, RecipientRole } from '@prisma/client';
|
import { type Field, FieldType, type Recipient, RecipientRole } from '@prisma/client';
|
||||||
import { Controller, useForm } from 'react-hook-form';
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { z } from 'zod';
|
|
||||||
|
|
||||||
import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics';
|
import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics';
|
||||||
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
import { useOptionalSession } from '@documenso/lib/client-only/providers/session';
|
||||||
@ -33,13 +31,6 @@ import {
|
|||||||
import { DocumentSigningCompleteDialog } from './document-signing-complete-dialog';
|
import { DocumentSigningCompleteDialog } from './document-signing-complete-dialog';
|
||||||
import { useRequiredDocumentSigningContext } from './document-signing-provider';
|
import { useRequiredDocumentSigningContext } from './document-signing-provider';
|
||||||
|
|
||||||
export const ZSigningFormSchema = z.object({
|
|
||||||
name: z.string().min(1, 'Name is required').optional(),
|
|
||||||
email: z.string().email('Invalid email address').optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export type TSigningFormSchema = z.infer<typeof ZSigningFormSchema>;
|
|
||||||
|
|
||||||
export type DocumentSigningFormProps = {
|
export type DocumentSigningFormProps = {
|
||||||
document: DocumentAndSender;
|
document: DocumentAndSender;
|
||||||
recipient: Recipient;
|
recipient: Recipient;
|
||||||
@ -76,8 +67,11 @@ export const DocumentSigningForm = ({
|
|||||||
const [isConfirmationDialogOpen, setIsConfirmationDialogOpen] = useState(false);
|
const [isConfirmationDialogOpen, setIsConfirmationDialogOpen] = useState(false);
|
||||||
const [isAssistantSubmitting, setIsAssistantSubmitting] = useState(false);
|
const [isAssistantSubmitting, setIsAssistantSubmitting] = useState(false);
|
||||||
|
|
||||||
const { mutateAsync: completeDocumentWithToken } =
|
const {
|
||||||
trpc.recipient.completeDocumentWithToken.useMutation();
|
mutateAsync: completeDocumentWithToken,
|
||||||
|
isPending,
|
||||||
|
isSuccess,
|
||||||
|
} = trpc.recipient.completeDocumentWithToken.useMutation();
|
||||||
|
|
||||||
const assistantForm = useForm<{ selectedSignerId: number | undefined }>({
|
const assistantForm = useForm<{ selectedSignerId: number | undefined }>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@ -85,12 +79,8 @@ export const DocumentSigningForm = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { handleSubmit, formState } = useForm<TSigningFormSchema>({
|
|
||||||
resolver: zodResolver(ZSigningFormSchema),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keep the loading state going if successful since the redirect may take some time.
|
// Keep the loading state going if successful since the redirect may take some time.
|
||||||
const isSubmitting = formState.isSubmitting || formState.isSubmitSuccessful;
|
const isSubmitting = isPending || isSuccess;
|
||||||
|
|
||||||
const fieldsRequiringValidation = useMemo(
|
const fieldsRequiringValidation = useMemo(
|
||||||
() => fields.filter(isFieldUnsignedAndRequired),
|
() => fields.filter(isFieldUnsignedAndRequired),
|
||||||
@ -112,34 +102,6 @@ export const DocumentSigningForm = ({
|
|||||||
validateFieldsInserted(fieldsRequiringValidation);
|
validateFieldsInserted(fieldsRequiringValidation);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFormSubmit = async (data: TSigningFormSchema) => {
|
|
||||||
try {
|
|
||||||
setValidateUninsertedFields(true);
|
|
||||||
|
|
||||||
const isFieldsValid = validateFieldsInserted(fieldsRequiringValidation);
|
|
||||||
|
|
||||||
if (!isFieldsValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextSigner =
|
|
||||||
data.email && data.name
|
|
||||||
? {
|
|
||||||
email: data.email,
|
|
||||||
name: data.name,
|
|
||||||
}
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
await completeDocument(undefined, nextSigner);
|
|
||||||
} catch (error) {
|
|
||||||
toast({
|
|
||||||
title: 'Error',
|
|
||||||
description: error instanceof Error ? error.message : 'An error occurred while signing',
|
|
||||||
variant: 'destructive',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onAssistantFormSubmit = () => {
|
const onAssistantFormSubmit = () => {
|
||||||
if (uninsertedRecipientFields.length > 0) {
|
if (uninsertedRecipientFields.length > 0) {
|
||||||
return;
|
return;
|
||||||
@ -214,8 +176,6 @@ export const DocumentSigningForm = ({
|
|||||||
: undefined;
|
: undefined;
|
||||||
}, [document.documentMeta?.signingOrder, allRecipients, recipient.id]);
|
}, [document.documentMeta?.signingOrder, allRecipients, recipient.id]);
|
||||||
|
|
||||||
console.log('nextRecipient', nextRecipient);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@ -356,9 +316,8 @@ export const DocumentSigningForm = ({
|
|||||||
className="w-full"
|
className="w-full"
|
||||||
size="lg"
|
size="lg"
|
||||||
loading={isAssistantSubmitting}
|
loading={isAssistantSubmitting}
|
||||||
disabled={isAssistantSubmitting || uninsertedRecipientFields.length > 0}
|
|
||||||
>
|
>
|
||||||
{isAssistantSubmitting ? <Trans>Submitting...</Trans> : <Trans>Continue</Trans>}
|
<Trans>Continue</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -381,7 +340,7 @@ export const DocumentSigningForm = ({
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
<div>
|
||||||
<p className="text-muted-foreground mt-2 text-sm">
|
<p className="text-muted-foreground mt-2 text-sm">
|
||||||
{recipient.role === RecipientRole.APPROVER && !hasSignatureField ? (
|
{recipient.role === RecipientRole.APPROVER && !hasSignatureField ? (
|
||||||
<Trans>Please review the document before approving.</Trans>
|
<Trans>Please review the document before approving.</Trans>
|
||||||
@ -463,7 +422,7 @@ export const DocumentSigningForm = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -341,9 +341,6 @@ test('[NEXT_RECIPIENT_DICTATION]: should allow assistant to dictate next signer'
|
|||||||
await expect(page.getByRole('dialog')).toBeVisible();
|
await expect(page.getByRole('dialog')).toBeVisible();
|
||||||
await expect(page.getByText('The next recipient to sign this document will be')).toBeVisible();
|
await expect(page.getByText('The next recipient to sign this document will be')).toBeVisible();
|
||||||
|
|
||||||
// Update next recipient
|
|
||||||
await page.locator('button').filter({ hasText: 'Update Recipient' }).click();
|
|
||||||
|
|
||||||
// Use dialog context to ensure we're targeting the correct form fields
|
// Use dialog context to ensure we're targeting the correct form fields
|
||||||
const dialog = page.getByRole('dialog');
|
const dialog = page.getByRole('dialog');
|
||||||
await dialog.getByLabel('Name').fill('New Signer');
|
await dialog.getByLabel('Name').fill('New Signer');
|
||||||
|
|||||||
@ -148,6 +148,10 @@ test('[TEAMS]: check signature modes work for templates', async ({ page }) => {
|
|||||||
|
|
||||||
await page.getByRole('button', { name: 'Update' }).first().click();
|
await page.getByRole('button', { name: 'Update' }).first().click();
|
||||||
|
|
||||||
|
// Wait for finish
|
||||||
|
await page.getByText('Document preferences updated').waitFor({ state: 'visible' });
|
||||||
|
await page.getByTestId('toast-close').click();
|
||||||
|
|
||||||
const template = await seedTeamTemplateWithMeta(team);
|
const template = await seedTeamTemplateWithMeta(team);
|
||||||
|
|
||||||
await page.goto(`/t/${team.url}/templates/${template.id}`);
|
await page.goto(`/t/${team.url}/templates/${template.id}`);
|
||||||
|
|||||||
@ -5049,11 +5049,6 @@ msgstr "Schritt <0>{step} von {maxStep}</0>"
|
|||||||
msgid "Subject <0>(Optional)</0>"
|
msgid "Subject <0>(Optional)</0>"
|
||||||
msgstr "Betreff <0>(Optional)</0>"
|
msgstr "Betreff <0>(Optional)</0>"
|
||||||
|
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-form.tsx
|
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Submitting..."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/remix/app/components/general/billing-plans.tsx
|
#: apps/remix/app/components/general/billing-plans.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -6121,7 +6116,6 @@ msgstr "Profil aktualisieren"
|
|||||||
|
|
||||||
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Update Recipient"
|
msgid "Update Recipient"
|
||||||
msgstr "Empfänger aktualisieren"
|
msgstr "Empfänger aktualisieren"
|
||||||
|
|
||||||
|
|||||||
@ -5044,11 +5044,6 @@ msgstr "Step <0>{step} of {maxStep}</0>"
|
|||||||
msgid "Subject <0>(Optional)</0>"
|
msgid "Subject <0>(Optional)</0>"
|
||||||
msgstr "Subject <0>(Optional)</0>"
|
msgstr "Subject <0>(Optional)</0>"
|
||||||
|
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-form.tsx
|
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Submitting..."
|
|
||||||
msgstr "Submitting..."
|
|
||||||
|
|
||||||
#: apps/remix/app/components/general/billing-plans.tsx
|
#: apps/remix/app/components/general/billing-plans.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Subscribe"
|
msgstr "Subscribe"
|
||||||
@ -6118,7 +6113,6 @@ msgstr "Update profile"
|
|||||||
|
|
||||||
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Update Recipient"
|
msgid "Update Recipient"
|
||||||
msgstr "Update Recipient"
|
msgstr "Update Recipient"
|
||||||
|
|
||||||
|
|||||||
@ -5049,11 +5049,6 @@ msgstr "Paso <0>{step} de {maxStep}</0>"
|
|||||||
msgid "Subject <0>(Optional)</0>"
|
msgid "Subject <0>(Optional)</0>"
|
||||||
msgstr "Asunto <0>(Opcional)</0>"
|
msgstr "Asunto <0>(Opcional)</0>"
|
||||||
|
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-form.tsx
|
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Submitting..."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/remix/app/components/general/billing-plans.tsx
|
#: apps/remix/app/components/general/billing-plans.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -6121,7 +6116,6 @@ msgstr "Actualizar perfil"
|
|||||||
|
|
||||||
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Update Recipient"
|
msgid "Update Recipient"
|
||||||
msgstr "Actualizar destinatario"
|
msgstr "Actualizar destinatario"
|
||||||
|
|
||||||
|
|||||||
@ -5049,11 +5049,6 @@ msgstr "Étape <0>{step} sur {maxStep}</0>"
|
|||||||
msgid "Subject <0>(Optional)</0>"
|
msgid "Subject <0>(Optional)</0>"
|
||||||
msgstr "Objet <0>(Optionnel)</0>"
|
msgstr "Objet <0>(Optionnel)</0>"
|
||||||
|
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-form.tsx
|
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Submitting..."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/remix/app/components/general/billing-plans.tsx
|
#: apps/remix/app/components/general/billing-plans.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -6121,7 +6116,6 @@ msgstr "Mettre à jour le profil"
|
|||||||
|
|
||||||
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Update Recipient"
|
msgid "Update Recipient"
|
||||||
msgstr "Mettre à jour le destinataire"
|
msgstr "Mettre à jour le destinataire"
|
||||||
|
|
||||||
|
|||||||
@ -5049,11 +5049,6 @@ msgstr "Passo <0>{step} di {maxStep}</0>"
|
|||||||
msgid "Subject <0>(Optional)</0>"
|
msgid "Subject <0>(Optional)</0>"
|
||||||
msgstr "Oggetto <0>(Opzionale)</0>"
|
msgstr "Oggetto <0>(Opzionale)</0>"
|
||||||
|
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-form.tsx
|
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Submitting..."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/remix/app/components/general/billing-plans.tsx
|
#: apps/remix/app/components/general/billing-plans.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -6121,7 +6116,6 @@ msgstr "Aggiorna profilo"
|
|||||||
|
|
||||||
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Update Recipient"
|
msgid "Update Recipient"
|
||||||
msgstr "Aggiorna destinatario"
|
msgstr "Aggiorna destinatario"
|
||||||
|
|
||||||
|
|||||||
@ -5049,11 +5049,6 @@ msgstr "Krok <0>{step} z {maxStep}</0>"
|
|||||||
msgid "Subject <0>(Optional)</0>"
|
msgid "Subject <0>(Optional)</0>"
|
||||||
msgstr "Temat <0>(Opcjonalnie)</0>"
|
msgstr "Temat <0>(Opcjonalnie)</0>"
|
||||||
|
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-form.tsx
|
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Submitting..."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: apps/remix/app/components/general/billing-plans.tsx
|
#: apps/remix/app/components/general/billing-plans.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -6121,7 +6116,6 @@ msgstr "Zaktualizuj profil"
|
|||||||
|
|
||||||
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
#: apps/remix/app/components/tables/admin-document-recipient-item-table.tsx
|
||||||
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
#: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx
|
||||||
#: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx
|
|
||||||
msgid "Update Recipient"
|
msgid "Update Recipient"
|
||||||
msgstr "Zaktualizuj odbiorcę"
|
msgstr "Zaktualizuj odbiorcę"
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,7 @@ export const updateDocumentRoute = authenticatedProcedure
|
|||||||
redirectUrl: meta.redirectUrl,
|
redirectUrl: meta.redirectUrl,
|
||||||
distributionMethod: meta.distributionMethod,
|
distributionMethod: meta.distributionMethod,
|
||||||
signingOrder: meta.signingOrder,
|
signingOrder: meta.signingOrder,
|
||||||
|
allowDictateNextSigner: meta.allowDictateNextSigner,
|
||||||
emailSettings: meta.emailSettings,
|
emailSettings: meta.emailSettings,
|
||||||
requestMetadata: ctx.metadata,
|
requestMetadata: ctx.metadata,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -78,6 +78,7 @@ const ToastClose = React.forwardRef<
|
|||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<ToastPrimitives.Close
|
<ToastPrimitives.Close
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
data-testid="toast-close"
|
||||||
className={cn(
|
className={cn(
|
||||||
'text-foreground/50 hover:text-foreground absolute right-2 top-2 rounded-md p-1 opacity-100 transition-opacity focus:opacity-100 focus:outline-none focus:ring-2 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 md:opacity-0 group-hover:md:opacity-100',
|
'text-foreground/50 hover:text-foreground absolute right-2 top-2 rounded-md p-1 opacity-100 transition-opacity focus:opacity-100 focus:outline-none focus:ring-2 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 md:opacity-0 group-hover:md:opacity-100',
|
||||||
className,
|
className,
|
||||||
|
|||||||
Reference in New Issue
Block a user