mirror of
https://github.com/documenso/documenso.git
synced 2025-11-20 03:32:14 +10:00
fix: handle loading files in embedded authoring update flows
This commit is contained in:
@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { DocumentData, FieldType } from '@prisma/client';
|
||||
import type { EnvelopeItem, FieldType } from '@prisma/client';
|
||||
import { ReadStatus, type Recipient, SendStatus, SigningStatus } from '@prisma/client';
|
||||
import { base64 } from '@scure/base';
|
||||
import { ChevronsUpDown } from 'lucide-react';
|
||||
@ -40,7 +40,8 @@ const DEFAULT_WIDTH_PX = MIN_WIDTH_PX * 2.5;
|
||||
|
||||
export type ConfigureFieldsViewProps = {
|
||||
configData: TConfigureEmbedFormSchema;
|
||||
documentData?: DocumentData;
|
||||
presignToken?: string | undefined;
|
||||
envelopeItem?: Pick<EnvelopeItem, 'id' | 'envelopeId'>;
|
||||
defaultValues?: Partial<TConfigureFieldsFormSchema>;
|
||||
onBack?: (data: TConfigureFieldsFormSchema) => void;
|
||||
onSubmit: (data: TConfigureFieldsFormSchema) => void;
|
||||
@ -48,7 +49,8 @@ export type ConfigureFieldsViewProps = {
|
||||
|
||||
export const ConfigureFieldsView = ({
|
||||
configData,
|
||||
documentData,
|
||||
presignToken,
|
||||
envelopeItem,
|
||||
defaultValues,
|
||||
onBack,
|
||||
onSubmit,
|
||||
@ -82,12 +84,12 @@ export const ConfigureFieldsView = ({
|
||||
}, []);
|
||||
|
||||
const normalizedDocumentData = useMemo(() => {
|
||||
if (documentData) {
|
||||
return documentData.data;
|
||||
if (envelopeItem) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!configData.documentData) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return base64.encode(configData.documentData.data);
|
||||
@ -534,56 +536,55 @@ export const ConfigureFieldsView = ({
|
||||
)}
|
||||
|
||||
<Form {...form}>
|
||||
{normalizedDocumentData && (
|
||||
<div>
|
||||
<PDFViewer
|
||||
overrideData={normalizedDocumentData}
|
||||
envelopeItem={{
|
||||
id: '',
|
||||
envelopeId: '',
|
||||
}}
|
||||
token={undefined}
|
||||
version="signed"
|
||||
/>
|
||||
{normalizedDocumentData ||
|
||||
(envelopeItem && (
|
||||
<div>
|
||||
<PDFViewer
|
||||
presignToken={presignToken}
|
||||
overrideData={normalizedDocumentData}
|
||||
envelopeItem={envelopeItem}
|
||||
token={undefined}
|
||||
version="signed"
|
||||
/>
|
||||
|
||||
<ElementVisible
|
||||
target={`${PDF_VIEWER_PAGE_SELECTOR}[data-page-number="${highestPageNumber}"]`}
|
||||
>
|
||||
{localFields.map((field, index) => {
|
||||
const recipientIndex = recipients.findIndex(
|
||||
(r) => r.id === field.recipientId,
|
||||
);
|
||||
<ElementVisible
|
||||
target={`${PDF_VIEWER_PAGE_SELECTOR}[data-page-number="${highestPageNumber}"]`}
|
||||
>
|
||||
{localFields.map((field, index) => {
|
||||
const recipientIndex = recipients.findIndex(
|
||||
(r) => r.id === field.recipientId,
|
||||
);
|
||||
|
||||
return (
|
||||
<FieldItem
|
||||
key={field.formId}
|
||||
field={field}
|
||||
minHeight={MIN_HEIGHT_PX}
|
||||
minWidth={MIN_WIDTH_PX}
|
||||
defaultHeight={DEFAULT_HEIGHT_PX}
|
||||
defaultWidth={DEFAULT_WIDTH_PX}
|
||||
onResize={(node) => onFieldResize(node, index)}
|
||||
onMove={(node) => onFieldMove(node, index)}
|
||||
onRemove={() => remove(index)}
|
||||
onDuplicate={() => onFieldCopy(null, { duplicate: true })}
|
||||
onDuplicateAllPages={() => onFieldCopy(null, { duplicateAll: true })}
|
||||
onFocus={() => setLastActiveField(field)}
|
||||
onBlur={() => setLastActiveField(null)}
|
||||
onAdvancedSettings={() => {
|
||||
setCurrentField(field);
|
||||
setShowAdvancedSettings(true);
|
||||
}}
|
||||
recipientIndex={recipientIndex}
|
||||
active={activeFieldId === field.formId}
|
||||
onFieldActivate={() => setActiveFieldId(field.formId)}
|
||||
onFieldDeactivate={() => setActiveFieldId(null)}
|
||||
disabled={selectedRecipient?.id !== field.recipientId}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ElementVisible>
|
||||
</div>
|
||||
)}
|
||||
return (
|
||||
<FieldItem
|
||||
key={field.formId}
|
||||
field={field}
|
||||
minHeight={MIN_HEIGHT_PX}
|
||||
minWidth={MIN_WIDTH_PX}
|
||||
defaultHeight={DEFAULT_HEIGHT_PX}
|
||||
defaultWidth={DEFAULT_WIDTH_PX}
|
||||
onResize={(node) => onFieldResize(node, index)}
|
||||
onMove={(node) => onFieldMove(node, index)}
|
||||
onRemove={() => remove(index)}
|
||||
onDuplicate={() => onFieldCopy(null, { duplicate: true })}
|
||||
onDuplicateAllPages={() => onFieldCopy(null, { duplicateAll: true })}
|
||||
onFocus={() => setLastActiveField(field)}
|
||||
onBlur={() => setLastActiveField(null)}
|
||||
onAdvancedSettings={() => {
|
||||
setCurrentField(field);
|
||||
setShowAdvancedSettings(true);
|
||||
}}
|
||||
recipientIndex={recipientIndex}
|
||||
active={activeFieldId === field.formId}
|
||||
onFieldActivate={() => setActiveFieldId(field.formId)}
|
||||
onFieldDeactivate={() => setActiveFieldId(null)}
|
||||
disabled={selectedRecipient?.id !== field.recipientId}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ElementVisible>
|
||||
</div>
|
||||
))}
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -75,6 +75,7 @@ export const loader = async ({ request, params }: Route.LoaderArgs) => {
|
||||
}));
|
||||
|
||||
return {
|
||||
token,
|
||||
document: {
|
||||
...document,
|
||||
fields,
|
||||
@ -86,7 +87,7 @@ export default function EmbeddingAuthoringDocumentEditPage() {
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { document } = useLoaderData<typeof loader>();
|
||||
const { document, token } = useLoaderData<typeof loader>();
|
||||
|
||||
const [hasFinishedInit, setHasFinishedInit] = useState(false);
|
||||
|
||||
@ -321,7 +322,8 @@ export default function EmbeddingAuthoringDocumentEditPage() {
|
||||
|
||||
<ConfigureFieldsView
|
||||
configData={configuration!}
|
||||
documentData={document.documentData}
|
||||
presignToken={token}
|
||||
envelopeItem={document.envelopeItems[0]}
|
||||
defaultValues={fields ?? undefined}
|
||||
onBack={canGoBack ? handleBackToConfig : undefined}
|
||||
onSubmit={handleConfigureFieldsSubmit}
|
||||
|
||||
@ -75,6 +75,7 @@ export const loader = async ({ request, params }: Route.LoaderArgs) => {
|
||||
}));
|
||||
|
||||
return {
|
||||
token,
|
||||
template: {
|
||||
...template,
|
||||
fields,
|
||||
@ -86,7 +87,7 @@ export default function EmbeddingAuthoringTemplateEditPage() {
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { template } = useLoaderData<typeof loader>();
|
||||
const { template, token } = useLoaderData<typeof loader>();
|
||||
|
||||
const [hasFinishedInit, setHasFinishedInit] = useState(false);
|
||||
|
||||
@ -321,7 +322,8 @@ export default function EmbeddingAuthoringTemplateEditPage() {
|
||||
|
||||
<ConfigureFieldsView
|
||||
configData={configuration!}
|
||||
documentData={template.templateDocumentData}
|
||||
presignToken={token}
|
||||
envelopeItem={template.envelopeItems[0]}
|
||||
defaultValues={fields ?? undefined}
|
||||
onBack={canGoBack ? handleBackToConfig : undefined}
|
||||
onSubmit={handleConfigureFieldsSubmit}
|
||||
|
||||
@ -5,6 +5,7 @@ import { Hono } from 'hono';
|
||||
import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session';
|
||||
import { APP_DOCUMENT_UPLOAD_SIZE_LIMIT } from '@documenso/lib/constants/app';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { verifyEmbeddingPresignToken } from '@documenso/lib/server-only/embedding-presign/verify-embedding-presign-token';
|
||||
import { getTeamById } from '@documenso/lib/server-only/team/get-team';
|
||||
import { putNormalizedPdfFileServerSide } from '@documenso/lib/universal/upload/put-file.server';
|
||||
import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions';
|
||||
@ -16,6 +17,7 @@ import {
|
||||
type TGetPresignedPostUrlResponse,
|
||||
ZGetEnvelopeItemFileDownloadRequestParamsSchema,
|
||||
ZGetEnvelopeItemFileRequestParamsSchema,
|
||||
ZGetEnvelopeItemFileRequestQuerySchema,
|
||||
ZGetEnvelopeItemFileTokenDownloadRequestParamsSchema,
|
||||
ZGetEnvelopeItemFileTokenRequestParamsSchema,
|
||||
ZGetPresignedPostUrlRequestSchema,
|
||||
@ -68,12 +70,24 @@ export const filesRoute = new Hono<HonoEnv>()
|
||||
.get(
|
||||
'/envelope/:envelopeId/envelopeItem/:envelopeItemId',
|
||||
sValidator('param', ZGetEnvelopeItemFileRequestParamsSchema),
|
||||
sValidator('query', ZGetEnvelopeItemFileRequestQuerySchema),
|
||||
async (c) => {
|
||||
const { envelopeId, envelopeItemId } = c.req.valid('param');
|
||||
const { token } = c.req.query();
|
||||
|
||||
const session = await getOptionalSession(c);
|
||||
|
||||
if (!session.user) {
|
||||
let userId = session.user?.id;
|
||||
|
||||
if (token) {
|
||||
const presignToken = await verifyEmbeddingPresignToken({
|
||||
token,
|
||||
}).catch(() => undefined);
|
||||
|
||||
userId = presignToken?.userId;
|
||||
}
|
||||
|
||||
if (!userId) {
|
||||
return c.json({ error: 'Unauthorized' }, 401);
|
||||
}
|
||||
|
||||
@ -104,7 +118,7 @@ export const filesRoute = new Hono<HonoEnv>()
|
||||
}
|
||||
|
||||
const team = await getTeamById({
|
||||
userId: session.user.id,
|
||||
userId: userId,
|
||||
teamId: envelope.teamId,
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
|
||||
@ -36,6 +36,14 @@ export type TGetEnvelopeItemFileRequestParams = z.infer<
|
||||
typeof ZGetEnvelopeItemFileRequestParamsSchema
|
||||
>;
|
||||
|
||||
export const ZGetEnvelopeItemFileRequestQuerySchema = z.object({
|
||||
token: z.string().optional(),
|
||||
});
|
||||
|
||||
export type TGetEnvelopeItemFileRequestQuery = z.infer<
|
||||
typeof ZGetEnvelopeItemFileRequestQuerySchema
|
||||
>;
|
||||
|
||||
export const ZGetEnvelopeItemFileTokenRequestParamsSchema = z.object({
|
||||
token: z.string().min(1),
|
||||
envelopeItemId: z.string().min(1),
|
||||
|
||||
Reference in New Issue
Block a user