mirror of
https://github.com/documenso/documenso.git
synced 2025-11-15 01:01:49 +10:00
@ -5,15 +5,14 @@ import { EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import type { TSetEnvelopeRecipientsRequest } from '@documenso/trpc/server/envelope-router/set-envelope-recipients.types';
|
||||
import type { RecipientColorStyles, TRecipientColor } from '@documenso/ui/lib/recipient-colors';
|
||||
import {
|
||||
AVAILABLE_RECIPIENT_COLORS,
|
||||
getRecipientColorStyles,
|
||||
} from '@documenso/ui/lib/recipient-colors';
|
||||
import type { TUpdateEnvelopeRequest } from '@documenso/trpc/server/envelope-router/update-envelope.types';
|
||||
import type { TRecipientColor } from '@documenso/ui/lib/recipient-colors';
|
||||
import { AVAILABLE_RECIPIENT_COLORS } from '@documenso/ui/lib/recipient-colors';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
import type { TDocumentEmailSettings } from '../../types/document-email';
|
||||
import type { TEnvelope } from '../../types/envelope';
|
||||
import { formatDocumentsPath, formatTemplatesPath } from '../../utils/teams';
|
||||
import { useEditorFields } from '../hooks/use-editor-fields';
|
||||
import type { TLocalField } from '../hooks/use-editor-fields';
|
||||
import { useEnvelopeAutosave } from '../hooks/use-envelope-autosave';
|
||||
@ -38,25 +37,35 @@ export const useDebounceFunction = <Args extends unknown[]>(
|
||||
);
|
||||
};
|
||||
|
||||
type UpdateEnvelopePayload = Pick<TUpdateEnvelopeRequest, 'data' | 'meta'>;
|
||||
|
||||
type EnvelopeEditorProviderValue = {
|
||||
envelope: TEnvelope;
|
||||
isDocument: boolean;
|
||||
isTemplate: boolean;
|
||||
setLocalEnvelope: (localEnvelope: Partial<TEnvelope>) => void;
|
||||
|
||||
updateEnvelope: (envelopeUpdates: Partial<TEnvelope>) => void;
|
||||
updateEnvelope: (envelopeUpdates: UpdateEnvelopePayload) => void;
|
||||
setRecipientsDebounced: (recipients: TSetEnvelopeRecipientsRequest['recipients']) => void;
|
||||
setRecipientsAsync: (recipients: TSetEnvelopeRecipientsRequest['recipients']) => Promise<void>;
|
||||
|
||||
getFieldColor: (field: TLocalField) => RecipientColorStyles;
|
||||
getRecipientColorKey: (recipientId: number) => TRecipientColor;
|
||||
|
||||
editorFields: ReturnType<typeof useEditorFields>;
|
||||
|
||||
isAutosaving: boolean;
|
||||
flushAutosave: () => void;
|
||||
flushAutosave: () => Promise<void>;
|
||||
autosaveError: boolean;
|
||||
|
||||
relativePath: {
|
||||
basePath: string;
|
||||
envelopePath: string;
|
||||
editorPath: string;
|
||||
documentRootPath: string;
|
||||
templateRootPath: string;
|
||||
};
|
||||
|
||||
syncEnvelope: () => Promise<void>;
|
||||
// refetchEnvelope: () => Promise<void>;
|
||||
// updateEnvelope: (envelope: TEnvelope) => Promise<void>;
|
||||
};
|
||||
@ -86,12 +95,10 @@ export const EnvelopeEditorProvider = ({
|
||||
const { toast } = useToast();
|
||||
|
||||
const [envelope, setEnvelope] = useState(initialEnvelope);
|
||||
|
||||
const [autosaveError, setAutosaveError] = useState<boolean>(false);
|
||||
|
||||
const envelopeUpdateMutationQuery = trpc.envelope.update.useMutation({
|
||||
onSuccess: (response, input) => {
|
||||
console.log(input.meta?.emailSettings);
|
||||
setEnvelope({
|
||||
...envelope,
|
||||
...response,
|
||||
@ -106,7 +113,9 @@ export const EnvelopeEditorProvider = ({
|
||||
|
||||
setAutosaveError(false);
|
||||
},
|
||||
onError: (error) => {
|
||||
onError: (err) => {
|
||||
console.error(err);
|
||||
|
||||
setAutosaveError(true);
|
||||
|
||||
toast({
|
||||
@ -122,7 +131,9 @@ export const EnvelopeEditorProvider = ({
|
||||
onSuccess: () => {
|
||||
setAutosaveError(false);
|
||||
},
|
||||
onError: (error) => {
|
||||
onError: (err) => {
|
||||
console.error(err);
|
||||
|
||||
setAutosaveError(true);
|
||||
|
||||
toast({
|
||||
@ -135,10 +146,17 @@ export const EnvelopeEditorProvider = ({
|
||||
});
|
||||
|
||||
const envelopeRecipientSetMutationQuery = trpc.envelope.recipient.set.useMutation({
|
||||
onSuccess: () => {
|
||||
onSuccess: ({ recipients }) => {
|
||||
setEnvelope((prev) => ({
|
||||
...prev,
|
||||
recipients,
|
||||
}));
|
||||
|
||||
setAutosaveError(false);
|
||||
},
|
||||
onError: (error) => {
|
||||
onError: (err) => {
|
||||
console.error(err);
|
||||
|
||||
setAutosaveError(true);
|
||||
|
||||
toast({
|
||||
@ -178,21 +196,28 @@ export const EnvelopeEditorProvider = ({
|
||||
triggerSave: setEnvelopeDebounced,
|
||||
flush: setEnvelopeAsync,
|
||||
isPending: isEnvelopeMutationPending,
|
||||
} = useEnvelopeAutosave(async (envelopeUpdates: Partial<TEnvelope>) => {
|
||||
} = useEnvelopeAutosave(async (envelopeUpdates: UpdateEnvelopePayload) => {
|
||||
await envelopeUpdateMutationQuery.mutateAsync({
|
||||
envelopeId: envelope.id,
|
||||
envelopeType: envelope.type,
|
||||
data: {
|
||||
...envelopeUpdates,
|
||||
},
|
||||
data: envelopeUpdates.data,
|
||||
meta: envelopeUpdates.meta,
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
/**
|
||||
* Updates the local envelope and debounces the update to the server.
|
||||
*/
|
||||
const updateEnvelope = (envelopeUpdates: Partial<TEnvelope>) => {
|
||||
setEnvelope((prev) => ({ ...prev, ...envelopeUpdates }));
|
||||
const updateEnvelope = (envelopeUpdates: UpdateEnvelopePayload) => {
|
||||
setEnvelope((prev) => ({
|
||||
...prev,
|
||||
...envelopeUpdates.data,
|
||||
meta: {
|
||||
...prev.documentMeta,
|
||||
...envelopeUpdates.meta,
|
||||
},
|
||||
}));
|
||||
|
||||
setEnvelopeDebounced(envelopeUpdates);
|
||||
};
|
||||
|
||||
@ -201,28 +226,17 @@ export const EnvelopeEditorProvider = ({
|
||||
handleFieldsUpdate: (fields) => setFieldsDebounced(fields),
|
||||
});
|
||||
|
||||
const getFieldColor = useCallback(
|
||||
(field: TLocalField) => {
|
||||
// Todo: Envelopes - Local recipients
|
||||
const recipientIndex = envelope.recipients.findIndex(
|
||||
(recipient) => recipient.id === field.recipientId,
|
||||
);
|
||||
|
||||
return getRecipientColorStyles(Math.max(recipientIndex, 0));
|
||||
},
|
||||
[envelope.recipients], // Todo: Envelopes - Local recipients
|
||||
);
|
||||
|
||||
const getRecipientColorKey = useCallback(
|
||||
(recipientId: number) => {
|
||||
// Todo: Envelopes - Local recipients
|
||||
const recipientIndex = envelope.recipients.findIndex(
|
||||
(recipient) => recipient.id === recipientId,
|
||||
);
|
||||
|
||||
return AVAILABLE_RECIPIENT_COLORS[Math.max(recipientIndex, 0)];
|
||||
return AVAILABLE_RECIPIENT_COLORS[
|
||||
Math.max(recipientIndex, 0) % AVAILABLE_RECIPIENT_COLORS.length
|
||||
];
|
||||
},
|
||||
[envelope.recipients], // Todo: Envelopes - Local recipients
|
||||
[envelope.recipients],
|
||||
);
|
||||
|
||||
const { refetch: reloadEnvelope, isLoading: isReloadingEnvelope } = trpc.envelope.get.useQuery(
|
||||
@ -234,6 +248,21 @@ export const EnvelopeEditorProvider = ({
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Fetch and sycn the envelope back into the editor.
|
||||
*
|
||||
* Overrides everything.
|
||||
*/
|
||||
const syncEnvelope = async () => {
|
||||
await flushAutosave();
|
||||
|
||||
const fetchedEnvelopeData = await reloadEnvelope();
|
||||
|
||||
if (fetchedEnvelopeData.data) {
|
||||
setEnvelope(fetchedEnvelopeData.data);
|
||||
}
|
||||
};
|
||||
|
||||
const setLocalEnvelope = (localEnvelope: Partial<TEnvelope>) => {
|
||||
setEnvelope((prev) => ({ ...prev, ...localEnvelope }));
|
||||
};
|
||||
@ -256,10 +285,23 @@ export const EnvelopeEditorProvider = ({
|
||||
isEnvelopeMutationPending,
|
||||
]);
|
||||
|
||||
const flushAutosave = () => {
|
||||
void setFieldsAsync();
|
||||
void setRecipientsAsync();
|
||||
void setEnvelopeAsync();
|
||||
const relativePath = useMemo(() => {
|
||||
const documentRootPath = formatDocumentsPath(envelope.team.url);
|
||||
const templateRootPath = formatTemplatesPath(envelope.team.url);
|
||||
|
||||
const basePath = envelope.type === EnvelopeType.DOCUMENT ? documentRootPath : templateRootPath;
|
||||
|
||||
return {
|
||||
basePath,
|
||||
envelopePath: `${basePath}/${envelope.id}`,
|
||||
editorPath: `${basePath}/${envelope.id}/edit`,
|
||||
documentRootPath,
|
||||
templateRootPath,
|
||||
};
|
||||
}, [envelope.type, envelope.id]);
|
||||
|
||||
const flushAutosave = async (): Promise<void> => {
|
||||
await Promise.all([setFieldsAsync(), setRecipientsAsync(), setEnvelopeAsync()]);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -269,7 +311,6 @@ export const EnvelopeEditorProvider = ({
|
||||
isDocument: envelope.type === EnvelopeType.DOCUMENT,
|
||||
isTemplate: envelope.type === EnvelopeType.TEMPLATE,
|
||||
setLocalEnvelope,
|
||||
getFieldColor,
|
||||
getRecipientColorKey,
|
||||
updateEnvelope,
|
||||
setRecipientsDebounced,
|
||||
@ -278,6 +319,8 @@ export const EnvelopeEditorProvider = ({
|
||||
autosaveError,
|
||||
flushAutosave,
|
||||
isAutosaving,
|
||||
relativePath,
|
||||
syncEnvelope,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user