diff --git a/apps/trust/src/components/AuditRow.tsx b/apps/trust/src/components/AuditRow.tsx index 0b65f8d49..8d2de853e 100644 --- a/apps/trust/src/components/AuditRow.tsx +++ b/apps/trust/src/components/AuditRow.tsx @@ -1,5 +1,6 @@ import { downloadFile, formatError } from "@probo/helpers"; import { useTranslate } from "@probo/i18n"; +import { UnAuthenticatedError } from "@probo/relay"; import { Breadcrumb, Button, @@ -13,13 +14,13 @@ import { Table, useToast, } from "@probo/ui"; -import { type PropsWithChildren, use, useState } from "react"; +import { type PropsWithChildren, useState } from "react"; import { useFragment, useMutation } from "react-relay"; -import { useLocation } from "react-router"; +import { useLocation, useNavigate, useSearchParams } from "react-router"; import { graphql } from "relay-runtime"; import { useMutationWithToasts } from "#/hooks/useMutationWithToast"; -import { Viewer } from "#/providers/Viewer"; +import { getPathPrefix } from "#/utils/pathPrefix"; import type { AuditRow_requestAccessMutation } from "./__generated__/AuditRow_requestAccessMutation.graphql"; import type { AuditRowDownloadMutation } from "./__generated__/AuditRowDownloadMutation.graphql"; @@ -63,8 +64,10 @@ const auditRowFragment = graphql` export function AuditRow(props: { audit: AuditRowFragment$key }) { const { __ } = useTranslate(); - const viewer = use(Viewer); const { toast } = useToast(); + const [searchParams] = useSearchParams(); + const location = useLocation(); + const navigate = useNavigate(); const audit = useFragment(auditRowFragment, props.audit); const [hasRequested, setHasRequested] = useState( @@ -100,6 +103,18 @@ export function AuditRow(props: { audit: AuditRowFragment$key }) { }); }, onError: (error) => { + if (error instanceof UnAuthenticatedError) { + const pathPrefix = getPathPrefix(); + searchParams.set("request-report-id", audit.report?.id ?? ""); + const urlSearchParams = new URLSearchParams([[ + "continue", + window.location.origin + pathPrefix + location.pathname + "?" + searchParams.toString(), + ]]); + void navigate(`/connect?${urlSearchParams.toString()}`); + + return; + } + toast({ title: __("Error"), description: error.message ?? __("Cannot request access"), @@ -143,28 +158,17 @@ export function AuditRow(props: { audit: AuditRowFragment$key }) { {downloading ? __("Downloading") : __("Download")} ) - : viewer - ? ( - - ) - : ( - - )} + : ( + + )} ); } diff --git a/apps/trust/src/components/OrganizationSidebar.tsx b/apps/trust/src/components/OrganizationSidebar.tsx index c5cd35c9d..5759d1afd 100644 --- a/apps/trust/src/components/OrganizationSidebar.tsx +++ b/apps/trust/src/components/OrganizationSidebar.tsx @@ -1,6 +1,7 @@ import { formatError } from "@probo/helpers"; import { useSystemTheme } from "@probo/hooks"; import { useTranslate } from "@probo/i18n"; +import { UnAuthenticatedError } from "@probo/relay"; import { Button, Card, @@ -9,12 +10,13 @@ import { IconMedal, useToast, } from "@probo/ui"; -import { type PropsWithChildren, use } from "react"; +import { type PropsWithChildren } from "react"; import { useMutation } from "react-relay"; +import { useNavigate, useSearchParams } from "react-router"; import { graphql } from "relay-runtime"; -import { Viewer } from "#/providers/Viewer"; import type { TrustGraphCurrentQuery$data } from "#/queries/__generated__/TrustGraphCurrentQuery.graphql"; +import { getPathPrefix } from "#/utils/pathPrefix"; import type { OrganizationSidebar_requestAllAccessesMutation } from "./__generated__/OrganizationSidebar_requestAllAccessesMutation.graphql"; import { AuditRowAvatar } from "./AuditRow"; @@ -35,9 +37,10 @@ export function OrganizationSidebar({ trustCenter: TrustGraphCurrentQuery$data["currentTrustCenter"]; }) { const { __ } = useTranslate(); - const isAuthenticated = !!use(Viewer); const { toast } = useToast(); const theme = useSystemTheme(); + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); const logoFileUrl = theme === "dark" ? (trustCenter?.darkLogoFileUrl ?? trustCenter?.logoFileUrl) : trustCenter?.logoFileUrl; @@ -65,6 +68,18 @@ export function OrganizationSidebar({ }); }, onError: (error) => { + if (error instanceof UnAuthenticatedError) { + const pathPrefix = getPathPrefix(); + searchParams.set("request-all", "true"); + const urlSearchParams = new URLSearchParams([[ + "continue", + window.location.origin + pathPrefix + location.pathname + "?" + searchParams.toString(), + ]]); + void navigate(`/connect?${urlSearchParams.toString()}`); + + return; + } + toast({ title: __("Error"), description: error.message ?? __("Cannot request access"), @@ -159,29 +174,15 @@ export function OrganizationSidebar({ )} - {/* Actions */} - {isAuthenticated - ? ( - - ) - : ( - - )} + ); diff --git a/apps/trust/src/components/TrustCenterFileRow.tsx b/apps/trust/src/components/TrustCenterFileRow.tsx index de84d6fbb..b6bb25306 100644 --- a/apps/trust/src/components/TrustCenterFileRow.tsx +++ b/apps/trust/src/components/TrustCenterFileRow.tsx @@ -1,5 +1,6 @@ import { downloadFile, formatError } from "@probo/helpers"; import { useTranslate } from "@probo/i18n"; +import { UnAuthenticatedError } from "@probo/relay"; import { Button, IconArrowInbox, @@ -8,12 +9,13 @@ import { Spinner, useToast, } from "@probo/ui"; -import { use, useState } from "react"; +import { useState } from "react"; import { useFragment, useMutation } from "react-relay"; +import { useLocation, useNavigate, useSearchParams } from "react-router"; import { graphql } from "relay-runtime"; import { useMutationWithToasts } from "#/hooks/useMutationWithToast"; -import { Viewer } from "#/providers/Viewer"; +import { getPathPrefix } from "#/utils/pathPrefix"; import type { TrustCenterFileRow_requestAccessMutation } from "./__generated__/TrustCenterFileRow_requestAccessMutation.graphql"; import type { TrustCenterFileRowDownloadMutation } from "./__generated__/TrustCenterFileRowDownloadMutation.graphql"; @@ -54,8 +56,10 @@ export function TrustCenterFileRow(props: { file: TrustCenterFileRowFragment$key; }) { const { __ } = useTranslate(); - const viewer = use(Viewer); const { toast } = useToast(); + const location = useLocation(); + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); const file = useFragment(trustCenterFileRowFragment, props.file); const [hasRequested, setHasRequested] = useState(file.hasUserRequestedAccess); @@ -91,6 +95,18 @@ export function TrustCenterFileRow(props: { }); }, onError: (error) => { + if (error instanceof UnAuthenticatedError) { + const pathPrefix = getPathPrefix(); + searchParams.set("request-file-id", file.id); + const urlSearchParams = new URLSearchParams([[ + "continue", + window.location.origin + pathPrefix + location.pathname + "?" + searchParams.toString(), + ]]); + void navigate(`/connect?${urlSearchParams.toString()}`); + + return; + } + toast({ title: __("Error"), description: error.message ?? __("Cannot request access"), @@ -131,28 +147,17 @@ export function TrustCenterFileRow(props: { {downloading ? __("Downloading") : __("Download")} ) - : viewer - ? ( - - ) - : ( - - )} + : ( + + )} ); } diff --git a/apps/trust/src/layouts/MainLayout.tsx b/apps/trust/src/layouts/MainLayout.tsx index f0a9a5876..d60820345 100644 --- a/apps/trust/src/layouts/MainLayout.tsx +++ b/apps/trust/src/layouts/MainLayout.tsx @@ -7,7 +7,6 @@ import { Outlet } from "react-router"; import { OrganizationSidebar } from "#/components/OrganizationSidebar"; import { useRequestAccessCallback } from "#/hooks/useRequestAccessCallback"; import { TrustCenterProvider } from "#/providers/TrustCenterProvider"; -import { Viewer } from "#/providers/Viewer"; import type { TrustGraphCurrentQuery } from "#/queries/__generated__/TrustGraphCurrentQuery.graphql"; import { currentTrustGraphQuery } from "#/queries/TrustGraph"; @@ -30,30 +29,28 @@ export function MainLayout(props: Props) { useRequestAccessCallback(); return ( - - -
- -
- - {__("Overview")} - {__("Documents")} - {trustCenter.vendorInfo.totalCount > 0 - && {__("Subprocessors")}} - - -
-
+ +
+ +
+ + {__("Overview")} + {__("Documents")} + {trustCenter.vendorInfo.totalCount > 0 + && {__("Subprocessors")}} + + +
+
- - {__("Powered by")} - {" "} - - -
-
+ + {__("Powered by")} + {" "} + + + ); } diff --git a/apps/trust/src/providers/Viewer.tsx b/apps/trust/src/providers/Viewer.tsx deleted file mode 100644 index 96f9a27dc..000000000 --- a/apps/trust/src/providers/Viewer.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { createContext } from "react"; - -interface ViewerContextValue { - fullName: string; - email: string; -} - -export const Viewer = createContext({ - email: "", - fullName: "", -}); diff --git a/apps/trust/src/queries/TrustGraph.ts b/apps/trust/src/queries/TrustGraph.ts index 7b2a707a4..82a724e08 100644 --- a/apps/trust/src/queries/TrustGraph.ts +++ b/apps/trust/src/queries/TrustGraph.ts @@ -3,10 +3,6 @@ import { graphql } from "relay-runtime"; // Queries for custom domain (subdomain) approach export const currentTrustGraphQuery = graphql` query TrustGraphCurrentQuery { - viewer { - email - fullName - } currentTrustCenter @required(action: THROW) { id slug diff --git a/apps/trust/src/queries/__generated__/TrustGraphCurrentQuery.graphql.ts b/apps/trust/src/queries/__generated__/TrustGraphCurrentQuery.graphql.ts index 695e445f0..7b41004d4 100644 --- a/apps/trust/src/queries/__generated__/TrustGraphCurrentQuery.graphql.ts +++ b/apps/trust/src/queries/__generated__/TrustGraphCurrentQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<700a3b76b18e7182c5a08c98b5d7fa2a>> + * @generated SignedSource<<69ddf57f16792925ca8a136115747014>> * @lightSyntaxTransform * @nogrep */ @@ -46,10 +46,6 @@ export type TrustGraphCurrentQuery$data = { }; readonly " $fragmentSpreads": FragmentRefs<"OverviewPageFragment">; }; - readonly viewer: { - readonly email: any; - readonly fullName: string; - } | null | undefined; }; export type TrustGraphCurrentQuery = { response: TrustGraphCurrentQuery$data; @@ -61,101 +57,94 @@ var v0 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "email", + "name": "id", "storageKey": null }, v1 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "fullName", + "name": "slug", "storageKey": null }, v2 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "id", + "name": "isViewerMember", "storageKey": null }, v3 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "slug", + "name": "logoFileUrl", "storageKey": null }, v4 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "isViewerMember", + "name": "darkLogoFileUrl", "storageKey": null }, v5 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "logoFileUrl", + "name": "fileName", "storageKey": null }, v6 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "darkLogoFileUrl", + "name": "fileUrl", "storageKey": null }, v7 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "fileName", + "name": "status", "storageKey": null }, v8 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "fileUrl", + "name": "name", "storageKey": null }, v9 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "status", + "name": "description", "storageKey": null }, v10 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "name", + "name": "websiteUrl", "storageKey": null }, v11 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "description", + "name": "email", "storageKey": null }, v12 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "websiteUrl", - "storageKey": null -}, -v13 = { "alias": null, "args": null, "kind": "ScalarField", "name": "headquarterAddress", "storageKey": null }, -v14 = { +v13 = { "alias": "vendorInfo", "args": [ { @@ -179,28 +168,28 @@ v14 = { ], "storageKey": "vendors(first:0)" }, -v15 = [ +v14 = [ { "kind": "Literal", "name": "first", "value": 50 } ], -v16 = [ +v15 = [ { "kind": "Literal", "name": "first", "value": 5 } ], -v17 = { +v16 = { "alias": null, "args": null, "kind": "ScalarField", "name": "isUserAuthorized", "storageKey": null }, -v18 = { +v17 = { "alias": null, "args": null, "kind": "ScalarField", @@ -214,19 +203,6 @@ return { "metadata": null, "name": "TrustGraphCurrentQuery", "selections": [ - { - "alias": null, - "args": null, - "concreteType": "Identity", - "kind": "LinkedField", - "name": "viewer", - "plural": false, - "selections": [ - (v0/*: any*/), - (v1/*: any*/) - ], - "storageKey": null - }, { "kind": "RequiredField", "field": { @@ -237,11 +213,11 @@ return { "name": "currentTrustCenter", "plural": false, "selections": [ + (v0/*: any*/), + (v1/*: any*/), (v2/*: any*/), (v3/*: any*/), (v4/*: any*/), - (v5/*: any*/), - (v6/*: any*/), { "alias": null, "args": null, @@ -250,8 +226,8 @@ return { "name": "nonDisclosureAgreement", "plural": false, "selections": [ - (v7/*: any*/), - (v8/*: any*/), + (v5/*: any*/), + (v6/*: any*/), { "alias": null, "args": null, @@ -260,7 +236,7 @@ return { "name": "viewerSignature", "plural": false, "selections": [ - (v9/*: any*/) + (v7/*: any*/) ], "storageKey": null } @@ -275,11 +251,11 @@ return { "name": "organization", "plural": false, "selections": [ + (v8/*: any*/), + (v9/*: any*/), (v10/*: any*/), (v11/*: any*/), - (v12/*: any*/), - (v0/*: any*/), - (v13/*: any*/) + (v12/*: any*/) ], "storageKey": null }, @@ -288,10 +264,10 @@ return { "kind": "FragmentSpread", "name": "OverviewPageFragment" }, - (v14/*: any*/), + (v13/*: any*/), { "alias": null, - "args": (v15/*: any*/), + "args": (v14/*: any*/), "concreteType": "AuditConnection", "kind": "LinkedField", "name": "audits", @@ -313,7 +289,7 @@ return { "name": "node", "plural": false, "selections": [ - (v2/*: any*/), + (v0/*: any*/), { "args": null, "kind": "FragmentSpread", @@ -343,20 +319,6 @@ return { "kind": "Operation", "name": "TrustGraphCurrentQuery", "selections": [ - { - "alias": null, - "args": null, - "concreteType": "Identity", - "kind": "LinkedField", - "name": "viewer", - "plural": false, - "selections": [ - (v0/*: any*/), - (v1/*: any*/), - (v2/*: any*/) - ], - "storageKey": null - }, { "alias": null, "args": null, @@ -365,11 +327,11 @@ return { "name": "currentTrustCenter", "plural": false, "selections": [ + (v0/*: any*/), + (v1/*: any*/), (v2/*: any*/), (v3/*: any*/), (v4/*: any*/), - (v5/*: any*/), - (v6/*: any*/), { "alias": null, "args": null, @@ -378,8 +340,8 @@ return { "name": "nonDisclosureAgreement", "plural": false, "selections": [ - (v7/*: any*/), - (v8/*: any*/), + (v5/*: any*/), + (v6/*: any*/), { "alias": null, "args": null, @@ -388,8 +350,8 @@ return { "name": "viewerSignature", "plural": false, "selections": [ - (v9/*: any*/), - (v2/*: any*/) + (v7/*: any*/), + (v0/*: any*/) ], "storageKey": null } @@ -404,12 +366,12 @@ return { "name": "organization", "plural": false, "selections": [ + (v8/*: any*/), + (v9/*: any*/), (v10/*: any*/), (v11/*: any*/), (v12/*: any*/), - (v0/*: any*/), - (v13/*: any*/), - (v2/*: any*/) + (v0/*: any*/) ], "storageKey": null }, @@ -443,8 +405,8 @@ return { "name": "node", "plural": false, "selections": [ - (v2/*: any*/), - (v10/*: any*/), + (v0/*: any*/), + (v8/*: any*/), { "alias": null, "args": null, @@ -452,7 +414,7 @@ return { "name": "logoUrl", "storageKey": null }, - (v12/*: any*/) + (v10/*: any*/) ], "storageKey": null } @@ -492,7 +454,7 @@ return { "name": "node", "plural": false, "selections": [ - (v2/*: any*/), + (v0/*: any*/), { "alias": null, "args": null, @@ -500,9 +462,9 @@ return { "name": "countries", "storageKey": null }, - (v10/*: any*/), - (v11/*: any*/), - (v12/*: any*/) + (v8/*: any*/), + (v9/*: any*/), + (v10/*: any*/) ], "storageKey": null } @@ -514,7 +476,7 @@ return { }, { "alias": null, - "args": (v16/*: any*/), + "args": (v15/*: any*/), "concreteType": "DocumentConnection", "kind": "LinkedField", "name": "documents", @@ -536,7 +498,7 @@ return { "name": "node", "plural": false, "selections": [ - (v2/*: any*/), + (v0/*: any*/), { "alias": null, "args": null, @@ -544,8 +506,8 @@ return { "name": "title", "storageKey": null }, + (v16/*: any*/), (v17/*: any*/), - (v18/*: any*/), { "alias": null, "args": null, @@ -564,7 +526,7 @@ return { }, { "alias": null, - "args": (v16/*: any*/), + "args": (v15/*: any*/), "concreteType": "TrustCenterFileConnection", "kind": "LinkedField", "name": "trustCenterFiles", @@ -586,7 +548,7 @@ return { "name": "node", "plural": false, "selections": [ - (v2/*: any*/), + (v0/*: any*/), { "alias": null, "args": null, @@ -594,9 +556,9 @@ return { "name": "category", "storageKey": null }, - (v10/*: any*/), - (v17/*: any*/), - (v18/*: any*/) + (v8/*: any*/), + (v16/*: any*/), + (v17/*: any*/) ], "storageKey": null } @@ -606,10 +568,10 @@ return { ], "storageKey": "trustCenterFiles(first:5)" }, - (v14/*: any*/), + (v13/*: any*/), { "alias": null, - "args": (v15/*: any*/), + "args": (v14/*: any*/), "concreteType": "AuditConnection", "kind": "LinkedField", "name": "audits", @@ -631,8 +593,8 @@ return { "name": "node", "plural": false, "selections": [ - (v2/*: any*/), - (v10/*: any*/), + (v0/*: any*/), + (v8/*: any*/), { "alias": null, "args": null, @@ -641,7 +603,7 @@ return { "name": "report", "plural": false, "selections": [ - (v2/*: any*/), + (v0/*: any*/), { "alias": null, "args": null, @@ -649,8 +611,8 @@ return { "name": "filename", "storageKey": null }, - (v17/*: any*/), - (v18/*: any*/) + (v16/*: any*/), + (v17/*: any*/) ], "storageKey": null }, @@ -662,8 +624,8 @@ return { "name": "framework", "plural": false, "selections": [ - (v2/*: any*/), - (v10/*: any*/), + (v0/*: any*/), + (v8/*: any*/), { "alias": null, "args": null, @@ -696,16 +658,16 @@ return { ] }, "params": { - "cacheID": "fab59d135402a3b935f277a385d33b93", + "cacheID": "fe1336b3897ba719a7e2210af673c378", "id": null, "metadata": {}, "name": "TrustGraphCurrentQuery", "operationKind": "query", - "text": "query TrustGraphCurrentQuery {\n viewer {\n email\n fullName\n id\n }\n currentTrustCenter {\n id\n slug\n isViewerMember\n logoFileUrl\n darkLogoFileUrl\n nonDisclosureAgreement {\n fileName\n fileUrl\n viewerSignature {\n status\n id\n }\n }\n organization {\n name\n description\n websiteUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n vendorInfo: vendors(first: 0) {\n totalCount\n }\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n name\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\n lightLogoURL\n darkLogoURL\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment OverviewPageFragment on TrustCenter {\n references(first: 14) {\n edges {\n node {\n id\n name\n logoUrl\n websiteUrl\n }\n }\n }\n vendors(first: 3) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n trustCenterFiles(first: 5) {\n edges {\n node {\n id\n category\n ...TrustCenterFileRowFragment\n }\n }\n }\n}\n\nfragment TrustCenterFileRowFragment on TrustCenterFile {\n id\n name\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment VendorRowFragment on Vendor {\n name\n description\n websiteUrl\n countries\n}\n" + "text": "query TrustGraphCurrentQuery {\n currentTrustCenter {\n id\n slug\n isViewerMember\n logoFileUrl\n darkLogoFileUrl\n nonDisclosureAgreement {\n fileName\n fileUrl\n viewerSignature {\n status\n id\n }\n }\n organization {\n name\n description\n websiteUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n vendorInfo: vendors(first: 0) {\n totalCount\n }\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n name\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\n lightLogoURL\n darkLogoURL\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment OverviewPageFragment on TrustCenter {\n references(first: 14) {\n edges {\n node {\n id\n name\n logoUrl\n websiteUrl\n }\n }\n }\n vendors(first: 3) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n trustCenterFiles(first: 5) {\n edges {\n node {\n id\n category\n ...TrustCenterFileRowFragment\n }\n }\n }\n}\n\nfragment TrustCenterFileRowFragment on TrustCenterFile {\n id\n name\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment VendorRowFragment on Vendor {\n name\n description\n websiteUrl\n countries\n}\n" } }; })(); -(node as any).hash = "64b166174da80cd3082ab4becf716b1c"; +(node as any).hash = "48f3ca2547e97d2378ccb0375ae9fae8"; export default node;