Update public apps for dedicated host routing
Stop relying on the /trust/{id} path prefix in the public trust app and
serve it from the host root, reading contact and profile data from the
trust center instead of the organization. Mirror the same fragment
ownership change in the compliance portal hero.
Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
@@ -24,29 +24,29 @@ import { graphql, useFragment } from "react-relay";
|
|||||||
|
|
||||||
import { externalHref, hostnameOf } from "#/lib/url/hostname";
|
import { externalHref, hostnameOf } from "#/lib/url/hostname";
|
||||||
|
|
||||||
import type { OrganizationContactInfo_organization$key } from "./__generated__/OrganizationContactInfo_organization.graphql";
|
import type { TrustCenterContactInfo_trustCenter$key } from "./__generated__/TrustCenterContactInfo_trustCenter.graphql";
|
||||||
import { organizationContactInfo } from "./variants";
|
import { organizationContactInfo } from "./variants";
|
||||||
|
|
||||||
const organizationContactInfoFragment = graphql`
|
const trustCenterContactInfoFragment = graphql`
|
||||||
fragment OrganizationContactInfo_organization on Organization {
|
fragment TrustCenterContactInfo_trustCenter on TrustCenter {
|
||||||
websiteUrl
|
websiteUrl
|
||||||
email
|
email
|
||||||
headquarterAddress
|
headquarterAddress
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface OrganizationContactInfoProps {
|
interface TrustCenterContactInfoProps {
|
||||||
organizationKey: OrganizationContactInfo_organization$key;
|
trustCenterKey: TrustCenterContactInfo_trustCenter$key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Organization contact details (website, email, HQ) rendered as an icon + label
|
// Trust center contact details (website, email, HQ) rendered as an icon + label
|
||||||
// row. Owns its fragment so it can be reused wherever the org is in scope.
|
// row. Owns its fragment so it can be reused wherever the trust center is in scope.
|
||||||
export function OrganizationContactInfo({ organizationKey }: OrganizationContactInfoProps) {
|
export function TrustCenterContactInfo({ trustCenterKey }: TrustCenterContactInfoProps) {
|
||||||
const organization = useFragment(organizationContactInfoFragment, organizationKey);
|
const trustCenter = useFragment(trustCenterContactInfoFragment, trustCenterKey);
|
||||||
|
|
||||||
const hasWebsite = organization.websiteUrl != null && organization.websiteUrl !== "";
|
const hasWebsite = trustCenter.websiteUrl != null && trustCenter.websiteUrl !== "";
|
||||||
const hasEmail = organization.email != null && organization.email !== "";
|
const hasEmail = trustCenter.email != null && trustCenter.email !== "";
|
||||||
const hasAddress = organization.headquarterAddress != null && organization.headquarterAddress !== "";
|
const hasAddress = trustCenter.headquarterAddress != null && trustCenter.headquarterAddress !== "";
|
||||||
|
|
||||||
// Nothing to show — render no row (and therefore no divider) at all.
|
// Nothing to show — render no row (and therefore no divider) at all.
|
||||||
if (!hasWebsite && !hasEmail && !hasAddress) {
|
if (!hasWebsite && !hasEmail && !hasAddress) {
|
||||||
@@ -60,21 +60,21 @@ export function OrganizationContactInfo({ organizationKey }: OrganizationContact
|
|||||||
{hasWebsite && (
|
{hasWebsite && (
|
||||||
<a
|
<a
|
||||||
className={link()}
|
className={link()}
|
||||||
href={externalHref(organization.websiteUrl)}
|
href={externalHref(trustCenter.websiteUrl)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<GlobeSimpleIcon />
|
<GlobeSimpleIcon />
|
||||||
<Text size={2} color="neutral">
|
<Text size={2} color="neutral">
|
||||||
{hostnameOf(organization.websiteUrl)}
|
{hostnameOf(trustCenter.websiteUrl)}
|
||||||
</Text>
|
</Text>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
{hasEmail && (
|
{hasEmail && (
|
||||||
<a className={link()} href={`mailto:${organization.email}`}>
|
<a className={link()} href={`mailto:${trustCenter.email}`}>
|
||||||
<EnvelopeIcon />
|
<EnvelopeIcon />
|
||||||
<Text size={2} color="neutral">
|
<Text size={2} color="neutral">
|
||||||
{organization.email}
|
{trustCenter.email}
|
||||||
</Text>
|
</Text>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
@@ -82,7 +82,7 @@ export function OrganizationContactInfo({ organizationKey }: OrganizationContact
|
|||||||
<div className={item()}>
|
<div className={item()}>
|
||||||
<MapPinSimpleIcon />
|
<MapPinSimpleIcon />
|
||||||
<Text size={2} color="neutral">
|
<Text size={2} color="neutral">
|
||||||
{organization.headquarterAddress}
|
{trustCenter.headquarterAddress}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -24,7 +24,7 @@ import { graphql, usePreloadedQuery } from "react-relay";
|
|||||||
|
|
||||||
import { ComplianceFrameworksSection } from "#/components/ComplianceFrameworks/ComplianceFrameworksSection";
|
import { ComplianceFrameworksSection } from "#/components/ComplianceFrameworks/ComplianceFrameworksSection";
|
||||||
import { Hero } from "#/components/Hero/Hero";
|
import { Hero } from "#/components/Hero/Hero";
|
||||||
import { OrganizationContactInfo } from "#/components/Hero/OrganizationContactInfo";
|
import { TrustCenterContactInfo } from "#/components/Hero/TrustCenterContactInfo";
|
||||||
import { RecentUpdatesSection } from "#/components/RecentUpdates/RecentUpdatesSection";
|
import { RecentUpdatesSection } from "#/components/RecentUpdates/RecentUpdatesSection";
|
||||||
import { SecurityCommitmentsSection } from "#/components/SecurityCommitments/SecurityCommitmentsSection";
|
import { SecurityCommitmentsSection } from "#/components/SecurityCommitments/SecurityCommitmentsSection";
|
||||||
import { TrustedBySection } from "#/components/TrustedBy/TrustedBySection";
|
import { TrustedBySection } from "#/components/TrustedBy/TrustedBySection";
|
||||||
@@ -36,8 +36,8 @@ export const homePageQuery = graphql`
|
|||||||
currentTrustCenter @required(action: THROW) {
|
currentTrustCenter @required(action: THROW) {
|
||||||
organization {
|
organization {
|
||||||
name
|
name
|
||||||
...OrganizationContactInfo_organization
|
|
||||||
}
|
}
|
||||||
|
...TrustCenterContactInfo_trustCenter
|
||||||
...ComplianceFrameworksSection_trustCenter
|
...ComplianceFrameworksSection_trustCenter
|
||||||
...SecurityCommitmentsSection_trustCenter
|
...SecurityCommitmentsSection_trustCenter
|
||||||
...TrustedBySection_trustCenter
|
...TrustedBySection_trustCenter
|
||||||
@@ -62,7 +62,7 @@ export function HomePage({ queryRef }: HomePageProps) {
|
|||||||
title={t("home.heroTitle", { name: organization.name })}
|
title={t("home.heroTitle", { name: organization.name })}
|
||||||
description={t("home.heroDescription")}
|
description={t("home.heroDescription")}
|
||||||
>
|
>
|
||||||
<OrganizationContactInfo organizationKey={organization} />
|
<TrustCenterContactInfo trustCenterKey={currentTrustCenter} />
|
||||||
</Hero>
|
</Hero>
|
||||||
<div className="flex w-full flex-col items-center px-8 max-md:px-4">
|
<div className="flex w-full flex-col items-center px-8 max-md:px-4">
|
||||||
<div className="flex w-full max-w-5xl flex-col">
|
<div className="flex w-full max-w-5xl flex-col">
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ import { useFragment, useMutation } from "react-relay";
|
|||||||
import { useLocation, useNavigate, useSearchParams } from "react-router";
|
import { useLocation, useNavigate, useSearchParams } from "react-router";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { AuditRow_requestAccessMutation } from "./__generated__/AuditRow_requestAccessMutation.graphql";
|
import type { AuditRow_requestAccessMutation } from "./__generated__/AuditRow_requestAccessMutation.graphql";
|
||||||
import type { AuditRowFragment$key } from "./__generated__/AuditRowFragment.graphql";
|
import type { AuditRowFragment$key } from "./__generated__/AuditRowFragment.graphql";
|
||||||
|
|
||||||
@@ -121,11 +119,10 @@ export function AuditRow(props: { audit: AuditRowFragment$key }) {
|
|||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (error instanceof UnAuthenticatedError) {
|
if (error instanceof UnAuthenticatedError) {
|
||||||
const pathPrefix = getPathPrefix();
|
|
||||||
searchParams.set("request-report-id", audit.reportFile?.id ?? "");
|
searchParams.set("request-report-id", audit.reportFile?.id ?? "");
|
||||||
const urlSearchParams = new URLSearchParams([[
|
const urlSearchParams = new URLSearchParams([[
|
||||||
"continue",
|
"continue",
|
||||||
window.location.origin + pathPrefix + location.pathname + "?" + searchParams.toString(),
|
window.location.origin + location.pathname + "?" + searchParams.toString(),
|
||||||
]]);
|
]]);
|
||||||
void navigate(`/connect?${urlSearchParams.toString()}`);
|
void navigate(`/connect?${urlSearchParams.toString()}`);
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ import {
|
|||||||
import { Button, IconChevronLeft, IconPageCross } from "@probo/ui";
|
import { Button, IconChevronLeft, IconPageCross } from "@probo/ui";
|
||||||
import { Link, Navigate, useLocation, useRouteError } from "react-router";
|
import { Link, Navigate, useLocation, useRouteError } from "react-router";
|
||||||
|
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
export function DocumentPageErrorBoundary() {
|
export function DocumentPageErrorBoundary() {
|
||||||
const error = useRouteError();
|
const error = useRouteError();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -36,7 +34,7 @@ export function DocumentPageErrorBoundary() {
|
|||||||
|
|
||||||
const search = new URLSearchParams();
|
const search = new URLSearchParams();
|
||||||
|
|
||||||
if (location.pathname !== (getPathPrefix() || "/") || location.search !== "") {
|
if (location.pathname !== "/" || location.search !== "") {
|
||||||
search.set("continue", window.location.href);
|
search.set("continue", window.location.href);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ import { useFragment, useMutation } from "react-relay";
|
|||||||
import { useLocation, useNavigate, useSearchParams } from "react-router";
|
import { useLocation, useNavigate, useSearchParams } from "react-router";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { DocumentRow_requestAccessMutation } from "./__generated__/DocumentRow_requestAccessMutation.graphql";
|
import type { DocumentRow_requestAccessMutation } from "./__generated__/DocumentRow_requestAccessMutation.graphql";
|
||||||
import type { DocumentRowFragment$key } from "./__generated__/DocumentRowFragment.graphql";
|
import type { DocumentRowFragment$key } from "./__generated__/DocumentRowFragment.graphql";
|
||||||
|
|
||||||
@@ -103,11 +101,10 @@ export function DocumentRow(props: { document: DocumentRowFragment$key }) {
|
|||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (error instanceof UnAuthenticatedError) {
|
if (error instanceof UnAuthenticatedError) {
|
||||||
const pathPrefix = getPathPrefix();
|
|
||||||
searchParams.set("request-document-id", document.id);
|
searchParams.set("request-document-id", document.id);
|
||||||
const urlSearchParams = new URLSearchParams([[
|
const urlSearchParams = new URLSearchParams([[
|
||||||
"continue",
|
"continue",
|
||||||
window.location.origin + pathPrefix + location.pathname + "?" + searchParams.toString(),
|
window.location.origin + location.pathname + "?" + searchParams.toString(),
|
||||||
]]);
|
]]);
|
||||||
void navigate(`/connect?${urlSearchParams.toString()}`);
|
void navigate(`/connect?${urlSearchParams.toString()}`);
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ import { useLocation, useNavigate, useSearchParams } from "react-router";
|
|||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import type { TrustGraphCurrentQuery$data } from "#/queries/__generated__/TrustGraphCurrentQuery.graphql";
|
import type { TrustGraphCurrentQuery$data } from "#/queries/__generated__/TrustGraphCurrentQuery.graphql";
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { OrganizationSidebar_requestAllAccessesMutation } from "./__generated__/OrganizationSidebar_requestAllAccessesMutation.graphql";
|
import type { OrganizationSidebar_requestAllAccessesMutation } from "./__generated__/OrganizationSidebar_requestAllAccessesMutation.graphql";
|
||||||
import type { OrganizationSidebar_subscribeToMailingListMutation } from "./__generated__/OrganizationSidebar_subscribeToMailingListMutation.graphql";
|
import type { OrganizationSidebar_subscribeToMailingListMutation } from "./__generated__/OrganizationSidebar_subscribeToMailingListMutation.graphql";
|
||||||
@@ -132,11 +131,10 @@ export function OrganizationSidebar({
|
|||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (error instanceof UnAuthenticatedError) {
|
if (error instanceof UnAuthenticatedError) {
|
||||||
const pathPrefix = getPathPrefix();
|
|
||||||
searchParams.set("request-all", "true");
|
searchParams.set("request-all", "true");
|
||||||
const urlSearchParams = new URLSearchParams([[
|
const urlSearchParams = new URLSearchParams([[
|
||||||
"continue",
|
"continue",
|
||||||
window.location.origin + pathPrefix + location.pathname + "?" + searchParams.toString(),
|
window.location.origin + location.pathname + "?" + searchParams.toString(),
|
||||||
]]);
|
]]);
|
||||||
void navigate(`/connect?${urlSearchParams.toString()}`);
|
void navigate(`/connect?${urlSearchParams.toString()}`);
|
||||||
|
|
||||||
@@ -237,7 +235,7 @@ export function OrganizationSidebar({
|
|||||||
)}
|
)}
|
||||||
<h1 className="text-2xl mt-6">{trustCenter.organization.name}</h1>
|
<h1 className="text-2xl mt-6">{trustCenter.organization.name}</h1>
|
||||||
<p className="text-sm text-txt-secondary mt-1">
|
<p className="text-sm text-txt-secondary mt-1">
|
||||||
{trustCenter.organization.description}
|
{trustCenter.description}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr className="my-6 -mx-6 h-px bg-border-low border-none" />
|
<hr className="my-6 -mx-6 h-px bg-border-low border-none" />
|
||||||
@@ -248,32 +246,32 @@ export function OrganizationSidebar({
|
|||||||
<IconBlock size={16} />
|
<IconBlock size={16} />
|
||||||
{__("Business information")}
|
{__("Business information")}
|
||||||
</h2>
|
</h2>
|
||||||
{trustCenter.organization.websiteUrl && (
|
{trustCenter.websiteUrl && (
|
||||||
<BusinessInfo label={__("Website")}>
|
<BusinessInfo label={__("Website")}>
|
||||||
<a {...externalLinkProps(trustCenter.organization.websiteUrl)}>
|
<a {...externalLinkProps(trustCenter.websiteUrl)}>
|
||||||
<span className="text-txt-info hover:underline ">
|
<span className="text-txt-info hover:underline ">
|
||||||
{new URL(trustCenter.organization.websiteUrl).host}
|
{new URL(trustCenter.websiteUrl).host}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</BusinessInfo>
|
</BusinessInfo>
|
||||||
)}
|
)}
|
||||||
{trustCenter.organization.email && (
|
{trustCenter.email && (
|
||||||
<BusinessInfo label={__("Contact")}>
|
<BusinessInfo label={__("Contact")}>
|
||||||
<a href={`mailto:${trustCenter.organization.email}`}>
|
<a href={`mailto:${trustCenter.email}`}>
|
||||||
<span className="text-txt-info hover:underline ">
|
<span className="text-txt-info hover:underline ">
|
||||||
{trustCenter.organization.email}
|
{trustCenter.email}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</BusinessInfo>
|
</BusinessInfo>
|
||||||
)}
|
)}
|
||||||
{trustCenter.organization.headquarterAddress && (
|
{trustCenter.headquarterAddress && (
|
||||||
<BusinessInfo label={__("HQ address")}>
|
<BusinessInfo label={__("HQ address")}>
|
||||||
{trustCenter.organization.headquarterAddress}
|
{trustCenter.headquarterAddress}
|
||||||
</BusinessInfo>
|
</BusinessInfo>
|
||||||
)}
|
)}
|
||||||
{trustCenter.externalUrls.edges.length > 0 && (
|
{trustCenter.customLinks.edges.length > 0 && (
|
||||||
<div className="flex flex-wrap gap-x-4 gap-y-2">
|
<div className="flex flex-wrap gap-x-4 gap-y-2">
|
||||||
{trustCenter.externalUrls.edges.map(({ node }) => (
|
{trustCenter.customLinks.edges.map(({ node }) => (
|
||||||
<a
|
<a
|
||||||
key={node.id}
|
key={node.id}
|
||||||
{...externalLinkProps(node.url)}
|
{...externalLinkProps(node.url)}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
import { FullNameRequiredError, NDASignatureRequiredError, UnAuthenticatedError } from "@probo/relay";
|
import { FullNameRequiredError, NDASignatureRequiredError, UnAuthenticatedError } from "@probo/relay";
|
||||||
import { Navigate, useLocation, useRouteError } from "react-router";
|
import { Navigate, useLocation, useRouteError } from "react-router";
|
||||||
|
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import { PageError } from "./PageError";
|
import { PageError } from "./PageError";
|
||||||
|
|
||||||
export function RootErrorBoundary() {
|
export function RootErrorBoundary() {
|
||||||
@@ -31,7 +29,7 @@ export function RootErrorBoundary() {
|
|||||||
|
|
||||||
const search = new URLSearchParams();
|
const search = new URLSearchParams();
|
||||||
|
|
||||||
if (location.pathname !== (getPathPrefix() || "/") || location.search !== "") {
|
if (location.pathname !== "/" || location.search !== "") {
|
||||||
search.set("continue", window.location.href);
|
search.set("continue", window.location.href);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ import { useFragment, useMutation } from "react-relay";
|
|||||||
import { useLocation, useNavigate, useSearchParams } from "react-router";
|
import { useLocation, useNavigate, useSearchParams } from "react-router";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { TrustCenterFileRow_requestAccessMutation } from "./__generated__/TrustCenterFileRow_requestAccessMutation.graphql";
|
import type { TrustCenterFileRow_requestAccessMutation } from "./__generated__/TrustCenterFileRow_requestAccessMutation.graphql";
|
||||||
import type { TrustCenterFileRowFragment$key } from "./__generated__/TrustCenterFileRowFragment.graphql";
|
import type { TrustCenterFileRowFragment$key } from "./__generated__/TrustCenterFileRowFragment.graphql";
|
||||||
|
|
||||||
@@ -107,11 +105,10 @@ export function TrustCenterFileRow(props: {
|
|||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (error instanceof UnAuthenticatedError) {
|
if (error instanceof UnAuthenticatedError) {
|
||||||
const pathPrefix = getPathPrefix();
|
|
||||||
searchParams.set("request-file-id", file.id);
|
searchParams.set("request-file-id", file.id);
|
||||||
const urlSearchParams = new URLSearchParams([[
|
const urlSearchParams = new URLSearchParams([[
|
||||||
"continue",
|
"continue",
|
||||||
window.location.origin + pathPrefix + location.pathname + "?" + searchParams.toString(),
|
window.location.origin + location.pathname + "?" + searchParams.toString(),
|
||||||
]]);
|
]]);
|
||||||
void navigate(`/connect?${urlSearchParams.toString()}`);
|
void navigate(`/connect?${urlSearchParams.toString()}`);
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ import { useMutation } from "react-relay";
|
|||||||
import { useLocation, useSearchParams } from "react-router";
|
import { useLocation, useSearchParams } from "react-router";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { useRequestAccessCallback_allMutation } from "./__generated__/useRequestAccessCallback_allMutation.graphql";
|
import type { useRequestAccessCallback_allMutation } from "./__generated__/useRequestAccessCallback_allMutation.graphql";
|
||||||
import type { useRequestAccessCallback_documentMutation } from "./__generated__/useRequestAccessCallback_documentMutation.graphql";
|
import type { useRequestAccessCallback_documentMutation } from "./__generated__/useRequestAccessCallback_documentMutation.graphql";
|
||||||
import type { useRequestAccessCallback_fileMutation } from "./__generated__/useRequestAccessCallback_fileMutation.graphql";
|
import type { useRequestAccessCallback_fileMutation } from "./__generated__/useRequestAccessCallback_fileMutation.graphql";
|
||||||
@@ -192,7 +190,7 @@ export function useRequestAccessCallback() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toast(successToastArgs(__));
|
toast(successToastArgs(__));
|
||||||
window.location.href = window.location.origin + getPathPrefix() + location.pathname;
|
window.location.href = window.location.origin + location.pathname;
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
toast(errorToastArgs(__, error));
|
toast(errorToastArgs(__, error));
|
||||||
|
|||||||
@@ -21,14 +21,11 @@
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useSearchParams } from "react-router";
|
import { useSearchParams } from "react-router";
|
||||||
|
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
export function useSafeContinueUrl(): URL {
|
export function useSafeContinueUrl(): URL {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
const continueUrlParam = searchParams.get("continue");
|
const continueUrlParam = searchParams.get("continue");
|
||||||
const prefix = getPathPrefix();
|
const fallback = window.location.origin + "/";
|
||||||
const fallback = window.location.origin + (prefix || "/");
|
|
||||||
|
|
||||||
const safeContinueUrl = useMemo(() => {
|
const safeContinueUrl = useMemo(() => {
|
||||||
if (continueUrlParam) {
|
if (continueUrlParam) {
|
||||||
@@ -40,7 +37,7 @@ export function useSafeContinueUrl(): URL {
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
continueUrl.origin === window.location.origin
|
continueUrl.origin === window.location.origin
|
||||||
&& continueUrl.pathname.startsWith(`${prefix}/`)
|
&& continueUrl.pathname.startsWith("/")
|
||||||
) {
|
) {
|
||||||
return new URL(
|
return new URL(
|
||||||
continueUrl.pathname + continueUrl.search,
|
continueUrl.pathname + continueUrl.search,
|
||||||
@@ -50,7 +47,7 @@ export function useSafeContinueUrl(): URL {
|
|||||||
return new URL(fallback, window.location.origin);
|
return new URL(fallback, window.location.origin);
|
||||||
}
|
}
|
||||||
return new URL(fallback, window.location.origin);
|
return new URL(fallback, window.location.origin);
|
||||||
}, [continueUrlParam, fallback, prefix]);
|
}, [continueUrlParam, fallback]);
|
||||||
|
|
||||||
return safeContinueUrl;
|
return safeContinueUrl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import { Link, useLocation, useNavigate, useSearchParams } from "react-router";
|
|||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import { PDFPreview } from "#/components/PDFPreview";
|
import { PDFPreview } from "#/components/PDFPreview";
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { DocumentPageExportDocumentMutation } from "./__generated__/DocumentPageExportDocumentMutation.graphql";
|
import type { DocumentPageExportDocumentMutation } from "./__generated__/DocumentPageExportDocumentMutation.graphql";
|
||||||
import type { DocumentPageExportReportMutation } from "./__generated__/DocumentPageExportReportMutation.graphql";
|
import type { DocumentPageExportReportMutation } from "./__generated__/DocumentPageExportReportMutation.graphql";
|
||||||
@@ -322,10 +321,9 @@ export function DocumentPage({ queryRef }: Props) {
|
|||||||
const handleRequestAccess = () => {
|
const handleRequestAccess = () => {
|
||||||
const onError = (error: Error) => {
|
const onError = (error: Error) => {
|
||||||
if (error instanceof UnAuthenticatedError) {
|
if (error instanceof UnAuthenticatedError) {
|
||||||
const pathPrefix = getPathPrefix();
|
|
||||||
const urlSearchParams = new URLSearchParams([[
|
const urlSearchParams = new URLSearchParams([[
|
||||||
"continue",
|
"continue",
|
||||||
window.location.origin + pathPrefix + location.pathname + "?" + searchParams.toString(),
|
window.location.origin + location.pathname + "?" + searchParams.toString(),
|
||||||
]]);
|
]]);
|
||||||
void navigate(`/connect?${urlSearchParams.toString()}`);
|
void navigate(`/connect?${urlSearchParams.toString()}`);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import { graphql } from "relay-runtime";
|
|||||||
import { useWindowSize } from "usehooks-ts";
|
import { useWindowSize } from "usehooks-ts";
|
||||||
|
|
||||||
import { PDFPreview } from "#/components/PDFPreview";
|
import { PDFPreview } from "#/components/PDFPreview";
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { NDAPageAcceptElectronicSignatureMutation } from "./__generated__/NDAPageAcceptElectronicSignatureMutation.graphql";
|
import type { NDAPageAcceptElectronicSignatureMutation } from "./__generated__/NDAPageAcceptElectronicSignatureMutation.graphql";
|
||||||
import type { NDAPageFragment$key } from "./__generated__/NDAPageFragment.graphql";
|
import type { NDAPageFragment$key } from "./__generated__/NDAPageFragment.graphql";
|
||||||
@@ -125,16 +124,16 @@ export function NDAPage(props: {
|
|||||||
if (continueUrlParam) {
|
if (continueUrlParam) {
|
||||||
try {
|
try {
|
||||||
const continueUrl = new URL(continueUrlParam, window.location.origin);
|
const continueUrl = new URL(continueUrlParam, window.location.origin);
|
||||||
if (continueUrl.origin === window.location.origin && continueUrl.pathname.startsWith(`${getPathPrefix()}/`)) {
|
if (continueUrl.origin === window.location.origin && continueUrl.pathname.startsWith("/")) {
|
||||||
safeContinueUrl = window.location.origin + continueUrl.pathname + continueUrl.search;
|
safeContinueUrl = window.location.origin + continueUrl.pathname + continueUrl.search;
|
||||||
} else {
|
} else {
|
||||||
safeContinueUrl = window.location.origin + getPathPrefix();
|
safeContinueUrl = window.location.origin;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
safeContinueUrl = window.location.origin + getPathPrefix();
|
safeContinueUrl = window.location.origin;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
safeContinueUrl = window.location.origin + getPathPrefix();
|
safeContinueUrl = window.location.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [acceptSignature, isAccepting] = useMutation<NDAPageAcceptElectronicSignatureMutation>(
|
const [acceptSignature, isAccepting] = useMutation<NDAPageAcceptElectronicSignatureMutation>(
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
||||||
import { useSafeContinueUrl } from "#/hooks/useSafeContinueUrl";
|
import { useSafeContinueUrl } from "#/hooks/useSafeContinueUrl";
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { ConnectPageMutation, SendMagicLinkInput } from "./__generated__/ConnectPageMutation.graphql";
|
import type { ConnectPageMutation, SendMagicLinkInput } from "./__generated__/ConnectPageMutation.graphql";
|
||||||
import type { ConnectPageQuery } from "./__generated__/ConnectPageQuery.graphql";
|
import type { ConnectPageQuery } from "./__generated__/ConnectPageQuery.graphql";
|
||||||
@@ -131,7 +130,7 @@ export function ConnectPage(props: {
|
|||||||
if (errors) {
|
if (errors) {
|
||||||
for (const err of errors) {
|
for (const err of errors) {
|
||||||
if (err.extensions?.code === "ALREADY_AUTHENTICATED") {
|
if (err.extensions?.code === "ALREADY_AUTHENTICATED") {
|
||||||
window.location.href = getPathPrefix() || "/";
|
window.location.href = "/";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import { graphql } from "relay-runtime";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { FullNamePageMutation } from "./__generated__/FullNamePageMutation.graphql";
|
import type { FullNamePageMutation } from "./__generated__/FullNamePageMutation.graphql";
|
||||||
|
|
||||||
@@ -57,16 +56,16 @@ export default function FullNamePage() {
|
|||||||
if (continueUrlParam) {
|
if (continueUrlParam) {
|
||||||
try {
|
try {
|
||||||
const continueUrl = new URL(continueUrlParam, window.location.origin);
|
const continueUrl = new URL(continueUrlParam, window.location.origin);
|
||||||
if (continueUrl.origin === window.location.origin && continueUrl.pathname.startsWith(`${getPathPrefix()}/`)) {
|
if (continueUrl.origin === window.location.origin && continueUrl.pathname.startsWith("/")) {
|
||||||
safeContinueUrl = window.location.origin + continueUrl.pathname + continueUrl.search;
|
safeContinueUrl = window.location.origin + continueUrl.pathname + continueUrl.search;
|
||||||
} else {
|
} else {
|
||||||
safeContinueUrl = window.location.origin + getPathPrefix();
|
safeContinueUrl = window.location.origin;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
safeContinueUrl = window.location.origin + getPathPrefix();
|
safeContinueUrl = window.location.origin;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
safeContinueUrl = window.location.origin + getPathPrefix();
|
safeContinueUrl = window.location.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -94,7 +93,7 @@ export default function FullNamePage() {
|
|||||||
if (errors) {
|
if (errors) {
|
||||||
for (const err of errors) {
|
for (const err of errors) {
|
||||||
if (err.extensions?.code === "ALREADY_AUTHENTICATED") {
|
if (err.extensions?.code === "ALREADY_AUTHENTICATED") {
|
||||||
window.location.href = getPathPrefix() || "/";
|
window.location.href = "/";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ import { useMutation } from "react-relay";
|
|||||||
import { Link, useNavigate, useSearchParams } from "react-router";
|
import { Link, useNavigate, useSearchParams } from "react-router";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
import type { VerifyMagicLinkPageMutation } from "./__generated__/VerifyMagicLinkPageMutation.graphql";
|
import type { VerifyMagicLinkPageMutation } from "./__generated__/VerifyMagicLinkPageMutation.graphql";
|
||||||
|
|
||||||
const verifyMagicLinkMutation = graphql`
|
const verifyMagicLinkMutation = graphql`
|
||||||
@@ -63,7 +61,7 @@ export default function VerifyMagicLinkPagePageMutation() {
|
|||||||
if (errors) {
|
if (errors) {
|
||||||
for (const err of errors) {
|
for (const err of errors) {
|
||||||
if (err.extensions?.code === "ALREADY_AUTHENTICATED") {
|
if (err.extensions?.code === "ALREADY_AUTHENTICATED") {
|
||||||
window.location.href = window.location.origin + getPathPrefix();
|
window.location.href = window.location.origin;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,10 +97,10 @@ export default function VerifyMagicLinkPagePageMutation() {
|
|||||||
const continueUrl = new URL(verifyMagicLink.continue, window.location.origin);
|
const continueUrl = new URL(verifyMagicLink.continue, window.location.origin);
|
||||||
window.location.href = window.location.origin + continueUrl.pathname + continueUrl.search;
|
window.location.href = window.location.origin + continueUrl.pathname + continueUrl.search;
|
||||||
} catch {
|
} catch {
|
||||||
window.location.href = window.location.origin + getPathPrefix();
|
window.location.href = window.location.origin;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
window.location.href = window.location.origin + getPathPrefix();
|
window.location.href = window.location.origin;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (err) => {
|
onError: (err) => {
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ import {
|
|||||||
Store,
|
Store,
|
||||||
} from "relay-runtime";
|
} from "relay-runtime";
|
||||||
|
|
||||||
import { getPathPrefix } from "#/utils/pathPrefix";
|
|
||||||
|
|
||||||
export function buildEndpoint(): string {
|
export function buildEndpoint(): string {
|
||||||
let host = import.meta.env.VITE_API_URL;
|
let host = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
@@ -44,15 +42,8 @@ export function buildEndpoint(): string {
|
|||||||
|
|
||||||
const url = new URL(formattedHost);
|
const url = new URL(formattedHost);
|
||||||
|
|
||||||
const prefix = getPathPrefix();
|
// Compliance pages are always served at the root of a dedicated host.
|
||||||
let path: string;
|
url.pathname = `/api/trust/v1/graphql`;
|
||||||
if (prefix) {
|
|
||||||
path = `${prefix}/api/trust/v1/graphql`;
|
|
||||||
} else {
|
|
||||||
path = `/api/trust/v1/graphql`;
|
|
||||||
}
|
|
||||||
|
|
||||||
url.pathname = path;
|
|
||||||
|
|
||||||
return url.toString();
|
return url.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ export const currentTrustGraphQuery = graphql`
|
|||||||
currentTrustCenter @required(action: THROW) {
|
currentTrustCenter @required(action: THROW) {
|
||||||
id
|
id
|
||||||
slug
|
slug
|
||||||
|
description
|
||||||
|
websiteUrl
|
||||||
|
email
|
||||||
|
headquarterAddress
|
||||||
viewerSubscription {
|
viewerSubscription {
|
||||||
id
|
id
|
||||||
email
|
email
|
||||||
@@ -52,12 +56,8 @@ export const currentTrustGraphQuery = graphql`
|
|||||||
}
|
}
|
||||||
organization {
|
organization {
|
||||||
name
|
name
|
||||||
description
|
|
||||||
websiteUrl
|
|
||||||
email
|
|
||||||
headquarterAddress
|
|
||||||
}
|
}
|
||||||
externalUrls(first: 20) {
|
customLinks(first: 20) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -173,15 +173,4 @@ const routes = [
|
|||||||
},
|
},
|
||||||
] satisfies AppRoute[];
|
] satisfies AppRoute[];
|
||||||
|
|
||||||
// Detect basename from current URL path
|
export const router = createBrowserRouter(routes.map(routeFromAppRoute), {});
|
||||||
// If URL starts with /trust/{slug}, extract that as the basename
|
|
||||||
// Otherwise, use "/" for custom domains
|
|
||||||
function getBasename(): string {
|
|
||||||
const path = window.location.pathname;
|
|
||||||
const trustMatch = path.match(/^\/trust\/[^/]+/);
|
|
||||||
return trustMatch ? trustMatch[0] : "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
export const router = createBrowserRouter(routes.map(routeFromAppRoute), {
|
|
||||||
basename: getBasename(),
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
import { matchPath } from "react-router";
|
|
||||||
|
|
||||||
export function getPathPrefix() {
|
|
||||||
const match = matchPath(
|
|
||||||
{ path: "/trust/:id", caseSensitive: false, end: false },
|
|
||||||
window.location.pathname,
|
|
||||||
);
|
|
||||||
|
|
||||||
let prefix = "";
|
|
||||||
if (match) {
|
|
||||||
prefix = `/trust/${match.params.id}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user