diff --git a/.env.example b/.env.example index df6023619..90f2c2d47 100644 --- a/.env.example +++ b/.env.example @@ -18,7 +18,7 @@ # ── Base URL & ports ────────────────────────────────────────────────── # PROBOD_BASE_URL=http://localhost:8080 # PROBOD_API_ADDR=:8080 -# PROBOD_API_CORS_ALLOWED_ORIGINS=http://localhost:8080,http://localhost:5173,http://localhost:5174,http://localhost:5175 +# PROBOD_API_CORS_ALLOWED_ORIGINS=http://localhost:8080,http://localhost:5173,http://localhost:5174 # PROBOD_TRUST_CENTER_HTTP_ADDR=:10080 # PROBOD_TRUST_CENTER_HTTPS_ADDR=:443 # PROBOD_TRUST_CENTER_BASE_DOMAIN=probopage.localhost diff --git a/.github/workflows/make.yaml b/.github/workflows/make.yaml index 487e7a3cf..aca0fc35d 100644 --- a/.github/workflows/make.yaml +++ b/.github/workflows/make.yaml @@ -245,10 +245,9 @@ jobs: node: "false" - name: "Create placeholder dist files" run: | - mkdir -p apps/console/dist apps/compliance-portal/dist apps/trust/dist packages/emails/dist + mkdir -p apps/console/dist apps/compliance-portal/dist packages/emails/dist echo dev-server > apps/console/dist/index.html echo dev-server > apps/compliance-portal/dist/index.html - echo dev-server > apps/trust/dist/index.html echo dev-server > packages/emails/dist/placeholder - name: "Generate Go code" run: | @@ -310,10 +309,9 @@ jobs: - uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 - name: "Create placeholder dist files" run: | - mkdir -p apps/console/dist apps/compliance-portal/dist apps/trust/dist packages/emails/dist + mkdir -p apps/console/dist apps/compliance-portal/dist packages/emails/dist echo dev-server > apps/console/dist/index.html echo dev-server > apps/compliance-portal/dist/index.html - echo dev-server > apps/trust/dist/index.html echo dev-server > packages/emails/dist/placeholder - name: "Generate Go code" run: | @@ -371,7 +369,7 @@ jobs: env: REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - for dir in apps/console apps/trust apps/compliance-portal packages/ui packages/eslint-config; do + for dir in apps/console apps/compliance-portal packages/ui packages/eslint-config; do (cd "$dir" && npx eslint . --concurrency 4 --format stylish 2>/dev/null) | \ reviewdog -f=eslint -reporter=github-pr-review -filter-mode=nofilter -name="eslint ($dir)" || true done @@ -389,10 +387,9 @@ jobs: - uses: "./.github/actions/setup" - name: "Create placeholder dist files" run: | - mkdir -p apps/console/dist apps/compliance-portal/dist apps/trust/dist + mkdir -p apps/console/dist apps/compliance-portal/dist echo dev-server > apps/console/dist/index.html echo dev-server > apps/compliance-portal/dist/index.html - echo dev-server > apps/trust/dist/index.html - run: "npm --workspace @probo/emails run build" - run: "make test" env: diff --git a/GNUmakefile b/GNUmakefile index 1a1754413..aea65db34 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -72,7 +72,6 @@ GENERATED= pkg/server/api/connect/v1/schema/schema.go \ EMBEDDED= apps/console/dist/index.html \ apps/compliance-portal/dist/index.html \ - apps/trust/dist/index.html \ @probo/emails PROBOD_BIN_EXTRA_DEPS= @@ -138,7 +137,7 @@ go-lint: generate $(GOLINTCMD) run ./... .PHONY: test -test: generate apps/trust/dist/index.html +test: generate test: CGO_ENABLED=1 test: ## Run tests with race detection and coverage (usage: make test [MODULE=./pkg/some/module]) $(GO_TEST) $(if $(MODULE),$(MODULE),$(shell $(GO) list ./... | grep -v /e2e/)) @@ -211,7 +210,7 @@ cfg/dev.yaml: bin/probod-bootstrap $(CFG_DEV_OAUTH2_KEY) compose/step-ca/certs/r PROBOD_AUTH_PASSWORD_PEPPER="this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes"; \ PROBOD_AUTH_COOKIE_SECURE=false; \ PROBOD_OAUTH2_SERVER_SIGNING_KEY="$$($(CAT) $(CFG_DEV_OAUTH2_KEY))"; \ - PROBOD_API_CORS_ALLOWED_ORIGINS="http://localhost:8080,http://localhost:5173,http://localhost:5174,http://localhost:5175"; \ + PROBOD_API_CORS_ALLOWED_ORIGINS="http://localhost:8080,http://localhost:5173,http://localhost:5174"; \ PROBOD_PG_ADDR=localhost:5432; \ PROBOD_PG_USERNAME=postgres; \ PROBOD_PG_PASSWORD=postgres; \ @@ -387,7 +386,7 @@ fmt-go: ## Format Go code clean: ## Clean the project (node_modules and build artifacts) $(RM) -rf bin/* $(RM) -rf node_modules - $(RM) -rf apps/{console,compliance-portal,trust}/{dist,node_modules} + $(RM) -rf apps/{console,compliance-portal}/{dist,node_modules} $(RM) -rf packages/emails/{dist,node_modules} $(RM) -rf sbom-docker.json sbom.json $(RM) -rf coverage.out coverage.html coverage-e2e.out coverage-e2e.html coverage-combined.out coverage-combined.html @@ -443,7 +442,7 @@ compose/keycloak/probo-realm.json: compose/keycloak/probo-realm.json.tmpl compos -e "s|PRIVATE_KEY_PLACEHOLDER|$$(awk 'NR==1 {printf "%s", $$0; next} {printf "\\\\n%s", $$0}' compose/keycloak/certs/private-key.pem)|g" \ $@.tmpl > $@ -apps/console/dist/index.html apps/compliance-portal/dist/index.html apps/trust/dist/index.html: +apps/console/dist/index.html apps/compliance-portal/dist/index.html: $(MKDIR) $(dir $@) $(ECHO) dev-server > $@ diff --git a/apps/trust/.env.example b/apps/trust/.env.example deleted file mode 100644 index 460e575be..000000000 --- a/apps/trust/.env.example +++ /dev/null @@ -1 +0,0 @@ -VITE_API_URL=http://localhost:8080 diff --git a/apps/trust/.gitattributes b/apps/trust/.gitattributes deleted file mode 100644 index 7a1fb9a7a..000000000 --- a/apps/trust/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -__generated__/*.graphql linguist-generated -__generated__/*.js linguist-generated diff --git a/apps/trust/.gitignore b/apps/trust/.gitignore deleted file mode 100644 index b403dd978..000000000 --- a/apps/trust/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -public/pdfjs -# Logs -old -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/apps/trust/README.md b/apps/trust/README.md deleted file mode 100644 index 28ac5f8b9..000000000 --- a/apps/trust/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Trust app (compliance portal) - diff --git a/apps/trust/index.html b/apps/trust/index.html deleted file mode 100644 index a5d9cb778..000000000 --- a/apps/trust/index.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - {{.Title}} - - - - - - - - -
- - - - diff --git a/apps/trust/package.json b/apps/trust/package.json deleted file mode 100644 index 3d503247d..000000000 --- a/apps/trust/package.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "@probo/trust", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite --port 5175", - "build": "tsc -b && vite build", - "check": "tsc --noEmit -p tsconfig.app.json", - "preview": "vite preview" - }, - "dependencies": { - "@hookform/resolvers": "^5.0.1", - "@probo/helpers": "1.0.0", - "@probo/hooks": "1.0.0", - "@probo/i18n": "1.0.0", - "@probo/routes": "^1.0.0", - "@probo/ui": "1.0.0", - "clsx": "^2.1.1", - "react": "^19.2.7", - "react-dom": "^19.2.7", - "react-error-boundary": "^6.0.0", - "react-hook-form": "^7.56.4", - "react-pdf": "^10.3.0", - "react-relay": "^21.0.1", - "react-router": "^8.1.0", - "relay-runtime": "^21.0.1", - "usehooks-ts": "^3.1.1", - "zod": "^4.4.3" - }, - "devDependencies": { - "@babel/core": "^8.0.1", - "@rolldown/plugin-babel": "^0.2.3", - "@tailwindcss/vite": "^4.3.2", - "@types/babel__core": "^7.20.5", - "@types/node": "^26", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.2", - "babel-plugin-relay": "^21.0.1", - "graphql": "^17.0.1", - "tailwindcss": "^4.3.1", - "typescript": "~6.0.3", - "vite": "^8.1.2" - }, - "volta": { - "node": "24.4.0" - } -} diff --git a/apps/trust/public/favicons/apple-touch-icon-114x114.png b/apps/trust/public/favicons/apple-touch-icon-114x114.png deleted file mode 100644 index 444ea14a8..000000000 Binary files a/apps/trust/public/favicons/apple-touch-icon-114x114.png and /dev/null differ diff --git a/apps/trust/public/favicons/apple-touch-icon-120x120.png b/apps/trust/public/favicons/apple-touch-icon-120x120.png deleted file mode 100644 index def547fc9..000000000 Binary files a/apps/trust/public/favicons/apple-touch-icon-120x120.png and /dev/null differ diff --git a/apps/trust/public/favicons/apple-touch-icon-144x144.png b/apps/trust/public/favicons/apple-touch-icon-144x144.png deleted file mode 100644 index 7149269f0..000000000 Binary files a/apps/trust/public/favicons/apple-touch-icon-144x144.png and /dev/null differ diff --git a/apps/trust/public/favicons/apple-touch-icon-152x152.png b/apps/trust/public/favicons/apple-touch-icon-152x152.png deleted file mode 100644 index 26b41822b..000000000 Binary files a/apps/trust/public/favicons/apple-touch-icon-152x152.png and /dev/null differ diff --git a/apps/trust/public/favicons/apple-touch-icon-57x57.png b/apps/trust/public/favicons/apple-touch-icon-57x57.png deleted file mode 100644 index f53ce4bcf..000000000 Binary files a/apps/trust/public/favicons/apple-touch-icon-57x57.png and /dev/null differ diff --git a/apps/trust/public/favicons/apple-touch-icon-60x60.png b/apps/trust/public/favicons/apple-touch-icon-60x60.png deleted file mode 100644 index 6209814a1..000000000 Binary files a/apps/trust/public/favicons/apple-touch-icon-60x60.png and /dev/null differ diff --git a/apps/trust/public/favicons/apple-touch-icon-72x72.png b/apps/trust/public/favicons/apple-touch-icon-72x72.png deleted file mode 100644 index b59da6556..000000000 Binary files a/apps/trust/public/favicons/apple-touch-icon-72x72.png and /dev/null differ diff --git a/apps/trust/public/favicons/apple-touch-icon-76x76.png b/apps/trust/public/favicons/apple-touch-icon-76x76.png deleted file mode 100644 index c40e2387c..000000000 Binary files a/apps/trust/public/favicons/apple-touch-icon-76x76.png and /dev/null differ diff --git a/apps/trust/public/favicons/favicon-128.png b/apps/trust/public/favicons/favicon-128.png deleted file mode 100644 index 015f14572..000000000 Binary files a/apps/trust/public/favicons/favicon-128.png and /dev/null differ diff --git a/apps/trust/public/favicons/favicon-16x16.png b/apps/trust/public/favicons/favicon-16x16.png deleted file mode 100644 index ab74a6336..000000000 Binary files a/apps/trust/public/favicons/favicon-16x16.png and /dev/null differ diff --git a/apps/trust/public/favicons/favicon-196x196.png b/apps/trust/public/favicons/favicon-196x196.png deleted file mode 100644 index f9a182d38..000000000 Binary files a/apps/trust/public/favicons/favicon-196x196.png and /dev/null differ diff --git a/apps/trust/public/favicons/favicon-32x32.png b/apps/trust/public/favicons/favicon-32x32.png deleted file mode 100644 index 0d5835f0e..000000000 Binary files a/apps/trust/public/favicons/favicon-32x32.png and /dev/null differ diff --git a/apps/trust/public/favicons/favicon-96x96.png b/apps/trust/public/favicons/favicon-96x96.png deleted file mode 100644 index d45c99538..000000000 Binary files a/apps/trust/public/favicons/favicon-96x96.png and /dev/null differ diff --git a/apps/trust/public/favicons/favicon.ico b/apps/trust/public/favicons/favicon.ico deleted file mode 100644 index d3925d54e..000000000 Binary files a/apps/trust/public/favicons/favicon.ico and /dev/null differ diff --git a/apps/trust/public/favicons/mstile-144x144.png b/apps/trust/public/favicons/mstile-144x144.png deleted file mode 100644 index 7149269f0..000000000 Binary files a/apps/trust/public/favicons/mstile-144x144.png and /dev/null differ diff --git a/apps/trust/public/favicons/mstile-150x150.png b/apps/trust/public/favicons/mstile-150x150.png deleted file mode 100644 index a1b242663..000000000 Binary files a/apps/trust/public/favicons/mstile-150x150.png and /dev/null differ diff --git a/apps/trust/public/favicons/mstile-310x150.png b/apps/trust/public/favicons/mstile-310x150.png deleted file mode 100644 index 33898ee97..000000000 Binary files a/apps/trust/public/favicons/mstile-310x150.png and /dev/null differ diff --git a/apps/trust/public/favicons/mstile-310x310.png b/apps/trust/public/favicons/mstile-310x310.png deleted file mode 100644 index 7e2b51750..000000000 Binary files a/apps/trust/public/favicons/mstile-310x310.png and /dev/null differ diff --git a/apps/trust/public/favicons/mstile-70x70.png b/apps/trust/public/favicons/mstile-70x70.png deleted file mode 100644 index 015f14572..000000000 Binary files a/apps/trust/public/favicons/mstile-70x70.png and /dev/null differ diff --git a/apps/trust/public/robots.txt b/apps/trust/public/robots.txt deleted file mode 100644 index 1f53798bb..000000000 --- a/apps/trust/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/apps/trust/src/App.tsx b/apps/trust/src/App.tsx deleted file mode 100644 index f3721914f..000000000 --- a/apps/trust/src/App.tsx +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { Toasts } from "@probo/ui"; -import { RouterProvider } from "react-router"; - -import { router } from "./routes"; - -export function App() { - return ( - <> - - - - ); -} diff --git a/apps/trust/src/components/AuditRow.tsx b/apps/trust/src/components/AuditRow.tsx deleted file mode 100644 index 7ae52cee5..000000000 --- a/apps/trust/src/components/AuditRow.tsx +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { formatError } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { UnAuthenticatedError } from "@probo/relay"; -import { - Breadcrumb, - Button, - Dialog, - DialogContent, - FrameworkLogo, - IconArrowLink, - IconLock, - IconMedal, - Table, - useToast, -} from "@probo/ui"; -import { type PropsWithChildren } from "react"; -import { useFragment, useMutation } from "react-relay"; -import { useLocation, useNavigate, useSearchParams } from "react-router"; -import { graphql } from "relay-runtime"; - -import type { AuditRow_requestAccessMutation } from "./__generated__/AuditRow_requestAccessMutation.graphql"; -import type { AuditRowFragment$key } from "./__generated__/AuditRowFragment.graphql"; - -const requestAccessMutation = graphql` - mutation AuditRow_requestAccessMutation($input: RequestReportAccessInput!) { - requestReportAccess(input: $input) { - audit { - reportFile { - access { - id - status - } - } - } - } - } -`; - -const auditRowFragment = graphql` - fragment AuditRowFragment on Audit { - name - reportFile { - id - alias - isUserAuthorized - access { - id - status - } - } - framework { - id - name - lightLogo { - downloadUrl - } - darkLogo { - downloadUrl - } - } - } -`; - -export function AuditRow(props: { audit: AuditRowFragment$key }) { - const { __ } = useTranslate(); - const { toast } = useToast(); - const [searchParams] = useSearchParams(); - const location = useLocation(); - const navigate = useNavigate(); - - const audit = useFragment(auditRowFragment, props.audit); - const reportPath = audit.reportFile?.alias ?? audit.reportFile?.id; - const hasRequested = audit.reportFile?.access?.status === "REQUESTED"; - - const [requestAccess, isRequestingAccess] - = useMutation(requestAccessMutation); - - const handleRequestAccess = () => { - requestAccess({ - variables: { - input: { - reportId: audit.reportFile?.id ?? "", - }, - }, - onCompleted: (_, errors) => { - if (errors?.length) { - toast({ - title: __("Error"), - description: formatError(__("Cannot request access"), errors), - variant: "error", - }); - return; - } - toast({ - title: __("Success"), - description: __("Access request submitted successfully."), - variant: "success", - }); - }, - onError: (error) => { - if (error instanceof UnAuthenticatedError) { - searchParams.set("request-report-id", audit.reportFile?.id ?? ""); - const urlSearchParams = new URLSearchParams([[ - "continue", - window.location.origin + location.pathname + "?" + searchParams.toString(), - ]]); - void navigate(`/connect?${urlSearchParams.toString()}`); - - return; - } - - toast({ - title: __("Error"), - description: error.message ?? __("Cannot request access"), - variant: "error", - }); - }, - }); - }; - - return ( -
-
- - {audit.name ?? audit.framework.name} -
- {audit.reportFile && ( - audit.reportFile.isUserAuthorized - ? ( - - ) - : ( - - ) - )} -
- ); -} - -export function AuditRowAvatar(props: { audit: AuditRowFragment$key }) { - const audit = useFragment(auditRowFragment, props.audit); - - return ( - <> - - - - - ); -} - -function AuditDialog( - props: PropsWithChildren<{ audit: AuditRowFragment$key; logo?: string }>, -) { - const audit = useFragment(auditRowFragment, props.audit); - const location = useLocation(); - const { __ } = useTranslate(); - const items = [ - { - label: __("Certifications"), - to: location.pathname, - }, - { - label: audit.framework.name, - to: location.pathname, - }, - ]; - return ( - } - > - - -

{audit.framework.name}

- - -
-
-
- ); -} diff --git a/apps/trust/src/components/CompliancePortalFileRow.tsx b/apps/trust/src/components/CompliancePortalFileRow.tsx deleted file mode 100644 index ada0985aa..000000000 --- a/apps/trust/src/components/CompliancePortalFileRow.tsx +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { formatError } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { UnAuthenticatedError } from "@probo/relay"; -import { - Button, - IconArrowLink, - IconLock, - IconPageTextLine, - useToast, -} from "@probo/ui"; -import { useFragment, useMutation } from "react-relay"; -import { useLocation, useNavigate, useSearchParams } from "react-router"; -import { graphql } from "relay-runtime"; - -import type { CompliancePortalFileRow_requestAccessMutation } from "./__generated__/CompliancePortalFileRow_requestAccessMutation.graphql"; -import type { CompliancePortalFileRowFragment$key } from "./__generated__/CompliancePortalFileRowFragment.graphql"; - -const requestAccessMutation = graphql` - mutation CompliancePortalFileRow_requestAccessMutation( - $input: RequestCompliancePortalFileAccessInput! - ) { - requestCompliancePortalFileAccess(input: $input) { - file { - access { - id - status - } - } - } - } -`; - -const compliancePortalFileRowFragment = graphql` - fragment CompliancePortalFileRowFragment on CompliancePortalFile { - id - alias - name - isUserAuthorized - access { - id - status - } - } -`; - -export function CompliancePortalFileRow(props: { - file: CompliancePortalFileRowFragment$key; -}) { - const { __ } = useTranslate(); - const { toast } = useToast(); - const location = useLocation(); - const [searchParams] = useSearchParams(); - const navigate = useNavigate(); - - const file = useFragment(compliancePortalFileRowFragment, props.file); - const filePath = file.alias ?? file.id; - const hasRequested = file.access?.status === "REQUESTED"; - - const [requestAccess, isRequestingAccess] - = useMutation( - requestAccessMutation, - ); - - const handleRequestAccess = () => { - requestAccess({ - variables: { - input: { - compliancePortalFileId: file.id, - }, - }, - onCompleted: (_, errors) => { - if (errors?.length) { - toast({ - title: __("Error"), - description: formatError(__("Cannot request access"), errors), - variant: "error", - }); - return; - } - toast({ - title: __("Success"), - description: __("Access request submitted successfully."), - variant: "success", - }); - }, - onError: (error) => { - if (error instanceof UnAuthenticatedError) { - searchParams.set("request-file-id", file.id); - const urlSearchParams = new URLSearchParams([[ - "continue", - window.location.origin + location.pathname + "?" + searchParams.toString(), - ]]); - void navigate(`/connect?${urlSearchParams.toString()}`); - - return; - } - - toast({ - title: __("Error"), - description: error.message ?? __("Cannot request access"), - variant: "error", - }); - }, - }); - }; - - return ( -
-
- - {file.name} -
- {file.isUserAuthorized - ? ( - - ) - : ( - - )} -
- ); -} diff --git a/apps/trust/src/components/DocumentPageErrorBoundary.tsx b/apps/trust/src/components/DocumentPageErrorBoundary.tsx deleted file mode 100644 index 8af28bfe5..000000000 --- a/apps/trust/src/components/DocumentPageErrorBoundary.tsx +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { useTranslate } from "@probo/i18n"; -import { - FullNameRequiredError, - NDASignatureRequiredError, - UnAuthenticatedError, -} from "@probo/relay"; -import { Button, IconChevronLeft, IconPageCross } from "@probo/ui"; -import { Link, Navigate, useLocation, useRouteError } from "react-router"; - -export function DocumentPageErrorBoundary() { - const error = useRouteError(); - const location = useLocation(); - const { __ } = useTranslate(); - - const search = new URLSearchParams(); - - if (location.pathname !== "/" || location.search !== "") { - search.set("continue", window.location.href); - } - - const queryString = search.toString(); - - if (error instanceof UnAuthenticatedError) { - return ( - - ); - } - - if (error instanceof FullNameRequiredError) { - return ( - - ); - } - - if (error instanceof NDASignatureRequiredError) { - return ( - - ); - } - - return ( -
-
- - - -
-
-
- -

- {__("Document not found")} -

-

- {__("The document you are looking for does not exist or has been removed.")} -

- -
-
-
- ); -} diff --git a/apps/trust/src/components/DocumentRow.tsx b/apps/trust/src/components/DocumentRow.tsx deleted file mode 100644 index a0b31a5fb..000000000 --- a/apps/trust/src/components/DocumentRow.tsx +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { formatError } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { UnAuthenticatedError } from "@probo/relay"; -import { - Button, - IconArrowLink, - IconLock, - IconPageTextLine, - useToast, -} from "@probo/ui"; -import { useFragment, useMutation } from "react-relay"; -import { useLocation, useNavigate, useSearchParams } from "react-router"; -import { graphql } from "relay-runtime"; - -import type { DocumentRow_requestAccessMutation } from "./__generated__/DocumentRow_requestAccessMutation.graphql"; -import type { DocumentRowFragment$key } from "./__generated__/DocumentRowFragment.graphql"; - -const requestAccessMutation = graphql` - mutation DocumentRow_requestAccessMutation( - $input: RequestDocumentAccessInput! - ) { - requestDocumentAccess(input: $input) { - document { - access { - id - status - } - } - } - } -`; - -const documentRowFragment = graphql` - fragment DocumentRowFragment on Document { - id - alias - title - isUserAuthorized - access { - id - status - } - } -`; - -export function DocumentRow(props: { document: DocumentRowFragment$key }) { - const { __ } = useTranslate(); - const { toast } = useToast(); - const navigate = useNavigate(); - const location = useLocation(); - const [searchParams] = useSearchParams(); - - const document = useFragment(documentRowFragment, props.document); - const documentPath = document.alias ?? document.id; - const hasRequested = document.access?.status === "REQUESTED"; - - const [requestAccess, isRequestingAccess] - = useMutation(requestAccessMutation); - - const handleRequestAccess = () => { - requestAccess({ - variables: { - input: { - documentId: document.id, - }, - }, - onCompleted: (_, errors) => { - if (errors?.length) { - toast({ - title: __("Error"), - description: formatError(__("Cannot request access"), errors), - variant: "error", - }); - return; - } - toast({ - title: __("Success"), - description: __("Access request submitted successfully."), - variant: "success", - }); - }, - onError: (error) => { - if (error instanceof UnAuthenticatedError) { - searchParams.set("request-document-id", document.id); - const urlSearchParams = new URLSearchParams([[ - "continue", - window.location.origin + location.pathname + "?" + searchParams.toString(), - ]]); - void navigate(`/connect?${urlSearchParams.toString()}`); - - return; - } - - toast({ - title: __("Error"), - description: error.message ?? __("Cannot request access"), - variant: "error", - }); - }, - }); - }; - - return ( -
-
- - {document.title} -
- {document.isUserAuthorized - ? ( - - ) - : ( - - )} -
- ); -} diff --git a/apps/trust/src/components/FrameworkBadge.tsx b/apps/trust/src/components/FrameworkBadge.tsx deleted file mode 100644 index 0e14612c2..000000000 --- a/apps/trust/src/components/FrameworkBadge.tsx +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { FrameworkLogo } from "@probo/ui"; -import { useFragment } from "react-relay"; -import { graphql } from "relay-runtime"; - -import type { FrameworkBadgeFragment$key } from "./__generated__/FrameworkBadgeFragment.graphql"; - -const frameworkFragment = graphql` - fragment FrameworkBadgeFragment on Framework { - # eslint-disable-next-line relay/unused-fields - id - name - lightLogo { - downloadUrl - } - darkLogo { - downloadUrl - } - } -`; - -export function FrameworkBadge(props: { framework: FrameworkBadgeFragment$key }) { - const framework = useFragment(frameworkFragment, props.framework); - - return ( -
- -
- {framework.name} -
-
- ); -} diff --git a/apps/trust/src/components/OrganizationSidebar.tsx b/apps/trust/src/components/OrganizationSidebar.tsx deleted file mode 100644 index 240e1c830..000000000 --- a/apps/trust/src/components/OrganizationSidebar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { detectSocialName, externalLinkProps, formatError } from "@probo/helpers"; -import { useSystemTheme } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; -import { UnAuthenticatedError } from "@probo/relay"; -import { - Button, - Card, - IconBell2, - IconBlock, - IconLock, - IconMedal, - SocialIcon, - useToast, -} from "@probo/ui"; -import { type PropsWithChildren } from "react"; -import { useMutation } from "react-relay"; -import { useLocation, useNavigate, useSearchParams } from "react-router"; -import { graphql } from "relay-runtime"; - -import type { CompliancePortalGraphCurrentQuery$data } from "#/queries/__generated__/CompliancePortalGraphCurrentQuery.graphql"; - -import type { OrganizationSidebar_requestAllAccessesMutation } from "./__generated__/OrganizationSidebar_requestAllAccessesMutation.graphql"; -import type { OrganizationSidebar_subscribeToMailingListMutation } from "./__generated__/OrganizationSidebar_subscribeToMailingListMutation.graphql"; -import type { OrganizationSidebar_unsubscribeFromMailingListMutation } from "./__generated__/OrganizationSidebar_unsubscribeFromMailingListMutation.graphql"; -import { FrameworkBadge } from "./FrameworkBadge"; - -const requestAllAccessesMutation = graphql` - mutation OrganizationSidebar_requestAllAccessesMutation { - requestAllAccesses { - compliancePortalAccess { - id - } - } - } -`; - -const subscribeToMailingListMutation = graphql` - mutation OrganizationSidebar_subscribeToMailingListMutation { - subscribeToMailingList { - subscription { - id - email - createdAt - updatedAt - } - } - } -`; - -const unsubscribeFromMailingListMutation = graphql` - mutation OrganizationSidebar_unsubscribeFromMailingListMutation { - unsubscribeFromMailingList { - deletedMailingListSubscriberId @deleteRecord - } - } -`; - -export function OrganizationSidebar({ - compliancePortal, - isAuthenticated, -}: { - compliancePortal: CompliancePortalGraphCurrentQuery$data["currentCompliancePortal"]; - isAuthenticated: boolean; -}) { - const compliancePortalId = compliancePortal?.id; - const { __ } = useTranslate(); - const { toast } = useToast(); - const theme = useSystemTheme(); - const [searchParams] = useSearchParams(); - const navigate = useNavigate(); - const location = useLocation(); - - const logoFileUrl = theme === "dark" - ? (compliancePortal?.darkLogo?.downloadUrl ?? compliancePortal?.logo?.downloadUrl) - : compliancePortal?.logo?.downloadUrl; - - const [requestAllAccesses, isRequestingAccess] - = useMutation( - requestAllAccessesMutation, - ); - - const [subscribeToMailingList, isSubscribing] - = useMutation( - subscribeToMailingListMutation, - ); - - const [unsubscribeFromMailingList, isUnsubscribing] - = useMutation( - unsubscribeFromMailingListMutation, - ); - - const handleRequestAllAccesses = () => { - requestAllAccesses({ - variables: {}, - onCompleted: (_, errors) => { - if (errors?.length) { - toast({ - title: __("Error"), - description: formatError(__("Cannot request access"), errors), - variant: "error", - }); - return; - } - toast({ - title: __("Success"), - description: __("Access request submitted successfully."), - variant: "success", - }); - - window.location.href = location.pathname; - }, - onError: (error) => { - if (error instanceof UnAuthenticatedError) { - searchParams.set("request-all", "true"); - const urlSearchParams = new URLSearchParams([[ - "continue", - window.location.origin + location.pathname + "?" + searchParams.toString(), - ]]); - void navigate(`/connect?${urlSearchParams.toString()}`); - - return; - } - - toast({ - title: __("Error"), - description: error.message ?? __("Cannot request access"), - variant: "error", - }); - }, - }); - }; - - const handleSubscribe = () => { - subscribeToMailingList({ - variables: {}, - updater: (store, data) => { - const subscription = data?.subscribeToMailingList?.subscription; - if (!subscription?.id || !compliancePortalId) return; - const compliancePortalRecord = store.get(compliancePortalId); - if (!compliancePortalRecord) return; - const subscriptionRecord = store.get(subscription.id); - if (!subscriptionRecord) return; - compliancePortalRecord.setLinkedRecord(subscriptionRecord, "viewerSubscription"); - }, - onCompleted: (_, errors) => { - if (errors?.length) { - toast({ - title: __("Error"), - description: formatError(__("Cannot subscribe"), errors), - variant: "error", - }); - return; - } - toast({ - title: __("Subscribed"), - description: __("You will be notified of security updates."), - variant: "success", - }); - }, - onError: (error) => { - toast({ - title: __("Error"), - description: error.message ?? __("Cannot subscribe"), - variant: "error", - }); - }, - }); - }; - - const handleUnsubscribe = () => { - unsubscribeFromMailingList({ - variables: {}, - onCompleted: (_, errors) => { - if (errors?.length) { - toast({ - title: __("Error"), - description: formatError(__("Cannot unsubscribe"), errors), - variant: "error", - }); - return; - } - toast({ - title: __("Unsubscribed"), - description: __("You will no longer receive security updates."), - variant: "success", - }); - }, - onError: (error) => { - toast({ - title: __("Error"), - description: error.message ?? __("Cannot unsubscribe"), - variant: "error", - }); - }, - }); - }; - - if (!compliancePortal) { - return null; - } - - return ( - -
- {logoFileUrl - ? ( - - ) - : ( -
- )} -

{compliancePortal.entityName}

-

- {compliancePortal.description} -

- -
- - {/* Business information */} -
-

- - {__("Business information")} -

- {compliancePortal.websiteUrl && ( - - - - {new URL(compliancePortal.websiteUrl).host} - - - - )} - {compliancePortal.email && ( - - - - {compliancePortal.email} - - - - )} - {compliancePortal.headquarterAddress && ( - - {compliancePortal.headquarterAddress} - - )} - {compliancePortal.customLinks.edges.length > 0 && ( -
- {compliancePortal.customLinks.edges.map(({ node }) => ( - - - {node.name} - - ))} -
- )} - -
- - {/* Certifications */} - {compliancePortal.complianceFrameworks.edges.length > 0 && ( - <> -
-

- - {__("Frameworks")} -

-
- {compliancePortal.complianceFrameworks.edges.map(edge => ( - - ))} -
-
- -
- - )} - - {/* Actions */} -
- - {isAuthenticated && ( - compliancePortal.viewerSubscription - ? ( - - ) - : ( - - ) - )} -
-
- - ); -} - -function BusinessInfo({ - children, - label, -}: PropsWithChildren<{ label: string }>) { - return ( -
-
{label}
-
{children}
-
- ); -} diff --git a/apps/trust/src/components/PDFPreview.tsx b/apps/trust/src/components/PDFPreview.tsx deleted file mode 100644 index 7e85fe7a8..000000000 --- a/apps/trust/src/components/PDFPreview.tsx +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 "react-pdf/dist/Page/TextLayer.css"; -import "react-pdf/dist/Page/AnnotationLayer.css"; - -import { times } from "@probo/helpers"; -import { - IconArrowInbox, - IconChevronLeft, - IconChevronRight, - IconPlusLarge, - Spinner, -} from "@probo/ui"; -import { IconMinusLarge } from "@probo/ui/src/Atoms/Icons/IconMinusLarge"; -import { type ComponentProps, useCallback, useEffect, useRef, useState } from "react"; -import { Document, Page, pdfjs } from "react-pdf"; - -// Worker for PDF.js -pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`; - -const btnClass - = "size-8 grid place-items-center hover:bg-secondary-hover cursor-pointer rounded-sm disabled:opacity-30 transition-all"; - -export function PDFPreview({ src, name }: { src: string; name?: string }) { - const [numPages, setNumPages] = useState(0); - const [scale, setScale] = useState(1.0); - const [currentPage, setCurrentPage] = useState(1); - const documentRef: ComponentProps["ref"] = useRef(null); - const wrapperRef = useRef(null); - - const onDocumentLoadSuccess: ComponentProps< - typeof Document - >["onLoadSuccess"] = (document) => { - setNumPages(document.numPages); - setCurrentPage(1); - }; - - const zoomFactor = (factor: number) => () => { - setScale(scale * factor); - }; - - const currentPageRef = useRef(currentPage); - useEffect(() => { - currentPageRef.current = currentPage; - }, [currentPage]); - - const movePage = useCallback((direction: 1 | -1) => { - const prev = currentPageRef.current; - if (prev === 1 && direction === -1) { - return; - } - const newPage = prev + direction; - const page = documentRef.current?.pages.current[newPage - 1]; - if (!page) { - return; - } - page.scrollIntoView({ - behavior: "smooth", - block: "start", - inline: "center", - }); - setCurrentPage(newPage); - }, []); - - const resolveCurrentPage = useCallback(() => { - if (!wrapperRef.current) { - return; - } - const pages = documentRef.current?.pages.current; - if (!pages?.length) { - return; - } - const parentRect = wrapperRef.current.getBoundingClientRect(); - const parentMiddleY = parentRect.top + parentRect.height / 2; - for (let i = 0; i < pages.length; i++) { - const childRect = pages[i].getBoundingClientRect(); - if (childRect.top <= parentMiddleY && childRect.bottom >= parentMiddleY) { - setCurrentPage(i + 1); - return; - } - } - }, []); - - const handleDownload = () => { - const link = document.createElement("a"); - link.href = src; - link.download = name || "document.pdf"; - link.click(); - }; - - return ( -
- {/* Custom Zoom Controls */} - - - {/* PDF Document */} -
- - {numPages === 0 && } - {times(numPages, index => ( - - ))} - -
-
- ); -} diff --git a/apps/trust/src/components/PageError.tsx b/apps/trust/src/components/PageError.tsx deleted file mode 100644 index b67ede768..000000000 --- a/apps/trust/src/components/PageError.tsx +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { useTranslate } from "@probo/i18n"; -import { - Button, - ErrorDetailMessage, - ErrorDetails, - ErrorLayout, -} from "@probo/ui"; -import { useEffect, useRef } from "react"; -import { Link, useLocation, useRouteError } from "react-router"; - -type Props = { - resetErrorBoundary?: () => void; - error?: Error; -}; - -export function PageError({ resetErrorBoundary, error: propsError }: Props) { - const routeError = useRouteError(); - const error = routeError ?? propsError; - const { __ } = useTranslate(); - const location = useLocation(); - const baseLocation = useRef(location); - - const isFullPage = Boolean(routeError ?? propsError); - - // Reset error boundary on page change - useEffect(() => { - if ( - location.pathname !== baseLocation.current.pathname - && resetErrorBoundary - ) { - resetErrorBoundary(); - } - }, [location, resetErrorBoundary]); - - const actions = ( - - ); - - const layoutProps = { - fullPage: isFullPage, - showLogo: isFullPage, - actions, - }; - - if (!error) { - return ( - - ); - } - - if (error instanceof Error - && error.message - .toLowerCase() - .match(/(token|expired|invalid|401|unauthorized)/) - ) { - const isExpiredToken = error.message.toLowerCase().includes("expired"); - const title = isExpiredToken - ? __("Expired token") - : __("Invalid Access Link"); - const description = isExpiredToken - ? __( - "This access link has expired. Compliance page access links are valid for 7 days for security reasons.", - ) - : __( - "This access link is not valid. It may have been revoked or the link might be incorrect.", - ); - return ( - - ); - } - - return ( - - {error instanceof Error && ( - - {error.message} - - )} - - ); -} diff --git a/apps/trust/src/components/RootErrorBoundary.tsx b/apps/trust/src/components/RootErrorBoundary.tsx deleted file mode 100644 index 90daa68da..000000000 --- a/apps/trust/src/components/RootErrorBoundary.tsx +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { FullNameRequiredError, NDASignatureRequiredError, UnAuthenticatedError } from "@probo/relay"; -import { Navigate, useLocation, useRouteError } from "react-router"; - -import { PageError } from "./PageError"; - -export function RootErrorBoundary() { - const error = useRouteError(); - const location = useLocation(); - - const search = new URLSearchParams(); - - if (location.pathname !== "/" || location.search !== "") { - search.set("continue", window.location.href); - } - - const queryString = search.toString(); - - if (error instanceof UnAuthenticatedError) { - return ( - - ); - } - - if (error instanceof FullNameRequiredError) { - return ( - - ); - } - - if (error instanceof NDASignatureRequiredError) { - return ( - - ); - } - - return ; -} diff --git a/apps/trust/src/components/RowHeader.tsx b/apps/trust/src/components/RowHeader.tsx deleted file mode 100644 index e3af96a96..000000000 --- a/apps/trust/src/components/RowHeader.tsx +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 type { PropsWithChildren } from "react"; - -export function RowHeader({ children }: PropsWithChildren) { - return ( -
- {children} -
- ); -} diff --git a/apps/trust/src/components/Rows.tsx b/apps/trust/src/components/Rows.tsx deleted file mode 100644 index bff9d35a0..000000000 --- a/apps/trust/src/components/Rows.tsx +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { clsx } from "clsx"; -import type { PropsWithChildren } from "react"; - -export function Rows({ - children, - className, -}: PropsWithChildren<{ className?: string }>) { - return ( -
- {children} -
- ); -} diff --git a/apps/trust/src/components/Skeletons/MainSkeleton.tsx b/apps/trust/src/components/Skeletons/MainSkeleton.tsx deleted file mode 100644 index c1677c5e6..000000000 --- a/apps/trust/src/components/Skeletons/MainSkeleton.tsx +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { getCompliancePortalUrl } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { Skeleton, TabLink, Tabs } from "@probo/ui"; - -import { TabSkeleton } from "./TabSkeleton"; - -export function MainSkeleton() { - const { __ } = useTranslate(); - return ( -
- -
- - {__("Overview")} - {__("Documents")} - - {__("Subprocessors")} - - {__("Updates")} - - -
-
- ); -} diff --git a/apps/trust/src/components/Skeletons/TabSkeleton.tsx b/apps/trust/src/components/Skeletons/TabSkeleton.tsx deleted file mode 100644 index 83614a7e5..000000000 --- a/apps/trust/src/components/Skeletons/TabSkeleton.tsx +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { Skeleton } from "@probo/ui"; - -export function TabSkeleton() { - return ( -
- - - -
- ); -} diff --git a/apps/trust/src/components/SubprocessorRow.tsx b/apps/trust/src/components/SubprocessorRow.tsx deleted file mode 100644 index 2e1494ecd..000000000 --- a/apps/trust/src/components/SubprocessorRow.tsx +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { faviconUrl, getCountryName } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { IconPin } from "@probo/ui"; -import { useFragment } from "react-relay"; -import { graphql } from "relay-runtime"; - -import type { SubprocessorRowFragment$key } from "./__generated__/SubprocessorRowFragment.graphql"; - -const subprocessorRowFragment = graphql` - fragment SubprocessorRowFragment on Subprocessor { - name - description - websiteUrl - countries - } -`; - -export function SubprocessorRow(props: { subprocessor: SubprocessorRowFragment$key; hasAnyCountries?: boolean }) { - const subprocessor = useFragment(subprocessorRowFragment, props.subprocessor); - const logo = faviconUrl(subprocessor.websiteUrl); - const { __ } = useTranslate(); - - return ( -
- {logo - ? ( - - ) - : ( -
- )} -
- {subprocessor.name} -
{subprocessor.description}
- {props.hasAnyCountries - && ( -
- {subprocessor.countries.length > 0 && ( - <> - - - {subprocessor.countries - .map(country => getCountryName(__, country)) - .join(", ")} - - - )} -
- )} -
-
- ); -} diff --git a/apps/trust/src/helpers/documents.ts b/apps/trust/src/helpers/documents.ts deleted file mode 100644 index b9f53b7be..000000000 --- a/apps/trust/src/helpers/documents.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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. - -export function documentTypeLabel(type: string, __: (s: string) => string) { - switch (type) { - case "POLICY": - return __("Policy"); - case "GOVERNANCE": - return __("Governance"); - case "PROCEDURE": - return __("Procedure"); - case "PLAN": - return __("Plan"); - case "REGISTER": - return __("Register"); - case "RECORD": - return __("Record"); - case "REPORT": - return __("Report"); - case "TEMPLATE": - return __("Template"); - default: - return __("Other"); - } -} diff --git a/apps/trust/src/hooks/useCompliancePortal.ts b/apps/trust/src/hooks/useCompliancePortal.ts deleted file mode 100644 index 8dcd3385e..000000000 --- a/apps/trust/src/hooks/useCompliancePortal.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { useContext } from "react"; - -import { CompliancePortalContext } from "#/providers/CompliancePortalProvider"; - -export function useCompliancePortal(): { - id: string; - entityName: string; -} { - const context = useContext(CompliancePortalContext); - if (!context) { - throw new Error("useCompliancePortal must be used within a CompliancePortalProvider"); - } - return context; -} diff --git a/apps/trust/src/hooks/useFormWithSchema.ts b/apps/trust/src/hooks/useFormWithSchema.ts deleted file mode 100644 index 4534edbcf..000000000 --- a/apps/trust/src/hooks/useFormWithSchema.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { standardSchemaResolver } from "@hookform/resolvers/standard-schema"; -import { type FieldValues, useForm, type UseFormReturn } from "react-hook-form"; -import type { z } from "zod"; - -export function useFormWithSchema>( - schema: T, - options: Parameters, unknown, z.output>>[0], -): UseFormReturn, unknown, z.output> { - return useForm, unknown, z.output>({ - ...options, - resolver: standardSchemaResolver(schema), - }); -} diff --git a/apps/trust/src/hooks/useMutationWithToast.ts b/apps/trust/src/hooks/useMutationWithToast.ts deleted file mode 100644 index 90fca2a5d..000000000 --- a/apps/trust/src/hooks/useMutationWithToast.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { useTranslate } from "@probo/i18n"; -import { useToast } from "@probo/ui"; -import { useCallback } from "react"; -import { useMutation, type UseMutationConfig } from "react-relay"; -import type { GraphQLTaggedNode, MutationParameters } from "relay-runtime"; - -/** - * A decorated useMutation hook that emits toast notifications on success or error. - */ -export function useMutationWithToasts( - query: GraphQLTaggedNode, - baseOptions?: { - onSuccess?: (response: T["response"]) => void; - errorMessage?: string; - }, -) { - const [mutate, isLoading] = useMutation(query); - const { toast } = useToast(); - const { __ } = useTranslate(); - const mutateWithToast = useCallback( - ( - queryOptions: UseMutationConfig & { - onSuccess?: (response: T["response"]) => void; - errorMessage?: string; - }, - ) => { - const options = { ...baseOptions, ...queryOptions }; - return new Promise((resolve, reject) => - mutate({ - ...queryOptions, - onCompleted: (response, error) => { - options.onCompleted?.(response, error); - if (error) { - toast({ - title: __("Error"), - description: - options.errorMessage - ?? __("Failed to commit this operation."), - variant: "error", - }); - reject(error instanceof Error ? error : new Error(__("Failed to commit this operation."))); - return; - } - options.onSuccess?.(response); - resolve(); - }, - onError: (error) => { - toast({ - title: __("Error"), - description: - options.errorMessage ?? __("Failed to commit this operation."), - variant: "error", - }); - reject(error); - }, - }), - ); - }, - [mutate, toast, __, baseOptions], - ); - - return [mutateWithToast, isLoading] as const; -} diff --git a/apps/trust/src/hooks/useRequestAccessCallback.ts b/apps/trust/src/hooks/useRequestAccessCallback.ts deleted file mode 100644 index 41b8768d5..000000000 --- a/apps/trust/src/hooks/useRequestAccessCallback.ts +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { formatError, type GraphQLError } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { useToast } from "@probo/ui"; -import { useEffect } from "react"; -import { useMutation } from "react-relay"; -import { useLocation, useSearchParams } from "react-router"; -import { graphql } from "relay-runtime"; - -import type { useRequestAccessCallback_allMutation } from "./__generated__/useRequestAccessCallback_allMutation.graphql"; -import type { useRequestAccessCallback_documentMutation } from "./__generated__/useRequestAccessCallback_documentMutation.graphql"; -import type { useRequestAccessCallback_fileMutation } from "./__generated__/useRequestAccessCallback_fileMutation.graphql"; -import type { useRequestAccessCallback_reportMutation } from "./__generated__/useRequestAccessCallback_reportMutation.graphql"; - -const documentMutation = graphql` - mutation useRequestAccessCallback_documentMutation( - $input: RequestDocumentAccessInput! - ) { - requestDocumentAccess(input: $input) { - document { - access { - id - status - } - } - } - } -`; - -const reportMutation = graphql` - mutation useRequestAccessCallback_reportMutation( - $input: RequestReportAccessInput! - ) { - requestReportAccess(input: $input) { - audit { - reportFile { - access { - id - status - } - } - } - } - } -`; - -const fileMutation = graphql` - mutation useRequestAccessCallback_fileMutation( - $input: RequestCompliancePortalFileAccessInput! - ) { - requestCompliancePortalFileAccess(input: $input) { - file { - access { - id - status - } - } - } - } -`; - -const allMutation = graphql` - mutation useRequestAccessCallback_allMutation { - requestAllAccesses { - compliancePortalAccess { - id - } - } - } -`; - -function errorToastArgs(__: (s: string) => string, error: GraphQLError | GraphQLError[]) { - return { - title: __("Error"), - description: formatError(__("Cannot request access"), error), - variant: "error" as const, - }; -} - -function successToastArgs(__: (s: string) => string) { - return { - title: __("Success"), - description: __("Access request submitted successfully."), - variant: "success" as const, - }; -} - -export function useRequestAccessCallback() { - const [searchParams, setSearchParams] = useSearchParams(); - const location = useLocation(); - - const documentId = searchParams.get("request-document-id"); - const reportId = searchParams.get("request-report-id"); - const fileId = searchParams.get("request-file-id"); - const all = searchParams.get("request-all"); - - const { __ } = useTranslate(); - const { toast } = useToast(); - - const [requestDocumentAccess] = useMutation(documentMutation); - const [requestReportAccess] = useMutation(reportMutation); - const [requestFileAccess] = useMutation(fileMutation); - const [requestAll] = useMutation(allMutation); - - useEffect(() => { - if (documentId) { - searchParams.delete("request-document-id"); - void requestDocumentAccess({ - variables: { - input: { documentId }, - }, - onCompleted: (_, errors) => { - if (errors?.length) { - toast(errorToastArgs(__, errors)); - return; - } - - toast(successToastArgs(__)); - }, - onError: (error) => { - toast(errorToastArgs(__, error)); - }, - }); - setSearchParams(searchParams); - } else if (reportId) { - searchParams.delete("request-report-id"); - void requestReportAccess({ - variables: { - input: { reportId }, - }, - onCompleted: (_, errors) => { - if (errors?.length) { - toast(errorToastArgs(__, errors)); - return; - } - - toast(successToastArgs(__)); - }, - onError: (error) => { - toast(errorToastArgs(__, error)); - }, - }); - setSearchParams(searchParams); - } else if (fileId) { - searchParams.delete("request-file-id"); - void requestFileAccess({ - variables: { - input: { compliancePortalFileId: fileId }, - }, - onCompleted: (_, errors) => { - if (errors?.length) { - toast(errorToastArgs(__, errors)); - return; - } - - toast(successToastArgs(__)); - }, - onError: (error) => { - toast(errorToastArgs(__, error)); - }, - }); - setSearchParams(searchParams); - } else if (all) { - searchParams.delete("request-all"); - void requestAll({ - variables: {}, - onCompleted: (_, errors) => { - if (errors?.length) { - toast(errorToastArgs(__, errors)); - return; - } - - toast(successToastArgs(__)); - window.location.href = window.location.origin + location.pathname; - }, - onError: (error) => { - toast(errorToastArgs(__, error)); - }, - }); - setSearchParams(searchParams); - } - }, [ - documentId, - reportId, - fileId, - all, - __, - requestDocumentAccess, - requestReportAccess, - requestFileAccess, - requestAll, - searchParams, - setSearchParams, - toast, - location, - ]); -} diff --git a/apps/trust/src/hooks/useSafeContinueUrl.ts b/apps/trust/src/hooks/useSafeContinueUrl.ts deleted file mode 100644 index e42bdc446..000000000 --- a/apps/trust/src/hooks/useSafeContinueUrl.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { useMemo } from "react"; -import { useSearchParams } from "react-router"; - -export function useSafeContinueUrl(): URL { - const [searchParams] = useSearchParams(); - - const continueUrlParam = searchParams.get("continue"); - const fallback = window.location.origin + "/"; - - const safeContinueUrl = useMemo(() => { - if (continueUrlParam) { - let continueUrl: URL; - try { - continueUrl = new URL(continueUrlParam, window.location.origin); - } catch { - return new URL(fallback, window.location.origin); - } - if ( - continueUrl.origin === window.location.origin - && continueUrl.pathname.startsWith("/") - ) { - return new URL( - continueUrl.pathname + continueUrl.search, - window.location.origin, - ); - } - return new URL(fallback, window.location.origin); - } - return new URL(fallback, window.location.origin); - }, [continueUrlParam, fallback]); - - return safeContinueUrl; -} diff --git a/apps/trust/src/index.css b/apps/trust/src/index.css deleted file mode 100644 index a4e4ea3fb..000000000 --- a/apps/trust/src/index.css +++ /dev/null @@ -1,10 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap"); -@import "tailwindcss"; -@import "@probo/ui/src/theme.css"; -@import "tw-animate-css"; -@source "../../../packages/ui/src"; -@source "../../../packages/helpers/src"; - -.react-pdf__Page__annotations.annotationLayer { - display: none; -} diff --git a/apps/trust/src/layouts/MainLayout.tsx b/apps/trust/src/layouts/MainLayout.tsx deleted file mode 100644 index 69408722f..000000000 --- a/apps/trust/src/layouts/MainLayout.tsx +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { useFavicon, useSystemTheme } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; -import { Logo, TabLink, Tabs } from "@probo/ui"; -import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; -import { Outlet } from "react-router"; - -import { OrganizationSidebar } from "#/components/OrganizationSidebar"; -import { useRequestAccessCallback } from "#/hooks/useRequestAccessCallback"; -import { CompliancePortalProvider } from "#/providers/CompliancePortalProvider"; -import type { CompliancePortalGraphCurrentQuery } from "#/queries/__generated__/CompliancePortalGraphCurrentQuery.graphql"; -import { currentCompliancePortalGraphQuery } from "#/queries/CompliancePortalGraph"; - -type Props = { - queryRef: PreloadedQuery; -}; - -export function MainLayout(props: Props) { - const { __ } = useTranslate(); - const data = usePreloadedQuery(currentCompliancePortalGraphQuery, props.queryRef); - const compliancePortal = data.currentCompliancePortal; - const isAuthenticated = data.viewer != null; - - const theme = useSystemTheme(); - - useFavicon( - theme === "dark" - ? (compliancePortal?.darkLogo?.downloadUrl ?? compliancePortal?.logo?.downloadUrl) - : compliancePortal?.logo?.downloadUrl, - ); - useRequestAccessCallback(); - - return ( - -
- -
- - {__("Overview")} - {__("Documents")} - {compliancePortal.subprocessorInfo.totalCount > 0 - && {__("Subprocessors")}} - {__("Updates")} - - -
-
- - - {__("Powered by")} - {" "} - - -
- ); -} diff --git a/apps/trust/src/main.tsx b/apps/trust/src/main.tsx deleted file mode 100644 index a116ab17e..000000000 --- a/apps/trust/src/main.tsx +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { createRoot } from "react-dom/client"; - -import "./index.css"; - -import { App } from "./App"; -import { RelayProvider } from "./providers/RelayProviders"; -import { TranslatorProvider } from "./providers/TranslatorProvider"; - -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - refetchOnWindowFocus: false, - }, - }, -}); - -createRoot(document.getElementById("root")!).render( - - - - - - - , -); diff --git a/apps/trust/src/module.d.ts b/apps/trust/src/module.d.ts deleted file mode 100644 index ab0d3b44b..000000000 --- a/apps/trust/src/module.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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. - -declare module "https://cdn.jsdelivr.net/npm/pdfjs-dist@5.4.149/+esm" { - export * from "pdfjs-dist"; -} diff --git a/apps/trust/src/pages/DocumentPage.tsx b/apps/trust/src/pages/DocumentPage.tsx deleted file mode 100644 index e1b57c582..000000000 --- a/apps/trust/src/pages/DocumentPage.tsx +++ /dev/null @@ -1,502 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { formatError } from "@probo/helpers"; -import { useSystemTheme } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; -import { UnAuthenticatedError } from "@probo/relay"; -import { - Button, - IconArrowDown, - IconChevronLeft, - IconLock, - Spinner, - useToast, -} from "@probo/ui"; -import { useEffect, useState } from "react"; -import { - type PreloadedQuery, - useMutation, - usePreloadedQuery, -} from "react-relay"; -import { Link, useLocation, useNavigate, useSearchParams } from "react-router"; -import { graphql } from "relay-runtime"; - -import { PDFPreview } from "#/components/PDFPreview"; - -import type { DocumentPageExportCompliancePortalFileMutation } from "./__generated__/DocumentPageExportCompliancePortalFileMutation.graphql"; -import type { DocumentPageExportDocumentMutation } from "./__generated__/DocumentPageExportDocumentMutation.graphql"; -import type { DocumentPageExportReportMutation } from "./__generated__/DocumentPageExportReportMutation.graphql"; -import type { DocumentPageQuery as DocumentPageQueryType } from "./__generated__/DocumentPageQuery.graphql"; -import type { DocumentPageRequestCompliancePortalFileAccessMutation } from "./__generated__/DocumentPageRequestCompliancePortalFileAccessMutation.graphql"; -import type { DocumentPageRequestDocumentAccessMutation } from "./__generated__/DocumentPageRequestDocumentAccessMutation.graphql"; -import type { DocumentPageRequestReportAccessMutation } from "./__generated__/DocumentPageRequestReportAccessMutation.graphql"; - -export const documentPageQuery = graphql` - query DocumentPageQuery($alias: String!) { - currentCompliancePortal { - logo { - downloadUrl - } - darkLogo { - downloadUrl - } - } - aliasedNode(alias: $alias) @required(action: THROW) { - __typename - ... on Document { - id - title - isUserAuthorized - access { - id - status - } - } - ... on CompliancePortalFile { - id - name - isUserAuthorized - access { - id - status - } - } - ... on AuditReport { - id - fileName - isUserAuthorized - access { - id - status - } - } - } - } -`; - -const exportDocumentMutation = graphql` - mutation DocumentPageExportDocumentMutation( - $input: ExportDocumentPDFInput! - ) { - exportDocumentPDF(input: $input) { - data - } - } -`; - -const exportCompliancePortalFileMutation = graphql` - mutation DocumentPageExportCompliancePortalFileMutation( - $input: ExportCompliancePortalFileInput! - ) { - exportCompliancePortalFile(input: $input) { - data - } - } -`; - -const exportReportMutation = graphql` - mutation DocumentPageExportReportMutation( - $input: ExportReportPDFInput! - ) { - exportReportPDF(input: $input) { - data - } - } -`; - -const requestDocumentAccessMutation = graphql` - mutation DocumentPageRequestDocumentAccessMutation( - $input: RequestDocumentAccessInput! - ) { - requestDocumentAccess(input: $input) { - document { - access { - id - status - } - } - } - } -`; - -const requestCompliancePortalFileAccessMutation = graphql` - mutation DocumentPageRequestCompliancePortalFileAccessMutation( - $input: RequestCompliancePortalFileAccessInput! - ) { - requestCompliancePortalFileAccess(input: $input) { - file { - access { - id - status - } - } - } - } -`; - -const requestReportAccessMutation = graphql` - mutation DocumentPageRequestReportAccessMutation( - $input: RequestReportAccessInput! - ) { - requestReportAccess(input: $input) { - audit { - reportFile { - access { - id - status - } - } - } - } - } -`; - -type Props = { - queryRef: PreloadedQuery; -}; - -function isPdfDataUri(dataUri: string): boolean { - return dataUri.startsWith("data:application/pdf;"); -} - -function extractBase64Data(dataUri: string): string { - const commaIndex = dataUri.indexOf(","); - if (commaIndex === -1) return dataUri; - return dataUri.substring(commaIndex + 1); -} - -function extractMimeType(dataUri: string): string { - const match = dataUri.match(/^data:([^;]+);/); - return match?.[1] ?? "application/octet-stream"; -} - -function getNodeTitle(node: DocumentPageQueryType["response"]["aliasedNode"]): string | undefined { - switch (node.__typename) { - case "Document": - return node.title; - case "CompliancePortalFile": - return node.name; - case "AuditReport": - return node.fileName; - default: - return undefined; - } -} - -function getNodeId(node: DocumentPageQueryType["response"]["aliasedNode"]): string | undefined { - switch (node.__typename) { - case "Document": - case "CompliancePortalFile": - case "AuditReport": - return node.id; - default: - return undefined; - } -} - -export function DocumentPage({ queryRef }: Props) { - const { __ } = useTranslate(); - const { toast } = useToast(); - const theme = useSystemTheme(); - const navigate = useNavigate(); - const location = useLocation(); - const [searchParams] = useSearchParams(); - const [pdfData, setPdfData] = useState(null); - const [fileData, setFileData] = useState(null); - const [exportError, setExportError] = useState(null); - - const data = usePreloadedQuery(documentPageQuery, queryRef); - const compliancePortal = data.currentCompliancePortal; - const node = data.aliasedNode; - - if ( - node.__typename !== "Document" - && node.__typename !== "CompliancePortalFile" - && node.__typename !== "AuditReport" - ) { - throw new Error(`Unexpected node type: ${node.__typename}`); - } - - const nodeTitle = getNodeTitle(node); - const nodeId = getNodeId(node); - - const logoFileUrl = theme === "dark" - ? (compliancePortal?.darkLogo?.downloadUrl ?? compliancePortal?.logo?.downloadUrl) - : compliancePortal?.logo?.downloadUrl; - - const [exportDocument, isExportingDocument] - = useMutation(exportDocumentMutation); - const [exportFile, isExportingFile] - = useMutation(exportCompliancePortalFileMutation); - const [exportReport, isExportingReport] - = useMutation(exportReportMutation); - const [requestAccess, isRequestingAccess] - = useMutation(requestDocumentAccessMutation); - const [requestFileAccess, isRequestingFileAccess] - = useMutation(requestCompliancePortalFileAccessMutation); - const [requestReportAccess, isRequestingReportAccess] - = useMutation(requestReportAccessMutation); - - const isExporting = isExportingDocument || isExportingFile || isExportingReport; - - const [prevNodeId, setPrevNodeId] = useState(nodeId); - if (prevNodeId !== nodeId) { - setPrevNodeId(nodeId); - setPdfData(null); - setFileData(null); - setExportError(null); - } - - useEffect(() => { - if (!node.isUserAuthorized || pdfData || fileData || exportError) return; - - const onError = (error: Error) => { - setExportError(error.message ?? __("Cannot export document")); - }; - - const onCompletedErrors = (errors: readonly { message: string }[] | null | undefined) => { - if (errors?.length) { - setExportError(formatError(__("Cannot export document"), [...errors])); - return true; - } - return false; - }; - - switch (node.__typename) { - case "Document": - exportDocument({ - variables: { input: { documentId: node.id } }, - onCompleted: (response, errors) => { - if (onCompletedErrors(errors)) return; - setPdfData(response.exportDocumentPDF.data); - }, - onError, - }); - break; - case "CompliancePortalFile": - exportFile({ - variables: { input: { compliancePortalFileId: node.id } }, - onCompleted: (response, errors) => { - if (onCompletedErrors(errors)) return; - if (isPdfDataUri(response.exportCompliancePortalFile.data)) { - setPdfData(response.exportCompliancePortalFile.data); - } else { - setFileData(response.exportCompliancePortalFile.data); - } - }, - onError, - }); - break; - case "AuditReport": - exportReport({ - variables: { input: { reportId: node.id } }, - onCompleted: (response, errors) => { - if (onCompletedErrors(errors)) return; - setPdfData(response.exportReportPDF.data); - }, - onError, - }); - break; - } - }, [node, pdfData, fileData, exportError, exportDocument, exportFile, exportReport, __]); - - const handleRequestAccess = () => { - const onError = (error: Error) => { - if (error instanceof UnAuthenticatedError) { - const urlSearchParams = new URLSearchParams([[ - "continue", - window.location.origin + location.pathname + "?" + searchParams.toString(), - ]]); - void navigate(`/connect?${urlSearchParams.toString()}`); - return; - } - toast({ - title: __("Error"), - description: error.message ?? __("Cannot request access"), - variant: "error", - }); - }; - - const onCompleted = (_: unknown, errors: readonly { message: string }[] | null | undefined) => { - if (errors?.length) { - toast({ - title: __("Error"), - description: formatError(__("Cannot request access"), [...errors]), - variant: "error", - }); - return; - } - toast({ - title: __("Success"), - description: __("Access request submitted successfully."), - variant: "success", - }); - }; - - switch (node.__typename) { - case "Document": - requestAccess({ - variables: { input: { documentId: node.id } }, - onCompleted, - onError, - }); - break; - case "CompliancePortalFile": - requestFileAccess({ - variables: { input: { compliancePortalFileId: node.id } }, - onCompleted, - onError, - }); - break; - case "AuditReport": - requestReportAccess({ - variables: { input: { reportId: node.id } }, - onCompleted, - onError, - }); - break; - } - }; - - const isRequesting = isRequestingAccess || isRequestingFileAccess || isRequestingReportAccess; - const hasRequested = node.access?.status === "REQUESTED"; - const isPdf = node.__typename === "Document" || node.__typename === "AuditReport" || (node.__typename === "CompliancePortalFile" && pdfData !== null); - - const handleDownload = () => { - if (!fileData || !nodeTitle) return; - const base64 = extractBase64Data(fileData); - const mimeType = extractMimeType(fileData); - const byteCharacters = atob(base64); - const byteNumbers = new Uint8Array(byteCharacters.length); - for (let i = 0; i < byteCharacters.length; i++) { - byteNumbers[i] = byteCharacters.charCodeAt(i); - } - const blob = new Blob([byteNumbers], { type: mimeType }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = nodeTitle; - a.click(); - URL.revokeObjectURL(url); - }; - - return ( -
-
- - - - {logoFileUrl && ( - - )} - - {nodeTitle} - -
- -
- {exportError - ? ( -
-
-

- {__("Failed to load document")} -

-

- {exportError} -

-
-
- ) - : node.isUserAuthorized - ? ( - isPdf - ? ( - isExporting || !pdfData - ? ( -
- -
- ) - : ( - - ) - ) - : ( - isExporting || !fileData - ? ( -
- -
- ) - : ( -
-
-

- {nodeTitle} -

-

- {__("This file cannot be previewed in the browser.")} -

- -
-
- ) - ) - ) - : ( -
-
- -

- {nodeTitle} -

-

- {__("This document requires access approval before viewing.")} -

- -
-
- )} -
-
- ); -} diff --git a/apps/trust/src/pages/DocumentPageLoader.tsx b/apps/trust/src/pages/DocumentPageLoader.tsx deleted file mode 100644 index 848f86d53..000000000 --- a/apps/trust/src/pages/DocumentPageLoader.tsx +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { useEffect } from "react"; -import { useQueryLoader } from "react-relay"; -import { useParams } from "react-router"; - -import { RelayProvider } from "#/providers/RelayProviders"; - -import type { DocumentPageQuery } from "./__generated__/DocumentPageQuery.graphql"; -import { DocumentPage, documentPageQuery } from "./DocumentPage"; - -function DocumentPageQueryLoader() { - const { documentId } = useParams<{ documentId: string }>(); - const [queryRef, loadQuery] = useQueryLoader(documentPageQuery); - - useEffect(() => { - if (documentId) { - loadQuery({ alias: documentId }); - } - }, [documentId, loadQuery]); - - if (!queryRef) return null; - - return ; -} - -export default function DocumentPageLoader() { - return ( - - - - ); -} diff --git a/apps/trust/src/pages/DocumentsPage.tsx b/apps/trust/src/pages/DocumentsPage.tsx deleted file mode 100644 index 91c372199..000000000 --- a/apps/trust/src/pages/DocumentsPage.tsx +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { groupBy, objectEntries } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { Fragment } from "react"; -import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; - -import { CompliancePortalFileRow } from "#/components/CompliancePortalFileRow"; -import { DocumentRow } from "#/components/DocumentRow"; -import { RowHeader } from "#/components/RowHeader"; -import { Rows } from "#/components/Rows"; -import { documentTypeLabel } from "#/helpers/documents"; -import type { CompliancePortalGraphCurrentDocumentsQuery } from "#/queries/__generated__/CompliancePortalGraphCurrentDocumentsQuery.graphql"; -import { currentTrustDocumentsQuery } from "#/queries/CompliancePortalGraph"; - -type Props = { - queryRef: PreloadedQuery; -}; - -export function DocumentsPage({ queryRef }: Props) { - const { __ } = useTranslate(); - const data = usePreloadedQuery( - currentTrustDocumentsQuery, - queryRef, - ); - const documents - = data.currentCompliancePortal?.documents.edges.map(edge => edge.node) ?? []; - const files - = data.currentCompliancePortal?.compliancePortalFiles.edges.map(edge => edge.node) ?? []; - const documentsPerType = groupBy(documents, document => - documentTypeLabel(document.documentType, __), - ); - const filesPerCategory = groupBy(files, file => file.category); - return ( -
-

{__("Documents")}

-

- {__("Security and compliance documentation:")} -

- - {objectEntries(documentsPerType).map(([label, documents]) => ( - - {label} - {documents.map(document => ( - - ))} - - ))} - {objectEntries(filesPerCategory).map(([category, files]) => ( - - {category} - {files.map(file => ( - - ))} - - ))} - -
- ); -} diff --git a/apps/trust/src/pages/NDAPage.tsx b/apps/trust/src/pages/NDAPage.tsx deleted file mode 100644 index 05f8aef7b..000000000 --- a/apps/trust/src/pages/NDAPage.tsx +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { sprintf } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { Button, Card, IconCircleX, Logo, Spinner } from "@probo/ui"; -import { startTransition, useEffect, useRef } from "react"; -import { - type PreloadedQuery, - useMutation, - usePreloadedQuery, - useRefetchableFragment, -} from "react-relay"; -import { Navigate, useSearchParams } from "react-router"; -import { graphql } from "relay-runtime"; -import { useWindowSize } from "usehooks-ts"; - -import { PDFPreview } from "#/components/PDFPreview"; - -import type { NDAPageAcceptElectronicSignatureMutation } from "./__generated__/NDAPageAcceptElectronicSignatureMutation.graphql"; -import type { NDAPageFragment$key } from "./__generated__/NDAPageFragment.graphql"; -import type { NDAPageQuery as NDAPageQueryType } from "./__generated__/NDAPageQuery.graphql"; -import type { NDAPageRecordSigningEventMutation } from "./__generated__/NDAPageRecordSigningEventMutation.graphql"; -import type { NDAPageRefetchQuery } from "./__generated__/NDAPageRefetchQuery.graphql"; - -export const ndaPageQuery = graphql` - query NDAPageQuery { - viewer { - # eslint-disable-next-line relay/unused-fields - id - } - currentCompliancePortal @required(action: THROW) { - entityName - nonDisclosureAgreement { - fileName - fileUrl - viewerSignature { - status - } - } - ...NDAPageFragment - } - } -`; - -const ndaPageFragment = graphql` - fragment NDAPageFragment on CompliancePortal - @refetchable(queryName: "NDAPageRefetchQuery") { - nonDisclosureAgreement @required(action: THROW) { - viewerSignature { - id - status - consentText - lastError - } - } - } -`; - -const acceptElectronicSignatureMutation = graphql` - mutation NDAPageAcceptElectronicSignatureMutation( - $input: AcceptElectronicSignatureInput! - ) { - acceptElectronicSignature(input: $input) { - signature { - id - status - } - } - } -`; - -const recordSigningEventMutation = graphql` - mutation NDAPageRecordSigningEventMutation( - $input: RecordSigningEventInput! - ) { - recordSigningEvent(input: $input) { - success - } - } -`; - -export function NDAPage(props: { - queryRef: PreloadedQuery; -}) { - const { __ } = useTranslate(); - const [searchParams] = useSearchParams(); - const documentViewedRef = useRef(false); - const { width } = useWindowSize(); - const isMobile = width < 1100; - const isDesktop = !isMobile; - - const queryData = usePreloadedQuery(ndaPageQuery, props.queryRef); - const compliancePortal = queryData.currentCompliancePortal; - const viewer = queryData.viewer; - - const [data, refetch] = useRefetchableFragment( - ndaPageFragment, - compliancePortal, - ); - const ndaSignature = data.nonDisclosureAgreement.viewerSignature; - - const continueUrlParam = searchParams.get("continue"); - let safeContinueUrl: string; - if (continueUrlParam) { - try { - const continueUrl = new URL(continueUrlParam, window.location.origin); - if (continueUrl.origin === window.location.origin && continueUrl.pathname.startsWith("/")) { - safeContinueUrl = window.location.origin + continueUrl.pathname + continueUrl.search; - } else { - safeContinueUrl = window.location.origin; - } - } catch { - safeContinueUrl = window.location.origin; - } - } else { - safeContinueUrl = window.location.origin; - } - - const [acceptSignature, isAccepting] = useMutation( - acceptElectronicSignatureMutation, - ); - - const [recordSigningEvent] = useMutation( - recordSigningEventMutation, - ); - - const isProcessing - = ndaSignature?.status === "ACCEPTED" - || ndaSignature?.status === "PROCESSING"; - - const isFailed = ndaSignature?.status === "FAILED"; - const isCompleted = ndaSignature?.status === "COMPLETED"; - - useEffect(() => { - if (isCompleted) { - window.location.href = safeContinueUrl; - } - }, [isCompleted, safeContinueUrl]); - - useEffect(() => { - if (!isProcessing) return; - - const poll = () => startTransition(() => { - refetch({}, { fetchPolicy: "network-only" }); - }); - const interval = setInterval(poll, 1500); - - return () => clearInterval(interval); - }, [isProcessing, refetch]); - - useEffect(() => { - if ( - ndaSignature - && ndaSignature.status === "PENDING" - && !documentViewedRef.current - ) { - documentViewedRef.current = true; - recordSigningEvent({ - variables: { - input: { - signatureId: ndaSignature.id, - eventType: "DOCUMENT_VIEWED", - }, - }, - }); - } - }, [ndaSignature, recordSigningEvent]); - - const handleAccept = () => { - if (!ndaSignature) return; - - if (ndaSignature.status === "PENDING") { - recordSigningEvent({ - variables: { - input: { - signatureId: ndaSignature.id, - eventType: "FULL_NAME_TYPED", - }, - }, - }); - } - - recordSigningEvent({ - variables: { - input: { - signatureId: ndaSignature.id, - eventType: "CONSENT_GIVEN", - }, - }, - onCompleted: () => { - acceptSignature({ - variables: { - input: { - signatureId: ndaSignature.id, - }, - }, - }); - }, - }); - }; - - const nda = compliancePortal.nonDisclosureAgreement; - if (!viewer) { - return ; - } - - if (!nda || !nda.viewerSignature || nda.viewerSignature.status === "COMPLETED") { - return ; - } - - const consentText = ndaSignature?.consentText; - - return ( -
-
- -
-
-
-
-

- {__("Non-Disclosure Agreement")} -

-

- {sprintf( - __( - "%s requires you to sign an NDA before accessing compliance documents.", - ), - compliancePortal.entityName, - )} -

- {isMobile && nda?.fileUrl && ( - - {nda?.fileName} - - - )} -
-

- {consentText} -

- {isFailed && ( -
- -
-

- {__("Signature processing failed")} -

-

- {ndaSignature?.lastError - ?? __("We encountered an issue processing your signature. Please try again.")} -

-
-
- )} - {isProcessing - ? ( - - ) - : ( - - )} -
-
- - Powered by - {" "} - - -
- {isDesktop && ( -
- {nda?.fileUrl && } -
- )} -
-
- ); -} diff --git a/apps/trust/src/pages/NDAPageLoader.tsx b/apps/trust/src/pages/NDAPageLoader.tsx deleted file mode 100644 index b3dbd4bee..000000000 --- a/apps/trust/src/pages/NDAPageLoader.tsx +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { useEffect } from "react"; -import { useQueryLoader } from "react-relay"; - -import { RelayProvider } from "#/providers/RelayProviders"; - -import type { NDAPageQuery } from "./__generated__/NDAPageQuery.graphql"; -import { NDAPage, ndaPageQuery } from "./NDAPage"; - -function NDAPageQueryLoader() { - const [queryRef, loadQuery] - = useQueryLoader(ndaPageQuery); - - useEffect(() => { - if (!queryRef) { - loadQuery({}); - } - }); - - if (!queryRef) return null; - - return ; -} - -export default function NDAPageLoader() { - return ( - - - - ); -} diff --git a/apps/trust/src/pages/OverviewPage.tsx b/apps/trust/src/pages/OverviewPage.tsx deleted file mode 100644 index ca2eb1f3e..000000000 --- a/apps/trust/src/pages/OverviewPage.tsx +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { - getCompliancePortalUrl, - groupBy, - objectEntries, - sprintf, -} from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { Card, IconChevronRight } from "@probo/ui"; -import { Fragment } from "react"; -import { useFragment } from "react-relay"; -import { Link, useOutletContext } from "react-router"; -import { graphql } from "relay-runtime"; - -import { AuditRow } from "#/components/AuditRow"; -import { CompliancePortalFileRow } from "#/components/CompliancePortalFileRow"; -import { DocumentRow } from "#/components/DocumentRow"; -import { RowHeader } from "#/components/RowHeader"; -import { Rows } from "#/components/Rows"; -import { SubprocessorRow } from "#/components/SubprocessorRow"; -import { documentTypeLabel } from "#/helpers/documents"; -import type { CompliancePortalGraphCurrentQuery$data } from "#/queries/__generated__/CompliancePortalGraphCurrentQuery.graphql"; - -import type { - OverviewPageFragment$data, - OverviewPageFragment$key, -} from "./__generated__/OverviewPageFragment.graphql"; - -const overviewFragment = graphql` - fragment OverviewPageFragment on CompliancePortal { - references(first: 14) { - edges { - node { - id - name - logo { - downloadUrl - } - websiteUrl - } - } - } - subprocessors(first: 3) { - edges { - node { - id - countries - ...SubprocessorRowFragment - } - } - } - documents(first: 5) { - edges { - node { - id - documentType - ...DocumentRowFragment - } - } - } - compliancePortalFiles(first: 5) { - edges { - node { - id - category - ...CompliancePortalFileRowFragment - } - } - } - } -`; - -export function OverviewPage() { - const { compliancePortal } = useOutletContext<{ - compliancePortal: OverviewPageFragment$key - & CompliancePortalGraphCurrentQuery$data["currentCompliancePortal"]; - }>(); - const fragment = useFragment(overviewFragment, compliancePortal); - return ( -
- edge.node)} - /> - - -
- ); -} - -function Documents({ - documents, - files, - audits, - url, -}: { - documents: OverviewPageFragment$data["documents"]["edges"]; - files: OverviewPageFragment$data["compliancePortalFiles"]["edges"]; - audits: NonNullable< - CompliancePortalGraphCurrentQuery$data["currentCompliancePortal"] - >["audits"]["edges"]; - url: string; -}) { - const { __ } = useTranslate(); - const documentsPerType = groupBy( - documents.map(edge => edge.node), - node => documentTypeLabel(node.documentType, __), - ); - const filesPerCategory = groupBy( - files.map(edge => edge.node), - node => node.category, - ); - const hasAudits = audits.length > 0; - const hasDocuments = hasAudits || documents.length > 0 || files.length > 0; - - if (!hasDocuments) { - return null; - } - - return ( -
-

{__("Documents")}

-

- {__("Security and compliance documentation:")} -

- - {audits.length > 0 && ( - <> - {__("Compliance")} - {audits.map(audit => ( - - ))} - - )} - {objectEntries(documentsPerType).map(([label, documents]) => ( - - {label} - {documents.map(document => ( - - ))} - - ))} - {objectEntries(filesPerCategory).map(([category, files]) => ( - - {category} - {files.map(file => ( - - ))} - - ))} - - {__("See all documents")} - - - -
- ); -} - -function Subprocessors({ - subprocessors, - url, - title, -}: { - subprocessors: OverviewPageFragment$data["subprocessors"]["edges"]; - url: string; - title: string; -}) { - const { __ } = useTranslate(); - if (subprocessors.length === 0) { - return null; - } - - const hasAnyCountries = subprocessors.some((subprocessor) => { - const subprocessorData = subprocessor.node; - return subprocessorData.countries && subprocessorData.countries.length > 0; - }); - - return ( -
-

{__("Subprocessors")}

-

- {sprintf( - __("Third-party subprocessors %s work with:"), - title, - )} -

- - {subprocessors.map(subprocessor => ( - - ))} - - {__("See all subprocessors")} - - - -
- ); -} - -type Reference = { - name: string; - logo: { downloadUrl: string } | null; - websiteUrl: string; - id: string; -}; - -function References({ references }: { references: Reference[] }) { - const { __ } = useTranslate(); - - if (references.length === 0) { - return null; - } - - return ( -
-

{__("Trusted by")}

- - {references.map(reference => ( - - {reference.name} - {reference.name} - - ))} - -
- ); -} diff --git a/apps/trust/src/pages/SubprocessorsPage.tsx b/apps/trust/src/pages/SubprocessorsPage.tsx deleted file mode 100644 index 338ced46b..000000000 --- a/apps/trust/src/pages/SubprocessorsPage.tsx +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { sprintf } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; - -import { Rows } from "#/components/Rows"; -import { SubprocessorRow } from "#/components/SubprocessorRow"; -import type { CompliancePortalGraphCurrentSubprocessorsQuery } from "#/queries/__generated__/CompliancePortalGraphCurrentSubprocessorsQuery.graphql"; -import { currentTrustSubprocessorsQuery } from "#/queries/CompliancePortalGraph"; - -type Props = { - queryRef: PreloadedQuery; -}; - -export function SubprocessorsPage({ queryRef }: Props) { - const { __ } = useTranslate(); - const data = usePreloadedQuery(currentTrustSubprocessorsQuery, queryRef); - const subprocessors - = data.currentCompliancePortal?.subprocessors.edges.map(edge => edge.node) ?? []; - - const hasAnyCountries = subprocessors.some(subprocessor => subprocessor.countries.length > 0); - - return ( -
-

{__("Subprocessors")}

-

- {sprintf( - __("Third-party subprocessors %s work with:"), - data.currentCompliancePortal?.entityName ?? "", - )} -

- - {subprocessors.map(subprocessor => ( - - ))} - -
- ); -} diff --git a/apps/trust/src/pages/UpdatesPage.tsx b/apps/trust/src/pages/UpdatesPage.tsx deleted file mode 100644 index d98863cfe..000000000 --- a/apps/trust/src/pages/UpdatesPage.tsx +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { useTranslate } from "@probo/i18n"; -import { IconChevronDown } from "@probo/ui"; -import { useState } from "react"; -import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; -import { graphql } from "relay-runtime"; - -import { Rows } from "#/components/Rows"; -import type { UpdatesPageQuery } from "#/pages/__generated__/UpdatesPageQuery.graphql"; - -export const currentTrustUpdatesQuery = graphql` - query UpdatesPageQuery { - currentCompliancePortal { - id - updates(first: 50) { - edges { - node { - id - title - body - updatedAt - } - } - } - } - } -`; - -type Props = { - queryRef: PreloadedQuery; -}; - -export function UpdatesPage({ queryRef }: Props) { - const { __ } = useTranslate(); - const data = usePreloadedQuery( - currentTrustUpdatesQuery, - queryRef, - ); - - const items - = data.currentCompliancePortal?.updates.edges.map(e => e.node) ?? []; - - return ( -
-

{__("Updates")}

- {items.length === 0 - ? ( - -
- {__("No updates have been published yet.")} -
-
- ) - : ( - <> -

- {__("Latest compliance and security updates")} -

-
- {items.map(item => ( - - ))} -
- - )} -
- ); -} - -type UpdateItemType = { - id: string; - title: string; - body: string; - updatedAt: string; -}; - -function UpdateItem({ item }: { item: UpdateItemType }) { - const [open, setOpen] = useState(false); - - return ( -
- - {open && ( -
-

- {item.body} -

-

- {new Date(item.updatedAt).toLocaleDateString(undefined, { - year: "numeric", - month: "short", - day: "numeric", - })} -

-
- )} -
- ); -} diff --git a/apps/trust/src/pages/auth/AuthLayout.tsx b/apps/trust/src/pages/auth/AuthLayout.tsx deleted file mode 100644 index 4dea72238..000000000 --- a/apps/trust/src/pages/auth/AuthLayout.tsx +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { useSystemTheme } from "@probo/hooks"; -import { Card, Logo } from "@probo/ui"; -import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; -import { Outlet } from "react-router"; -import { graphql } from "relay-runtime"; - -import type { AuthLayoutQuery } from "./__generated__/AuthLayoutQuery.graphql"; - -export const authLayoutQuery = graphql` - query AuthLayoutQuery { - currentCompliancePortal @required(action: THROW) { - logo { - downloadUrl - } - darkLogo { - downloadUrl - } - } - } -`; - -export function AuthLayout(props: { queryRef: PreloadedQuery }) { - const { queryRef } = props; - - const { currentCompliancePortal: compliancePage } = usePreloadedQuery(authLayoutQuery, queryRef); - const theme = useSystemTheme(); - - const logoFileUrl = theme === "dark" - ? compliancePage.darkLogo?.downloadUrl ?? compliancePage.logo?.downloadUrl - : compliancePage.logo?.downloadUrl; - - return ( -
- -
- {logoFileUrl - ? ( - - ) - : } -
-
- - - -
- ); -} diff --git a/apps/trust/src/pages/auth/AuthLayoutLoader.tsx b/apps/trust/src/pages/auth/AuthLayoutLoader.tsx deleted file mode 100644 index bf26b7684..000000000 --- a/apps/trust/src/pages/auth/AuthLayoutLoader.tsx +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { useEffect } from "react"; -import { useQueryLoader } from "react-relay"; - -import { RelayProvider } from "#/providers/RelayProviders"; - -import type { AuthLayoutQuery } from "./__generated__/AuthLayoutQuery.graphql"; -import { AuthLayout, authLayoutQuery } from "./AuthLayout"; - -function AuthLayoutQueryLoader() { - const [queryRef, loadQuery] = useQueryLoader(authLayoutQuery); - - useEffect(() => { - if (!queryRef) { - return loadQuery({}); - } - }); - - if (!queryRef) return null; - - return ; -} - -export default function AuthLayoutLoader() { - return ( - - - - ); -} diff --git a/apps/trust/src/pages/auth/ConnectPage.tsx b/apps/trust/src/pages/auth/ConnectPage.tsx deleted file mode 100644 index 9ca7486fd..000000000 --- a/apps/trust/src/pages/auth/ConnectPage.tsx +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { usePageTitle } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; -import { Button } from "@probo/ui"; -import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; -import { graphql } from "relay-runtime"; - -import { useSafeContinueUrl } from "#/hooks/useSafeContinueUrl"; - -import type { ConnectPageQuery } from "./__generated__/ConnectPageQuery.graphql"; - -export const connectPageQuery = graphql` - query ConnectPageQuery { - currentCompliancePortal @required(action: THROW) { - entityName - } - } -`; - -export function ConnectPage(props: { - queryRef: PreloadedQuery; -}) { - const { queryRef } = props; - - const { __ } = useTranslate(); - const safeContinueUrl = useSafeContinueUrl(); - - const { - currentCompliancePortal: { entityName }, - } = usePreloadedQuery(connectPageQuery, queryRef); - - usePageTitle(__(`Connect to ${entityName}'s Compliance Page`)); - - const initiateURL = new URL("/initiate", window.location.origin); - initiateURL.searchParams.set("continue", safeContinueUrl.toString()); - - return ( -
-
-

- {__(`Connect to ${entityName}'s Compliance Page`)} -

-

- {__( - "Sign in to start requesting access to documents", - )} -

-
- - -
- ); -} diff --git a/apps/trust/src/pages/auth/ConnectPageLoader.tsx b/apps/trust/src/pages/auth/ConnectPageLoader.tsx deleted file mode 100644 index f468c8c25..000000000 --- a/apps/trust/src/pages/auth/ConnectPageLoader.tsx +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { Suspense, useEffect } from "react"; -import { useQueryLoader } from "react-relay"; - -import { RelayProvider } from "#/providers/RelayProviders"; - -import type { ConnectPageQuery } from "./__generated__/ConnectPageQuery.graphql"; -import { ConnectPage, connectPageQuery } from "./ConnectPage"; - -function ConnectPageQueryLoader() { - const [queryRef, loadQuery] - = useQueryLoader(connectPageQuery); - - useEffect(() => { - if (!queryRef) { - loadQuery({}); - } - }); - - if (!queryRef) return null; - - return ( - - - - ); -} - -export default function ConnectPageLoader() { - return ( - - - - ); -} diff --git a/apps/trust/src/pages/auth/FullNamePage.tsx b/apps/trust/src/pages/auth/FullNamePage.tsx deleted file mode 100644 index ddc8a849f..000000000 --- a/apps/trust/src/pages/auth/FullNamePage.tsx +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 type { GraphQLError } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; -import { Button, Field, useToast } from "@probo/ui"; -import { - useMutation, -} from "react-relay"; -import { useSearchParams } from "react-router"; -import { graphql } from "relay-runtime"; -import { z } from "zod"; - -import { useFormWithSchema } from "#/hooks/useFormWithSchema"; - -import type { FullNamePageMutation } from "./__generated__/FullNamePageMutation.graphql"; - -const updateMutation = graphql` - mutation FullNamePageMutation($input: UpdateFullNameInput!) { - updateFullName(input: $input) { - success - } - } -`; - -const schema = z.object({ - fullName: z.string().min(2), -}); - -type FormData = z.infer; - -export default function FullNamePage() { - const { __ } = useTranslate(); - const { toast } = useToast(); - const [searchParams] = useSearchParams(); - - const continueUrlParam = searchParams.get("continue"); - let safeContinueUrl: string; - if (continueUrlParam) { - try { - const continueUrl = new URL(continueUrlParam, window.location.origin); - if (continueUrl.origin === window.location.origin && continueUrl.pathname.startsWith("/")) { - safeContinueUrl = window.location.origin + continueUrl.pathname + continueUrl.search; - } else { - safeContinueUrl = window.location.origin; - } - } catch { - safeContinueUrl = window.location.origin; - } - } else { - safeContinueUrl = window.location.origin; - } - - const { - handleSubmit: handleSubmitWrapper, - register, - formState, - } = useFormWithSchema(schema, { - defaultValues: { - fullName: "", - }, - }); - - const [update] = useMutation( - updateMutation, - ); - - const handleSubmit = handleSubmitWrapper(({ fullName }: FormData) => { - update({ - variables: { - input: { - fullName, - }, - }, - onCompleted: (_, errors: GraphQLError[] | null) => { - if (errors) { - for (const err of errors) { - if (err.extensions?.code === "ALREADY_AUTHENTICATED") { - window.location.href = "/"; - return; - } - } - toast({ - title: __("Error"), - description: __("Cannot send magic link"), - variant: "error", - }); - return; - } - - toast({ - title: __("Success"), - description: __("Full name updated!"), - variant: "success", - }); - - window.location.href = safeContinueUrl; - }, - onError: (error) => { - toast({ - title: __("Error"), - description: error.message, - variant: "error", - }); - }, - }); - }); - - return ( -
-
-

- {__("Please set your profile's full name")} -

-
- -
void handleSubmit(e)} className="space-y-6"> - - - - -
- ); -} diff --git a/apps/trust/src/pages/auth/MagicLinkAlreadyUsedPage.tsx b/apps/trust/src/pages/auth/MagicLinkAlreadyUsedPage.tsx deleted file mode 100644 index ba3798a81..000000000 --- a/apps/trust/src/pages/auth/MagicLinkAlreadyUsedPage.tsx +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { usePageTitle } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; -import { Button } from "@probo/ui"; -import { useNavigate } from "react-router"; - -export default function MagicLinkAlreadyUsedPage() { - const { __ } = useTranslate(); - const navigate = useNavigate(); - - usePageTitle(__("Link Already Used")); - - return ( -
-
-

{__("Link Already Used")}

-

- {__( - "This magic link has already been used. Magic links can only be used once. Please request a new one if you need to sign in again.", - )} -

-
-
- -
-
- ); -} diff --git a/apps/trust/src/pages/auth/MagicLinkExpiredPage.tsx b/apps/trust/src/pages/auth/MagicLinkExpiredPage.tsx deleted file mode 100644 index ab34083c9..000000000 --- a/apps/trust/src/pages/auth/MagicLinkExpiredPage.tsx +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { usePageTitle } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; -import { Button } from "@probo/ui"; -import { useNavigate } from "react-router"; - -export default function MagicLinkExpiredPage() { - const { __ } = useTranslate(); - const navigate = useNavigate(); - - usePageTitle(__("Link Expired")); - - return ( -
-
-

{__("Link Expired")}

-

- {__( - "This magic link has expired. Magic links are only valid for 15 minutes. Please request a new one.", - )} -

-
-
- -
-
- ); -} diff --git a/apps/trust/src/pages/auth/_components/Divider.tsx b/apps/trust/src/pages/auth/_components/Divider.tsx deleted file mode 100644 index 14c990c1d..000000000 --- a/apps/trust/src/pages/auth/_components/Divider.tsx +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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. - -export function Divider({ children }: { children: React.ReactNode }) { - return ( -
-
- - {children} - -
- ); -} diff --git a/apps/trust/src/pages/auth/_components/OIDCButton.tsx b/apps/trust/src/pages/auth/_components/OIDCButton.tsx deleted file mode 100644 index bf250e473..000000000 --- a/apps/trust/src/pages/auth/_components/OIDCButton.tsx +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// 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 { useTranslate } from "@probo/i18n"; -import { Button, Google, Microsoft } from "@probo/ui"; -import type { ComponentProps } from "react"; -import { useFragment } from "react-relay"; -import { useSearchParams } from "react-router"; -import { graphql } from "relay-runtime"; - -import { useSafeContinueUrl } from "#/hooks/useSafeContinueUrl"; - -import type { OIDCButtonFragment$key } from "./__generated__/OIDCButtonFragment.graphql"; - -const fragment = graphql` - fragment OIDCButtonFragment on OIDCProviderInfo { - name - loginURL - } -`; - -const providerIcons: Record< - string, - (props: ComponentProps<"svg">) => React.ReactNode -> = { - google: Google, - microsoft: Microsoft, -}; - -export function OIDCButton({ - providerRef, -}: { - providerRef: OIDCButtonFragment$key; -}) { - const { __ } = useTranslate(); - const [searchParams] = useSearchParams(); - const safeContinueUrl = useSafeContinueUrl(); - const provider = useFragment(fragment, providerRef); - const Icon = providerIcons[provider.name]; - const organizationId = searchParams.get("organization-id"); - - return ( - - ); -} diff --git a/apps/trust/src/providers/AuthProvider.tsx b/apps/trust/src/providers/AuthProvider.tsx deleted file mode 100644 index 87d6dacad..000000000 --- a/apps/trust/src/providers/AuthProvider.tsx +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { createContext, useMemo } from "react"; - -export const AuthContext = createContext({ isAuthenticated: false }); - -type Props = { - children: React.ReactNode; - isAuthenticated: boolean; -}; - -export function AuthProvider({ children, isAuthenticated }: Props) { - const value = useMemo(() => ({ isAuthenticated }), [isAuthenticated]); - return {children}; -} diff --git a/apps/trust/src/providers/CompliancePortalProvider.tsx b/apps/trust/src/providers/CompliancePortalProvider.tsx deleted file mode 100644 index 31cc18684..000000000 --- a/apps/trust/src/providers/CompliancePortalProvider.tsx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { createContext, type ReactNode } from "react"; - -import type { CompliancePortalGraphCurrentQuery$data } from "#/queries/__generated__/CompliancePortalGraphCurrentQuery.graphql"; - -export const CompliancePortalContext = createContext< - CompliancePortalGraphCurrentQuery$data["currentCompliancePortal"] | null ->(null); - -export const CompliancePortalProvider = ({ - children, - compliancePortal, -}: { - children: ReactNode; - compliancePortal: CompliancePortalGraphCurrentQuery$data["currentCompliancePortal"]; -}) => { - return ( - - {children} - - ); -}; diff --git a/apps/trust/src/providers/RelayProviders.tsx b/apps/trust/src/providers/RelayProviders.tsx deleted file mode 100644 index a1789a5e8..000000000 --- a/apps/trust/src/providers/RelayProviders.tsx +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { makeFetchQuery } from "@probo/relay"; -import type { PropsWithChildren } from "react"; -import { RelayEnvironmentProvider } from "react-relay"; -import { - Environment, - Network, - RecordSource, - Store, -} from "relay-runtime"; - -export function buildEndpoint(): string { - let host = import.meta.env.VITE_API_URL; - - if (!host) { - host = window.location.origin; - } - - const formattedHost - = host.startsWith("http://") || host.startsWith("https://") - ? host - : `https://${host}`; - - const url = new URL(formattedHost); - - // Compliance pages are always served at the root of a dedicated host. - url.pathname = "/graphql"; - - return url.toString(); -} - -const source = new RecordSource(); -const store = new Store(source, { - queryCacheExpirationTime: 1 * 60 * 1000, - gcReleaseBufferSize: 20, -}); - -export const consoleEnvironment = new Environment({ - configName: "compliance-page", - network: Network.create(makeFetchQuery(buildEndpoint())), - store, -}); - -/** - * Provider for relay with the probo environment - */ -export function RelayProvider({ children }: PropsWithChildren) { - return ( - - {children} - - ); -} diff --git a/apps/trust/src/providers/TranslatorProvider.tsx b/apps/trust/src/providers/TranslatorProvider.tsx deleted file mode 100644 index 32578e5df..000000000 --- a/apps/trust/src/providers/TranslatorProvider.tsx +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 type { PropsWithChildren } from "react"; - -import { TranslatorProvider as ProboTranslatorProvider } from "../../../../packages/i18n/TranslatorProvider"; - -// TODO : implement a way to retrieve translations strings -const loader = () => { - return Promise.resolve({} as Record); -}; - -/** - * Provider for the translator - */ -export function TranslatorProvider({ children }: PropsWithChildren) { - return ( - - {children} - - ); -} diff --git a/apps/trust/src/queries/CompliancePortalGraph.ts b/apps/trust/src/queries/CompliancePortalGraph.ts deleted file mode 100644 index a49a92725..000000000 --- a/apps/trust/src/queries/CompliancePortalGraph.ts +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { graphql } from "relay-runtime"; - -/* eslint-disable relay/unused-fields, relay/must-colocate-fragment-spreads */ - -// Queries for custom domain (subdomain) approach -export const currentCompliancePortalGraphQuery = graphql` - query CompliancePortalGraphCurrentQuery { - viewer { - id - } - currentCompliancePortal @required(action: THROW) { - id - slug - entityName - description - websiteUrl - email - headquarterAddress - viewerSubscription { - id - email - createdAt - updatedAt - } - logo { - downloadUrl - } - darkLogo { - downloadUrl - } - nonDisclosureAgreement { - fileName - fileUrl - viewerSignature { - status - } - } - customLinks(first: 20) { - edges { - node { - id - name - url - } - } - } - ...OverviewPageFragment - subprocessorInfo: subprocessors(first: 0) { - totalCount - } - audits(first: 50) { - edges { - node { - id - ...AuditRowFragment - } - } - } - complianceFrameworks(first: 50) { - edges { - node { - id - framework { - ...FrameworkBadgeFragment - } - } - } - } - } - } -`; - -export const currentTrustDocumentsQuery = graphql` - query CompliancePortalGraphCurrentDocumentsQuery { - currentCompliancePortal { - id - documents(first: 50) { - edges { - node { - id - documentType - ...DocumentRowFragment - } - } - } - compliancePortalFiles(first: 50) { - edges { - node { - id - category - ...CompliancePortalFileRowFragment - } - } - } - } - } -`; - -export const currentTrustSubprocessorsQuery = graphql` - query CompliancePortalGraphCurrentSubprocessorsQuery { - currentCompliancePortal { - id - entityName - subprocessors(first: 50) { - edges { - node { - id - countries - ...SubprocessorRowFragment - } - } - } - } - } -`; diff --git a/apps/trust/src/routes.tsx b/apps/trust/src/routes.tsx deleted file mode 100644 index dd81876ec..000000000 --- a/apps/trust/src/routes.tsx +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { lazy } from "@probo/react-lazy"; -import { - type AppRoute, - loaderFromQueryLoader, - routeFromAppRoute, - withQueryRef, -} from "@probo/routes"; -import { Fragment } from "react"; -import { loadQuery } from "react-relay"; -import { createBrowserRouter, redirect } from "react-router"; - -import { MainLayout } from "#/layouts/MainLayout"; -import { DocumentsPage } from "#/pages/DocumentsPage"; -import { OverviewPage } from "#/pages/OverviewPage"; -import { SubprocessorsPage } from "#/pages/SubprocessorsPage"; -import { currentTrustUpdatesQuery, UpdatesPage } from "#/pages/UpdatesPage"; -import { - currentCompliancePortalGraphQuery, - currentTrustDocumentsQuery, - currentTrustSubprocessorsQuery, -} from "#/queries/CompliancePortalGraph"; - -import { DocumentPageErrorBoundary } from "./components/DocumentPageErrorBoundary"; -import { PageError } from "./components/PageError"; -import { RootErrorBoundary } from "./components/RootErrorBoundary"; -import { MainSkeleton } from "./components/Skeletons/MainSkeleton"; -import { TabSkeleton } from "./components/Skeletons/TabSkeleton"; -import { consoleEnvironment } from "./providers/RelayProviders"; - -const routes = [ - { - Component: lazy(() => import("#/pages/auth/AuthLayoutLoader")), - children: [ - { - path: "/connect", - Component: lazy(() => import("#/pages/auth/ConnectPageLoader")), - }, - { - path: "/full-name", - Component: lazy(() => import("#/pages/auth/FullNamePage")), - }, - ], - }, - { - path: "/", - loader: () => { - // eslint-disable-next-line - throw redirect("/overview"); - }, - Component: Fragment, - ErrorBoundary: RootErrorBoundary, - }, - { - path: "/nda", - Component: lazy(() => import("#/pages/NDAPageLoader")), - ErrorBoundary: RootErrorBoundary, - }, - // Custom domain routes (subdomain-based) - { - path: "/overview", - loader: loaderFromQueryLoader(() => - loadQuery(consoleEnvironment, currentCompliancePortalGraphQuery, {}), - ), - Component: withQueryRef(MainLayout), - Fallback: MainSkeleton, - ErrorBoundary: RootErrorBoundary, - children: [ - { - path: "", - Fallback: TabSkeleton, - Component: OverviewPage, - }, - ], - }, - { - path: "/documents/:documentId", - Component: lazy(() => import("#/pages/DocumentPageLoader")), - ErrorBoundary: DocumentPageErrorBoundary, - }, - { - path: "/documents", - loader: loaderFromQueryLoader(() => - loadQuery(consoleEnvironment, currentCompliancePortalGraphQuery, {}), - ), - Component: withQueryRef(MainLayout), - Fallback: MainSkeleton, - ErrorBoundary: RootErrorBoundary, - children: [ - { - path: "", - loader: loaderFromQueryLoader(() => - loadQuery(consoleEnvironment, currentTrustDocumentsQuery, {}), - ), - Fallback: TabSkeleton, - Component: withQueryRef(DocumentsPage), - }, - ], - }, - { - path: "/subprocessors", - loader: loaderFromQueryLoader(() => - loadQuery(consoleEnvironment, currentCompliancePortalGraphQuery, {}), - ), - Component: withQueryRef(MainLayout), - Fallback: MainSkeleton, - ErrorBoundary: RootErrorBoundary, - children: [ - { - path: "", - loader: loaderFromQueryLoader(() => - loadQuery(consoleEnvironment, currentTrustSubprocessorsQuery, {}), - ), - Fallback: TabSkeleton, - Component: withQueryRef(SubprocessorsPage), - }, - ], - }, - { - path: "/updates", - loader: loaderFromQueryLoader(() => - loadQuery(consoleEnvironment, currentCompliancePortalGraphQuery, {}), - ), - Component: withQueryRef(MainLayout), - Fallback: MainSkeleton, - ErrorBoundary: RootErrorBoundary, - children: [ - { - path: "", - loader: loaderFromQueryLoader(() => - loadQuery(consoleEnvironment, currentTrustUpdatesQuery, {}), - ), - Fallback: TabSkeleton, - Component: withQueryRef(UpdatesPage), - }, - ], - }, - // Fallback URL to the NotFound Page - { - path: "*", - Component: PageError, - }, -] satisfies AppRoute[]; - -export const router = createBrowserRouter(routes.map(routeFromAppRoute), {}); diff --git a/apps/trust/src/types.ts b/apps/trust/src/types.ts deleted file mode 100644 index 7917aec15..000000000 --- a/apps/trust/src/types.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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. - -export type NodeOf - = NonNullable extends - | { readonly edges: ReadonlyArray<{ readonly node: infer U }> } - | undefined - ? U - : never; - -export type ItemOf = T extends (infer U)[] ? U : never; diff --git a/apps/trust/src/vite-env.d.ts b/apps/trust/src/vite-env.d.ts deleted file mode 100644 index 43adc10cc..000000000 --- a/apps/trust/src/vite-env.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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. - -/// - -interface ImportMetaEnv { - readonly VITE_API_URL: string; -} - -interface ImportMeta { - readonly env: ImportMetaEnv; -} diff --git a/apps/trust/trust.go b/apps/trust/trust.go deleted file mode 100644 index b5b809836..000000000 --- a/apps/trust/trust.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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. - -package truststatics - -import "embed" - -//go:embed dist -var StaticFiles embed.FS diff --git a/apps/trust/tsconfig.app.json b/apps/trust/tsconfig.app.json deleted file mode 100644 index a60b37b47..000000000 --- a/apps/trust/tsconfig.app.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": false, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "paths": { - "#/*": ["./src/*"] - }, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/apps/trust/tsconfig.json b/apps/trust/tsconfig.json deleted file mode 100644 index 1ffef600d..000000000 --- a/apps/trust/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/apps/trust/tsconfig.node.json b/apps/trust/tsconfig.node.json deleted file mode 100644 index 87ae7cd5e..000000000 --- a/apps/trust/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "allowJs": true, - "target": "ES2022", - "lib": ["ES2023"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": false, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/apps/trust/vite.config.ts b/apps/trust/vite.config.ts deleted file mode 100644 index b32e5a4a1..000000000 --- a/apps/trust/vite.config.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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 { fileURLToPath, URL } from "node:url"; - -import babel from "@rolldown/plugin-babel"; -import tailwindcss from "@tailwindcss/vite"; -import react from "@vitejs/plugin-react"; -import { defineConfig } from "vite"; - -// https://vite.dev/config/ -// @vitejs/plugin-react@6 (Vite 8) no longer runs Babel, so the Relay tagged -// template transform is applied via @rolldown/plugin-babel instead. -export default defineConfig({ - plugins: [ - react(), - babel({ plugins: ["relay"] }), - tailwindcss(), - ], - build: { - assetsDir: "assets", - }, - base: "./", - server: { - port: 5175, - proxy: { - "^/trust/[^/]+/api": { - target: "http://localhost:8080", - changeOrigin: true, - }, - }, - }, - resolve: { - alias: { - "#": fileURLToPath(new URL("./src", import.meta.url)), - }, - }, -}); diff --git a/contrib/claude/file-naming.md b/contrib/claude/file-naming.md index 1dadcf969..080ea5404 100644 --- a/contrib/claude/file-naming.md +++ b/contrib/claude/file-naming.md @@ -5,7 +5,7 @@ Template files use the extension pattern `..tmpl`: ``` -pkg/trust/sitemap.xml.tmpl +pkg/complianceportal/visitor/sitemap.xml.tmpl pkg/server/mailactions/templates/page.html.tmpl pkg/cookiebanner/prompts/tracker_identification.txt.tmpl pkg/probo/templates/risk_list.json.tmpl diff --git a/contrib/claude/relay.md b/contrib/claude/relay.md index 8f2f49797..0c5aa46f2 100644 --- a/contrib/claude/relay.md +++ b/contrib/claude/relay.md @@ -17,7 +17,7 @@ Configured in `apps/console/src/environments.ts`. Each has its own store with 1- ## Relay compiler -Config lives in `relay.config.json` at the repo root with three projects (`core`, `iam`, `trust`) mapped to different source directories and schemas. Each project uses `schema` pointing to `base.graphql` and `schemaExtensions` pointing to the `graphql/` directory containing the per-entity schema files. Generated files go into `__generated__/` directories. +Config lives in `relay.config.json` at the repo root with three projects (`core`, `iam`, `complianceportal`) mapped to different source directories and schemas. Each project uses `schema` pointing to `base.graphql` and `schemaExtensions` pointing to the `graphql/` directory containing the per-entity schema files. Generated files go into `__generated__/` directories. ```sh make relay # merge split schemas + clean + compile diff --git a/contrib/lima/provision.sh b/contrib/lima/provision.sh index 40bfd1664..4f749f2e7 100755 --- a/contrib/lima/provision.sh +++ b/contrib/lima/provision.sh @@ -120,7 +120,7 @@ PROBOD_AUTH_COOKIE_SECRET="this-is-a-secure-secret-for-cookie-signing-at-least-3 PROBOD_AUTH_PASSWORD_PEPPER="this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes" \ PROBOD_ENCRYPTION_KEY="thisisnotasecretAAAAAAAAAAAAAAAAAAAAAAAAAAA=" \ PROBOD_OAUTH2_SERVER_SIGNING_KEY="$(cat "${OAUTH2_SIGNING_KEY_PATH}")" \ -PROBOD_API_CORS_ALLOWED_ORIGINS="http://${VM_IP}:8080,http://${VM_IP}:5173,http://${VM_IP}:5174,http://${VM_IP}:5175" \ +PROBOD_API_CORS_ALLOWED_ORIGINS="http://${VM_IP}:8080,http://${VM_IP}:5173,http://${VM_IP}:5174" \ PROBOD_AWS_ENDPOINT="http://127.0.0.1:8333" \ PROBOD_AWS_ACCESS_KEY_ID="probod" \ PROBOD_AWS_SECRET_ACCESS_KEY="thisisnotasecret" \ diff --git a/eslint.config.mjs b/eslint.config.mjs index 1fce7c0ad..604d1910a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -4,7 +4,7 @@ import { defineConfig, globalIgnores } from "eslint/config"; // Workspaces that are linted by this root config. Each gets the shared rule // sets below; everything else is ignored so a bare `eslint .` keeps the same // scope as the previous per-workspace configs. -const appDirs = ["apps/console/**", "apps/trust/**", "apps/compliance-portal/**"]; +const appDirs = ["apps/console/**", "apps/compliance-portal/**"]; const reactDirs = [...appDirs, "packages/ui/**", "packages/relay/**", "packages/routes/**"]; const lintedDirs = [...reactDirs, "packages/eslint-config/**"]; @@ -50,8 +50,8 @@ export default defineConfig([ { // compliance-portal mutates through the awaitable useMutation bound in // #/lib/relay/useMutation (over @probo/relay's createUseMutation), never - // react-relay's useMutation directly. Scoped to this app only: console and - // trust still use react-relay's useMutation. + // react-relay's useMutation directly. Scoped to this app only: console + // still uses react-relay's useMutation. files: ["apps/compliance-portal/**"], rules: { "no-restricted-imports": [ diff --git a/package-lock.json b/package-lock.json index 08150cc0d..8067470fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -594,292 +594,6 @@ "url": "https://github.com/sponsors/colinhacks" } }, - "apps/trust": { - "name": "@probo/trust", - "version": "0.0.0", - "dependencies": { - "@hookform/resolvers": "^5.0.1", - "@probo/helpers": "1.0.0", - "@probo/hooks": "1.0.0", - "@probo/i18n": "1.0.0", - "@probo/routes": "^1.0.0", - "@probo/ui": "1.0.0", - "clsx": "^2.1.1", - "react": "^19.2.7", - "react-dom": "^19.2.7", - "react-error-boundary": "^6.0.0", - "react-hook-form": "^7.56.4", - "react-pdf": "^10.3.0", - "react-relay": "^21.0.1", - "react-router": "^8.1.0", - "relay-runtime": "^21.0.1", - "usehooks-ts": "^3.1.1", - "zod": "^4.4.3" - }, - "devDependencies": { - "@babel/core": "^8.0.1", - "@rolldown/plugin-babel": "^0.2.3", - "@tailwindcss/vite": "^4.3.2", - "@types/babel__core": "^7.20.5", - "@types/node": "^26", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.2", - "babel-plugin-relay": "^21.0.1", - "graphql": "^17.0.1", - "tailwindcss": "^4.3.1", - "typescript": "~6.0.3", - "vite": "^8.1.2" - } - }, - "apps/trust/node_modules/@babel/code-frame": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-8.0.0.tgz", - "integrity": "sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^8.0.0", - "js-tokens": "^10.0.0" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/compat-data": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-8.0.0.tgz", - "integrity": "sha512-DOjnob/cXOUgDOozCDeq/aK2p5y8dUIVdf6tNhEV1HQRd6I8aQ4f4fbtHRVEvb6lP3BGomrKHiS8ICAASSVQSw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/core": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-8.0.1.tgz", - "integrity": "sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^8.0.0", - "@babel/generator": "^8.0.0", - "@babel/helper-compilation-targets": "^8.0.0", - "@babel/helpers": "^8.0.0", - "@babel/parser": "^8.0.0", - "@babel/template": "^8.0.0", - "@babel/traverse": "^8.0.0", - "@babel/types": "^8.0.0", - "@types/gensync": "^1.0.5", - "convert-source-map": "^2.0.0", - "empathic": "^2.0.1", - "gensync": "^1.0.0-beta.2", - "import-meta-resolve": "^4.2.0", - "json5": "^2.2.3", - "obug": "^2.1.1", - "semver": "^7.7.3" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "apps/trust/node_modules/@babel/generator": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0.tgz", - "integrity": "sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^8.0.0", - "@babel/types": "^8.0.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "@types/jsesc": "^2.5.0", - "jsesc": "^3.0.2" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/helper-compilation-targets": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-8.0.0.tgz", - "integrity": "sha512-JwculLABZvyPvyLBpwU/E/IbH2uM3mnxNtIJpxnIfb24y1PrdVxK5Dqjle4DpgqpGRnwgC7G8IkzPdSXZrO1Ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^8.0.0", - "@babel/helper-validator-option": "^8.0.0", - "browserslist": "^4.24.0", - "lru-cache": "^11.0.0", - "semver": "^7.7.3" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/helper-globals": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-8.0.0.tgz", - "integrity": "sha512-lLozHOM6sWWlxNo8CYqHy4MBZeTvHXNgVPBfPOGsjPKUzHC2Az9QwB6gxdQmpwHl6GlQtbGgS+lj5887guDiLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/helper-string-parser": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz", - "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/helper-validator-identifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz", - "integrity": "sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/helper-validator-option": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-8.0.0.tgz", - "integrity": "sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/helpers": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-8.0.0.tgz", - "integrity": "sha512-wfbi91pM3py96oIiJEz7qIpyXDytgr9zQC1HEWwlGNVRAEmItuU/0a41ZUKu1sJGyhhOIpc4t5vk4PYzt8wpsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^8.0.0", - "@babel/types": "^8.0.0" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/parser": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0.tgz", - "integrity": "sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^8.0.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/template": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-8.0.0.tgz", - "integrity": "sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^8.0.0", - "@babel/parser": "^8.0.0", - "@babel/types": "^8.0.0" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/traverse": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-8.0.0.tgz", - "integrity": "sha512-bxTj/W2VclGE6CctlfQOpxg8MPDzXArRqkOBePw8EHfebcjF7fETWSS3BriEECo+UiU/Yblq+xUtSImFu7cTbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^8.0.0", - "@babel/generator": "^8.0.0", - "@babel/helper-globals": "^8.0.0", - "@babel/parser": "^8.0.0", - "@babel/template": "^8.0.0", - "@babel/types": "^8.0.0", - "obug": "^2.1.1" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/@babel/types": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0.tgz", - "integrity": "sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^8.0.0", - "@babel/helper-validator-identifier": "^8.0.0" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - } - }, - "apps/trust/node_modules/js-tokens": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", - "dev": true, - "license": "MIT" - }, - "apps/trust/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "apps/trust/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "apps/trust/node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "examples/cookie-banner-react": { "name": "@probo/example-cookie-banner-react", "version": "0.0.0", @@ -4826,10 +4540,6 @@ "resolved": "packages/skills", "link": true }, - "node_modules/@probo/trust": { - "resolved": "apps/trust", - "link": true - }, "node_modules/@probo/tsconfig": { "resolved": "packages/tsconfig", "link": true diff --git a/packages/helpers/src/compliancePortalUrl.ts b/packages/helpers/src/compliancePortalUrl.ts deleted file mode 100644 index 63ad4f083..000000000 --- a/packages/helpers/src/compliancePortalUrl.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2025-2026 Probo Inc . -// -// 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. - -export function getCompliancePortalUrl(path: string): string { - const currentPath = window.location.pathname; - const trustMatch = currentPath.match(/^\/trust\/([^/]+)/); - - if (!trustMatch) { - return `/${path}`; - } - - return `../${path}`; -} diff --git a/packages/helpers/src/index.ts b/packages/helpers/src/index.ts index 8b63499af..b6164556d 100644 --- a/packages/helpers/src/index.ts +++ b/packages/helpers/src/index.ts @@ -122,7 +122,6 @@ export { fromMaxAgeSeconds, } from "./duration"; export { getTrackerTypeBadge, getTrackerSourceBadge } from "./tracker"; -export { getCompliancePortalUrl } from "./compliancePortalUrl"; export { detectSocialName } from "./socialUrl"; export { formatError, type GraphQLError } from "./error"; export { Role, roles, getAssignableRoles } from "./roles"; diff --git a/relay.config.json b/relay.config.json index 94ba92463..afe97274c 100644 --- a/relay.config.json +++ b/relay.config.json @@ -7,7 +7,6 @@ "sources": { "apps/console/src/pages/iam": "iam", "apps/console/src": "core", - "apps/trust/src": "trust", "apps/compliance-portal/src": "complianceportal" }, "projects": { @@ -43,16 +42,6 @@ "Map": "Record" } }, - "trust": { - "schema": "pkg/server/api/complianceportal/v1/schema.graphql", - "language": "typescript", - "noFutureProofEnums": true, - "customScalarTypes": { - "Datetime": "string", - "CursorKey": "string", - "EmailAddr": "string" - } - }, "complianceportal": { "schema": "pkg/server/api/complianceportal/v1/schema.graphql", "language": "typescript",