Add electronic signature

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2026-02-16 23:12:09 +01:00
parent e6f9d7aae2
commit c191d25e9a
58 changed files with 7557 additions and 292 deletions

View File

@@ -0,0 +1,332 @@
import { sprintf } from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
import { Button, Card, Field, IconCircleX, Logo, Spinner } from "@probo/ui";
import { startTransition, useEffect, useRef } from "react";
import {
type PreloadedQuery,
useMutation,
usePreloadedQuery,
useRefetchableFragment,
} from "react-relay";
import { Navigate, useNavigate } from "react-router";
import { graphql } from "relay-runtime";
import { useWindowSize } from "usehooks-ts";
import { z } from "zod";
import { PDFPreview } from "#/components/PDFPreview";
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
import type { NDAPageAcceptElectronicSignatureMutation } from "./__generated__/NDAPageAcceptElectronicSignatureMutation.graphql";
import type { NDAPageFragment$key } from "./__generated__/NDAPageFragment.graphql";
import type { NDAPageQuery as NDAPageQueryType } from "./__generated__/NDAPageQuery.graphql";
import type { NDAPageRecordSigningEventMutation } from "./__generated__/NDAPageRecordSigningEventMutation.graphql";
import type { NDAPageRefetchQuery } from "./__generated__/NDAPageRefetchQuery.graphql";
export const ndaPageQuery = graphql`
query NDAPageQuery {
viewer {
fullName
}
currentTrustCenter @required(action: THROW) {
organization {
name
}
ndaFileUrl
ndaFileName
ndaSignature {
status
}
...NDAPageFragment
}
}
`;
const ndaPageFragment = graphql`
fragment NDAPageFragment on TrustCenter
@refetchable(queryName: "NDAPageRefetchQuery") {
ndaSignature @required(action: THROW) {
id
status
consentText
lastError
}
}
`;
const acceptElectronicSignatureMutation = graphql`
mutation NDAPageAcceptElectronicSignatureMutation(
$input: AcceptElectronicSignatureInput!
) {
acceptElectronicSignature(input: $input) {
signature {
id
status
}
}
}
`;
const recordSigningEventMutation = graphql`
mutation NDAPageRecordSigningEventMutation(
$input: RecordSigningEventInput!
) {
recordSigningEvent(input: $input) {
success
}
}
`;
const schema = z.object({
fullName: z.string().min(1),
});
export function NDAPage(props: {
queryRef: PreloadedQuery<NDAPageQueryType>;
}) {
const { __ } = useTranslate();
const navigate = useNavigate();
const documentViewedRef = useRef(false);
const queryData = usePreloadedQuery(ndaPageQuery, props.queryRef);
const trustCenter = queryData.currentTrustCenter;
const viewer = queryData.viewer;
const [data, refetch] = useRefetchableFragment<NDAPageRefetchQuery, NDAPageFragment$key>(
ndaPageFragment,
trustCenter,
);
const ndaSignature = data.ndaSignature;
const { width } = useWindowSize();
const isMobile = width < 1100;
const isDesktop = !isMobile;
const {
handleSubmit: handleSubmitWrapper,
register,
formState,
} = useFormWithSchema(schema, {
defaultValues: {
fullName: viewer?.fullName,
},
});
const [acceptSignature, isAccepting] = useMutation<NDAPageAcceptElectronicSignatureMutation>(
acceptElectronicSignatureMutation,
);
const [recordSigningEvent] = useMutation<NDAPageRecordSigningEventMutation>(
recordSigningEventMutation,
);
const isProcessing
= ndaSignature.status === "ACCEPTED"
|| ndaSignature.status === "PROCESSING";
const isFailed = ndaSignature.status === "FAILED";
const isCompleted = ndaSignature.status === "COMPLETED";
useEffect(() => {
if (isCompleted) {
navigate("/overview", { replace: true });
}
}, [isCompleted, navigate]);
useEffect(() => {
if (!isProcessing) return;
const poll = () => startTransition(() => {
refetch({}, { fetchPolicy: "network-only" });
});
const interval = setInterval(poll, 1500);
return () => clearInterval(interval);
}, [isProcessing, refetch]);
useEffect(() => {
if (
ndaSignature
&& ndaSignature.status === "PENDING"
&& !documentViewedRef.current
) {
documentViewedRef.current = true;
recordSigningEvent({
variables: {
input: {
signatureId: ndaSignature.id,
eventType: "DOCUMENT_VIEWED",
},
},
});
}
}, [ndaSignature, recordSigningEvent]);
const handleSubmit = handleSubmitWrapper(({ fullName }) => {
if (!ndaSignature) return;
if (ndaSignature.status === "PENDING") {
recordSigningEvent({
variables: {
input: {
signatureId: ndaSignature.id,
eventType: "FULL_NAME_TYPED",
},
},
});
}
recordSigningEvent({
variables: {
input: {
signatureId: ndaSignature.id,
eventType: "CONSENT_GIVEN",
},
},
onCompleted: () => {
acceptSignature({
variables: {
input: {
signatureId: ndaSignature.id,
fullName,
},
},
});
},
});
});
const handleTryAgain = () => {
if (ndaSignature && viewer?.fullName) {
acceptSignature({
variables: {
input: {
signatureId: ndaSignature.id,
fullName: viewer.fullName,
},
},
});
}
};
if (
!trustCenter.ndaFileUrl
|| !trustCenter.ndaSignature
|| trustCenter.ndaSignature.status === "COMPLETED"
) {
return <Navigate to="/overview" replace />;
}
const consentText = ndaSignature?.consentText
? ndaSignature.consentText
: __(
"By clicking Review & Sign, you agree to the terms of this NDA. If you have questions about the NDA, please contact security@probo.com.",
);
return (
<div className="bg-level-2 flex flex-col min-h-screen lg:h-screen">
<header className="flex items-center h-12 justify-between border-b border-border-solid px-4 flex-none">
<Logo />
</header>
<div className="grid lg:grid-cols-2 min-h-0 flex-1">
<div className="flex flex-col items-center overflow-y-auto">
<div className="max-w-[440px] w-full mx-auto px-4 py-12 lg:py-20 flex-1">
<h1 className="text-2xl font-semibold">
{__("Non-Disclosure Agreement")}
</h1>
<p className="text-txt-secondary mt-2">
{sprintf(
__(
"%s requires you to sign an NDA before accessing compliance documents.",
),
trustCenter.organization.name,
)}
</p>
{isMobile && trustCenter.ndaFileUrl && (
<Card className="flex justify-between py-3 px-4 text-sm items-center mt-6">
{trustCenter.ndaFileName}
<Button variant="secondary" asChild>
<a target="_blank" rel="noopener noreferrer" href={trustCenter.ndaFileUrl}>
{__("View document")}
</a>
</Button>
</Card>
)}
<form
onSubmit={
isFailed
? (e) => {
e.preventDefault();
handleTryAgain();
}
: e => void handleSubmit(e)
}
className="mt-8"
>
<Field
required
label={__("Full name")}
placeholder="John Doe"
{...register("fullName")}
type="text"
disabled={isProcessing}
/>
<p className="text-xs text-txt-tertiary mt-6">
{consentText}
</p>
{isFailed && (
<div className="flex items-start gap-2 mt-4 rounded-md bg-red-50 border border-red-200 p-3 text-sm text-red-800">
<IconCircleX size={16} className="mt-0.5 shrink-0" />
<div>
<p className="font-medium">
{__("Signature processing failed")}
</p>
<p className="mt-0.5 text-red-600">
{ndaSignature?.lastError
?? __("We encountered an issue processing your signature. Please try again.")}
</p>
</div>
</div>
)}
{isProcessing
? (
<Button
type="button"
className="h-10 w-full mt-4"
disabled
icon={Spinner}
>
{__("Sealing your signature...")}
</Button>
)
: (
<Button
type="submit"
className="h-10 w-full mt-4"
disabled={formState.isSubmitting || !formState.isValid}
icon={isAccepting ? Spinner : undefined}
>
{isFailed
? __("Try again")
: __("Accept")}
</Button>
)}
</form>
</div>
<a
href="https://www.getprobo.com/"
className="flex gap-1 text-sm font-medium text-txt-tertiary items-center py-6"
>
Powered by
{" "}
<Logo withPicto className="h-6" />
</a>
</div>
{isDesktop && (
<div className="bg-subtle h-full border-l border-border-solid min-h-0">
{trustCenter.ndaFileUrl && <PDFPreview src={trustCenter.ndaFileUrl} name={trustCenter.ndaFileName ?? ""} />}
</div>
)}
</div>
</div>
);
}

