mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 00:03:33 +10:00
fix: resolve issues with signing document stickiness
This commit is contained in:
@ -12,7 +12,7 @@ export type AdminSectionLayoutProps = {
|
||||
};
|
||||
|
||||
export default async function AdminSectionLayout({ children }: AdminSectionLayoutProps) {
|
||||
const user = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
if (!isAdmin(user)) {
|
||||
redirect('/documents');
|
||||
|
||||
@ -30,11 +30,11 @@ export default async function DocumentPage({ params }: DocumentPageProps) {
|
||||
redirect('/documents');
|
||||
}
|
||||
|
||||
const session = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
const document = await getDocumentById({
|
||||
id: documentId,
|
||||
userId: session.id,
|
||||
userId: user.id,
|
||||
}).catch(() => null);
|
||||
|
||||
if (!document || !document.documentData) {
|
||||
@ -50,11 +50,11 @@ export default async function DocumentPage({ params }: DocumentPageProps) {
|
||||
const [recipients, fields] = await Promise.all([
|
||||
await getRecipientsForDocument({
|
||||
documentId,
|
||||
userId: session.id,
|
||||
userId: user.id,
|
||||
}),
|
||||
await getFieldsForDocument({
|
||||
documentId,
|
||||
userId: session.id,
|
||||
userId: user.id,
|
||||
}),
|
||||
]);
|
||||
|
||||
@ -87,7 +87,7 @@ export default async function DocumentPage({ params }: DocumentPageProps) {
|
||||
<EditDocumentForm
|
||||
className="mt-8"
|
||||
document={document}
|
||||
user={session}
|
||||
user={user}
|
||||
recipients={recipients}
|
||||
fields={fields}
|
||||
dataUrl={documentDataUrl}
|
||||
|
||||
@ -25,7 +25,7 @@ export type DocumentsPageProps = {
|
||||
};
|
||||
|
||||
export default async function DocumentsPage({ searchParams = {} }: DocumentsPageProps) {
|
||||
const user = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
const stats = await getStats({
|
||||
user,
|
||||
|
||||
@ -24,7 +24,7 @@ export default async function AuthenticatedDashboardLayout({
|
||||
redirect('/signin');
|
||||
}
|
||||
|
||||
const user = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
return (
|
||||
<NextAuthProvider session={session}>
|
||||
|
||||
@ -12,7 +12,7 @@ import { Button } from '@documenso/ui/primitives/button';
|
||||
import { LocaleDate } from '~/components/formatter/locale-date';
|
||||
|
||||
export default async function BillingSettingsPage() {
|
||||
const user = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
const isBillingEnabled = await getServerComponentFlag('app_billing');
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-
|
||||
import { PasswordForm } from '~/components/forms/password';
|
||||
|
||||
export default async function PasswordSettingsPage() {
|
||||
const user = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@ -3,7 +3,7 @@ import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-
|
||||
import { ProfileForm } from '~/components/forms/profile';
|
||||
|
||||
export default async function ProfileSettingsPage() {
|
||||
const user = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@ -53,7 +53,7 @@ export default async function CompletedSigningPage({
|
||||
recipient.email;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center pt-24 lg:pt-36 xl:pt-44">
|
||||
<div className="-mx-4 flex max-w-[100vw] flex-col items-center overflow-x-hidden px-4 pt-24 md:-mx-8 md:px-8 lg:pt-36 xl:pt-44">
|
||||
{/* Card with recipient */}
|
||||
<SigningCard3D name={recipientName} signingCelebrationImage={signingCelebration} />
|
||||
|
||||
|
||||
@ -106,7 +106,7 @@ export const ShareButton = ({ token, documentId }: ShareButtonProps) => {
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent>
|
||||
<DialogContent position="end">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Share</DialogTitle>
|
||||
|
||||
@ -119,7 +119,7 @@ export const ShareButton = ({ token, documentId }: ShareButtonProps) => {
|
||||
<span className="font-medium text-blue-400">@documenso</span>
|
||||
. Check it out!
|
||||
<span className="mt-2 block" />
|
||||
<span className="font-medium text-blue-400">
|
||||
<span className="break-all font-medium text-blue-400">
|
||||
{window.location.origin}/share/{shareLink?.slug || '...'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@ -4,6 +4,7 @@ import { useMemo, useState } from 'react';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token';
|
||||
@ -27,6 +28,7 @@ export type SigningFormProps = {
|
||||
|
||||
export const SigningForm = ({ document, recipient, fields }: SigningFormProps) => {
|
||||
const router = useRouter();
|
||||
const { data: session } = useSession();
|
||||
|
||||
const { fullName, signature, setFullName, setSignature } = useRequiredSigningContext();
|
||||
|
||||
@ -60,7 +62,11 @@ export const SigningForm = ({ document, recipient, fields }: SigningFormProps) =
|
||||
return (
|
||||
<form
|
||||
className={cn(
|
||||
'dark:bg-background border-border bg-widget sticky top-20 flex h-full max-h-[80rem] flex-col rounded-xl border px-4 py-6',
|
||||
'dark:bg-background border-border bg-widget sticky flex h-full flex-col rounded-xl border px-4 py-6',
|
||||
{
|
||||
'top-20 max-h-[min(68rem,calc(100vh-6rem))]': session,
|
||||
'top-4 max-h-[min(68rem,calc(100vh-2rem))]': !session,
|
||||
},
|
||||
)}
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
>
|
||||
|
||||
@ -10,11 +10,11 @@ export type SigningLayoutProps = {
|
||||
};
|
||||
|
||||
export default async function SigningLayout({ children }: SigningLayoutProps) {
|
||||
const user = await getServerComponentSession();
|
||||
const { user, session } = await getServerComponentSession();
|
||||
|
||||
return (
|
||||
<NextAuthProvider>
|
||||
<div className="min-h-screen overflow-hidden">
|
||||
<NextAuthProvider session={session}>
|
||||
<div className="min-h-screen">
|
||||
{user && <AuthenticatedHeader user={user} />}
|
||||
|
||||
<main className="mb-8 mt-8 px-4 md:mb-12 md:mt-12 md:px-8">{children}</main>
|
||||
|
||||
@ -51,7 +51,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
|
||||
.then((buffer) => Buffer.from(buffer).toString('base64'))
|
||||
.then((data) => `data:application/pdf;base64,${data}`);
|
||||
|
||||
const user = await getServerComponentSession();
|
||||
const { user } = await getServerComponentSession();
|
||||
|
||||
if (
|
||||
document.status === DocumentStatus.COMPLETED ||
|
||||
@ -62,7 +62,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
|
||||
|
||||
return (
|
||||
<SigningProvider email={recipient.email} fullName={recipient.name} signature={user?.signature}>
|
||||
<div className="mx-auto w-full max-w-screen-xl px-4 md:px-8">
|
||||
<div className="mx-auto w-full max-w-screen-xl">
|
||||
<h1 className="mt-4 truncate text-2xl font-semibold md:text-3xl" title={document.title}>
|
||||
{document.title}
|
||||
</h1>
|
||||
|
||||
@ -6,7 +6,7 @@ import { Button } from '@documenso/ui/primitives/button';
|
||||
import NotFoundPartial from '~/components/partials/not-found';
|
||||
|
||||
export default async function NotFound() {
|
||||
const session = await getServerComponentSession();
|
||||
const { session } = await getServerComponentSession();
|
||||
|
||||
return (
|
||||
<NotFoundPartial>
|
||||
|
||||
@ -11,10 +11,10 @@ export type AddFieldsActionInput = TAddFieldsFormSchema & {
|
||||
export const addFields = async ({ documentId, fields }: AddFieldsActionInput) => {
|
||||
'use server';
|
||||
|
||||
const { id: userId } = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
await setFieldsForDocument({
|
||||
userId,
|
||||
userId: user.id,
|
||||
documentId,
|
||||
fields: fields.map((field) => ({
|
||||
id: field.nativeId,
|
||||
|
||||
@ -11,10 +11,10 @@ export type AddSignersActionInput = TAddSignersFormSchema & {
|
||||
export const addSigners = async ({ documentId, signers }: AddSignersActionInput) => {
|
||||
'use server';
|
||||
|
||||
const { id: userId } = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
await setRecipientsForDocument({
|
||||
userId,
|
||||
userId: user.id,
|
||||
documentId,
|
||||
recipients: signers.map((signer) => ({
|
||||
id: signer.nativeId,
|
||||
|
||||
@ -12,7 +12,7 @@ export type CompleteDocumentActionInput = TAddSubjectFormSchema & {
|
||||
export const completeDocument = async ({ documentId, email }: CompleteDocumentActionInput) => {
|
||||
'use server';
|
||||
|
||||
const { id: userId } = await getRequiredServerComponentSession();
|
||||
const { user } = await getRequiredServerComponentSession();
|
||||
|
||||
if (email.message || email.subject) {
|
||||
await upsertDocumentMeta({
|
||||
@ -23,7 +23,7 @@ export const completeDocument = async ({ documentId, email }: CompleteDocumentAc
|
||||
}
|
||||
|
||||
return await sendDocument({
|
||||
userId,
|
||||
userId: user.id,
|
||||
documentId,
|
||||
});
|
||||
};
|
||||
|
||||
@ -15,7 +15,7 @@ export const getServerSession = async ({ req, res }: GetServerSessionOptions) =>
|
||||
const session = await getNextAuthServerSession(req, res, NEXT_AUTH_OPTIONS);
|
||||
|
||||
if (!session || !session.user?.email) {
|
||||
return null;
|
||||
return { user: null, session: null };
|
||||
}
|
||||
|
||||
const user = await prisma.user.findFirstOrThrow({
|
||||
@ -24,14 +24,14 @@ export const getServerSession = async ({ req, res }: GetServerSessionOptions) =>
|
||||
},
|
||||
});
|
||||
|
||||
return user;
|
||||
return { user, session };
|
||||
};
|
||||
|
||||
export const getServerComponentSession = async () => {
|
||||
const session = await getNextAuthServerSession(NEXT_AUTH_OPTIONS);
|
||||
|
||||
if (!session || !session.user?.email) {
|
||||
return null;
|
||||
return { user: null, session: null };
|
||||
}
|
||||
|
||||
const user = await prisma.user.findFirstOrThrow({
|
||||
@ -40,15 +40,15 @@ export const getServerComponentSession = async () => {
|
||||
},
|
||||
});
|
||||
|
||||
return user;
|
||||
return { user, session };
|
||||
};
|
||||
|
||||
export const getRequiredServerComponentSession = async () => {
|
||||
const session = await getServerComponentSession();
|
||||
const { user, session } = await getServerComponentSession();
|
||||
|
||||
if (!session) {
|
||||
if (!user || !session) {
|
||||
throw new Error('No session found');
|
||||
}
|
||||
|
||||
return session;
|
||||
return { user, session };
|
||||
};
|
||||
|
||||
@ -17,7 +17,7 @@ import { alphaid } from '../id';
|
||||
export const getPresignPostUrl = async (fileName: string, contentType: string) => {
|
||||
const client = getS3Client();
|
||||
|
||||
const user = await getServerComponentSession();
|
||||
const { user } = await getServerComponentSession();
|
||||
|
||||
// Get the basename and extension for the file
|
||||
const { name, ext } = path.parse(fileName);
|
||||
|
||||
@ -3,7 +3,7 @@ import { CreateNextContextOptions } from '@trpc/server/adapters/next';
|
||||
import { getServerSession } from '@documenso/lib/next-auth/get-server-session';
|
||||
|
||||
export const createTrpcContext = async ({ req, res }: CreateNextContextOptions) => {
|
||||
const session = await getServerSession({ req, res });
|
||||
const { session, user } = await getServerSession({ req, res });
|
||||
|
||||
if (!session) {
|
||||
return {
|
||||
@ -12,9 +12,16 @@ export const createTrpcContext = async ({ req, res }: CreateNextContextOptions)
|
||||
};
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return {
|
||||
session: null,
|
||||
user: null,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
session,
|
||||
user: session,
|
||||
user,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -11,9 +11,19 @@ const Dialog = DialogPrimitive.Root;
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger;
|
||||
|
||||
const DialogPortal = ({ className, children, ...props }: DialogPrimitive.DialogPortalProps) => (
|
||||
const DialogPortal = ({
|
||||
className,
|
||||
children,
|
||||
position = 'start',
|
||||
...props
|
||||
}: DialogPrimitive.DialogPortalProps & { position?: 'start' | 'end' }) => (
|
||||
<DialogPrimitive.Portal className={cn(className)} {...props}>
|
||||
<div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">
|
||||
<div
|
||||
className={cn('fixed inset-0 z-50 flex justify-center sm:items-center', {
|
||||
'items-start': position === 'start',
|
||||
'items-end': position === 'end',
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</DialogPrimitive.Portal>
|
||||
@ -39,14 +49,14 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & { position?: 'start' | 'end' }
|
||||
>(({ className, children, position = 'start', ...props }, ref) => (
|
||||
<DialogPortal position={position}>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'bg-background animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0 fixed z-50 grid w-full gap-4 rounded-b-lg border p-6 shadow-lg sm:max-w-lg sm:rounded-lg',
|
||||
'bg-background animate-in data-[state=open]:fade-in-90 sm:zoom-in-90 data-[state=open]:slide-in-from-bottom-10 data-[state=open]:sm:slide-in-from-bottom-0 fixed z-50 grid w-full gap-4 rounded-b-lg border p-6 shadow-lg sm:max-w-lg sm:rounded-lg',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
Reference in New Issue
Block a user