mirror of
https://github.com/documenso/documenso.git
synced 2025-11-14 08:42:12 +10:00
feat: add reminder interval to document settings
This commit is contained in:
@ -175,7 +175,8 @@ export const DocumentEditForm = ({
|
|||||||
|
|
||||||
const onAddSettingsFormSubmit = async (data: TAddSettingsFormSchema) => {
|
const onAddSettingsFormSubmit = async (data: TAddSettingsFormSchema) => {
|
||||||
try {
|
try {
|
||||||
const { timezone, dateFormat, redirectUrl, language, signatureTypes } = data.meta;
|
const { timezone, dateFormat, redirectUrl, language, signatureTypes, reminderInterval } =
|
||||||
|
data.meta;
|
||||||
|
|
||||||
await updateDocument({
|
await updateDocument({
|
||||||
documentId: document.id,
|
documentId: document.id,
|
||||||
@ -194,6 +195,7 @@ export const DocumentEditForm = ({
|
|||||||
typedSignatureEnabled: signatureTypes.includes(DocumentSignatureType.TYPE),
|
typedSignatureEnabled: signatureTypes.includes(DocumentSignatureType.TYPE),
|
||||||
uploadSignatureEnabled: signatureTypes.includes(DocumentSignatureType.UPLOAD),
|
uploadSignatureEnabled: signatureTypes.includes(DocumentSignatureType.UPLOAD),
|
||||||
drawSignatureEnabled: signatureTypes.includes(DocumentSignatureType.DRAW),
|
drawSignatureEnabled: signatureTypes.includes(DocumentSignatureType.DRAW),
|
||||||
|
reminderInterval,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
import type { DocumentDistributionMethod, DocumentSigningOrder } from '@prisma/client';
|
import type {
|
||||||
|
DocumentDistributionMethod,
|
||||||
|
DocumentReminderInterval,
|
||||||
|
DocumentSigningOrder,
|
||||||
|
} from '@prisma/client';
|
||||||
|
|
||||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
|
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
|
||||||
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||||
@ -30,6 +34,7 @@ export type CreateDocumentMetaOptions = {
|
|||||||
uploadSignatureEnabled?: boolean;
|
uploadSignatureEnabled?: boolean;
|
||||||
drawSignatureEnabled?: boolean;
|
drawSignatureEnabled?: boolean;
|
||||||
language?: SupportedLanguageCodes;
|
language?: SupportedLanguageCodes;
|
||||||
|
reminderInterval?: DocumentReminderInterval;
|
||||||
requestMetadata: ApiRequestMetadata;
|
requestMetadata: ApiRequestMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,6 +56,7 @@ export const upsertDocumentMeta = async ({
|
|||||||
uploadSignatureEnabled,
|
uploadSignatureEnabled,
|
||||||
drawSignatureEnabled,
|
drawSignatureEnabled,
|
||||||
language,
|
language,
|
||||||
|
reminderInterval,
|
||||||
requestMetadata,
|
requestMetadata,
|
||||||
}: CreateDocumentMetaOptions) => {
|
}: CreateDocumentMetaOptions) => {
|
||||||
const document = await prisma.document.findFirst({
|
const document = await prisma.document.findFirst({
|
||||||
@ -106,6 +112,7 @@ export const upsertDocumentMeta = async ({
|
|||||||
uploadSignatureEnabled,
|
uploadSignatureEnabled,
|
||||||
drawSignatureEnabled,
|
drawSignatureEnabled,
|
||||||
language,
|
language,
|
||||||
|
reminderInterval,
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
subject,
|
subject,
|
||||||
@ -122,6 +129,7 @@ export const upsertDocumentMeta = async ({
|
|||||||
uploadSignatureEnabled,
|
uploadSignatureEnabled,
|
||||||
drawSignatureEnabled,
|
drawSignatureEnabled,
|
||||||
language,
|
language,
|
||||||
|
reminderInterval,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -56,6 +56,8 @@ export const ZDocumentSchema = DocumentSchema.pick({
|
|||||||
allowDictateNextSigner: true,
|
allowDictateNextSigner: true,
|
||||||
language: true,
|
language: true,
|
||||||
emailSettings: true,
|
emailSettings: true,
|
||||||
|
reminderInterval: true,
|
||||||
|
lastReminderSentAt: true,
|
||||||
}).nullable(),
|
}).nullable(),
|
||||||
recipients: ZRecipientLiteSchema.array(),
|
recipients: ZRecipientLiteSchema.array(),
|
||||||
fields: ZFieldSchema.array(),
|
fields: ZFieldSchema.array(),
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "DocumentReminderInterval" AS ENUM ('NONE', 'EVERY_1_HOUR', 'EVERY_6_HOURS', 'EVERY_12_HOURS', 'DAILY', 'EVERY_3_DAYS', 'WEEKLY', 'EVERY_2_WEEKS', 'MONTHLY');
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "DocumentMeta" ADD COLUMN "lastReminderSentAt" TIMESTAMP(3),
|
||||||
|
ADD COLUMN "reminderInterval" "DocumentReminderInterval" NOT NULL DEFAULT 'NONE';
|
||||||
@ -36,4 +36,4 @@
|
|||||||
"tsx": "^4.19.2",
|
"tsx": "^4.19.2",
|
||||||
"typescript": "5.6.2"
|
"typescript": "5.6.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -388,6 +388,18 @@ enum DocumentDistributionMethod {
|
|||||||
NONE
|
NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DocumentReminderInterval {
|
||||||
|
NONE
|
||||||
|
EVERY_1_HOUR
|
||||||
|
EVERY_6_HOURS
|
||||||
|
EVERY_12_HOURS
|
||||||
|
DAILY
|
||||||
|
EVERY_3_DAYS
|
||||||
|
WEEKLY
|
||||||
|
EVERY_2_WEEKS
|
||||||
|
MONTHLY
|
||||||
|
}
|
||||||
|
|
||||||
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';"])
|
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';"])
|
||||||
model DocumentMeta {
|
model DocumentMeta {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
@ -409,6 +421,9 @@ model DocumentMeta {
|
|||||||
language String @default("en")
|
language String @default("en")
|
||||||
distributionMethod DocumentDistributionMethod @default(EMAIL)
|
distributionMethod DocumentDistributionMethod @default(EMAIL)
|
||||||
emailSettings Json? /// [DocumentEmailSettings] @zod.custom.use(ZDocumentEmailSettingsSchema)
|
emailSettings Json? /// [DocumentEmailSettings] @zod.custom.use(ZDocumentEmailSettingsSchema)
|
||||||
|
|
||||||
|
reminderInterval DocumentReminderInterval @default(NONE)
|
||||||
|
lastReminderSentAt DateTime?
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ReadStatus {
|
enum ReadStatus {
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import { authenticatedProcedure } from '../trpc';
|
|||||||
import {
|
import {
|
||||||
ZUpdateDocumentRequestSchema,
|
ZUpdateDocumentRequestSchema,
|
||||||
ZUpdateDocumentResponseSchema,
|
ZUpdateDocumentResponseSchema,
|
||||||
|
updateDocumentMeta,
|
||||||
} from './update-document.types';
|
} from './update-document.types';
|
||||||
import { updateDocumentMeta } from './update-document.types';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public route.
|
* Public route.
|
||||||
@ -39,6 +39,7 @@ export const updateDocumentRoute = authenticatedProcedure
|
|||||||
signingOrder: meta.signingOrder,
|
signingOrder: meta.signingOrder,
|
||||||
allowDictateNextSigner: meta.allowDictateNextSigner,
|
allowDictateNextSigner: meta.allowDictateNextSigner,
|
||||||
emailSettings: meta.emailSettings,
|
emailSettings: meta.emailSettings,
|
||||||
|
reminderInterval: meta.reminderInterval,
|
||||||
requestMetadata: ctx.metadata,
|
requestMetadata: ctx.metadata,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { DocumentSigningOrder } from '@prisma/client';
|
import { DocumentReminderInterval, DocumentSigningOrder } from '@prisma/client';
|
||||||
// import type { OpenApiMeta } from 'trpc-to-openapi';
|
// import type { OpenApiMeta } from 'trpc-to-openapi';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
@ -61,6 +61,7 @@ export const ZUpdateDocumentRequestSchema = z.object({
|
|||||||
uploadSignatureEnabled: ZDocumentMetaUploadSignatureEnabledSchema.optional(),
|
uploadSignatureEnabled: ZDocumentMetaUploadSignatureEnabledSchema.optional(),
|
||||||
drawSignatureEnabled: ZDocumentMetaDrawSignatureEnabledSchema.optional(),
|
drawSignatureEnabled: ZDocumentMetaDrawSignatureEnabledSchema.optional(),
|
||||||
emailSettings: ZDocumentEmailSettingsSchema.optional(),
|
emailSettings: ZDocumentEmailSettingsSchema.optional(),
|
||||||
|
reminderInterval: z.nativeEnum(DocumentReminderInterval).optional(),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans, useLingui } from '@lingui/react/macro';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import {
|
||||||
import { DocumentVisibility, TeamMemberRole } from '@prisma/client';
|
DocumentReminderInterval,
|
||||||
import { DocumentStatus, type Field, type Recipient, SendStatus } from '@prisma/client';
|
DocumentStatus,
|
||||||
|
DocumentVisibility,
|
||||||
|
type Field,
|
||||||
|
type Recipient,
|
||||||
|
SendStatus,
|
||||||
|
TeamMemberRole,
|
||||||
|
} from '@prisma/client';
|
||||||
import { InfoIcon } from 'lucide-react';
|
import { InfoIcon } from 'lucide-react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
@ -108,6 +114,7 @@ export const AddSettingsFormPartial = ({
|
|||||||
redirectUrl: document.documentMeta?.redirectUrl ?? '',
|
redirectUrl: document.documentMeta?.redirectUrl ?? '',
|
||||||
language: document.documentMeta?.language ?? 'en',
|
language: document.documentMeta?.language ?? 'en',
|
||||||
signatureTypes: extractTeamSignatureSettings(document.documentMeta),
|
signatureTypes: extractTeamSignatureSettings(document.documentMeta),
|
||||||
|
reminderInterval: document.documentMeta?.reminderInterval ?? DocumentReminderInterval.NONE,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -353,6 +360,67 @@ export const AddSettingsFormPartial = ({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="meta.reminderInterval"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="flex flex-row items-center">
|
||||||
|
<Trans>Reminder Interval</Trans>{' '}
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<InfoIcon className="mx-2 h-4 w-4" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
|
||||||
|
<TooltipContent className="text-muted-foreground max-w-xs">
|
||||||
|
<Trans>Set the interval between reminders for this document.</Trans>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormControl>
|
||||||
|
<Select {...field} onValueChange={field.onChange}>
|
||||||
|
<SelectTrigger className="bg-background">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value={DocumentReminderInterval.NONE}>
|
||||||
|
No reminders
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={DocumentReminderInterval.EVERY_1_HOUR}>
|
||||||
|
Every hour
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={DocumentReminderInterval.EVERY_6_HOURS}>
|
||||||
|
Every 6 hours
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={DocumentReminderInterval.EVERY_12_HOURS}>
|
||||||
|
Every 12 hours
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={DocumentReminderInterval.DAILY}>
|
||||||
|
Daily
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={DocumentReminderInterval.EVERY_3_DAYS}>
|
||||||
|
Every 3 days
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={DocumentReminderInterval.WEEKLY}>
|
||||||
|
Weekly
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={DocumentReminderInterval.EVERY_2_WEEKS}>
|
||||||
|
Every 2 weeks
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={DocumentReminderInterval.MONTHLY}>
|
||||||
|
Monthly
|
||||||
|
</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="meta.dateFormat"
|
name="meta.dateFormat"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { msg } from '@lingui/core/macro';
|
import { msg } from '@lingui/core/macro';
|
||||||
import { DocumentVisibility } from '@prisma/client';
|
import { DocumentReminderInterval, DocumentVisibility } from '@prisma/client';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||||
@ -57,6 +57,7 @@ export const ZAddSettingsFormSchema = z.object({
|
|||||||
signatureTypes: z.array(z.nativeEnum(DocumentSignatureType)).min(1, {
|
signatureTypes: z.array(z.nativeEnum(DocumentSignatureType)).min(1, {
|
||||||
message: msg`At least one signature type must be enabled`.id,
|
message: msg`At least one signature type must be enabled`.id,
|
||||||
}),
|
}),
|
||||||
|
reminderInterval: z.nativeEnum(DocumentReminderInterval).optional(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user