View File

@@ -0,0 +1,34 @@
import { Suspense, useEffect } from "react";
import { useQueryLoader } from "react-relay";
import { RelayProvider } from "#/providers/RelayProviders";
import type { NDAPageQuery } from "./__generated__/NDAPageQuery.graphql";
import { NDAPage, ndaPageQuery } from "./NDAPage";
function NDAPageQueryLoader() {
const [queryRef, loadQuery]
= useQueryLoader<NDAPageQuery>(ndaPageQuery);
useEffect(() => {
if (!queryRef) {
loadQuery({});
}
});
if (!queryRef) return null;
return (
<Suspense>
<NDAPage queryRef={queryRef} />
</Suspense>
);
}
export default function NDAPageLoader() {
return (
<RelayProvider>
<NDAPageQueryLoader />
</RelayProvider>
);
}

View File

@@ -0,0 +1,115 @@
/**
* @generated SignedSource<<41e415a03c63efbb590b1c2c782d5eac>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ElectronicSignatureStatus = "ACCEPTED" | "COMPLETED" | "FAILED" | "PENDING" | "PROCESSING";
export type AcceptElectronicSignatureInput = {
fullName: string;
signatureId: string;
};
export type NDAPageAcceptElectronicSignatureMutation$variables = {
input: AcceptElectronicSignatureInput;
};
export type NDAPageAcceptElectronicSignatureMutation$data = {
readonly acceptElectronicSignature: {
readonly signature: {
readonly id: string;
readonly status: ElectronicSignatureStatus;
};
} | null | undefined;
};
export type NDAPageAcceptElectronicSignatureMutation = {
response: NDAPageAcceptElectronicSignatureMutation$data;
variables: NDAPageAcceptElectronicSignatureMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "AcceptElectronicSignaturePayload",
"kind": "LinkedField",
"name": "acceptElectronicSignature",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ElectronicSignature",
"kind": "LinkedField",
"name": "signature",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "NDAPageAcceptElectronicSignatureMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "NDAPageAcceptElectronicSignatureMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "db0c219a7133025b56252836d7f1a85d",
"id": null,
"metadata": {},
"name": "NDAPageAcceptElectronicSignatureMutation",
"operationKind": "mutation",
"text": "mutation NDAPageAcceptElectronicSignatureMutation(\n $input: AcceptElectronicSignatureInput!\n) {\n acceptElectronicSignature(input: $input) {\n signature {\n id\n status\n }\n }\n}\n"
}
};
})();
(node as any).hash = "b4ab543bd58878bb4968de6ea8b7c448";
export default node;

View File

@@ -0,0 +1,103 @@
/**
* @generated SignedSource<<93f8676826dfa28c1681da68a6ac1cf2>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type ElectronicSignatureStatus = "ACCEPTED" | "COMPLETED" | "FAILED" | "PENDING" | "PROCESSING";
import { FragmentRefs } from "relay-runtime";
export type NDAPageFragment$data = {
readonly id: string;
readonly ndaSignature: {
readonly consentText: string;
readonly id: string;
readonly lastError: string | null | undefined;
readonly status: ElectronicSignatureStatus;
};
readonly " $fragmentType": "NDAPageFragment";
};
export type NDAPageFragment$key = {
readonly " $data"?: NDAPageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"NDAPageFragment">;
};
import NDAPageRefetchQuery_graphql from './NDAPageRefetchQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": {
"refetch": {
"connection": null,
"fragmentPathInResult": [
"node"
],
"operation": NDAPageRefetchQuery_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "NDAPageFragment",
"selections": [
{
"kind": "RequiredField",
"field": {
"alias": null,
"args": null,
"concreteType": "ElectronicSignature",
"kind": "LinkedField",
"name": "ndaSignature",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "consentText",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lastError",
"storageKey": null
}
],
"storageKey": null
},
"action": "THROW"
},
(v0/*: any*/)
],
"type": "TrustCenter",
"abstractKey": null
};
})();
(node as any).hash = "b53a5f455508ed45124b7d09cfb573da";
export default node;

