mirror of
https://github.com/documenso/documenso.git
synced 2025-11-09 20:12:31 +10:00
fix: remove lazy pdf loader
This commit is contained in:
@ -13,7 +13,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@documenso/ui/primitives/dialog';
|
} from '@documenso/ui/primitives/dialog';
|
||||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
|
||||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
|
|
||||||
import { useOptionalCurrentTeam } from '~/providers/team';
|
import { useOptionalCurrentTeam } from '~/providers/team';
|
||||||
@ -97,7 +97,7 @@ export const DocumentDuplicateDialog = ({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="p-2 [&>div]:h-[50vh] [&>div]:overflow-y-scroll">
|
<div className="p-2 [&>div]:h-[50vh] [&>div]:overflow-y-scroll">
|
||||||
<LazyPDFViewer key={document?.id} documentData={documentData} />
|
<PDFViewer key={document?.id} documentData={documentData} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ import { Card, CardContent } from '@documenso/ui/primitives/card';
|
|||||||
import { ElementVisible } from '@documenso/ui/primitives/element-visible';
|
import { ElementVisible } from '@documenso/ui/primitives/element-visible';
|
||||||
import { Input } from '@documenso/ui/primitives/input';
|
import { Input } from '@documenso/ui/primitives/input';
|
||||||
import { Label } from '@documenso/ui/primitives/label';
|
import { Label } from '@documenso/ui/primitives/label';
|
||||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
|
||||||
import { SignaturePad } from '@documenso/ui/primitives/signature-pad';
|
import { SignaturePad } from '@documenso/ui/primitives/signature-pad';
|
||||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
|
|
||||||
@ -338,7 +338,7 @@ export const EmbedDirectTemplateClientPage = ({
|
|||||||
<div className="relative flex w-full flex-col gap-x-6 gap-y-12 md:flex-row">
|
<div className="relative flex w-full flex-col gap-x-6 gap-y-12 md:flex-row">
|
||||||
{/* Viewer */}
|
{/* Viewer */}
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<LazyPDFViewer
|
<PDFViewer
|
||||||
documentData={documentData}
|
documentData={documentData}
|
||||||
onDocumentLoad={() => setHasDocumentLoaded(true)}
|
onDocumentLoad={() => setHasDocumentLoaded(true)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import { Card, CardContent } from '@documenso/ui/primitives/card';
|
|||||||
import { ElementVisible } from '@documenso/ui/primitives/element-visible';
|
import { ElementVisible } from '@documenso/ui/primitives/element-visible';
|
||||||
import { Input } from '@documenso/ui/primitives/input';
|
import { Input } from '@documenso/ui/primitives/input';
|
||||||
import { Label } from '@documenso/ui/primitives/label';
|
import { Label } from '@documenso/ui/primitives/label';
|
||||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
|
||||||
import { RadioGroup, RadioGroupItem } from '@documenso/ui/primitives/radio-group';
|
import { RadioGroup, RadioGroupItem } from '@documenso/ui/primitives/radio-group';
|
||||||
import { SignaturePad } from '@documenso/ui/primitives/signature-pad';
|
import { SignaturePad } from '@documenso/ui/primitives/signature-pad';
|
||||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
@ -278,7 +278,7 @@ export const EmbedSignDocumentClientPage = ({
|
|||||||
<div className="embed--DocumentContainer relative flex w-full flex-col gap-x-6 gap-y-12 md:flex-row">
|
<div className="embed--DocumentContainer relative flex w-full flex-col gap-x-6 gap-y-12 md:flex-row">
|
||||||
{/* Viewer */}
|
{/* Viewer */}
|
||||||
<div className="embed--DocumentViewer flex-1">
|
<div className="embed--DocumentViewer flex-1">
|
||||||
<LazyPDFViewer
|
<PDFViewer
|
||||||
documentData={documentData}
|
documentData={documentData}
|
||||||
onDocumentLoad={() => setHasDocumentLoaded(true)}
|
onDocumentLoad={() => setHasDocumentLoaded(true)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { trpc } from '@documenso/trpc/react';
|
|||||||
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
||||||
import { DocumentFlowFormContainer } from '@documenso/ui/primitives/document-flow/document-flow-root';
|
import { DocumentFlowFormContainer } from '@documenso/ui/primitives/document-flow/document-flow-root';
|
||||||
import type { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types';
|
import type { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types';
|
||||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
|
||||||
import { Stepper } from '@documenso/ui/primitives/stepper';
|
import { Stepper } from '@documenso/ui/primitives/stepper';
|
||||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ export const DirectTemplatePageView = ({
|
|||||||
gradient
|
gradient
|
||||||
>
|
>
|
||||||
<CardContent className="p-2">
|
<CardContent className="p-2">
|
||||||
<LazyPDFViewer
|
<PDFViewer
|
||||||
key={template.id}
|
key={template.id}
|
||||||
documentData={template.templateDocumentData}
|
documentData={template.templateDocumentData}
|
||||||
onDocumentLoad={() => setIsDocumentPdfLoaded(true)}
|
onDocumentLoad={() => setIsDocumentPdfLoaded(true)}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import type { FieldWithSignatureAndFieldMeta } from '@documenso/prisma/types/fie
|
|||||||
import type { RecipientWithFields } from '@documenso/prisma/types/recipient-with-fields';
|
import type { RecipientWithFields } from '@documenso/prisma/types/recipient-with-fields';
|
||||||
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
||||||
import { ElementVisible } from '@documenso/ui/primitives/element-visible';
|
import { ElementVisible } from '@documenso/ui/primitives/element-visible';
|
||||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
|
||||||
|
|
||||||
import { DocumentSigningAutoSign } from '~/components/general/document-signing/document-signing-auto-sign';
|
import { DocumentSigningAutoSign } from '~/components/general/document-signing/document-signing-auto-sign';
|
||||||
import { DocumentSigningCheckboxField } from '~/components/general/document-signing/document-signing-checkbox-field';
|
import { DocumentSigningCheckboxField } from '~/components/general/document-signing/document-signing-checkbox-field';
|
||||||
@ -140,12 +140,7 @@ export const DocumentSigningPageView = ({
|
|||||||
gradient
|
gradient
|
||||||
>
|
>
|
||||||
<CardContent className="p-2">
|
<CardContent className="p-2">
|
||||||
<LazyPDFViewer
|
<PDFViewer key={documentData.id} documentData={documentData} document={document} />
|
||||||
key={documentData.id}
|
|
||||||
documentData={documentData}
|
|
||||||
document={document}
|
|
||||||
password={documentMeta?.password}
|
|
||||||
/>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import { AddSubjectFormPartial } from '@documenso/ui/primitives/document-flow/ad
|
|||||||
import type { TAddSubjectFormSchema } from '@documenso/ui/primitives/document-flow/add-subject.types';
|
import type { TAddSubjectFormSchema } from '@documenso/ui/primitives/document-flow/add-subject.types';
|
||||||
import { DocumentFlowFormContainer } from '@documenso/ui/primitives/document-flow/document-flow-root';
|
import { DocumentFlowFormContainer } from '@documenso/ui/primitives/document-flow/document-flow-root';
|
||||||
import type { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types';
|
import type { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types';
|
||||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
|
||||||
import { Stepper } from '@documenso/ui/primitives/stepper';
|
import { Stepper } from '@documenso/ui/primitives/stepper';
|
||||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
|
|
||||||
@ -132,9 +132,6 @@ export const DocumentEditForm = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { mutateAsync: setPasswordForDocument } =
|
|
||||||
trpc.document.setPasswordForDocument.useMutation();
|
|
||||||
|
|
||||||
const documentFlow: Record<EditDocumentStep, DocumentFlowStep> = {
|
const documentFlow: Record<EditDocumentStep, DocumentFlowStep> = {
|
||||||
settings: {
|
settings: {
|
||||||
title: msg`General`,
|
title: msg`General`,
|
||||||
@ -315,13 +312,6 @@ export const DocumentEditForm = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPasswordSubmit = async (password: string) => {
|
|
||||||
await setPasswordForDocument({
|
|
||||||
documentId: document.id,
|
|
||||||
password,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const currentDocumentFlow = documentFlow[step];
|
const currentDocumentFlow = documentFlow[step];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -340,12 +330,10 @@ export const DocumentEditForm = ({
|
|||||||
gradient
|
gradient
|
||||||
>
|
>
|
||||||
<CardContent className="p-2">
|
<CardContent className="p-2">
|
||||||
<LazyPDFViewer
|
<PDFViewer
|
||||||
key={document.documentData.id}
|
key={document.documentData.id}
|
||||||
documentData={document.documentData}
|
documentData={document.documentData}
|
||||||
document={document}
|
document={document}
|
||||||
password={document.documentMeta?.password}
|
|
||||||
onPasswordSubmit={onPasswordSubmit}
|
|
||||||
onDocumentLoad={() => setIsDocumentPdfLoaded(true)}
|
onDocumentLoad={() => setIsDocumentPdfLoaded(true)}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import { cn } from '@documenso/ui/lib/utils';
|
|||||||
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
||||||
import { DocumentFlowFormContainer } from '@documenso/ui/primitives/document-flow/document-flow-root';
|
import { DocumentFlowFormContainer } from '@documenso/ui/primitives/document-flow/document-flow-root';
|
||||||
import type { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types';
|
import type { DocumentFlowStep } from '@documenso/ui/primitives/document-flow/types';
|
||||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
|
||||||
import { Stepper } from '@documenso/ui/primitives/stepper';
|
import { Stepper } from '@documenso/ui/primitives/stepper';
|
||||||
import { AddTemplateFieldsFormPartial } from '@documenso/ui/primitives/template-flow/add-template-fields';
|
import { AddTemplateFieldsFormPartial } from '@documenso/ui/primitives/template-flow/add-template-fields';
|
||||||
import type { TAddTemplateFieldsFormSchema } from '@documenso/ui/primitives/template-flow/add-template-fields.types';
|
import type { TAddTemplateFieldsFormSchema } from '@documenso/ui/primitives/template-flow/add-template-fields.types';
|
||||||
@ -236,7 +236,7 @@ export const TemplateEditForm = ({
|
|||||||
gradient
|
gradient
|
||||||
>
|
>
|
||||||
<CardContent className="p-2">
|
<CardContent className="p-2">
|
||||||
<LazyPDFViewer
|
<PDFViewer
|
||||||
key={templateDocumentData.id}
|
key={templateDocumentData.id}
|
||||||
documentData={templateDocumentData}
|
documentData={templateDocumentData}
|
||||||
onDocumentLoad={() => setIsDocumentPdfLoaded(true)}
|
onDocumentLoad={() => setIsDocumentPdfLoaded(true)}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
|||||||
import { Badge } from '@documenso/ui/primitives/badge';
|
import { Badge } from '@documenso/ui/primitives/badge';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
||||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
|
||||||
|
|
||||||
import { DocumentHistorySheet } from '~/components/general/document/document-history-sheet';
|
import { DocumentHistorySheet } from '~/components/general/document/document-history-sheet';
|
||||||
import { DocumentPageViewButton } from '~/components/general/document/document-page-view-button';
|
import { DocumentPageViewButton } from '~/components/general/document/document-page-view-button';
|
||||||
@ -196,7 +196,7 @@ export default function DocumentPage() {
|
|||||||
gradient
|
gradient
|
||||||
>
|
>
|
||||||
<CardContent className="p-2">
|
<CardContent className="p-2">
|
||||||
<LazyPDFViewer document={document} key={documentData.id} documentData={documentData} />
|
<PDFViewer document={document} key={documentData.id} documentData={documentData} />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { getSubscriptionsByUserId } from '@documenso/lib/server-only/subscriptio
|
|||||||
import { BillingPlans } from '~/components/general/billing-plans';
|
import { BillingPlans } from '~/components/general/billing-plans';
|
||||||
import { BillingPortalButton } from '~/components/general/billing-portal-button';
|
import { BillingPortalButton } from '~/components/general/billing-portal-button';
|
||||||
import { appMetaTags } from '~/utils/meta';
|
import { appMetaTags } from '~/utils/meta';
|
||||||
|
import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
||||||
|
|
||||||
import type { Route } from './+types/billing';
|
import type { Route } from './+types/billing';
|
||||||
|
|
||||||
@ -62,17 +63,17 @@ export async function loader({ request }: Route.LoaderArgs) {
|
|||||||
const isMissingOrInactiveOrFreePlan =
|
const isMissingOrInactiveOrFreePlan =
|
||||||
!subscription || subscription.status === SubscriptionStatus.INACTIVE;
|
!subscription || subscription.status === SubscriptionStatus.INACTIVE;
|
||||||
|
|
||||||
return {
|
return superLoaderJson({
|
||||||
prices,
|
prices,
|
||||||
subscription,
|
subscription,
|
||||||
subscriptionProductName: subscriptionProduct?.name,
|
subscriptionProductName: subscriptionProduct?.name,
|
||||||
isMissingOrInactiveOrFreePlan,
|
isMissingOrInactiveOrFreePlan,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TeamsSettingBillingPage({ loaderData }: Route.ComponentProps) {
|
export default function TeamsSettingBillingPage() {
|
||||||
const { prices, subscription, subscriptionProductName, isMissingOrInactiveOrFreePlan } =
|
const { prices, subscription, subscriptionProductName, isMissingOrInactiveOrFreePlan } =
|
||||||
loaderData;
|
useSuperLoaderData<typeof loader>();
|
||||||
|
|
||||||
const { i18n } = useLingui();
|
const { i18n } = useLingui();
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { Card, CardContent } from '@documenso/ui/primitives/card';
|
|||||||
import { SettingsHeader } from '~/components/general/settings-header';
|
import { SettingsHeader } from '~/components/general/settings-header';
|
||||||
import { TeamBillingPortalButton } from '~/components/general/teams/team-billing-portal-button';
|
import { TeamBillingPortalButton } from '~/components/general/teams/team-billing-portal-button';
|
||||||
import { TeamSettingsBillingInvoicesTable } from '~/components/tables/team-settings-billing-invoices-table';
|
import { TeamSettingsBillingInvoicesTable } from '~/components/tables/team-settings-billing-invoices-table';
|
||||||
|
import { superLoaderJson, useSuperLoaderData } from '~/utils/super-json-loader';
|
||||||
|
|
||||||
import type { Route } from './+types/settings.billing';
|
import type { Route } from './+types/settings.billing';
|
||||||
|
|
||||||
@ -31,16 +32,16 @@ export async function loader({ request, params }: Route.LoaderArgs) {
|
|||||||
teamSubscription = await stripe.subscriptions.retrieve(team.subscription.planId);
|
teamSubscription = await stripe.subscriptions.retrieve(team.subscription.planId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return superLoaderJson({
|
||||||
team,
|
team,
|
||||||
teamSubscription,
|
teamSubscription,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TeamsSettingBillingPage({ loaderData }: Route.ComponentProps) {
|
export default function TeamsSettingBillingPage() {
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
|
|
||||||
const { team, teamSubscription } = loaderData;
|
const { team, teamSubscription } = useSuperLoaderData<typeof loader>();
|
||||||
|
|
||||||
const canManageBilling = canExecuteTeamAction('MANAGE_BILLING', team.currentTeamMember.role);
|
const canManageBilling = canExecuteTeamAction('MANAGE_BILLING', team.currentTeamMember.role);
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { getTemplateById } from '@documenso/lib/server-only/template/get-templat
|
|||||||
import { formatDocumentsPath, formatTemplatesPath } from '@documenso/lib/utils/teams';
|
import { formatDocumentsPath, formatTemplatesPath } from '@documenso/lib/utils/teams';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
||||||
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
|
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
|
||||||
|
|
||||||
import { TemplateBulkSendDialog } from '~/components/dialogs/template-bulk-send-dialog';
|
import { TemplateBulkSendDialog } from '~/components/dialogs/template-bulk-send-dialog';
|
||||||
import { TemplateDirectLinkDialogWrapper } from '~/components/dialogs/template-direct-link-dialog-wrapper';
|
import { TemplateDirectLinkDialogWrapper } from '~/components/dialogs/template-direct-link-dialog-wrapper';
|
||||||
@ -144,11 +144,7 @@ export default function TemplatePage() {
|
|||||||
gradient
|
gradient
|
||||||
>
|
>
|
||||||
<CardContent className="p-2">
|
<CardContent className="p-2">
|
||||||
<LazyPDFViewer
|
<PDFViewer document={template} key={template.id} documentData={templateDocumentData} />
|
||||||
document={template}
|
|
||||||
key={template.id}
|
|
||||||
documentData={templateDocumentData}
|
|
||||||
/>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
@ -76,7 +76,7 @@
|
|||||||
"@babel/preset-typescript": "^7.26.0",
|
"@babel/preset-typescript": "^7.26.0",
|
||||||
"@lingui/babel-plugin-lingui-macro": "^5.2.0",
|
"@lingui/babel-plugin-lingui-macro": "^5.2.0",
|
||||||
"@lingui/vite-plugin": "^5.2.0",
|
"@lingui/vite-plugin": "^5.2.0",
|
||||||
"@react-router/dev": "^7.1.1",
|
"@react-router/dev": "^7.1.5",
|
||||||
"@react-router/remix-routes-option-adapter": "^7.1.5",
|
"@react-router/remix-routes-option-adapter": "^7.1.5",
|
||||||
"@rollup/plugin-babel": "^6.0.4",
|
"@rollup/plugin-babel": "^6.0.4",
|
||||||
"@rollup/plugin-commonjs": "^28.0.2",
|
"@rollup/plugin-commonjs": "^28.0.2",
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
|
import { defineConfig } from '@lingui/cli';
|
||||||
import type { LinguiConfig } from '@lingui/conf';
|
import type { LinguiConfig } from '@lingui/conf';
|
||||||
|
import { formatter } from '@lingui/format-po';
|
||||||
|
|
||||||
import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
|
import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n';
|
||||||
|
|
||||||
@ -14,6 +16,7 @@ const config: LinguiConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
compileNamespace: 'es',
|
compileNamespace: 'es',
|
||||||
|
format: formatter({ lineNumbers: false }),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@ -158,7 +158,7 @@
|
|||||||
"@babel/preset-typescript": "^7.26.0",
|
"@babel/preset-typescript": "^7.26.0",
|
||||||
"@lingui/babel-plugin-lingui-macro": "^5.2.0",
|
"@lingui/babel-plugin-lingui-macro": "^5.2.0",
|
||||||
"@lingui/vite-plugin": "^5.2.0",
|
"@lingui/vite-plugin": "^5.2.0",
|
||||||
"@react-router/dev": "^7.1.1",
|
"@react-router/dev": "^7.1.5",
|
||||||
"@react-router/remix-routes-option-adapter": "^7.1.5",
|
"@react-router/remix-routes-option-adapter": "^7.1.5",
|
||||||
"@rollup/plugin-babel": "^6.0.4",
|
"@rollup/plugin-babel": "^6.0.4",
|
||||||
"@rollup/plugin-commonjs": "^28.0.2",
|
"@rollup/plugin-commonjs": "^28.0.2",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,6 @@ import { DateTime } from 'luxon';
|
|||||||
|
|
||||||
import { getServerLimits } from '@documenso/ee/server-only/limits/server';
|
import { getServerLimits } from '@documenso/ee/server-only/limits/server';
|
||||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||||
import { DOCUMENSO_ENCRYPTION_KEY } from '@documenso/lib/constants/crypto';
|
|
||||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||||
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
|
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
|
||||||
import { createDocumentData } from '@documenso/lib/server-only/document-data/create-document-data';
|
import { createDocumentData } from '@documenso/lib/server-only/document-data/create-document-data';
|
||||||
@ -26,7 +25,6 @@ import { searchDocumentsWithKeyword } from '@documenso/lib/server-only/document/
|
|||||||
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
|
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
|
||||||
import { updateDocument } from '@documenso/lib/server-only/document/update-document';
|
import { updateDocument } from '@documenso/lib/server-only/document/update-document';
|
||||||
import { getTeamById } from '@documenso/lib/server-only/team/get-team';
|
import { getTeamById } from '@documenso/lib/server-only/team/get-team';
|
||||||
import { symmetricEncrypt } from '@documenso/lib/universal/crypto';
|
|
||||||
import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions';
|
import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions';
|
||||||
|
|
||||||
import { authenticatedProcedure, procedure, router } from '../trpc';
|
import { authenticatedProcedure, procedure, router } from '../trpc';
|
||||||
@ -55,7 +53,6 @@ import {
|
|||||||
ZMoveDocumentToTeamSchema,
|
ZMoveDocumentToTeamSchema,
|
||||||
ZResendDocumentMutationSchema,
|
ZResendDocumentMutationSchema,
|
||||||
ZSearchDocumentsMutationSchema,
|
ZSearchDocumentsMutationSchema,
|
||||||
ZSetPasswordForDocumentMutationSchema,
|
|
||||||
ZSetSigningOrderForDocumentMutationSchema,
|
ZSetSigningOrderForDocumentMutationSchema,
|
||||||
ZSuccessResponseSchema,
|
ZSuccessResponseSchema,
|
||||||
ZUpdateDocumentRequestSchema,
|
ZUpdateDocumentRequestSchema,
|
||||||
@ -444,35 +441,6 @@ export const documentRouter = router({
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
setPasswordForDocument: authenticatedProcedure
|
|
||||||
.input(ZSetPasswordForDocumentMutationSchema)
|
|
||||||
.mutation(async ({ input, ctx }) => {
|
|
||||||
const { teamId } = ctx;
|
|
||||||
const { documentId, password } = input;
|
|
||||||
|
|
||||||
const key = DOCUMENSO_ENCRYPTION_KEY;
|
|
||||||
|
|
||||||
if (!key) {
|
|
||||||
throw new Error('Missing encryption key');
|
|
||||||
}
|
|
||||||
|
|
||||||
const securePassword = symmetricEncrypt({
|
|
||||||
data: password,
|
|
||||||
key,
|
|
||||||
});
|
|
||||||
|
|
||||||
await upsertDocumentMeta({
|
|
||||||
userId: ctx.user.id,
|
|
||||||
teamId,
|
|
||||||
documentId,
|
|
||||||
password: securePassword,
|
|
||||||
requestMetadata: ctx.metadata,
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*
|
*
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { X } from 'lucide-react';
|
|||||||
|
|
||||||
import { cn } from '../../lib/utils';
|
import { cn } from '../../lib/utils';
|
||||||
import { Dialog, DialogOverlay, DialogPortal, DialogTrigger } from '../../primitives/dialog';
|
import { Dialog, DialogOverlay, DialogPortal, DialogTrigger } from '../../primitives/dialog';
|
||||||
import { LazyPDFViewerNoLoader } from '../../primitives/lazy-pdf-viewer';
|
import PDFViewer from '../../primitives/pdf-viewer';
|
||||||
|
|
||||||
export type DocumentDialogProps = {
|
export type DocumentDialogProps = {
|
||||||
trigger?: React.ReactNode;
|
trigger?: React.ReactNode;
|
||||||
@ -43,7 +43,7 @@ export default function DocumentDialog({ trigger, documentData, ...props }: Docu
|
|||||||
)}
|
)}
|
||||||
onClick={() => props.onOpenChange?.(false)}
|
onClick={() => props.onOpenChange?.(false)}
|
||||||
>
|
>
|
||||||
<LazyPDFViewerNoLoader
|
<PDFViewer
|
||||||
className="mx-auto w-full max-w-3xl xl:max-w-5xl"
|
className="mx-auto w-full max-w-3xl xl:max-w-5xl"
|
||||||
documentData={documentData}
|
documentData={documentData}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
|||||||
@ -1,107 +0,0 @@
|
|||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
|
||||||
import { msg } from '@lingui/core/macro';
|
|
||||||
import { useLingui } from '@lingui/react';
|
|
||||||
import { Trans } from '@lingui/react/macro';
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import { z } from 'zod';
|
|
||||||
|
|
||||||
import { Button } from './button';
|
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from './dialog';
|
|
||||||
import { Form, FormControl, FormField, FormItem, FormMessage } from './form/form';
|
|
||||||
import { Input } from './input';
|
|
||||||
|
|
||||||
const ZPasswordDialogFormSchema = z.object({
|
|
||||||
password: z.string(),
|
|
||||||
});
|
|
||||||
|
|
||||||
type TPasswordDialogFormSchema = z.infer<typeof ZPasswordDialogFormSchema>;
|
|
||||||
|
|
||||||
type PasswordDialogProps = {
|
|
||||||
open: boolean;
|
|
||||||
onOpenChange: (_open: boolean) => void;
|
|
||||||
defaultPassword?: string;
|
|
||||||
onPasswordSubmit?: (password: string) => void;
|
|
||||||
isError?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PasswordDialog = ({
|
|
||||||
open,
|
|
||||||
onOpenChange,
|
|
||||||
defaultPassword,
|
|
||||||
onPasswordSubmit,
|
|
||||||
isError,
|
|
||||||
}: PasswordDialogProps) => {
|
|
||||||
const { _ } = useLingui();
|
|
||||||
|
|
||||||
const form = useForm<TPasswordDialogFormSchema>({
|
|
||||||
defaultValues: {
|
|
||||||
password: defaultPassword ?? '',
|
|
||||||
},
|
|
||||||
resolver: zodResolver(ZPasswordDialogFormSchema),
|
|
||||||
});
|
|
||||||
|
|
||||||
const onFormSubmit = ({ password }: TPasswordDialogFormSchema) => {
|
|
||||||
onPasswordSubmit?.(password);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isError) {
|
|
||||||
form.setError('password', {
|
|
||||||
type: 'manual',
|
|
||||||
message: _(msg`The password you have entered is incorrect. Please try again.`),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [form, isError]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog open={open}>
|
|
||||||
<DialogContent className="w-full max-w-md">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>
|
|
||||||
<Trans>Password Required</Trans>
|
|
||||||
</DialogTitle>
|
|
||||||
|
|
||||||
<DialogDescription className="text-muted-foreground">
|
|
||||||
<Trans>
|
|
||||||
This document is password protected. Please enter the password to view the document.
|
|
||||||
</Trans>
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<Form {...form}>
|
|
||||||
<form onSubmit={form.handleSubmit(onFormSubmit)}>
|
|
||||||
<fieldset className="flex flex-wrap items-start justify-between gap-4">
|
|
||||||
<FormField
|
|
||||||
name="password"
|
|
||||||
control={form.control}
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="relative flex-1">
|
|
||||||
<FormControl>
|
|
||||||
<Input
|
|
||||||
type="password"
|
|
||||||
className="bg-background"
|
|
||||||
placeholder={_(msg`Enter password`)}
|
|
||||||
autoComplete="off"
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Button>
|
|
||||||
<Trans>Submit</Trans>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
</Form>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
// Todo: (RR7) Not sure if this actually makes it client-only.
|
|
||||||
import { Suspense, lazy } from 'react';
|
|
||||||
|
|
||||||
import { Trans } from '@lingui/react/macro';
|
|
||||||
import { Loader } from 'lucide-react';
|
|
||||||
import { Await } from 'react-router';
|
|
||||||
|
|
||||||
const LoadingComponent = () => (
|
|
||||||
<div className="dark:bg-background flex h-[80vh] max-h-[60rem] flex-col items-center justify-center bg-white/50">
|
|
||||||
<Loader className="text-documenso h-12 w-12 animate-spin" />
|
|
||||||
<p className="text-muted-foreground mt-4">
|
|
||||||
<Trans>Loading document...</Trans>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
export const LazyPDFViewerImport = lazy(async () => import('./pdf-viewer'));
|
|
||||||
|
|
||||||
export const LazyPDFViewer = (props: React.ComponentProps<typeof LazyPDFViewerImport>) => (
|
|
||||||
<Suspense fallback={<LoadingComponent />}>
|
|
||||||
<Await resolve={LazyPDFViewerImport}>
|
|
||||||
<LazyPDFViewerImport {...props} />
|
|
||||||
</Await>
|
|
||||||
</Suspense>
|
|
||||||
);
|
|
||||||
|
|
||||||
export const LazyPDFViewerNoLoader = (props: React.ComponentProps<typeof LazyPDFViewer>) => (
|
|
||||||
<Suspense fallback={null}>
|
|
||||||
<LazyPDFViewerImport {...props} />
|
|
||||||
</Suspense>
|
|
||||||
);
|
|
||||||
@ -5,18 +5,15 @@ import { useLingui } from '@lingui/react';
|
|||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
import type { DocumentData } from '@prisma/client';
|
import type { DocumentData } from '@prisma/client';
|
||||||
import { Loader } from 'lucide-react';
|
import { Loader } from 'lucide-react';
|
||||||
import { type PDFDocumentProxy, PasswordResponses } from 'pdfjs-dist';
|
import { type PDFDocumentProxy } from 'pdfjs-dist';
|
||||||
import pdfWorker from 'pdfjs-dist/build/pdf.worker.min?url';
|
|
||||||
import { Document as PDFDocument, Page as PDFPage, pdfjs } from 'react-pdf';
|
import { Document as PDFDocument, Page as PDFPage, pdfjs } from 'react-pdf';
|
||||||
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
||||||
import 'react-pdf/dist/esm/Page/TextLayer.css';
|
import 'react-pdf/dist/esm/Page/TextLayer.css';
|
||||||
import { match } from 'ts-pattern';
|
|
||||||
|
|
||||||
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||||
import { getFile } from '@documenso/lib/universal/upload/get-file';
|
import { getFile } from '@documenso/lib/universal/upload/get-file';
|
||||||
|
|
||||||
import { cn } from '../lib/utils';
|
import { cn } from '../lib/utils';
|
||||||
import { PasswordDialog } from './document-password-dialog';
|
|
||||||
import { useToast } from './use-toast';
|
import { useToast } from './use-toast';
|
||||||
|
|
||||||
export type LoadedPDFDocument = PDFDocumentProxy;
|
export type LoadedPDFDocument = PDFDocumentProxy;
|
||||||
@ -24,7 +21,10 @@ export type LoadedPDFDocument = PDFDocumentProxy;
|
|||||||
/**
|
/**
|
||||||
* This imports the worker from the `pdfjs-dist` package.
|
* This imports the worker from the `pdfjs-dist` package.
|
||||||
*/
|
*/
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = pdfWorker;
|
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||||
|
'pdfjs-dist/build/pdf.worker.min.js',
|
||||||
|
import.meta.url,
|
||||||
|
).toString();
|
||||||
|
|
||||||
export type OnPDFViewerPageClick = (_event: {
|
export type OnPDFViewerPageClick = (_event: {
|
||||||
pageNumber: number;
|
pageNumber: number;
|
||||||
@ -49,8 +49,6 @@ const PDFLoader = () => (
|
|||||||
export type PDFViewerProps = {
|
export type PDFViewerProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
documentData: DocumentData;
|
documentData: DocumentData;
|
||||||
password?: string | null;
|
|
||||||
onPasswordSubmit?: (password: string) => void | Promise<void>;
|
|
||||||
onDocumentLoad?: (_doc: LoadedPDFDocument) => void;
|
onDocumentLoad?: (_doc: LoadedPDFDocument) => void;
|
||||||
onPageClick?: OnPDFViewerPageClick;
|
onPageClick?: OnPDFViewerPageClick;
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
@ -59,8 +57,6 @@ export type PDFViewerProps = {
|
|||||||
export const PDFViewer = ({
|
export const PDFViewer = ({
|
||||||
className,
|
className,
|
||||||
documentData,
|
documentData,
|
||||||
password: defaultPassword,
|
|
||||||
onPasswordSubmit,
|
|
||||||
onDocumentLoad,
|
onDocumentLoad,
|
||||||
onPageClick,
|
onPageClick,
|
||||||
...props
|
...props
|
||||||
@ -70,11 +66,7 @@ export const PDFViewer = ({
|
|||||||
|
|
||||||
const $el = useRef<HTMLDivElement>(null);
|
const $el = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const passwordCallbackRef = useRef<((password: string | null) => void) | null>(null);
|
|
||||||
|
|
||||||
const [isDocumentBytesLoading, setIsDocumentBytesLoading] = useState(false);
|
const [isDocumentBytesLoading, setIsDocumentBytesLoading] = useState(false);
|
||||||
const [isPasswordModalOpen, setIsPasswordModalOpen] = useState(false);
|
|
||||||
const [isPasswordError, setIsPasswordError] = useState(false);
|
|
||||||
const [documentBytes, setDocumentBytes] = useState<Uint8Array | null>(null);
|
const [documentBytes, setDocumentBytes] = useState<Uint8Array | null>(null);
|
||||||
|
|
||||||
const [width, setWidth] = useState(0);
|
const [width, setWidth] = useState(0);
|
||||||
@ -190,21 +182,6 @@ export const PDFViewer = ({
|
|||||||
className={cn('w-full overflow-hidden rounded', {
|
className={cn('w-full overflow-hidden rounded', {
|
||||||
'h-[80vh] max-h-[60rem]': numPages === 0,
|
'h-[80vh] max-h-[60rem]': numPages === 0,
|
||||||
})}
|
})}
|
||||||
onPassword={(callback, reason) => {
|
|
||||||
// If the document already has a password, we don't need to ask for it again.
|
|
||||||
if (defaultPassword && reason !== PasswordResponses.INCORRECT_PASSWORD) {
|
|
||||||
callback(defaultPassword);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsPasswordModalOpen(true);
|
|
||||||
|
|
||||||
passwordCallbackRef.current = callback;
|
|
||||||
|
|
||||||
match(reason)
|
|
||||||
.with(PasswordResponses.NEED_PASSWORD, () => setIsPasswordError(false))
|
|
||||||
.with(PasswordResponses.INCORRECT_PASSWORD, () => setIsPasswordError(true));
|
|
||||||
}}
|
|
||||||
onLoadSuccess={(d) => onDocumentLoaded(d)}
|
onLoadSuccess={(d) => onDocumentLoaded(d)}
|
||||||
// Uploading a invalid document causes an error which doesn't appear to be handled by the `error` prop.
|
// Uploading a invalid document causes an error which doesn't appear to be handled by the `error` prop.
|
||||||
// Therefore we add some additional custom error handling.
|
// Therefore we add some additional custom error handling.
|
||||||
@ -263,19 +240,6 @@ export const PDFViewer = ({
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</PDFDocument>
|
</PDFDocument>
|
||||||
|
|
||||||
<PasswordDialog
|
|
||||||
open={isPasswordModalOpen}
|
|
||||||
onOpenChange={setIsPasswordModalOpen}
|
|
||||||
onPasswordSubmit={(password) => {
|
|
||||||
passwordCallbackRef.current?.(password);
|
|
||||||
|
|
||||||
setIsPasswordModalOpen(false);
|
|
||||||
|
|
||||||
void onPasswordSubmit?.(password);
|
|
||||||
}}
|
|
||||||
isError={isPasswordError}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user