diff --git a/components/datarooms/folders/view-tree.tsx b/components/datarooms/folders/view-tree.tsx index 605d39fc6..ab81e9136 100644 --- a/components/datarooms/folders/view-tree.tsx +++ b/components/datarooms/folders/view-tree.tsx @@ -96,7 +96,7 @@ const FolderComponent = memo( }: { folder: DataroomFolderWithDocuments; folderId: string | null; - setFolderId: React.Dispatch>; + setFolderId: (id: string | null) => void; folderPath: Set | null; dataroomIndexEnabled?: boolean; }) => { @@ -182,7 +182,7 @@ const HomeLink = memo( setFolderId, }: { folderId: string | null; - setFolderId: React.Dispatch>; + setFolderId: (id: string | null) => void; }) => { const { usesLightText, palette } = useViewerSurfaceTheme(); @@ -238,7 +238,7 @@ const SidebarFolders = ({ folders: DataroomFolder[]; documents: DataroomDocumentWithVersion[]; folderId: string | null; - setFolderId: React.Dispatch>; + setFolderId: (id: string | null) => void; dataroomIndexEnabled?: boolean; }) => { const { usesLightText, palette } = useViewerSurfaceTheme(); @@ -303,7 +303,7 @@ export function ViewFolderTree({ }: { folders: DataroomFolder[]; documents: DataroomDocumentWithVersion[]; - setFolderId: React.Dispatch>; + setFolderId: (id: string | null) => void; folderId: string | null; dataroomIndexEnabled?: boolean; }) { diff --git a/components/view/dataroom/dataroom-view.tsx b/components/view/dataroom/dataroom-view.tsx index 85df1fe32..29c9cb1a1 100644 --- a/components/view/dataroom/dataroom-view.tsx +++ b/components/view/dataroom/dataroom-view.tsx @@ -48,6 +48,17 @@ export type DEFAULT_DATAROOM_VIEW_TYPE = { dataroomName?: string; }; +export type PreValidatedSession = { + viewId: string; + viewerEmail?: string; + viewerId?: string; + conversationsEnabled?: boolean; + enableVisitorUpload?: boolean; + isTeamMember?: boolean; + agentsEnabled?: boolean; + dataroomName?: string; +}; + export default function DataroomView({ link, userEmail, @@ -64,6 +75,8 @@ export default function DataroomView({ preview, dataroomIndexEnabled, textSelectionEnabled, + initialFolderId, + preValidatedSession, }: { link: LinkWithDataroom; userEmail: string | null | undefined; @@ -80,6 +93,8 @@ export default function DataroomView({ logoOnAccessForm?: boolean; dataroomIndexEnabled?: boolean; textSelectionEnabled?: boolean; + initialFolderId?: string | null; + preValidatedSession?: PreValidatedSession | null; }) { useDisablePrint(); const { @@ -93,14 +108,28 @@ export default function DataroomView({ const analytics = useAnalytics(); const router = useRouter(); - const [folderId, setFolderId] = useState(null); + const hasPreValidatedSession = !!preValidatedSession; + const [folderId, setFolderId] = useState( + initialFolderId ?? null, + ); const didMount = useRef(false); - const [submitted, setSubmitted] = useState(false); + const [submitted, setSubmitted] = useState(hasPreValidatedSession); const [isLoading, setIsLoading] = useState(false); - const [viewData, setViewData] = useState({ - viewId: "", - }); + const [viewData, setViewData] = useState( + hasPreValidatedSession + ? { + viewId: preValidatedSession.viewId, + viewerEmail: preValidatedSession.viewerEmail, + viewerId: preValidatedSession.viewerId, + conversationsEnabled: preValidatedSession.conversationsEnabled, + enableVisitorUpload: preValidatedSession.enableVisitorUpload, + isTeamMember: preValidatedSession.isTeamMember, + agentsEnabled: preValidatedSession.agentsEnabled, + dataroomName: preValidatedSession.dataroomName, + } + : { viewId: "" }, + ); const [data, setData] = useState( DEFAULT_ACCESS_FORM_DATA, ); @@ -118,8 +147,8 @@ export default function DataroomView({ ? brand?.accentColor : "#ffffff"; - const handleSubmission = async (): Promise => { - setIsLoading(true); + const handleSubmission = async (background = false): Promise => { + if (!background) setIsLoading(true); const response = await fetch("/api/views-dataroom", { method: "POST", headers: { @@ -144,8 +173,10 @@ export default function DataroomView({ const fetchData = await response.json(); if (fetchData.type === "email-verification") { - setVerificationRequested(true); - setIsLoading(false); + if (!background) { + setVerificationRequested(true); + setIsLoading(false); + } } else { const { viewId, @@ -174,14 +205,7 @@ export default function DataroomView({ teamId: link.teamId, }); - // set the verification token to the cookie if (verificationToken) { - // Cookies.set("pm_vft", verificationToken, { - // path: router.asPath.split("?")[0], - // expires: 1, - // sameSite: "strict", - // secure: true, - // }); setCode(null); } @@ -196,23 +220,27 @@ export default function DataroomView({ agentsEnabled, dataroomName, }); - setSubmitted(true); - setVerificationRequested(false); - setIsLoading(false); + if (!background) { + setSubmitted(true); + setVerificationRequested(false); + setIsLoading(false); + } } } else { - const data = await response.json(); - toast.error(data.message); + const responseData = await response.json(); + if (!background) { + toast.error(responseData.message); + } - if (data.resetVerification) { + if (responseData.resetVerification) { const currentPath = router.asPath.split("?")[0]; Cookies.remove("pm_vft", { path: currentPath }); setVerificationToken(null); setCode(null); - setIsInvalidCode(true); + if (!background) setIsInvalidCode(true); } - setIsLoading(false); + if (!background) setIsLoading(false); } }; @@ -223,10 +251,18 @@ export default function DataroomView({ await handleSubmission(); }; - // If token is present, run handle submit which will verify token and get document - // If link is not submitted and does not have email / password protection, show the access form + // For pre-validated sessions: fire background API call to record the view + // without blocking the UI (content is already visible) + useEffect(() => { + if (hasPreValidatedSession && !didMount.current) { + didMount.current = true; + handleSubmission(true); + } + }, [hasPreValidatedSession]); + + // Normal flow: verify token or auto-submit when not protected useEffect(() => { - if (!didMount.current) { + if (!hasPreValidatedSession && !didMount.current) { if ((!submitted && !isProtected) || token || preview || previewToken) { handleSubmission(); didMount.current = true; @@ -250,8 +286,8 @@ export default function DataroomView({ ); } - // If link is not submitted and does not have email / password protection, show the access form - if (!submitted && isProtected) { + // Show access form if not submitted, not pre-validated, and link is protected + if (!submitted && !hasPreValidatedSession && isProtected) { return ( void; + onNavigate: (id: string | null) => void; isLast: boolean; dataroomIndexEnabled?: boolean; }) => { @@ -90,7 +90,7 @@ const ViewerBreadcrumbItem = ({ return ( setFolderId(folder.id)} + onClick={() => onNavigate(folder.id)} className="cursor-pointer capitalize text-[var(--viewer-muted-text)] hover:text-[var(--viewer-text)]" style={HIERARCHICAL_DISPLAY_STYLE} > @@ -184,6 +184,63 @@ export default function DataroomViewer({ const router = useRouter(); const searchQuery = (router.query.search as string)?.toLowerCase() || ""; + const { domain, slug, previewToken: queryPreviewToken } = router.query as { + domain?: string; + slug?: string; + previewToken?: string; + }; + + const buildFolderUrl = useCallback( + (targetFolderId: string | null) => { + const queryString = queryPreviewToken + ? `?previewToken=${queryPreviewToken}&preview=1` + : ""; + + if (domain && slug) { + return targetFolderId + ? `/${slug}/f/${targetFolderId}${queryString}` + : `/${slug}${queryString}`; + } + return targetFolderId + ? `/view/${linkId}/f/${targetFolderId}${queryString}` + : `/view/${linkId}${queryString}`; + }, + [linkId, domain, slug, queryPreviewToken], + ); + + const handleFolderChange = useCallback( + (newFolderId: string | null) => { + setFolderId(newFolderId); + window.history.pushState( + { folderId: newFolderId }, + "", + buildFolderUrl(newFolderId), + ); + }, + [setFolderId, buildFolderUrl], + ); + + useEffect(() => { + const handlePopState = (event: PopStateEvent) => { + const stateFolderId = event.state?.folderId ?? null; + setFolderId(stateFolderId); + }; + + window.addEventListener("popstate", handlePopState); + return () => window.removeEventListener("popstate", handlePopState); + }, [setFolderId]); + + // Replace the initial history entry so back-button state is consistent + useEffect(() => { + if (folderId) { + window.history.replaceState( + { folderId }, + "", + buildFolderUrl(folderId), + ); + } + }, []); + // Tab state: "documents" (normal view) or "my-uploads" (visitor's uploads) const [activeTab, setActiveTab] = useState<"documents" | "my-uploads">( "documents", @@ -426,7 +483,7 @@ export default function DataroomViewer({ key={item.id} folder={item} dataroomId={dataroom?.id} - setFolderId={setFolderId} + setFolderId={handleFolderChange} isPreview={!!isPreview} linkId={linkId} viewId={viewId} @@ -534,7 +591,7 @@ export default function DataroomViewer({ @@ -580,7 +637,7 @@ export default function DataroomViewer({ @@ -600,7 +657,7 @@ export default function DataroomViewer({ setFolderId(null)} + onClick={() => handleFolderChange(null)} className="cursor-pointer text-[var(--viewer-muted-text)] hover:text-[var(--viewer-text)]" > Home @@ -615,7 +672,7 @@ export default function DataroomViewer({ @@ -735,7 +792,7 @@ export default function DataroomViewer({ linkId={linkId} showFolderPath onNavigateToFolder={(id) => { - setFolderId(id); + handleFolderChange(id); setActiveTab("documents"); }} /> diff --git a/pages/view/[linkId]/f/[folderId].tsx b/pages/view/[linkId]/f/[folderId].tsx new file mode 100644 index 000000000..c88ef9ab2 --- /dev/null +++ b/pages/view/[linkId]/f/[folderId].tsx @@ -0,0 +1,338 @@ +import { GetServerSidePropsContext } from "next"; +import { useRouter } from "next/router"; + +import { useEffect, useState } from "react"; + +import NotFound from "@/pages/404"; +import { DataroomBrand } from "@prisma/client"; +import Cookies from "js-cookie"; +import { useSession } from "next-auth/react"; +import z from "zod"; + +import { fetchLinkDataById } from "@/lib/api/links/link-data"; +import { verifyDataroomSessionInPagesRouter } from "@/lib/auth/dataroom-auth"; +import { getFeatureFlags } from "@/lib/featureFlags"; +import prisma from "@/lib/prisma"; +import { CustomUser, LinkWithDataroom } from "@/lib/types"; + +import LoadingSpinner from "@/components/ui/loading-spinner"; +import CustomMetaTag from "@/components/view/custom-metatag"; +import DataroomView from "@/components/view/dataroom/dataroom-view"; + +type DataroomLinkData = { + linkType: "DATAROOM_LINK"; + link: LinkWithDataroom; + brand: DataroomBrand | null; +}; + +type PreValidatedSession = { + viewId: string; + viewerEmail?: string; + viewerId?: string; + conversationsEnabled?: boolean; + enableVisitorUpload?: boolean; + isTeamMember?: boolean; + agentsEnabled?: boolean; + dataroomName?: string; +}; + +type FolderPageProps = { + linkData: DataroomLinkData; + meta: { + enableCustomMetatag: boolean; + metaTitle: string | null; + metaDescription: string | null; + metaImage: string | null; + metaFavicon: string; + metaUrl: string; + }; + useCustomAccessForm: boolean; + logoOnAccessForm: boolean; + dataroomIndexEnabled?: boolean; + textSelectionEnabled?: boolean; + initialFolderId: string; + preValidatedSession: PreValidatedSession | null; + error?: boolean; +}; + +export async function getServerSideProps(context: GetServerSidePropsContext) { + const { linkId: linkIdParam, folderId: folderIdParam } = context.params as { + linkId: string; + folderId: string; + }; + + try { + const linkId = z.string().cuid().parse(linkIdParam); + const folderId = z.string().cuid().parse(folderIdParam); + + const result = await fetchLinkDataById({ linkId }); + if (result.status !== "ok") { + return { notFound: true }; + } + + const { linkType, link, brand } = result; + if (!link || linkType !== "DATAROOM_LINK") { + return { notFound: true }; + } + + const folderExists = link.dataroom.folders.some( + (f: any) => f.id === folderId, + ); + if (!folderExists) { + return { notFound: true }; + } + + let documents = []; + for (const document of link.dataroom.documents) { + const { file, updatedAt, ...versionWithoutTypeAndFile } = + document.document.versions[0]; + + const newDocument = { + ...document.document, + dataroomDocumentId: document.id, + folderId: document.folderId, + orderIndex: document.orderIndex, + hierarchicalIndex: document.hierarchicalIndex, + versions: [ + { + ...versionWithoutTypeAndFile, + updatedAt: + document.updatedAt > updatedAt ? document.updatedAt : updatedAt, + }, + ], + }; + + documents.push(newDocument); + } + + const { teamId } = link.dataroom; + const featureFlags = await getFeatureFlags({ teamId }); + const dataroomIndexEnabled = featureFlags.dataroomIndex; + const textSelectionEnabled = featureFlags.textSelection; + + const lastUpdatedAt = link.dataroom.documents.reduce( + (max: number, doc: any) => { + return Math.max( + max, + new Date(doc.document.versions[0].updatedAt).getTime(), + ); + }, + new Date(link.dataroom.createdAt).getTime(), + ); + + // Server-side session validation + let preValidatedSession: PreValidatedSession | null = null; + const dataroomSession = await verifyDataroomSessionInPagesRouter( + context.req as any, + linkId, + link.dataroomId!, + ); + + if (dataroomSession) { + const [viewer, linkConfig] = await Promise.all([ + dataroomSession.viewerId + ? prisma.viewer.findUnique({ + where: { id: dataroomSession.viewerId }, + select: { email: true }, + }) + : null, + prisma.link.findUnique({ + where: { id: linkId }, + select: { + enableConversation: true, + enableUpload: true, + dataroom: { select: { agentsEnabled: true, name: true } }, + }, + }), + ]); + + preValidatedSession = { + viewId: dataroomSession.viewId, + viewerId: dataroomSession.viewerId, + viewerEmail: viewer?.email ?? undefined, + conversationsEnabled: linkConfig?.enableConversation ?? undefined, + enableVisitorUpload: linkConfig?.enableUpload ?? undefined, + agentsEnabled: linkConfig?.dataroom?.agentsEnabled ?? false, + dataroomName: linkConfig?.dataroom?.name ?? undefined, + }; + } + + return { + props: { + linkData: { + linkType: "DATAROOM_LINK", + link: { + ...link, + teamId: teamId, + dataroom: { + ...link.dataroom, + documents, + lastUpdatedAt: lastUpdatedAt, + }, + }, + brand, + }, + meta: { + enableCustomMetatag: link.enableCustomMetatag || false, + metaTitle: link.metaTitle, + metaDescription: link.metaDescription, + metaImage: link.metaImage, + metaFavicon: link.metaFavicon ?? "/favicon.ico", + metaUrl: `https://www.papermark.com/view/${linkId}/f/${folderId}`, + }, + useCustomAccessForm: [ + "cm0154tiv0000lr2t6nr5c6kp", + "clup33by90000oewh4rfvp2eg", + "cm76hfyvy0002q623hmen99pf", + "cm9ztf0s70005js04i689gefn", + "cmk2hnmqh0000k304zcoezt6n", + ].includes(teamId), + logoOnAccessForm: [ + "cm7nlkrhm0000qgh0nvyrrywr", + "clup33by90000oewh4rfvp2eg", + ].includes(teamId), + dataroomIndexEnabled, + textSelectionEnabled, + initialFolderId: folderId, + preValidatedSession, + }, + }; + } catch (error) { + console.error( + "Fetching error:", + error instanceof Error ? error.message : String(error), + ); + return { props: { error: true } }; + } +} + +export default function FolderViewPage({ + linkData, + meta, + useCustomAccessForm, + logoOnAccessForm, + dataroomIndexEnabled, + textSelectionEnabled, + initialFolderId, + preValidatedSession, + error, +}: FolderPageProps) { + const router = useRouter(); + const { data: session, status } = useSession(); + const [storedToken, setStoredToken] = useState(undefined); + const [storedEmail, setStoredEmail] = useState(undefined); + + useEffect(() => { + const cookieToken = Cookies.get(`pm_drs_flag_${router.query.linkId}`); + const storedEmail = window.localStorage.getItem("papermark.email"); + if (cookieToken) { + setStoredToken(cookieToken); + if (storedEmail) { + setStoredEmail(storedEmail.toLowerCase()); + } + } + }, [router.query.linkId]); + + if (error) { + return ( + + ); + } + + if (!linkData) { + return ( +
+ +
+ ); + } + + const { + email: verifiedEmail, + d: disableEditEmail, + previewToken, + preview, + } = router.query as { + email: string; + d: string; + previewToken?: string; + preview?: string; + }; + + const { link, brand } = linkData; + + if (!link || status === "loading") { + return ( + <> + +
+ +
+ + ); + } + + const { + expiresAt, + emailProtected, + password: linkPassword, + enableAgreement, + isArchived, + } = link; + + const { email: userEmail, id: userId } = (session?.user as CustomUser) || {}; + + if (expiresAt && new Date(expiresAt) < new Date()) { + return ( + + ); + } + + if (isArchived) { + return ( + + ); + } + + return ( + <> + + + + ); +} diff --git a/pages/view/domains/[domain]/[slug]/f/[folderId].tsx b/pages/view/domains/[domain]/[slug]/f/[folderId].tsx new file mode 100644 index 000000000..fb7a2452d --- /dev/null +++ b/pages/view/domains/[domain]/[slug]/f/[folderId].tsx @@ -0,0 +1,351 @@ +import { GetServerSidePropsContext } from "next"; +import { useRouter } from "next/router"; + +import { useEffect, useState } from "react"; + +import NotFound from "@/pages/404"; +import { DataroomBrand } from "@prisma/client"; +import Cookies from "js-cookie"; +import { useSession } from "next-auth/react"; +import z from "zod"; + +import { fetchLinkDataByDomainSlug } from "@/lib/api/links/link-data"; +import { verifyDataroomSessionInPagesRouter } from "@/lib/auth/dataroom-auth"; +import { getFeatureFlags } from "@/lib/featureFlags"; +import prisma from "@/lib/prisma"; +import { CustomUser, LinkWithDataroom } from "@/lib/types"; + +import LoadingSpinner from "@/components/ui/loading-spinner"; +import CustomMetaTag from "@/components/view/custom-metatag"; +import DataroomView from "@/components/view/dataroom/dataroom-view"; + +type DataroomLinkData = { + linkType: "DATAROOM_LINK"; + link: LinkWithDataroom; + brand: DataroomBrand | null; +}; + +type PreValidatedSession = { + viewId: string; + viewerEmail?: string; + viewerId?: string; + conversationsEnabled?: boolean; + enableVisitorUpload?: boolean; + isTeamMember?: boolean; + agentsEnabled?: boolean; + dataroomName?: string; +}; + +type FolderPageProps = { + linkData: DataroomLinkData; + meta: { + enableCustomMetatag: boolean; + metaTitle: string | null; + metaDescription: string | null; + metaImage: string | null; + metaFavicon: string; + metaUrl: string; + }; + useCustomAccessForm: boolean; + logoOnAccessForm: boolean; + dataroomIndexEnabled?: boolean; + textSelectionEnabled?: boolean; + initialFolderId: string; + preValidatedSession: PreValidatedSession | null; + error?: boolean; +}; + +export async function getServerSideProps(context: GetServerSidePropsContext) { + const { + domain: domainParam, + slug: slugParam, + folderId: folderIdParam, + } = context.params as { + domain: string; + slug: string; + folderId: string; + }; + + try { + const domain = z + .string() + .regex(/^([a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/) + .parse(domainParam); + const slug = z + .string() + .regex(/^[a-zA-Z0-9_-]+$/, "Invalid path parameter") + .parse(slugParam); + const folderId = z.string().cuid().parse(folderIdParam); + + const result = await fetchLinkDataByDomainSlug({ domain, slug }); + if (result.status !== "ok") { + return { notFound: true }; + } + + const { linkType, link, brand } = result; + if (!link || linkType !== "DATAROOM_LINK") { + return { notFound: true }; + } + + const folderExists = link.dataroom.folders.some( + (f: any) => f.id === folderId, + ); + if (!folderExists) { + return { notFound: true }; + } + + let documents = []; + for (const document of link.dataroom.documents) { + const { file, updatedAt, ...versionWithoutTypeAndFile } = + document.document.versions[0]; + + const newDocument = { + ...document.document, + dataroomDocumentId: document.id, + folderId: document.folderId, + orderIndex: document.orderIndex, + hierarchicalIndex: document.hierarchicalIndex, + versions: [ + { + ...versionWithoutTypeAndFile, + updatedAt: + document.updatedAt > updatedAt ? document.updatedAt : updatedAt, + }, + ], + }; + + documents.push(newDocument); + } + + const { teamId } = link.dataroom; + const featureFlags = await getFeatureFlags({ teamId }); + const dataroomIndexEnabled = featureFlags.dataroomIndex; + const textSelectionEnabled = featureFlags.textSelection; + + const lastUpdatedAt = link.dataroom.documents.reduce( + (max: number, doc: any) => { + return Math.max( + max, + new Date(doc.document.versions[0].updatedAt).getTime(), + ); + }, + new Date(link.dataroom.createdAt).getTime(), + ); + + // Server-side session validation using the link ID + const linkId = link.id; + let preValidatedSession: PreValidatedSession | null = null; + const dataroomSession = await verifyDataroomSessionInPagesRouter( + context.req as any, + linkId, + link.dataroomId!, + ); + + if (dataroomSession) { + const [viewer, linkConfig] = await Promise.all([ + dataroomSession.viewerId + ? prisma.viewer.findUnique({ + where: { id: dataroomSession.viewerId }, + select: { email: true }, + }) + : null, + prisma.link.findUnique({ + where: { id: linkId }, + select: { + enableConversation: true, + enableUpload: true, + dataroom: { select: { agentsEnabled: true, name: true } }, + }, + }), + ]); + + preValidatedSession = { + viewId: dataroomSession.viewId, + viewerId: dataroomSession.viewerId, + viewerEmail: viewer?.email ?? undefined, + conversationsEnabled: linkConfig?.enableConversation ?? undefined, + enableVisitorUpload: linkConfig?.enableUpload ?? undefined, + agentsEnabled: linkConfig?.dataroom?.agentsEnabled ?? false, + dataroomName: linkConfig?.dataroom?.name ?? undefined, + }; + } + + return { + props: { + linkData: { + linkType: "DATAROOM_LINK", + link: { + ...link, + teamId: teamId || null, + dataroom: { + ...link.dataroom, + documents, + lastUpdatedAt: lastUpdatedAt, + }, + }, + brand, + }, + meta: { + enableCustomMetatag: link.enableCustomMetatag || false, + metaTitle: link.metaTitle, + metaDescription: link.metaDescription, + metaImage: link.metaImage, + metaFavicon: link.metaFavicon || "/favicon.ico", + metaUrl: `https://${domain}/${slug}`, + }, + useCustomAccessForm: [ + "cm0154tiv0000lr2t6nr5c6kp", + "clup33by90000oewh4rfvp2eg", + "cm76hfyvy0002q623hmen99pf", + "cm9ztf0s70005js04i689gefn", + "cmk2hnmqh0000k304zcoezt6n", + ].includes(teamId), + logoOnAccessForm: [ + "cm7nlkrhm0000qgh0nvyrrywr", + "clup33by90000oewh4rfvp2eg", + ].includes(teamId), + dataroomIndexEnabled, + textSelectionEnabled, + initialFolderId: folderId, + preValidatedSession, + }, + }; + } catch (error) { + console.error( + "Fetching error:", + error instanceof Error ? error.message : String(error), + ); + return { props: { error: true } }; + } +} + +export default function FolderViewPage({ + linkData, + meta, + useCustomAccessForm, + logoOnAccessForm, + dataroomIndexEnabled, + textSelectionEnabled, + initialFolderId, + preValidatedSession, + error, +}: FolderPageProps) { + const router = useRouter(); + const { data: session, status } = useSession(); + const [storedToken, setStoredToken] = useState(undefined); + const [storedEmail, setStoredEmail] = useState(undefined); + + useEffect(() => { + const cookieToken = Cookies.get(`pm_drs_flag_${router.query.slug}`); + const storedEmail = window.localStorage.getItem("papermark.email"); + if (cookieToken) { + setStoredToken(cookieToken); + if (storedEmail) { + setStoredEmail(storedEmail.toLowerCase()); + } + } + }, [router.query.slug]); + + if (error) { + return ( + + ); + } + + if (!linkData) { + return ( +
+ +
+ ); + } + + const { + email: verifiedEmail, + d: disableEditEmail, + previewToken, + preview, + } = router.query as { + email: string; + d: string; + previewToken?: string; + preview?: string; + }; + + const { link, brand } = linkData; + + if (!link || status === "loading") { + return ( + <> + +
+ +
+ + ); + } + + const { + expiresAt, + emailProtected, + password: linkPassword, + enableAgreement, + isArchived, + } = link; + + const { email: userEmail, id: userId } = (session?.user as CustomUser) || {}; + + if (expiresAt && new Date(expiresAt) < new Date()) { + return ( + + ); + } + + if (isArchived) { + return ( + + ); + } + + return ( + <> + + + + ); +}