View File

@@ -0,0 +1,236 @@
/**
* @generated SignedSource<<f1cae8462501cdf634eb02eb143c3806>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ElectronicSignatureStatus = "ACCEPTED" | "COMPLETED" | "FAILED" | "PENDING" | "PROCESSING";
export type NDAPageQuery$variables = Record<PropertyKey, never>;
export type NDAPageQuery$data = {
readonly currentTrustCenter: {
readonly ndaFileName: string | null | undefined;
readonly ndaFileUrl: string | null | undefined;
readonly ndaSignature: {
readonly status: ElectronicSignatureStatus;
} | null | undefined;
readonly organization: {
readonly name: string;
};
readonly " $fragmentSpreads": FragmentRefs<"NDAPageFragment">;
};
readonly viewer: {
readonly fullName: string;
} | null | undefined;
};
export type NDAPageQuery = {
response: NDAPageQuery$data;
variables: NDAPageQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "ndaFileUrl",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "ndaFileName",
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "NDAPageQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Identity",
"kind": "LinkedField",
"name": "viewer",
"plural": false,
"selections": [
(v0/*: any*/)
],
"storageKey": null
},
{
"kind": "RequiredField",
"field": {
"alias": null,
"args": null,
"concreteType": "TrustCenter",
"kind": "LinkedField",
"name": "currentTrustCenter",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Organization",
"kind": "LinkedField",
"name": "organization",
"plural": false,
"selections": [
(v1/*: any*/)
],
"storageKey": null
},
(v2/*: any*/),
(v3/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "ElectronicSignature",
"kind": "LinkedField",
"name": "ndaSignature",
"plural": false,
"selections": [
(v4/*: any*/)
],
"storageKey": null
},
{
"args": null,
"kind": "FragmentSpread",
"name": "NDAPageFragment"
}
],
"storageKey": null
},
"action": "THROW"
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [],
"kind": "Operation",
"name": "NDAPageQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Identity",
"kind": "LinkedField",
"name": "viewer",
"plural": false,
"selections": [
(v0/*: any*/),
(v5/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "TrustCenter",
"kind": "LinkedField",
"name": "currentTrustCenter",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Organization",
"kind": "LinkedField",
"name": "organization",
"plural": false,
"selections": [
(v1/*: any*/),
(v5/*: any*/)
],
"storageKey": null
},
(v2/*: any*/),
(v3/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "ElectronicSignature",
"kind": "LinkedField",
"name": "ndaSignature",
"plural": false,
"selections": [
(v4/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "consentText",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lastError",
"storageKey": null
}
],
"storageKey": null
},
(v5/*: any*/)
],
"storageKey": null
}
]
},
"params": {
"cacheID": "c0b175c435c5730e390fcfde596d8bc3",
"id": null,
"metadata": {},
"name": "NDAPageQuery",
"operationKind": "query",
"text": "query NDAPageQuery {\n viewer {\n fullName\n id\n }\n currentTrustCenter {\n organization {\n name\n id\n }\n ndaFileUrl\n ndaFileName\n ndaSignature {\n status\n id\n }\n ...NDAPageFragment\n id\n }\n}\n\nfragment NDAPageFragment on TrustCenter {\n ndaSignature {\n id\n status\n consentText\n lastError\n }\n id\n}\n"
}
};
})();
(node as any).hash = "a78bf8b65feba4627ecb265ca882f645";
export default node;

