Fix custom domain trust center design

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-10-10 14:50:15 +02:00
parent 4b660119e3
commit a7d129a41c
14 changed files with 165 additions and 78 deletions

View File

@@ -15,7 +15,7 @@ import {
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import type { AuditRowDownloadMutation } from "./__generated__/AuditRowDownloadMutation.graphql"; import type { AuditRowDownloadMutation } from "./__generated__/AuditRowDownloadMutation.graphql";
import { useMutationWithToasts } from "/hooks/useMutationWithToast"; import { useMutationWithToasts } from "/hooks/useMutationWithToast";
import { downloadFile } from "@probo/helpers"; import { downloadFile, getLogoUrl } from "@probo/helpers";
import { type PropsWithChildren, useState } from "react"; import { type PropsWithChildren, useState } from "react";
import { useLocation } from "react-router"; import { useLocation } from "react-router";
import { RequestAccessDialog } from "/components/RequestAccessDialog.tsx"; import { RequestAccessDialog } from "/components/RequestAccessDialog.tsx";
@@ -103,15 +103,16 @@ export function AuditRow(props: { audit: AuditRowFragment$key }) {
); );
} }
const logos = {
"ISO 27001 (2022)": "/trust/logos/iso27001.svg",
"SOC 2": "/trust/logos/soc2.svg",
HIPAA: "/trust/logos/hipaa.svg",
GDPR: "/trust/logos/gdpr.svg",
};
export function AuditRowAvatar(props: { audit: AuditRowFragment$key }) { export function AuditRowAvatar(props: { audit: AuditRowFragment$key }) {
const audit = useFragment(auditRowFragment, props.audit); const audit = useFragment(auditRowFragment, props.audit);
const logos = {
"ISO 27001 (2022)": getLogoUrl("iso27001.svg"),
"SOC 2": getLogoUrl("soc2.svg"),
HIPAA: getLogoUrl("hipaa.svg"),
GDPR: getLogoUrl("gdpr.svg"),
};
return ( return (
<> <>
<AuditDialog <AuditDialog
@@ -130,7 +131,7 @@ export function AuditRowAvatar(props: { audit: AuditRowFragment$key }) {
) : ( ) : (
<div <div
className="bg-[#F0F7E2] aspect-square w-full rounded-full text-xs text-[#000] font-bold flex items-center justify-center pb-6 px-2" className="bg-[#F0F7E2] aspect-square w-full rounded-full text-xs text-[#000] font-bold flex items-center justify-center pb-6 px-2"
style={{ background: "url(/trust/logos/blank.svg) no-repeat" }} style={{ background: `url(${getLogoUrl("blank.svg")}) no-repeat` }}
> >
<span className="line-clamp-2 overflow-hidden"> <span className="line-clamp-2 overflow-hidden">
{" "} {" "}

View File

@@ -1,20 +1,18 @@
import { Skeleton, TabLink, Tabs } from "@probo/ui"; import { Skeleton, TabLink, Tabs } from "@probo/ui";
import { TabSkeleton } from "./TabSkeleton"; import { TabSkeleton } from "./TabSkeleton";
import { useParams } from "react-router";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { getTrustCenterUrl } from "@probo/helpers";
export function MainSkeleton() { export function MainSkeleton() {
const { slug } = useParams<{ slug: string }>();
const baseTabUrl = `/trust/${slug}`;
const { __ } = useTranslate(); const { __ } = useTranslate();
return ( return (
<div className="grid grid-cols-1 max-w-[1280px] mx-4 pt-6 gap-4 lg:mx-auto lg:gap-10 lg:pt-20 lg:grid-cols-[400px_1fr] "> <div className="grid grid-cols-1 max-w-[1280px] mx-4 pt-6 gap-4 lg:mx-auto lg:gap-10 lg:pt-20 lg:grid-cols-[400px_1fr] ">
<Skeleton className="w-full h-300" /> <Skeleton className="w-full h-300" />
<main> <main>
<Tabs className="mb-8"> <Tabs className="mb-8">
<TabLink to={`${baseTabUrl}/overview`}>{__("Overview")}</TabLink> <TabLink to={getTrustCenterUrl("overview")}>{__("Overview")}</TabLink>
<TabLink to={`${baseTabUrl}/documents`}>{__("Documents")}</TabLink> <TabLink to={getTrustCenterUrl("documents")}>{__("Documents")}</TabLink>
<TabLink to={`${baseTabUrl}/subprocessors`}> <TabLink to={getTrustCenterUrl("subprocessors")}>
{__("Subprocessors")} {__("Subprocessors")}
</TabLink> </TabLink>
</Tabs> </Tabs>

View File

@@ -1,7 +1,7 @@
import { graphql } from "relay-runtime"; import { graphql } from "relay-runtime";
import type { VendorRowFragment$key } from "./__generated__/VendorRowFragment.graphql"; import type { VendorRowFragment$key } from "./__generated__/VendorRowFragment.graphql";
import { useFragment } from "react-relay"; import { useFragment } from "react-relay";
import { IconPin } from "@probo/ui"; import { IconPin, IconShield } from "@probo/ui";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { faviconUrl, getCountryName } from "@probo/helpers"; import { faviconUrl, getCountryName } from "@probo/helpers";
@@ -16,11 +16,13 @@ const vendorRowFragment = graphql`
} }
`; `;
export function VendorRow(props: { vendor: VendorRowFragment$key }) { export function VendorRow(props: { vendor: VendorRowFragment$key; hasAnyCountries?: boolean }) {
const vendor = useFragment(vendorRowFragment, props.vendor); const vendor = useFragment(vendorRowFragment, props.vendor);
const logo = faviconUrl(vendor.websiteUrl); const logo = faviconUrl(vendor.websiteUrl);
const { __ } = useTranslate(); const { __ } = useTranslate();
const gridCols = props.hasAnyCountries ? "grid-cols-[1fr_1fr_1fr]" : "grid-cols-[1fr_1fr]";
return ( return (
<div className="flex text-sm leading-tight gap-3 md:items-center"> <div className="flex text-sm leading-tight gap-3 md:items-center">
{logo ? ( {logo ? (
@@ -32,19 +34,22 @@ export function VendorRow(props: { vendor: VendorRowFragment$key }) {
) : ( ) : (
<div className="size-8 md:size-6 flex-none rounded-lg" /> <div className="size-8 md:size-6 flex-none rounded-lg" />
)} )}
<div className="flex flex-col md:grid grid-cols-[1fr_1fr_1fr] flex-1 gap-0.5"> <div className={`flex flex-col md:grid ${gridCols} flex-1 gap-0.5`}>
<div>{vendor.name}</div> <div>{vendor.name}</div>
{vendor.privacyPolicyUrl && ( {vendor.privacyPolicyUrl ? (
<a <a
href={vendor.privacyPolicyUrl} href={vendor.privacyPolicyUrl}
target="_blank" target="_blank"
className="text-txt-info" className={`flex gap-1 text-txt-info items-center hover:underline ${!props.hasAnyCountries ? 'md:justify-end' : ''}`}
> >
{vendor.privacyPolicyUrl.split("//").at(-1)} <IconShield size={16} className="flex-none" />
<span>{__("Privacy")}</span>
</a> </a>
) : (
<div></div>
)} )}
{vendor.countries.length > 0 && ( {vendor.countries.length > 0 && (
<div className="flex gap-1 text-txt-secondary items-center md:justify-end"> <div className={`flex gap-1 text-txt-secondary items-center ${props.hasAnyCountries ? 'md:justify-end' : ''}`}>
<IconPin size={16} className="flex-none" /> <IconPin size={16} className="flex-none" />
<span> <span>
{vendor.countries {vendor.countries

View File

@@ -5,7 +5,7 @@ import type {
OverviewPageFragment$key, OverviewPageFragment$key,
} from "./__generated__/OverviewPageFragment.graphql"; } from "./__generated__/OverviewPageFragment.graphql";
import { Link, useOutletContext } from "react-router"; import { Link, useOutletContext } from "react-router";
import { groupBy, objectEntries, sprintf } from "@probo/helpers"; import { groupBy, objectEntries, sprintf, getTrustCenterUrl } from "@probo/helpers";
import type { TrustGraphQuery$data } from "/queries/__generated__/TrustGraphQuery.graphql"; import type { TrustGraphQuery$data } from "/queries/__generated__/TrustGraphQuery.graphql";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { Card, IconChevronRight } from "@probo/ui"; import { Card, IconChevronRight } from "@probo/ui";
@@ -33,6 +33,7 @@ const overviewFragment = graphql`
edges { edges {
node { node {
id id
countries
...VendorRowFragment ...VendorRowFragment
} }
} }
@@ -63,12 +64,12 @@ export function OverviewPage() {
<Documents <Documents
audits={trustCenter.audits.edges} audits={trustCenter.audits.edges}
documents={fragment.documents.edges} documents={fragment.documents.edges}
url={`/trust/${trustCenter.slug}/documents`} url={getTrustCenterUrl("documents")}
/> />
<Subprocessors <Subprocessors
organizationName={trustCenter.organization.name} organizationName={trustCenter.organization.name}
vendors={fragment.vendors.edges} vendors={fragment.vendors.edges}
url={`/trust/${trustCenter.slug}/subprocessors`} url={getTrustCenterUrl("subprocessors")}
/> />
</div> </div>
); );
@@ -143,6 +144,11 @@ function Subprocessors({
return null; return null;
} }
const hasAnyCountries = vendors.some(vendor => {
const vendorData = vendor.node as any;
return vendorData.countries && vendorData.countries.length > 0;
});
return ( return (
<div> <div>
<h2 className="font-medium mb-1">{__("Subprocessors")}</h2> <h2 className="font-medium mb-1">{__("Subprocessors")}</h2>
@@ -154,7 +160,7 @@ function Subprocessors({
</p> </p>
<Rows className="mb-8 *:py-5"> <Rows className="mb-8 *:py-5">
{vendors.map((vendor) => ( {vendors.map((vendor) => (
<VendorRow key={vendor.node.id} vendor={vendor.node} /> <VendorRow key={vendor.node.id} vendor={vendor.node} hasAnyCountries={hasAnyCountries} />
))} ))}
<Link to={url} className="text-sm font-medium flex gap-2 items-center"> <Link to={url} className="text-sm font-medium flex gap-2 items-center">
{__("See all subprocessors")} {__("See all subprocessors")}

View File

@@ -15,6 +15,9 @@ export function SubprocessorsPage({ queryRef }: Props) {
const data = usePreloadedQuery(currentTrustVendorsQuery, queryRef); const data = usePreloadedQuery(currentTrustVendorsQuery, queryRef);
const vendors = const vendors =
data.currentTrustCenter?.vendors.edges.map((edge) => edge.node) ?? []; data.currentTrustCenter?.vendors.edges.map((edge) => edge.node) ?? [];
const hasAnyCountries = vendors.some(vendor => vendor.countries.length > 0);
return ( return (
<div> <div>
<h2 className="font-medium mb-1">{__("Subprocessors")}</h2> <h2 className="font-medium mb-1">{__("Subprocessors")}</h2>
@@ -26,7 +29,7 @@ export function SubprocessorsPage({ queryRef }: Props) {
</p> </p>
<Rows> <Rows>
{vendors.map((vendor) => ( {vendors.map((vendor) => (
<VendorRow key={vendor.id} vendor={vendor} /> <VendorRow key={vendor.id} vendor={vendor} hasAnyCountries={hasAnyCountries} />
))} ))}
</Rows> </Rows>
</div> </div>

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<9f96c62a3e185fed5c07415cf6fa85d1>> * @generated SignedSource<<83bb224d046b751075c6a8667e91e88b>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -9,6 +9,7 @@
// @ts-nocheck // @ts-nocheck
import { ReaderFragment } from 'relay-runtime'; import { ReaderFragment } from 'relay-runtime';
export type CountryCode = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW";
export type DocumentType = "ISMS" | "OTHER" | "POLICY"; export type DocumentType = "ISMS" | "OTHER" | "POLICY";
import { FragmentRefs } from "relay-runtime"; import { FragmentRefs } from "relay-runtime";
export type OverviewPageFragment$data = { export type OverviewPageFragment$data = {
@@ -34,6 +35,7 @@ export type OverviewPageFragment$data = {
readonly vendors: { readonly vendors: {
readonly edges: ReadonlyArray<{ readonly edges: ReadonlyArray<{
readonly node: { readonly node: {
readonly countries: ReadonlyArray<CountryCode>;
readonly id: string; readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">; readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">;
}; };
@@ -152,6 +154,13 @@ return {
"plural": false, "plural": false,
"selections": [ "selections": [
(v0/*: any*/), (v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
},
{ {
"args": null, "args": null,
"kind": "FragmentSpread", "kind": "FragmentSpread",
@@ -224,6 +233,6 @@ return {
}; };
})(); })();
(node as any).hash = "df15ec9b9040d1f4314e04085a932ecb"; (node as any).hash = "0bda7993ef3be4cfe86083658fc77813";
export default node; export default node;

View File

@@ -61,6 +61,7 @@ export const trustVendorsQuery = graphql`
edges { edges {
node { node {
id id
countries
...VendorRowFragment ...VendorRowFragment
} }
} }
@@ -131,6 +132,7 @@ export const currentTrustVendorsQuery = graphql`
edges { edges {
node { node {
id id
countries
...VendorRowFragment ...VendorRowFragment
} }
} }

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<dcb43113e97ddd2db2834d5f81c3cd3d>> * @generated SignedSource<<c1dbff6aa4c7dd1ce114b8d1fb9b76e6>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -198,6 +198,20 @@ return {
"kind": "ScalarField", "kind": "ScalarField",
"name": "title", "name": "title",
"storageKey": null "storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "isUserAuthorized",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasUserRequestedAccess",
"storageKey": null
} }
], ],
"storageKey": null "storageKey": null
@@ -214,12 +228,12 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "f04b485bb7a2ff20ac409e123404a954", "cacheID": "9e99faf40ba87ee06df5ddd64431586e",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "TrustGraphCurrentDocumentsQuery", "name": "TrustGraphCurrentDocumentsQuery",
"operationKind": "query", "operationKind": "query",
"text": "query TrustGraphCurrentDocumentsQuery {\n currentTrustCenter {\n id\n organization {\n name\n id\n }\n documents(first: 50) {\n edges {\n node {\n id\n documentType\n ...DocumentRowFragment\n }\n }\n }\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n}\n" "text": "query TrustGraphCurrentDocumentsQuery {\n currentTrustCenter {\n id\n organization {\n name\n id\n }\n documents(first: 50) {\n edges {\n node {\n id\n documentType\n ...DocumentRowFragment\n }\n }\n }\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n isUserAuthorized\n hasUserRequestedAccess\n}\n"
} }
}; };
})(); })();

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<1f034e5f6819d3db77f6aa02ec4e92c5>> * @generated SignedSource<<fe440b5c7a8a8ed54723161632320857>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -134,7 +134,21 @@ v12 = [
"name": "first", "name": "first",
"value": 50 "value": 50
} }
]; ],
v13 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "isUserAuthorized",
"storageKey": null
},
v14 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasUserRequestedAccess",
"storageKey": null
};
return { return {
"fragment": { "fragment": {
"argumentDefinitions": [], "argumentDefinitions": [],
@@ -336,6 +350,13 @@ return {
"plural": false, "plural": false,
"selections": [ "selections": [
(v0/*: any*/), (v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
},
(v6/*: any*/), (v6/*: any*/),
{ {
"alias": null, "alias": null,
@@ -351,13 +372,6 @@ return {
"kind": "ScalarField", "kind": "ScalarField",
"name": "privacyPolicyUrl", "name": "privacyPolicyUrl",
"storageKey": null "storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
} }
], ],
"storageKey": null "storageKey": null
@@ -406,6 +420,8 @@ return {
"name": "title", "name": "title",
"storageKey": null "storageKey": null
}, },
(v13/*: any*/),
(v14/*: any*/),
{ {
"alias": null, "alias": null,
"args": null, "args": null,
@@ -462,7 +478,9 @@ return {
"kind": "ScalarField", "kind": "ScalarField",
"name": "filename", "name": "filename",
"storageKey": null "storageKey": null
} },
(v13/*: any*/),
(v14/*: any*/)
], ],
"storageKey": null "storageKey": null
}, },
@@ -494,12 +512,12 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "a12f51feed01678d5a39df58ef95ad29", "cacheID": "d2c9b2a457cd3840f4b23d71cd399c84",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "TrustGraphCurrentQuery", "name": "TrustGraphCurrentQuery",
"operationKind": "query", "operationKind": "query",
"text": "query TrustGraphCurrentQuery {\n currentTrustCenter {\n id\n slug\n isUserAuthenticated\n hasAcceptedNonDisclosureAgreement\n ndaFileName\n ndaFileUrl\n organization {\n name\n description\n websiteUrl\n logoUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n report {\n id\n filename\n }\n framework {\n id\n name\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\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 ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n" "text": "query TrustGraphCurrentQuery {\n currentTrustCenter {\n id\n slug\n isUserAuthenticated\n hasAcceptedNonDisclosureAgreement\n ndaFileName\n ndaFileUrl\n organization {\n name\n description\n websiteUrl\n logoUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\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}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n"
} }
}; };
})(); })();

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<66c7f989b05136848efd4ec2d918a0bd>> * @generated SignedSource<<110264c791e814d85da9967ff839191a>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -10,6 +10,7 @@
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime"; import { FragmentRefs } from "relay-runtime";
export type CountryCode = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW";
export type TrustGraphCurrentVendorsQuery$variables = Record<PropertyKey, never>; export type TrustGraphCurrentVendorsQuery$variables = Record<PropertyKey, never>;
export type TrustGraphCurrentVendorsQuery$data = { export type TrustGraphCurrentVendorsQuery$data = {
readonly currentTrustCenter: { readonly currentTrustCenter: {
@@ -20,6 +21,7 @@ export type TrustGraphCurrentVendorsQuery$data = {
readonly vendors: { readonly vendors: {
readonly edges: ReadonlyArray<{ readonly edges: ReadonlyArray<{
readonly node: { readonly node: {
readonly countries: ReadonlyArray<CountryCode>;
readonly id: string; readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">; readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">;
}; };
@@ -53,7 +55,14 @@ v2 = [
"name": "first", "name": "first",
"value": 50 "value": 50
} }
]; ],
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
};
return { return {
"fragment": { "fragment": {
"argumentDefinitions": [], "argumentDefinitions": [],
@@ -107,6 +116,7 @@ return {
"plural": false, "plural": false,
"selections": [ "selections": [
(v0/*: any*/), (v0/*: any*/),
(v3/*: any*/),
{ {
"args": null, "args": null,
"kind": "FragmentSpread", "kind": "FragmentSpread",
@@ -181,6 +191,7 @@ return {
"plural": false, "plural": false,
"selections": [ "selections": [
(v0/*: any*/), (v0/*: any*/),
(v3/*: any*/),
(v1/*: any*/), (v1/*: any*/),
{ {
"alias": null, "alias": null,
@@ -202,13 +213,6 @@ return {
"kind": "ScalarField", "kind": "ScalarField",
"name": "privacyPolicyUrl", "name": "privacyPolicyUrl",
"storageKey": null "storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
} }
], ],
"storageKey": null "storageKey": null
@@ -225,16 +229,16 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "1ae723b3588f13e1233ab6eb4c18215e", "cacheID": "9fde94112be0665245d50a25fd166d85",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "TrustGraphCurrentVendorsQuery", "name": "TrustGraphCurrentVendorsQuery",
"operationKind": "query", "operationKind": "query",
"text": "query TrustGraphCurrentVendorsQuery {\n currentTrustCenter {\n id\n organization {\n name\n id\n }\n vendors(first: 50) {\n edges {\n node {\n id\n ...VendorRowFragment\n }\n }\n }\n }\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n" "text": "query TrustGraphCurrentVendorsQuery {\n currentTrustCenter {\n id\n organization {\n name\n id\n }\n vendors(first: 50) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n }\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n"
} }
}; };
})(); })();
(node as any).hash = "a02b52855582163623c28763fbaeb568"; (node as any).hash = "313b5f7fecfc47790b866424093aaa63";
export default node; export default node;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<a763db35fb72256cc3905206fc18e60b>> * @generated SignedSource<<e1f3b93147b9e72d9cfc41e8e0befd6e>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -366,6 +366,13 @@ return {
"plural": false, "plural": false,
"selections": [ "selections": [
(v2/*: any*/), (v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
},
(v8/*: any*/), (v8/*: any*/),
{ {
"alias": null, "alias": null,
@@ -381,13 +388,6 @@ return {
"kind": "ScalarField", "kind": "ScalarField",
"name": "privacyPolicyUrl", "name": "privacyPolicyUrl",
"storageKey": null "storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
} }
], ],
"storageKey": null "storageKey": null
@@ -528,12 +528,12 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "512205bc2cccff46b097cabaab4ec338", "cacheID": "c3cb244842768ef771ea209a51a06c4a",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "TrustGraphQuery", "name": "TrustGraphQuery",
"operationKind": "query", "operationKind": "query",
"text": "query TrustGraphQuery(\n $slug: String!\n) {\n trustCenterBySlug(slug: $slug) {\n id\n slug\n isUserAuthenticated\n hasAcceptedNonDisclosureAgreement\n ndaFileName\n ndaFileUrl\n organization {\n name\n description\n websiteUrl\n logoUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\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 ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n" "text": "query TrustGraphQuery(\n $slug: String!\n) {\n trustCenterBySlug(slug: $slug) {\n id\n slug\n isUserAuthenticated\n hasAcceptedNonDisclosureAgreement\n ndaFileName\n ndaFileUrl\n organization {\n name\n description\n websiteUrl\n logoUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\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}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n"
} }
}; };
})(); })();

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<43ebc34eede5683873c41a65f93e58b1>> * @generated SignedSource<<d6179bd34f95f33feb568bfd5b465bbc>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -10,6 +10,7 @@
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime"; import { FragmentRefs } from "relay-runtime";
export type CountryCode = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW";
export type TrustGraphVendorsQuery$variables = { export type TrustGraphVendorsQuery$variables = {
slug: string; slug: string;
}; };
@@ -22,6 +23,7 @@ export type TrustGraphVendorsQuery$data = {
readonly vendors: { readonly vendors: {
readonly edges: ReadonlyArray<{ readonly edges: ReadonlyArray<{
readonly node: { readonly node: {
readonly countries: ReadonlyArray<CountryCode>;
readonly id: string; readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">; readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">;
}; };
@@ -69,7 +71,14 @@ v4 = [
"name": "first", "name": "first",
"value": 50 "value": 50
} }
]; ],
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
};
return { return {
"fragment": { "fragment": {
"argumentDefinitions": (v0/*: any*/), "argumentDefinitions": (v0/*: any*/),
@@ -123,6 +132,7 @@ return {
"plural": false, "plural": false,
"selections": [ "selections": [
(v2/*: any*/), (v2/*: any*/),
(v5/*: any*/),
{ {
"args": null, "args": null,
"kind": "FragmentSpread", "kind": "FragmentSpread",
@@ -197,6 +207,7 @@ return {
"plural": false, "plural": false,
"selections": [ "selections": [
(v2/*: any*/), (v2/*: any*/),
(v5/*: any*/),
(v3/*: any*/), (v3/*: any*/),
{ {
"alias": null, "alias": null,
@@ -218,13 +229,6 @@ return {
"kind": "ScalarField", "kind": "ScalarField",
"name": "privacyPolicyUrl", "name": "privacyPolicyUrl",
"storageKey": null "storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
} }
], ],
"storageKey": null "storageKey": null
@@ -241,16 +245,16 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "1975e4b062f66fef036fc08bd7ff0b53", "cacheID": "4b60b2757d58e49101104addf411eff2",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "TrustGraphVendorsQuery", "name": "TrustGraphVendorsQuery",
"operationKind": "query", "operationKind": "query",
"text": "query TrustGraphVendorsQuery(\n $slug: String!\n) {\n trustCenterBySlug(slug: $slug) {\n id\n organization {\n name\n id\n }\n vendors(first: 50) {\n edges {\n node {\n id\n ...VendorRowFragment\n }\n }\n }\n }\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n" "text": "query TrustGraphVendorsQuery(\n $slug: String!\n) {\n trustCenterBySlug(slug: $slug) {\n id\n organization {\n name\n id\n }\n vendors(first: 50) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n }\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n"
} }
}; };
})(); })();
(node as any).hash = "b21c7b35a682aa1fc4210e1c717e55b4"; (node as any).hash = "9a4c9326d25ea59f5898467e38083caa";
export default node; export default node;

View File

@@ -53,3 +53,4 @@ export {
export { promisifyMutation } from "./relay"; export { promisifyMutation } from "./relay";
export { fileType, fileSize } from "./file"; export { fileType, fileSize } from "./file";
export { formatDatetime, formatDate } from "./date"; export { formatDatetime, formatDate } from "./date";
export { getLogoUrl, getTrustCenterUrl } from "./trustCenter";

View File

@@ -0,0 +1,22 @@
export function getLogoUrl(logoPath: string): string {
const path = window.location.pathname;
const trustMatch = path.match(/^\/trust\/([^/]+)/);
if (!trustMatch) {
return `/logos/${logoPath}`;
}
const slug = trustMatch[1];
return `/trust/${slug}/logos/${logoPath}`;
}
export function getTrustCenterUrl(path: string): string {
const currentPath = window.location.pathname;
const trustMatch = currentPath.match(/^\/trust\/([^/]+)/);
if (!trustMatch) {
return `/${path}`;
}
return `../${path}`;
}