import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import { trpc } from '@documenso/trpc/react'; import { Button } from '@documenso/ui/primitives/button'; import { Trans } from '@lingui/react/macro'; import { AlertTriangleIcon, Loader2Icon } from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; export type CscRecipientSigningInProgressPageProps = { sessionId: string; recipientToken: string; }; /** * Rendered when the credential-scope OAuth callback has attached a SAD to the * server-side `CscSession` and set the `csc_sad_session` cookie. The page * auto-fires `enterprise.csc.signEnvelope` on mount and navigates to the * completion page on success. On failure, it surfaces an error message and * a retry CTA pointing at a fresh credential-scope OAuth round-trip. */ export const CscRecipientSigningInProgressPage = ({ sessionId, recipientToken, }: CscRecipientSigningInProgressPageProps) => { const { mutateAsync: signEnvelope } = trpc.enterprise.csc.signEnvelope.useMutation(); const [error, setError] = useState(null); // Ref rather than state for the fire-once guard. Refs mutate synchronously, // so React StrictMode's double-invoke of the effect sees the updated value // on the second pass and short-circuits. A useState guard would still let // the second effect fire because the queued setState from the first run // hasn't been committed yet when the second one reads it — that double-fire // races two signEnvelope calls; whichever loses sees the SAD already // consumed and flashes "Signing failed" before the winning call's // navigation kicks in. const hasFiredRef = useRef(false); useEffect(() => { if (hasFiredRef.current) { return; } hasFiredRef.current = true; const run = async () => { try { await signEnvelope({ sessionId, recipientToken }); window.location.href = `/sign/${recipientToken}/complete`; } catch (err) { const parsed = AppError.parseError(err); setError(parsed.code || AppErrorCode.UNKNOWN_ERROR); } }; void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const retryUrl = `/api/csc/oauth/authorize?scope=credential&session=${encodeURIComponent(sessionId)}`; return (
{error ? ( <>

Signing failed

{error === AppErrorCode.CSC_TSP_TIMEOUT ? ( The signing provider did not respond in time. Please retry. ) : error === AppErrorCode.CSC_SAD_EXPIRED_PRE_SIGN ? ( Your signing authorisation expired before the signature could be applied. Please reauthorise to retry. ) : ( Something went wrong while applying your signature. Please retry. )}

) : ( <>

Applying your signature

Please don't close this tab. The signing provider is finalising your signature.

)}
); };