View File

@@ -0,0 +1,94 @@
/**
* @generated SignedSource<<d2d531924e3667658020b431850c193e>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ElectronicSignatureEventType = "CERTIFICATE_GENERATED" | "CONSENT_GIVEN" | "DOCUMENT_VIEWED" | "FULL_NAME_TYPED" | "SEAL_COMPUTED" | "SIGNATURE_ACCEPTED" | "SIGNATURE_COMPLETED" | "TIMESTAMP_REQUESTED";
export type RecordSigningEventInput = {
eventType: ElectronicSignatureEventType;
signatureId: string;
};
export type NDAPageRecordSigningEventMutation$variables = {
input: RecordSigningEventInput;
};
export type NDAPageRecordSigningEventMutation$data = {
readonly recordSigningEvent: {
readonly success: boolean;
} | null | undefined;
};
export type NDAPageRecordSigningEventMutation = {
response: NDAPageRecordSigningEventMutation$data;
variables: NDAPageRecordSigningEventMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "RecordSigningEventPayload",
"kind": "LinkedField",
"name": "recordSigningEvent",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "success",
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "NDAPageRecordSigningEventMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "NDAPageRecordSigningEventMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "72aa3c3ec642d5bbb317a6e2a65703de",
"id": null,
"metadata": {},
"name": "NDAPageRecordSigningEventMutation",
"operationKind": "mutation",
"text": "mutation NDAPageRecordSigningEventMutation(\n $input: RecordSigningEventInput!\n) {\n recordSigningEvent(input: $input) {\n success\n }\n}\n"
}
};
})();
(node as any).hash = "ec40eb438c6d6b20f31974e099535887";
export default node;

View File

@@ -0,0 +1,155 @@
/**
* @generated SignedSource<<47d15b007fc81de3850393c9b158726c>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type NDAPageRefetchQuery$variables = {
id: string;
};
export type NDAPageRefetchQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"NDAPageFragment">;
};
};
export type NDAPageRefetchQuery = {
response: NDAPageRefetchQuery$data;
variables: NDAPageRefetchQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "NDAPageRefetchQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "NDAPageFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "NDAPageRefetchQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ElectronicSignature",
"kind": "LinkedField",
"name": "ndaSignature",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "consentText",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lastError",
"storageKey": null
}
],
"storageKey": null
}
],
"type": "TrustCenter",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "1c61baa555ad2b24794ce0bf5ecc14ac",
"id": null,
"metadata": {},
"name": "NDAPageRefetchQuery",
"operationKind": "query",
"text": "query NDAPageRefetchQuery(\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...NDAPageFragment\n id\n }\n}\n\nfragment NDAPageFragment on TrustCenter {\n ndaSignature {\n id\n status\n consentText\n lastError\n }\n id\n}\n"
}
};
})();
(node as any).hash = "b53a5f455508ed45124b7d09cfb573da";
export default node;