From 55e85e5f67dfb19408febb22932043001d62be94 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Fri, 26 Sep 2025 16:42:52 +0200 Subject: [PATCH] Add trust center v2 Signed-off-by: Jonathan --- GNUmakefile | 1 + apps/console/README.md | 55 +- apps/console/src/hooks/useFormWithSchema.ts | 6 +- apps/trust/.env.example | 1 + apps/trust/.gitattributes | 2 + apps/trust/.gitignore | 26 + apps/trust/README.md | 2 + apps/trust/eslint.config.js | 28 + apps/trust/graphql.config.yml | 5 + apps/trust/index.html | 37 ++ apps/trust/package.json | 57 ++ .../favicons/apple-touch-icon-114x114.png | Bin 0 -> 4390 bytes .../favicons/apple-touch-icon-120x120.png | Bin 0 -> 4583 bytes .../favicons/apple-touch-icon-144x144.png | Bin 0 -> 5726 bytes .../favicons/apple-touch-icon-152x152.png | Bin 0 -> 6170 bytes .../favicons/apple-touch-icon-57x57.png | Bin 0 -> 2115 bytes .../favicons/apple-touch-icon-60x60.png | Bin 0 -> 2190 bytes .../favicons/apple-touch-icon-72x72.png | Bin 0 -> 2660 bytes .../favicons/apple-touch-icon-76x76.png | Bin 0 -> 2861 bytes apps/trust/public/favicons/favicon-128.png | Bin 0 -> 4951 bytes apps/trust/public/favicons/favicon-16x16.png | Bin 0 -> 625 bytes .../trust/public/favicons/favicon-196x196.png | Bin 0 -> 8241 bytes apps/trust/public/favicons/favicon-32x32.png | Bin 0 -> 1203 bytes apps/trust/public/favicons/favicon-96x96.png | Bin 0 -> 3598 bytes apps/trust/public/favicons/favicon.ico | Bin 0 -> 34494 bytes apps/trust/public/favicons/mstile-144x144.png | Bin 0 -> 5726 bytes apps/trust/public/favicons/mstile-150x150.png | Bin 0 -> 12565 bytes apps/trust/public/favicons/mstile-310x150.png | Bin 0 -> 23170 bytes apps/trust/public/favicons/mstile-310x310.png | Bin 0 -> 35239 bytes apps/trust/public/favicons/mstile-70x70.png | Bin 0 -> 4951 bytes apps/trust/public/logos/gdpr.png | Bin 0 -> 4777 bytes apps/trust/public/logos/hipaa.png | Bin 0 -> 9226 bytes apps/trust/public/logos/iso27001.png | Bin 0 -> 4800 bytes apps/trust/public/logos/soc2.png | Bin 0 -> 4671 bytes apps/trust/public/logos/sox.png | Bin 0 -> 4715 bytes apps/trust/public/robots.txt | 2 + apps/trust/relay.config.json | 7 + apps/trust/src/App.tsx | 12 + apps/trust/src/components/AuditRow.tsx | 153 +++++ apps/trust/src/components/DocumentRow.tsx | 80 +++ apps/trust/src/components/NDADialog.tsx | 115 ++++ .../src/components/OrganizationSidebar.tsx | 125 +++++ apps/trust/src/components/PDFPreview.tsx | 130 +++++ apps/trust/src/components/PageError.tsx | 88 +++ .../src/components/RequestAccessDialog.tsx | 116 ++++ apps/trust/src/components/RowHeader.tsx | 9 + apps/trust/src/components/Rows.tsx | 18 + .../src/components/Skeletons/MainSkeleton.tsx | 25 + .../src/components/Skeletons/TabSkeleton.tsx | 11 + apps/trust/src/components/VendorRow.tsx | 53 ++ .../AuditRowDownloadMutation.graphql.ts | 92 +++ .../__generated__/AuditRowFragment.graphql.ts | 89 +++ .../DocumentRowDownloadMutation.graphql.ts | 92 +++ .../DocumentRowFragment.graphql.ts | 50 ++ .../NDADialogSignMutation.graphql.ts | 92 +++ .../RequestAccessDialogMutation.graphql.ts | 107 ++++ .../VendorRowFragment.graphql.ts | 84 +++ apps/trust/src/helpers/documents.ts | 10 + apps/trust/src/hooks/useDelayedEffect.ts | 19 + apps/trust/src/hooks/useFormWithSchema.ts | 13 + apps/trust/src/hooks/useIsAuthenticated.ts | 6 + apps/trust/src/hooks/useMutationWithToast.ts | 63 +++ apps/trust/src/hooks/useTrustCenter.ts | 13 + apps/trust/src/index.css | 10 + apps/trust/src/layouts/MainLayout.tsx | 67 +++ apps/trust/src/main.tsx | 27 + apps/trust/src/module.d.ts | 3 + apps/trust/src/pages/AccessPage.tsx | 80 +++ apps/trust/src/pages/DocumentsPage.tsx | 42 ++ apps/trust/src/pages/OverviewPage.tsx | 147 +++++ apps/trust/src/pages/SubprocessorsPage.tsx | 34 ++ .../__generated__/OverviewFragment.graphql.ts | 229 ++++++++ apps/trust/src/providers/AuthProvider.tsx | 13 + apps/trust/src/providers/RelayProviders.tsx | 146 +++++ .../src/providers/TranslatorProvider.tsx | 18 + .../src/providers/TrustCenterProvider.tsx | 20 + apps/trust/src/queries/TrustGraph.ts | 70 +++ .../TrustGraphDocumentsQuery.graphql.ts | 245 ++++++++ .../__generated__/TrustGraphQuery.graphql.ts | 525 ++++++++++++++++++ .../TrustGraphVendorsQuery.graphql.ts | 256 +++++++++ apps/trust/src/routes.tsx | 153 +++++ apps/trust/src/types.ts | 8 + apps/trust/src/vite-env.d.ts | 9 + apps/trust/tsconfig.app.json | 31 ++ apps/trust/tsconfig.json | 7 + apps/trust/tsconfig.node.json | 25 + apps/trust/vite.config.ts | 33 ++ package-lock.json | 333 ++++++++++- package.json | 2 +- packages/helpers/src/index.ts | 35 +- packages/helpers/src/string.ts | 8 + packages/ui/src/Atoms/Icons/Frame-1.svg | 3 - packages/ui/src/Atoms/Icons/Frame-2.svg | 3 - packages/ui/src/Atoms/Icons/Frame.svg | 3 - packages/ui/src/Atoms/Icons/IconMail.tsx | 19 + packages/ui/src/Atoms/Icons/IconMedal.tsx | 21 + .../ui/src/Atoms/Icons/IconMinusLarge.tsx | 19 + packages/ui/src/Atoms/Icons/IconPin.tsx | 27 + packages/ui/src/Atoms/Icons/Image.svg | 5 - packages/ui/src/Atoms/Icons/Send.svg | 3 - .../ui/src/Atoms/Icons/arrow-box-left.svg | 3 - .../Atoms/Icons/arrow-corner-down-left.svg | 3 - packages/ui/src/Atoms/Icons/arrow-down.svg | 3 - packages/ui/src/Atoms/Icons/arrow-inbox-1.svg | 3 - packages/ui/src/Atoms/Icons/arrow-inbox.svg | 3 - packages/ui/src/Atoms/Icons/arrow-link.svg | 4 - packages/ui/src/Atoms/Icons/arrow-up.svg | 3 - packages/ui/src/Atoms/Icons/bank.svg | 3 - packages/ui/src/Atoms/Icons/bell-2.svg | 3 - packages/ui/src/Atoms/Icons/block-1.svg | 3 - packages/ui/src/Atoms/Icons/block.svg | 3 - packages/ui/src/Atoms/Icons/book.svg | 3 - packages/ui/src/Atoms/Icons/calendar-1.svg | 4 - packages/ui/src/Atoms/Icons/calendar-2.svg | 3 - packages/ui/src/Atoms/Icons/checkmark-1.svg | 3 - .../ui/src/Atoms/Icons/checkmark-2-small.svg | 3 - packages/ui/src/Atoms/Icons/chevron-down.svg | 3 - .../Atoms/Icons/chevron-grabber-vertical.svg | 3 - packages/ui/src/Atoms/Icons/chevron-left.svg | 3 - packages/ui/src/Atoms/Icons/chevron-right.svg | 3 - .../Icons/chevron-triangle-down-small.svg | 3 - packages/ui/src/Atoms/Icons/chevron-up.svg | 3 - .../ui/src/Atoms/Icons/circle-check-1.svg | 4 - packages/ui/src/Atoms/Icons/circle-check.svg | 3 - packages/ui/src/Atoms/Icons/circle-info.svg | 3 - .../ui/src/Atoms/Icons/circle-progress.svg | 3 - .../src/Atoms/Icons/circle-questionmark-1.svg | 3 - .../Atoms/Icons/circle-questionmark-solid.svg | 3 - .../src/Atoms/Icons/circle-questionmark.svg | 5 - packages/ui/src/Atoms/Icons/circle-x.svg | 3 - packages/ui/src/Atoms/Icons/clock.svg | 3 - packages/ui/src/Atoms/Icons/collapse.svg | 3 - packages/ui/src/Atoms/Icons/cross-large-x.svg | 3 - .../Atoms/Icons/dot-grid-1x3-horizontal.svg | 5 - packages/ui/src/Atoms/Icons/expand.svg | 5 - packages/ui/src/Atoms/Icons/filter.svg | 5 - packages/ui/src/Atoms/Icons/fire-3.svg | 3 - packages/ui/src/Atoms/Icons/folder-2.svg | 3 - packages/ui/src/Atoms/Icons/folder-upload.svg | 3 - packages/ui/src/Atoms/Icons/generator.ts | 58 -- packages/ui/src/Atoms/Icons/group-1-1.svg | 6 - packages/ui/src/Atoms/Icons/group-1.svg | 3 - packages/ui/src/Atoms/Icons/home.svg | 3 - packages/ui/src/Atoms/Icons/import-2.svg | 4 - packages/ui/src/Atoms/Icons/in-progress.svg | 4 - packages/ui/src/Atoms/Icons/inbox-empty.svg | 3 - packages/ui/src/Atoms/Icons/index.tsx | 4 + packages/ui/src/Atoms/Icons/list-stack.svg | 5 - .../ui/src/Atoms/Icons/magnifying-glass.svg | 3 - packages/ui/src/Atoms/Icons/not-started.svg | 3 - packages/ui/src/Atoms/Icons/page-check-1.svg | 4 - packages/ui/src/Atoms/Icons/page-check.svg | 4 - packages/ui/src/Atoms/Icons/page-cross.svg | 4 - .../ui/src/Atoms/Icons/page-text-line.svg | 3 - .../ui/src/Atoms/Icons/page-text-solid.svg | 3 - packages/ui/src/Atoms/Icons/pencil.svg | 3 - .../ui/src/Atoms/Icons/people-add-2-line.svg | 3 - packages/ui/src/Atoms/Icons/people-add.svg | 5 - packages/ui/src/Atoms/Icons/plus-large.svg | 3 - packages/ui/src/Atoms/Icons/plus-small.svg | 3 - packages/ui/src/Atoms/Icons/priority.svg | 5 - .../ui/src/Atoms/Icons/radio-unchecked.svg | 3 - packages/ui/src/Atoms/Icons/rec-keyframe.svg | 3 - .../ui/src/Atoms/Icons/settings-gear-2.svg | 3 - packages/ui/src/Atoms/Icons/shield.svg | 3 - packages/ui/src/Atoms/Icons/signature.svg | 3 - .../Atoms/Icons/square-behind-square-2.svg | 3 - packages/ui/src/Atoms/Icons/store.svg | 5 - packages/ui/src/Atoms/Icons/sun.svg | 11 - packages/ui/src/Atoms/Icons/todo.svg | 4 - packages/ui/src/Atoms/Icons/todo2.svg | 7 - .../ui/src/Atoms/Icons/trash-can-solid.svg | 3 - packages/ui/src/Atoms/Icons/trash-can.svg | 7 - packages/ui/src/Atoms/Icons/upload.svg | 4 - packages/ui/src/Atoms/Icons/warning.svg | 1 - packages/ui/src/Atoms/Logo/Logo.tsx | 67 ++- packages/ui/src/Atoms/Table/Table.tsx | 12 +- .../Molecules/Badge/FrameworkLogo.stories.tsx | 17 + .../ui/src/Molecules/Badge/FrameworkLogo.tsx | 23 + packages/ui/src/Molecules/Dialog/Dialog.tsx | 16 +- packages/ui/src/index.ts | 1 + pkg/server/api/trust/v1/schema.graphql | 1 + 182 files changed, 4609 insertions(+), 425 deletions(-) create mode 100644 apps/trust/.env.example create mode 100644 apps/trust/.gitattributes create mode 100644 apps/trust/.gitignore create mode 100644 apps/trust/README.md create mode 100644 apps/trust/eslint.config.js create mode 100644 apps/trust/graphql.config.yml create mode 100644 apps/trust/index.html create mode 100644 apps/trust/package.json create mode 100644 apps/trust/public/favicons/apple-touch-icon-114x114.png create mode 100644 apps/trust/public/favicons/apple-touch-icon-120x120.png create mode 100644 apps/trust/public/favicons/apple-touch-icon-144x144.png create mode 100644 apps/trust/public/favicons/apple-touch-icon-152x152.png create mode 100644 apps/trust/public/favicons/apple-touch-icon-57x57.png create mode 100644 apps/trust/public/favicons/apple-touch-icon-60x60.png create mode 100644 apps/trust/public/favicons/apple-touch-icon-72x72.png create mode 100644 apps/trust/public/favicons/apple-touch-icon-76x76.png create mode 100644 apps/trust/public/favicons/favicon-128.png create mode 100644 apps/trust/public/favicons/favicon-16x16.png create mode 100644 apps/trust/public/favicons/favicon-196x196.png create mode 100644 apps/trust/public/favicons/favicon-32x32.png create mode 100644 apps/trust/public/favicons/favicon-96x96.png create mode 100644 apps/trust/public/favicons/favicon.ico create mode 100644 apps/trust/public/favicons/mstile-144x144.png create mode 100644 apps/trust/public/favicons/mstile-150x150.png create mode 100644 apps/trust/public/favicons/mstile-310x150.png create mode 100644 apps/trust/public/favicons/mstile-310x310.png create mode 100644 apps/trust/public/favicons/mstile-70x70.png create mode 100644 apps/trust/public/logos/gdpr.png create mode 100644 apps/trust/public/logos/hipaa.png create mode 100644 apps/trust/public/logos/iso27001.png create mode 100644 apps/trust/public/logos/soc2.png create mode 100644 apps/trust/public/logos/sox.png create mode 100644 apps/trust/public/robots.txt create mode 100644 apps/trust/relay.config.json create mode 100644 apps/trust/src/App.tsx create mode 100644 apps/trust/src/components/AuditRow.tsx create mode 100644 apps/trust/src/components/DocumentRow.tsx create mode 100644 apps/trust/src/components/NDADialog.tsx create mode 100644 apps/trust/src/components/OrganizationSidebar.tsx create mode 100644 apps/trust/src/components/PDFPreview.tsx create mode 100644 apps/trust/src/components/PageError.tsx create mode 100644 apps/trust/src/components/RequestAccessDialog.tsx create mode 100644 apps/trust/src/components/RowHeader.tsx create mode 100644 apps/trust/src/components/Rows.tsx create mode 100644 apps/trust/src/components/Skeletons/MainSkeleton.tsx create mode 100644 apps/trust/src/components/Skeletons/TabSkeleton.tsx create mode 100644 apps/trust/src/components/VendorRow.tsx create mode 100644 apps/trust/src/components/__generated__/AuditRowDownloadMutation.graphql.ts create mode 100644 apps/trust/src/components/__generated__/AuditRowFragment.graphql.ts create mode 100644 apps/trust/src/components/__generated__/DocumentRowDownloadMutation.graphql.ts create mode 100644 apps/trust/src/components/__generated__/DocumentRowFragment.graphql.ts create mode 100644 apps/trust/src/components/__generated__/NDADialogSignMutation.graphql.ts create mode 100644 apps/trust/src/components/__generated__/RequestAccessDialogMutation.graphql.ts create mode 100644 apps/trust/src/components/__generated__/VendorRowFragment.graphql.ts create mode 100644 apps/trust/src/helpers/documents.ts create mode 100644 apps/trust/src/hooks/useDelayedEffect.ts create mode 100644 apps/trust/src/hooks/useFormWithSchema.ts create mode 100644 apps/trust/src/hooks/useIsAuthenticated.ts create mode 100644 apps/trust/src/hooks/useMutationWithToast.ts create mode 100644 apps/trust/src/hooks/useTrustCenter.ts create mode 100644 apps/trust/src/index.css create mode 100644 apps/trust/src/layouts/MainLayout.tsx create mode 100644 apps/trust/src/main.tsx create mode 100644 apps/trust/src/module.d.ts create mode 100644 apps/trust/src/pages/AccessPage.tsx create mode 100644 apps/trust/src/pages/DocumentsPage.tsx create mode 100644 apps/trust/src/pages/OverviewPage.tsx create mode 100644 apps/trust/src/pages/SubprocessorsPage.tsx create mode 100644 apps/trust/src/pages/__generated__/OverviewFragment.graphql.ts create mode 100644 apps/trust/src/providers/AuthProvider.tsx create mode 100644 apps/trust/src/providers/RelayProviders.tsx create mode 100644 apps/trust/src/providers/TranslatorProvider.tsx create mode 100644 apps/trust/src/providers/TrustCenterProvider.tsx create mode 100644 apps/trust/src/queries/TrustGraph.ts create mode 100644 apps/trust/src/queries/__generated__/TrustGraphDocumentsQuery.graphql.ts create mode 100644 apps/trust/src/queries/__generated__/TrustGraphQuery.graphql.ts create mode 100644 apps/trust/src/queries/__generated__/TrustGraphVendorsQuery.graphql.ts create mode 100644 apps/trust/src/routes.tsx create mode 100644 apps/trust/src/types.ts create mode 100644 apps/trust/src/vite-env.d.ts create mode 100644 apps/trust/tsconfig.app.json create mode 100644 apps/trust/tsconfig.json create mode 100644 apps/trust/tsconfig.node.json create mode 100644 apps/trust/vite.config.ts delete mode 100644 packages/ui/src/Atoms/Icons/Frame-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/Frame-2.svg delete mode 100644 packages/ui/src/Atoms/Icons/Frame.svg create mode 100644 packages/ui/src/Atoms/Icons/IconMail.tsx create mode 100644 packages/ui/src/Atoms/Icons/IconMedal.tsx create mode 100644 packages/ui/src/Atoms/Icons/IconMinusLarge.tsx create mode 100644 packages/ui/src/Atoms/Icons/IconPin.tsx delete mode 100644 packages/ui/src/Atoms/Icons/Image.svg delete mode 100644 packages/ui/src/Atoms/Icons/Send.svg delete mode 100644 packages/ui/src/Atoms/Icons/arrow-box-left.svg delete mode 100644 packages/ui/src/Atoms/Icons/arrow-corner-down-left.svg delete mode 100644 packages/ui/src/Atoms/Icons/arrow-down.svg delete mode 100644 packages/ui/src/Atoms/Icons/arrow-inbox-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/arrow-inbox.svg delete mode 100644 packages/ui/src/Atoms/Icons/arrow-link.svg delete mode 100644 packages/ui/src/Atoms/Icons/arrow-up.svg delete mode 100644 packages/ui/src/Atoms/Icons/bank.svg delete mode 100644 packages/ui/src/Atoms/Icons/bell-2.svg delete mode 100644 packages/ui/src/Atoms/Icons/block-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/block.svg delete mode 100644 packages/ui/src/Atoms/Icons/book.svg delete mode 100644 packages/ui/src/Atoms/Icons/calendar-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/calendar-2.svg delete mode 100644 packages/ui/src/Atoms/Icons/checkmark-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/checkmark-2-small.svg delete mode 100644 packages/ui/src/Atoms/Icons/chevron-down.svg delete mode 100644 packages/ui/src/Atoms/Icons/chevron-grabber-vertical.svg delete mode 100644 packages/ui/src/Atoms/Icons/chevron-left.svg delete mode 100644 packages/ui/src/Atoms/Icons/chevron-right.svg delete mode 100644 packages/ui/src/Atoms/Icons/chevron-triangle-down-small.svg delete mode 100644 packages/ui/src/Atoms/Icons/chevron-up.svg delete mode 100644 packages/ui/src/Atoms/Icons/circle-check-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/circle-check.svg delete mode 100644 packages/ui/src/Atoms/Icons/circle-info.svg delete mode 100644 packages/ui/src/Atoms/Icons/circle-progress.svg delete mode 100644 packages/ui/src/Atoms/Icons/circle-questionmark-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/circle-questionmark-solid.svg delete mode 100644 packages/ui/src/Atoms/Icons/circle-questionmark.svg delete mode 100644 packages/ui/src/Atoms/Icons/circle-x.svg delete mode 100644 packages/ui/src/Atoms/Icons/clock.svg delete mode 100644 packages/ui/src/Atoms/Icons/collapse.svg delete mode 100644 packages/ui/src/Atoms/Icons/cross-large-x.svg delete mode 100644 packages/ui/src/Atoms/Icons/dot-grid-1x3-horizontal.svg delete mode 100644 packages/ui/src/Atoms/Icons/expand.svg delete mode 100644 packages/ui/src/Atoms/Icons/filter.svg delete mode 100644 packages/ui/src/Atoms/Icons/fire-3.svg delete mode 100644 packages/ui/src/Atoms/Icons/folder-2.svg delete mode 100644 packages/ui/src/Atoms/Icons/folder-upload.svg delete mode 100644 packages/ui/src/Atoms/Icons/generator.ts delete mode 100644 packages/ui/src/Atoms/Icons/group-1-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/group-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/home.svg delete mode 100644 packages/ui/src/Atoms/Icons/import-2.svg delete mode 100644 packages/ui/src/Atoms/Icons/in-progress.svg delete mode 100644 packages/ui/src/Atoms/Icons/inbox-empty.svg delete mode 100644 packages/ui/src/Atoms/Icons/list-stack.svg delete mode 100644 packages/ui/src/Atoms/Icons/magnifying-glass.svg delete mode 100644 packages/ui/src/Atoms/Icons/not-started.svg delete mode 100644 packages/ui/src/Atoms/Icons/page-check-1.svg delete mode 100644 packages/ui/src/Atoms/Icons/page-check.svg delete mode 100644 packages/ui/src/Atoms/Icons/page-cross.svg delete mode 100644 packages/ui/src/Atoms/Icons/page-text-line.svg delete mode 100644 packages/ui/src/Atoms/Icons/page-text-solid.svg delete mode 100644 packages/ui/src/Atoms/Icons/pencil.svg delete mode 100644 packages/ui/src/Atoms/Icons/people-add-2-line.svg delete mode 100644 packages/ui/src/Atoms/Icons/people-add.svg delete mode 100644 packages/ui/src/Atoms/Icons/plus-large.svg delete mode 100644 packages/ui/src/Atoms/Icons/plus-small.svg delete mode 100644 packages/ui/src/Atoms/Icons/priority.svg delete mode 100644 packages/ui/src/Atoms/Icons/radio-unchecked.svg delete mode 100644 packages/ui/src/Atoms/Icons/rec-keyframe.svg delete mode 100644 packages/ui/src/Atoms/Icons/settings-gear-2.svg delete mode 100644 packages/ui/src/Atoms/Icons/shield.svg delete mode 100644 packages/ui/src/Atoms/Icons/signature.svg delete mode 100644 packages/ui/src/Atoms/Icons/square-behind-square-2.svg delete mode 100644 packages/ui/src/Atoms/Icons/store.svg delete mode 100644 packages/ui/src/Atoms/Icons/sun.svg delete mode 100644 packages/ui/src/Atoms/Icons/todo.svg delete mode 100644 packages/ui/src/Atoms/Icons/todo2.svg delete mode 100644 packages/ui/src/Atoms/Icons/trash-can-solid.svg delete mode 100644 packages/ui/src/Atoms/Icons/trash-can.svg delete mode 100644 packages/ui/src/Atoms/Icons/upload.svg delete mode 100644 packages/ui/src/Atoms/Icons/warning.svg create mode 100644 packages/ui/src/Molecules/Badge/FrameworkLogo.stories.tsx create mode 100644 packages/ui/src/Molecules/Badge/FrameworkLogo.tsx diff --git a/GNUmakefile b/GNUmakefile index e05679d65..987769df0 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -176,3 +176,4 @@ goreleaser-snapshot: ## Build a snapshot release with goreleaser .PHONY: goreleaser-check goreleaser-check: ## Check goreleaser configuration goreleaser check + diff --git a/apps/console/README.md b/apps/console/README.md index da9844432..edbf97a48 100644 --- a/apps/console/README.md +++ b/apps/console/README.md @@ -1,54 +1 @@ -# React + TypeScript + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh - -## Expanding the ESLint configuration - -If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: - -```js -export default tseslint.config({ - extends: [ - // Remove ...tseslint.configs.recommended and replace with this - ...tseslint.configs.recommendedTypeChecked, - // Alternatively, use this for stricter rules - ...tseslint.configs.strictTypeChecked, - // Optionally, add this for stylistic rules - ...tseslint.configs.stylisticTypeChecked, - ], - languageOptions: { - // other options... - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - }, -}) -``` - -You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: - -```js -// eslint.config.js -import reactX from 'eslint-plugin-react-x' -import reactDom from 'eslint-plugin-react-dom' - -export default tseslint.config({ - plugins: { - // Add the react-x and react-dom plugins - 'react-x': reactX, - 'react-dom': reactDom, - }, - rules: { - // other rules... - // Enable its recommended typescript rules - ...reactX.configs['recommended-typescript'].rules, - ...reactDom.configs.recommended.rules, - }, -}) -``` +# Console app diff --git a/apps/console/src/hooks/useFormWithSchema.ts b/apps/console/src/hooks/useFormWithSchema.ts index 565c466d7..6a7de80be 100644 --- a/apps/console/src/hooks/useFormWithSchema.ts +++ b/apps/console/src/hooks/useFormWithSchema.ts @@ -1,10 +1,10 @@ import { useForm } from "react-hook-form"; -import type { z, ZodType } from "zod"; +import type { z, ZodTypeAny } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; -export function useFormWithSchema>( +export function useFormWithSchema( schema: T, - options: Parameters>>[0] + options: Parameters>>[0], ) { return useForm>({ ...options, diff --git a/apps/trust/.env.example b/apps/trust/.env.example new file mode 100644 index 000000000..460e575be --- /dev/null +++ b/apps/trust/.env.example @@ -0,0 +1 @@ +VITE_API_URL=http://localhost:8080 diff --git a/apps/trust/.gitattributes b/apps/trust/.gitattributes new file mode 100644 index 000000000..7a1fb9a7a --- /dev/null +++ b/apps/trust/.gitattributes @@ -0,0 +1,2 @@ +__generated__/*.graphql linguist-generated +__generated__/*.js linguist-generated diff --git a/apps/trust/.gitignore b/apps/trust/.gitignore new file mode 100644 index 000000000..b403dd978 --- /dev/null +++ b/apps/trust/.gitignore @@ -0,0 +1,26 @@ +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 new file mode 100644 index 000000000..0efe71567 --- /dev/null +++ b/apps/trust/README.md @@ -0,0 +1,2 @@ +# TrustCenter app + diff --git a/apps/trust/eslint.config.js b/apps/trust/eslint.config.js new file mode 100644 index 000000000..092408a9f --- /dev/null +++ b/apps/trust/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +) diff --git a/apps/trust/graphql.config.yml b/apps/trust/graphql.config.yml new file mode 100644 index 000000000..6b90c56ba --- /dev/null +++ b/apps/trust/graphql.config.yml @@ -0,0 +1,5 @@ +schema: '../../pkg/server/api/trust/v1/schema.graphql' +extensions: + endpoints: + TrustCenter: + url: http://localhost:8080/api/trust/v1/graphql diff --git a/apps/trust/index.html b/apps/trust/index.html new file mode 100644 index 000000000..d39ba7dd9 --- /dev/null +++ b/apps/trust/index.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Trust Center + + + +
+ + + + diff --git a/apps/trust/package.json b/apps/trust/package.json new file mode 100644 index 000000000..b93257c1b --- /dev/null +++ b/apps/trust/package.json @@ -0,0 +1,57 @@ +{ + "name": "@probo/trust", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "relay": "find src -type d -name \"__generated__\" -exec rm -rf {} + && npx relay-compiler ./relay.config.json", + "build": "tsc -b && vite build", + "lint": "eslint .", + "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/ui": "1.0.0", + "clsx": "^2.1.1", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-error-boundary": "^6.0.0", + "react-hook-form": "^7.56.4", + "react-pdf": "^10.1.0", + "react-relay": "^19.0.0", + "react-router": "^7.6.0", + "relay-runtime": "^19.0.0", + "usehooks-ts": "^3.1.1", + "zod": "^3.25.71" + }, + "devDependencies": { + "@eslint/js": "^9.25.0", + "@tailwindcss/vite": "^4.1.7", + "@types/node": "^22.15.21", + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", + "@types/react-relay": "^18.2.1", + "@types/relay-runtime": "^19.0.1", + "@vitejs/plugin-react": "^4.4.1", + "babel-plugin-relay": "^19.0.0", + "eslint": "^9.25.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^16.0.0", + "graphql": "^16.11.0", + "prettier": "^3.5.3", + "relay-compiler": "^19.0.0", + "tailwindcss": "^4.1.7", + "typescript": "~5.8.3", + "typescript-eslint": "^8.30.1", + "vite": "^6.3.6" + }, + "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 new file mode 100644 index 0000000000000000000000000000000000000000..444ea14a8f7eaf6132a1838af7c5b9331798cd09 GIT binary patch literal 4390 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 literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/apple-touch-icon-144x144.png b/apps/trust/public/favicons/apple-touch-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..7149269f04f059ab7d9bf2694cc0aaf107df4c8a GIT binary patch literal 5726 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 Q*Z=?k07*qoM6N<$f`+ss`2YX_ literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/apple-touch-icon-152x152.png b/apps/trust/public/favicons/apple-touch-icon-152x152.png new file mode 100644 index 0000000000000000000000000000000000000000..26b41822be4fc388ba069f6a616f561372017a5c GIT binary patch literal 6170 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 literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/apple-touch-icon-76x76.png b/apps/trust/public/favicons/apple-touch-icon-76x76.png new file mode 100644 index 0000000000000000000000000000000000000000..c40e2387c05fa0b26ca00960bb243a50984f86b0 GIT binary patch literal 2861 zcmV+|3)1w7P)FSs6eQY2*v|i-6U@Dqyyi z0mcCi08ax?hJ&H@Y>hJ#<_q{`Orq8U6^=}A?4l944|pOR4C(0_r6tT4@K*y{fF;h) zZA@bqureGB9UtnCLlWi-_-6q-0e=oBHkJ_rE)54m?+yIJAi`2)?dJ2Zg4xgnEFMT& zKf+RKxSubsWDP_JnA2B1dzSl@f#1Ua$?6L~uqDL}(BD5=%@@zWi(m;RH$X}yeF480 zI1E&c(xk>Znt+;cFm$rp6Tg9RM3yW=d4*2Z1dU>^PF@})6VTo+({Nm&xk<(_938R( zQ_41W6L!6$-8+oJLW6l1#F#rj&e^l$%s4fPr!YMu9qlq7ysxtVZ5O*=bMc?|^PHH* zDqy3OiVZ(?qDLp8sIX{Blq;`_uwYRPm&?A$9Qsh@xy^-af1!XxLMR$chbfXT;J*sk zI-FjdgxhVf;@U2*TiwZ|$(o~m2al+%U*~1-9+%xNu2$S7-fMubI5;m`kY!lDqKij1 zg}G#Dlwz;5MhKw9r?c$J2);6dxA(fx(?*PG@u7;Dq8U|8KQ+nEHnefhm*Tk}OoElG zI++qk^1~ZTiN!3bXswKy&l(j-5`6oHPPXl68X2qJqrx6cJ?rzeTUB;MJdFZxKEjF~ANQB+pxJhQc#OD>C!^w5KF z^O}>?o{|)8?vpXo$|HtJlQo{**2EdJ5+gZmTIA;&ti7j0w7Eyd%)yTcswZkZ^}A*Q zQ=N4ehKofPMwu~FNXpzQy&DxdMTt*m)3Yu31H&gv*Wt(~Ds>;JG#pomMkQP>gX)PI zv(8Ca_TMB4zIja-zj(l#t!cjG3;1K0yF59As=}scn>la3{gu!#VBgw58V7tgDr;WH&u6Fukqg^Rx$<+|_MBkS--Dl3e*IU34HKtIelHM<>?$)R+WmgzjOp$*AKy!)GHJY2o3f&=f^w-$+n#Lia=gxgP; znAP^lIW_oquWP5g!dk$lCE&UiaV>cu6j(33rW%^6{H&yTb8iio9Wl1aGz z2c`UZr*oc;Y9SS-34Gg}sG}^yT|a5Jq>6?C_pJ3fN*2H=(}lfw+S{_zkrTo$`+9`a z&amdmKf1A)9WRU98&ND+B<@;>ED(+pCd+WsttTx#^X48Gk3C%E^i-I0UYwd*F$psa zsQW0pg>sy*3onUMBOc5W4$ItohY!PgGA|<}32y$8aEwUZA(i&_QBcY2Zm{Na{c3$N zCmNl%49mU|VeUNf$l{INVz$%Kna-G*dqbF?o7`*Dq#{=T&&|Og-Apq z+$z&~QjEAI7mKHxj~!KbeV20%>e4GBti7v)BCqwOcEiuS=oYjpt>aN#tW#R5lSoLk zw#c+J%Oo>=yoF1|9mMV13T&%>UrhFE+NJwGrfPf1!Z4_FCK2%{q*`z+g%s z$I_$_~Z8BdGr;PIxDX2V%hQtZg*c>B_V3NLZ2%9{Qj&N z)dE|LW06&e$&P0?s=m1#a9({w^+js<_`$>hN2i;ex>;8`1&q!6>zx?W}cR0_PKG+ zn;)loqK2v(z3P`yn1=qNuECvae0(72Mht|_^iJ>BlO!yKLjV3}KKc0ux-KEh25O#p z0Hvtdz*nkMRi&9KUYjH^O~d6fP*k!=Q#UfVF?6{9o)Z2tjEqPI!o=)>s?wvT*`#uk+@al%?#hFX<|aUw9|6eV7K-ouK^D;y&WK#fKuq7jJ#kAc^#qxPt{ zn1q#Vi5dtM^V)C5&yq}-QrFlZqbR1`s;JbctkNkE*!%=D9B~5wJ)*LI zUp{;HxHwWj;zt*C%Oh$UG^Jw5`Z_~cVq)USjDBN%c1+<&y~?2v^LX#wJep37)b;V9 zp<-Snx0U*IyA9z(wc%Eoxr}t&+BoZ(-Fwc2wczZO(7hjxdrkVEdGt6$743jwwm8i=>QM*TEL7oSm?7>tZY- zDq|MGumvkyWXkB;YNya8V^$2Y1uJT%<~e_NXcQ2ZG0Usif|c;2f9`$UqD986MPm!G zn7D272s*f99LHqL!acT-h)cu;H++k7aGh@yP%mRvIkJt8b}_zI#<2^tD%~KmAj57^N)#^wZp2(x)1vN>xC=k?^s!M* zU-hT@1p7-N*EMBE*> zXq>2t`=Ap?9YdTL&1f{yL`4bes7Z`QUF%=6$K*6t224E11&%Uunht3cLm^LGX&Y zC8Q1Xf&R!^0g{401-K13$V?}SWX(EYp&AS=&9;H86d+JrGZk129GmTpi%4Y!aD^HS z)erWAgHnLN#0d(zekE`x;2-SGidae*xCvOK1~VTPGFE^c zgQ50J-kgyF1ZpRY1N~*-P%}L%VjHW0`D!qiKTjNOAp=`6rviozd? z_<_ZNiG7EHK0gF%YfhsW-W|#un_R!y$<84lxwx|iIKcL96|s}G2o6cDBJQ#P#*%JP z_(PwAlClPjteX^<<)AYKgV(1sb-y@M_KPv8F2VQ-aYm2UsI1Z`Ez|INbrc6A;(|!G zpsiid+^F#7b_ZL&aI(JM$+|Tzc6{YP*K_^Xa0Rdol0!f;ljlo{$s9ZJm*~u#73Ih| zJsf^Sl&RC=I9=u?w|$#~RquItdxeMh-u4gZDebzpz;V!}J%e_4Fq@RyIwEfvTUk!$yOew&_!1wI#L0%wW`XMpS zxuA;^=11`Rb7P-B{>a7Rd&_wDEstG8#3O1j^!=0qtYMg?btwwWJwC$4mvwQ-VbNT7 zXD5ICi<{eTsi6Kd=fH0^$67TQI#>j1C-^~cWtfcrLcnqJB3$+F9ZcCTp6l+UB^DDb zSyalBMWrOH>tYnB6oJ~B>A=U9-6oHiad?y)f7H(O8L?b%s;g|*Ikju$Wa=L9%;oVcbYmv0jgxSm}^cytD7gDZDvBP^rt1~ z?6-f6n|_>8ws)qCP%x@=3m!#*>le23)1Rw&Jh>0HTg92@ggNRPJ+hiBS1`)63mUgu z=NI?4a?zz-1?lJw1|i_)+uHDYr6_r6!7G5@uk+xet;{!PI8v=#6ctOEFaIuAbD!pvFu6UVocih#x$XPe$Q z#H&z%YXDA{&OHyba>S9tQ}`*)Ip4GbxKn%a6bwSZEw{IG^xWK;{jN^Ir)yl)f97KA z76%PG9CUOD;&Fk~sZ$Zq7&}g5%6>5pn;EriN?JEL&VkcoeENwi+a{a^rvR5;)hWaD z4Vv|zJ9+(8FYm1MvTm)5_#h&)Q>Vo_>%1^$o*S0sz3=3k$45*lfC$vq^iUwfz}({_ z+`FU|#isqjy2FB(UhwhElYZ8%&H78;$@mEgetMV6*JjHbx;|O$;@ne5Wc%@`2-McZ zC;%%kX`eVxztluone{=QaF^hT$4mIlBPF!9$kjHd6MnI%mE*r9XWAN#3T90oO{6=k z07$$b_TKY&bnbajwOsg`2G2e1XWr4H_|;uy(uEHYkHZhI3$T5gLrQyYw{B{=xF9xQ zyzZtBrX67II{p_Mom_ZUH8+px)`8o5%5&Yf8%-mO(`G`d1#I47S&3cw$mphdmrKLKz-PLAUe80O}aQ%V+xBjR? znlLgY+$H$Or{*0?fIwyTLt|bmz_mBFGj^OcbLhq$4lX>qnpa-*S<-$cY!Aut1AHdx z7xLEoKlqRs=U!mVe1FSkC*QxIiqKX$0?3w_q}iYlLreh_1s2}gX2}4x0y_@NW%J=%WZ*y?bdHErHFk%}r=;+8^jCrR39(e|L73_ha&!1s zzV7AmhfAckX_kGb#F;fm&T@8hlS0FeAz%UAZk-D+ksI-AZc@1UhKhXHk)scnUEL{d zhV$`9Zc~3>-YCHQQzMKXBX{h-bzuc97A)wP;ow7KoOp`7f|U>6Hy6Ini*H8=WM#ST z5fh({P@4+#y8$wY0kIF3k8^QcvR|YUw2sWv!CQ&z02hbIyvAVd4Fg9 zXD+sEHaD}$3k8sn+}MXlA1dX`?fEg^Pci$b9xlB~?hI$yQu7v0aY@+u$_(Wd8pq9( zSJctesPOnh`Q`QRvu~Wc?p1L}eB5F&!HdtEU&wNnmFXljop6^R7PG&u>V)|bsk?Fg z&#z1A>dK$`urXs3Jn%>>;jblh@SrFNG7p<$}s8omfn#t5Xn-+V=&Xe40Fu zxT#U$ncwHnKG$Q$CRp;D7RE`g>(_O7Op=xB<3V^lIzFFHG%Dz57p7L3GGWZv1c%L( zmm&Ma<0W)wmmDdbNp*4VThdBR@0tJ|DOTX!w>+%*SWYrYS{Ksm)A5(+M0<=ylx~Z5 zvpjBIMB0?7yIb(g6Z!G<&zu$Ij=NO?mAgeXC47yV2KV1xX1<{$y%b>2aoFe6DJe-1 ziwRU!(9y0)jjGK(L7wyX^8fl!)!a^M6a~KhuU%ZepcA*82Xqf!dcnu1YveWFO92Gw zlmLt++OgwwMvu`@TNPScltER-q@yCBG2?J~bK+c&{Ub+d+;mGDvt~z=R!#ows=Zy| zo}bB$ZwxAm;B@MY8k1o3*aRJI3eC+5ogLZPwb@7YAZrTx`DZSvPsLzR6qtW%H&-m^ zq^w-)CHB4#l#D_2?mNn8G_m%dj;z8+LO^9zg6a_oqESI}lR|ToGN{?ZoUhAs{$6_C zmy-pbgQmy0;u<5mx2G?o_w&=>`SaTzo_$Kbl`|1XG&J1n)0r?aLG7dj9qodqMup~P zN55N~3IVfb%UKT9G+4gO-k5*g=u8y$3Y3jXN`dFFq`Yt}yf zfl7_9AJfBe--#~_FPm)s{#!ife zOfH9}qq0ilu$fV2&5kmCMiiGTH#JnxJ?-bwCDyKM*q$ZnFVWfmKsnRD#s-DY|6$(y zFE7`qn-XW*0dWqV9%Eu%9H#>m#W)8jJ?V{ozeB(vB7twc>ES0otjO%mCa_%r+-{vw zqveeMAH1LW=^8>nNvTeCb%K$jG{%feFn&UUiId`t9HrrO?h<%rwTS7RyuE!?^!Ll% zSoOY}>#nLa9c#%1+ZAB!xP&xwDg>N)ZWt{g&~;;x#NpI&It@kh`E>k#ozilhiV6+4 z+Yqp#q%IwYL#}z>n?7dh9IkrL!&Tp_v~5kpegzmWZ)GeNgDF!D$IPMZdVol z1V79n>+Bv~hxRr}>MG3)3~X`Mt#$EV|5+|=Zy*`$^Z|6;P=u~72R@%pS-FuGCX+o< zq_QL&HZqtM#a#b%knRYiYp%1ycX92O8pt(uV(yUNgrc+s|QC6P45X&p%eB0S( zA?=P;Ge}K?m2Y@>=z&tc*qA??QlulJ-sw7Yv|25UcY^QTw5ytBe%`%a^>Z~__<)&wHmf^8uO+d>XpE}hCMLm5Vl)bN++C<19U zfZ1)0zUMSe^z-|4J=JyCxZcTo?|67;g(q)z95aC?O#ylniwPQbICd5t4SE= zlSn{T$(p|NpFK(4A<}K^>AU*>T>R~?ZW{7rk3mUjws0tD^2lguohQX7ttA0`A9V3QqpibO=e8%GTWtB;W% zMr=}m4cHJ4)->qslH){nebT`fTYcBY202+FvJaRXhAc_F*rfo1SAexv z-nBu}ez#-BCW@g^- z!B9PLqZK{q=`jwJkU{OlAzZIz4L2oa+lTbh5aL1Lc`JGm3d$JJErYlv;av~05jBJXwlxh{k@S@R7MSk>eXOqE^s=qZm^$UUoXcGm^v*k zt?ax&Sqq$w;J9=_o=h+mmQ#bFr3elNP6n2dVNyx`XL1z4>(kk1_{9UFz$?JX2o6z$ zp{2bScLs}TNhEK+3|JPZt*HX$0mlHdfT^U}f2dxjIC?zm)f*)O<4AcR&z<6Mk$D>#M?b99QPM2N^lmg!5<;GCT)RnSO3VX3u zzk95NJ8mhr^3TW?ja@siX&77aq^>B&z6=qJ>g-O8BHgCswGE?SXA`g?nYnEV{}1}i Vg4)!OasdDU002ovPDHLkV1iJAl}`Ww literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/favicon-16x16.png b/apps/trust/public/favicons/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..ab74a63363f7c1e64b0a0c5990eafc9f283917f6 GIT binary patch literal 625 zcmV-%0*?KOP)qkphzjWmbkEj3&DjTZgg3pKIk8yLc|nAa8r;{qy}SZVy)!%Hf_@6X2!)$(>5mJ zZ#QSocR0T@a|A#z8o2;W0w)0%p~{#N+(xhnS_nCu&r)KIY!>DX?XSUIpI9Rhl&o1AW20g6ORnbK(1}{p#_ts; zuI=$F^hO!CTQPE_48W7e-d*tFBR0uN3xE%^-K_j_8rOY3N#vje;OKE1uU8=@%)IcR z8!#BNxp=9<)zJ<1_SRXmH16Ksp1Cd+2mzt6BtEt>WEQub>&pcfn-u|oKOmb03_~FrNrk+N=g&O6n)a})|THkk~+@c_5(=eL`x;X{AZ&Rv{NMwXEB_U<+K+FsQ-Zh<}@IQvl#p= zIL|h4p#Bf0DH}*?W;T}s5WtnR!X$C00000 LNkvXXu0mjf3qBU2 literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/favicon-196x196.png b/apps/trust/public/favicons/favicon-196x196.png new file mode 100644 index 0000000000000000000000000000000000000000..f9a182d38125ce45fcbb1cfdd0f2b95b7a06160d GIT binary patch literal 8241 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 literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/favicon-32x32.png b/apps/trust/public/favicons/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..0d5835f0e4ef7ab9b7ecf91d25afb7cd50dd6cfa GIT binary patch literal 1203 zcmV;k1WfyhP)=#lxpdN1_iAJOBIVCK@u;;f)7F;D!pjhG*%?0QEa1QXi6qCNhZl; zGMRI>4`-6*%$`YR8v4JTwa?mXt-bCVtKhG#aRQw{2e1t&2fTn25ab3Ehyzhz0vHBP z0=?6LvH0>&+A87OfIgr#M?tw_2-rOx7#m(uASwJTP;#4vFCz?WpAL)-YsqIH7y6p((-hFV6GW z6EO;XrgAPN4D>tsu-nJ)zvZR7qC@l7)?5L$<|5eZmAt-xmd^~4mC3|(OBC{?^H<^6)WtdH6s;?)5f^WX^a^|#~z`qWhPRV`u$JzH*gtGFR|F^a+ z(b$yW+Esm-BbJYQsjC5_-PK=kN!GEJQWi*$>})h{ZIHd^%;LZ*5sx zt$@(U0=u4C;DH^BHkxU|+iw(cqA#-t1EcEo9*?wruWP-_C3$V%tU^Ehe&L$J0ov}3 zE40a=J#E%iVAqoiR8-oZ{$jtAo76QVxciKX&LNA=C63r@NZ`O+$$F%8{rN%I!F55pnBORvu1@kso|Ciw*tk4NJ6NF}|N z(SP2>D|?EG$F;QQBCftNV6|9(vAya|g#`Ke5^ug-w+WdBe15cmJ*h zIJ=;Y-|ObH87 zL1YOb$H9Y!{YVS%+SDF}yD1G?4%R literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/favicon-96x96.png b/apps/trust/public/favicons/favicon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..d45c995380cecfffd00b20cd846b3bad3ab69dd4 GIT binary patch literal 3598 zcmV+p4)O7cP)g6Fk=U)m*Sv^T%@B|5RiUog$j%p6ew2l6Wg-DAO*ICrfKWm zlI(7h%_ceLe1Du|$u662&YP3Vw*AeVKRTOp>GQnr^FEjNB2gm#j(`_f4x9=s0A>Mg zfFJMzuIyC@DA`NSyJ`U~@5*Ga6p+YXLqHVh1&#pwfqg(%G#DBx<;9Z7P5zF+Lf~>> zEr#%wQa)lDlL5MbCxC~d!O#J-4=|+we@9>$a5Hc*wbOcQ1r2x-*cc6lUM}{gq7>lo z2s8kjfonN&TYIr&fGxm{(O@Vx)sLrCfWISfCh!Qbu=H;`q38xKiv~k`kM*Ntnh}3T z;1XaLCxtJcR@ZC>h9SPtA6UT&c3dnjpFLKi6my2#-MZR}5(Zp=# zr0~nhLJS#?G1ddJLDn8l`uXK119awswfr9NZB7cm5-1qi1R&c3{2hV$z?&SWUXRDC zF?XIy`%IOlCJmQcN3rXu8Hq$(A{>@Edf3L>Zz;rMLg_KHXu#rVFw~uE@t@{65xykB z;?vT+@BJxOtW2?FS(+I$)uQgzbvSfT;l%!*9Sw%glCt^y0j8n-cQ|y` zt{dUP?#Uw6|IW!^O-YO<-zU!be@$e^-&9Cj2dpuB1v%RTv$xdcrV3V-dGj;;WNU=_ zGI=^j4%^uCLLINYYA1NmMz~*QbW}pILsPTHd*)~8JS)Y2tQjq-0W4gU;k47!y!NWS z*jp6I-w_z4ioL++)7bXg0p`8O+5z{-VH-QP*Yk%b>*;=@xHjhXYJ6sWf~&q5!{HE9 z#GSW!xaY?W#r`~%ni14mlL7P4kj&k;H}IF84(@$u z0FTGK5>~D<6&=e}ouPcy7hNyfBIB%^W{zi=kPthMC zS4H>^htB5PqA2##2HkX8V$(N$eC-R3M8ekoS2Pu#-{mlUpCn-_hN+4Nbj^ks^B0z8 z_lE{$zH&_?FZ{iH{=;E`9sp2p!jr1F0_M%nu>Km;{_;4&12X@0MH8>TR#?I6z6_W-0MlDB))uAV?~4yu%gp^ z!9~*`++Vy{E2aQRg0EgbT+%Z(ebdXH7b+7o&R>ub8mIbtY>bT5U=LWmW|ZY;ikI*n z{gsPHAE{j4@RL_0%=q(Tyl%2iTrmY){Y7z~|Ik4j-@B=DWs8zF|nX1p4>Cnu{GOq5y$3?HG?gT3=RQex5vgSFPU=?%B}#fPvawkb={GK#E-u3vG|J$GdrO2-CLtVwjbbkPdH7d zLga=99h+FdR}>emO$z7OAH2^^Z%-LNE)TCyVc-i3J%9AKm5BX`i9e z*rcIYl%SXuP&q@;_5AfV7tu)hhp5&zjV<>_IDKhplY8&Eqv#^cIL3=wf(DO{&zE6j zL?RlM8BL0N9~WGh6tbt93ctL+{H=ejw()^dFtPv{%egn7pm$6yaA% zCM6F~^z7AQgYUC{c90si zF6x~fQ2F?!BYgOx5uEipvPG6H5|+7sgTG|2u_S*-QDDXl&B&W)l`+s~qpwe<)7xf$P51$k8LEKhzS3QvzfK+Ox`VxpWqv zX5Rj1(h|>`%%$XLZPQq?EX|6QDVBGpaJh^CQ#7hAgs#K4ZuD8UXm6YXLajp4P+bGY~`EY_=E3xEp-ygQWKsX z5HpOal*Fe$7awzX6`L{mJL@&vZXK^r$L-d#LN)|#vsr6i3Zd(8+btgM`>D0@iDf1z zpP7QS)Y!1ZoQ_;een+^K6!c`MDtu?7k4JuKy?bnl0w#9&_8I0CpzF}zS9^=~W5W{H zf2EPIy303vM;;xOOs5!*g~y|d ztP~+^@yxbT&~@0p&BZ4#ZYitq0hD-5Vk9Bqa_e|J+A+5AD-O}6MU}{W7DLZbnQw3O zvGeKjn4F0yV9aHS4NJshwyd|I2``rLH;E~rOuLd4O(rez@Go54b4Np^wyXgr#sNCS zViK{K4X0Db=hyHzPVHCc|JCOcQ^4?0<^I$8=sG;}CntB`-oU}PDnC`W;2V=kiR8a+ z^z|C$x~3)#pMP>i^eZ;fneP9Y4D|NM^!CU|l2L$Z zZqbkhgqXB2{hT8nmw5GMJA3|F$L{~DW3bADd;v6J1>~dah8H91$&{M^*EHzwvk`n- zVSl&68?Pz6bwIIfxl$P!Q-EcNxUccJVb<#FbsP>IdmY&A?<}CwG>LRtA~hM6y)r#VZ6s^Rte8MkF!nC9Z0?^!AbvS~$i{DbE#>mJR3a|{jKpi-p zo|diG3NkXrX+f4DQi!p7Hr_NMC1Y%>UR8AcgzW(d%M~D!S(WAKyF*HeBxH<3$}B^~ zoLDs%bs91xW1J9Y8L1*>%}u0EaA%U^fT)adJfCHVg!yJxmLF&I${1%OT87A4uIac% znME9tF%G7*3^S|5bC}p&sG&C_h3Pz&ga218@^;t8vs8Xgc+Kug;RmydV?-l+pTj74eb z{ywoXUt9YL)dMu(A;>Bq8Vq#Oz#~3H6>?xm@QDTbv@FDYNX!abnre;Q$fds}8=i@d`dRJ4;o_BjCC3r=_ zgXZ(gPNy!suwxpa0as3TzWk)NA{q>B2d+j?2?yU6Ysw2s+)K1Z(SWP7GJO{Xjde5_ z+KQk#di#J_g{73;N@|px+1Xm?2ge*Ovs(KACI{vN`^6M+%Hr}KM_6IHF^({wwB_fR z(p|~gtrfss6d5NR=vIVW(Z#177d;?@A*&UW+5CwVaLmvZ9!HAr9Q=nJ8vCsURd%Im{ z(c)><3o;loxC!Hc=5_f&Rxt<}>uerl6R^oYH{eBQImV%&3owpGYF%iDJ~xk6=_0_mNF0m-6EO2lk@9 UT6k69{r~^~07*qoM6N<$f?de?C;$Ke literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/favicon.ico b/apps/trust/public/favicons/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d3925d54e8b720c5cb5a854d94590f15256076cc GIT binary patch literal 34494 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 Q*Z=?k07*qoM6N<$f`+ss`2YX_ literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/mstile-150x150.png b/apps/trust/public/favicons/mstile-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..a1b24266348e3a1fb2798e468c6bb351d4b5512a GIT binary patch literal 12565 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 Gf&T}m<6=+% literal 0 HcmV?d00001 diff --git a/apps/trust/public/favicons/mstile-310x150.png b/apps/trust/public/favicons/mstile-310x150.png new file mode 100644 index 0000000000000000000000000000000000000000..33898ee97022cc152a3c971166c41bb7ed76cb18 GIT binary patch literal 23170 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 Vg4)!OasdDU002ovPDHLkV1iJAl}`Ww literal 0 HcmV?d00001 diff --git a/apps/trust/public/logos/gdpr.png b/apps/trust/public/logos/gdpr.png new file mode 100644 index 0000000000000000000000000000000000000000..72510b40a70416c60fb9a1b8197300c639a80b19 GIT binary patch literal 4777 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 literal 0 HcmV?d00001 diff --git a/apps/trust/public/logos/iso27001.png b/apps/trust/public/logos/iso27001.png new file mode 100644 index 0000000000000000000000000000000000000000..00dff487edf7d1abf699457dfbfd46a5efbbd311 GIT binary patch literal 4800 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 B!#w~1 literal 0 HcmV?d00001 diff --git a/apps/trust/public/logos/sox.png b/apps/trust/public/logos/sox.png new file mode 100644 index 0000000000000000000000000000000000000000..7daf0bef5d69497c8113a28515aa670543b162a9 GIT binary patch literal 4715 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 + + + + ); +} diff --git a/apps/trust/src/components/AuditRow.tsx b/apps/trust/src/components/AuditRow.tsx new file mode 100644 index 000000000..31df66736 --- /dev/null +++ b/apps/trust/src/components/AuditRow.tsx @@ -0,0 +1,153 @@ +import { graphql } from "relay-runtime"; +import type { AuditRowFragment$key } from "./__generated__/AuditRowFragment.graphql"; +import { useFragment } from "react-relay"; +import { + Breadcrumb, + Button, + Dialog, + DialogContent, + FrameworkLogo, + IconArrowInbox, + IconLock, + IconMedal, + Spinner, + Table, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { useIsAuthenticated } from "/hooks/useIsAuthenticated"; +import type { AuditRowDownloadMutation } from "./__generated__/AuditRowDownloadMutation.graphql"; +import { useMutationWithToasts } from "/hooks/useMutationWithToast"; +import { downloadFile } from "@probo/helpers"; +import type { PropsWithChildren } from "react"; +import { useLocation } from "react-router"; +import { RequestAccessDialog } from "/components/RequestAccessDialog.tsx"; + +const downloadMutation = graphql` + mutation AuditRowDownloadMutation($input: ExportReportPDFInput!) { + exportReportPDF(input: $input) { + data + } + } +`; + +const auditRowFragment = graphql` + fragment AuditRowFragment on Audit { + report { + id + filename + } + framework { + id + name + } + } +`; + +export function AuditRow(props: { audit: AuditRowFragment$key }) { + const audit = useFragment(auditRowFragment, props.audit); + const { __ } = useTranslate(); + const isAuthenticated = useIsAuthenticated(); + const [commitDownload, downloading] = + useMutationWithToasts(downloadMutation); + const handleDownload = () => { + if (!audit.report?.id) { + return; + } + commitDownload({ + variables: { + input: { + reportId: audit.report.id, + }, + }, + onSuccess(response) { + downloadFile(response.exportReportPDF.data, audit.report!.filename); + }, + }); + }; + return ( +
+
+ + {audit.framework.name} +
+ {audit.report ? ( + isAuthenticated ? ( + + ) : ( + + + + ) + ) : ( + {__("No report")} + )} +
+ ); +} + +export function AuditRowAvatar(props: { audit: AuditRowFragment$key }) { + const audit = useFragment(auditRowFragment, props.audit); + return ( + + + + ); +} + +function AuditDialog( + props: PropsWithChildren<{ audit: AuditRowFragment$key }>, +) { + 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}

+

Framework description

+ + +
+
+
+ ); +} diff --git a/apps/trust/src/components/DocumentRow.tsx b/apps/trust/src/components/DocumentRow.tsx new file mode 100644 index 000000000..f45a2fc9d --- /dev/null +++ b/apps/trust/src/components/DocumentRow.tsx @@ -0,0 +1,80 @@ +import { graphql } from "relay-runtime"; +import type { DocumentRowFragment$key } from "./__generated__/DocumentRowFragment.graphql"; +import { useFragment } from "react-relay"; +import { + Button, + IconArrowInbox, + IconLock, + IconPageTextLine, + Spinner, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { useIsAuthenticated } from "/hooks/useIsAuthenticated"; +import type { DocumentRowDownloadMutation } from "./__generated__/DocumentRowDownloadMutation.graphql"; +import { useMutationWithToasts } from "/hooks/useMutationWithToast"; +import { downloadFile } from "@probo/helpers"; +import { RequestAccessDialog } from "/components/RequestAccessDialog.tsx"; + +const downloadMutation = graphql` + mutation DocumentRowDownloadMutation($input: ExportDocumentPDFInput!) { + exportDocumentPDF(input: $input) { + data + } + } +`; + +const documentRowFragment = graphql` + fragment DocumentRowFragment on Document { + id + title + } +`; + +export function DocumentRow(props: { document: DocumentRowFragment$key }) { + const document = useFragment(documentRowFragment, props.document); + const { __ } = useTranslate(); + const isAuthenticated = useIsAuthenticated(); + const [commitDownload, downloading] = + useMutationWithToasts(downloadMutation); + const handleDownload = () => { + commitDownload({ + variables: { + input: { + documentId: document.id, + }, + }, + onSuccess(response) { + downloadFile(response.exportDocumentPDF.data, document.title); + }, + }); + }; + return ( +
+
+ + {document.title} +
+ {isAuthenticated ? ( + + ) : ( + + + + )} +
+ ); +} diff --git a/apps/trust/src/components/NDADialog.tsx b/apps/trust/src/components/NDADialog.tsx new file mode 100644 index 000000000..9f1780335 --- /dev/null +++ b/apps/trust/src/components/NDADialog.tsx @@ -0,0 +1,115 @@ +import { Button, Card, Logo, Spinner } from "@probo/ui"; +import { sprintf } from "@probo/helpers"; +import { useTranslate } from "@probo/i18n"; +import { useEffect } from "react"; +import { PDFPreview } from "./PDFPreview"; +import { useWindowSize } from "usehooks-ts"; +import clsx from "clsx"; +import { graphql } from "relay-runtime"; +import { useMutationWithToasts } from "/hooks/useMutationWithToast"; + +const signMutation = graphql` + mutation NDADialogSignMutation($input: AcceptNonDisclosureAgreementInput!) { + acceptNonDisclosureAgreement(input: $input) { + success + } + } +`; + +export function NDADialog({ + name, + url, + fileName, + trustCenterId, +}: { + name: string; + url?: string | null; + fileName?: string | null; + trustCenterId: string; +}) { + const { __ } = useTranslate(); + useEffect(() => { + document.body.style.setProperty("overflow", "hidden"); + return () => { + document.body.style.removeProperty("overflow"); + }; + }, []); + const { width } = useWindowSize(); + const isMobile = width < 1100; + const isDesktop = !isMobile; + const [commitSigning, isSigning] = useMutationWithToasts(signMutation, { + onSuccess: () => { + window.location.reload(); + }, + }); + + const handleSign = () => { + commitSigning({ + variables: { + input: { + trustCenterId, + }, + }, + }); + }; + + return ( +
+ ); +} diff --git a/apps/trust/src/components/OrganizationSidebar.tsx b/apps/trust/src/components/OrganizationSidebar.tsx new file mode 100644 index 000000000..4d8cffa60 --- /dev/null +++ b/apps/trust/src/components/OrganizationSidebar.tsx @@ -0,0 +1,125 @@ +import { useTranslate } from "@probo/i18n"; +import { Button, Card, IconBlock, IconLock, IconMedal } from "@probo/ui"; +import type { TrustGraphQuery$data } from "/queries/__generated__/TrustGraphQuery.graphql"; +import type { PropsWithChildren } from "react"; +import { domain } from "@probo/helpers"; +import { AuditRowAvatar } from "./AuditRow"; +import { RequestAccessDialog } from "./RequestAccessDialog"; +import { useIsAuthenticated } from "/hooks/useIsAuthenticated"; + +export function OrganizationSidebar({ + trustCenter, +}: { + trustCenter: TrustGraphQuery$data["trustCenterBySlug"]; +}) { + const { __ } = useTranslate(); + const isAuthenticated = useIsAuthenticated(); + + if (!trustCenter) { + return null; + } + + return ( + +
+ {trustCenter.organization.logoUrl ? ( + + ) : ( +
+ )} +

{trustCenter.organization.name}

+

+ {trustCenter.organization.description} +

+ +
+ + {/* Business information */} +
+

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

+ {trustCenter.organization.websiteUrl && ( + + + + {domain(trustCenter.organization.websiteUrl)} + + + + )} + {trustCenter.organization.email && ( + + {trustCenter.organization.email} + + )} + {trustCenter.organization.headquarterAddress && ( + + {trustCenter.organization.headquarterAddress} + + )} + +
+ + {/* Certifications */} +
+

+ + {__("Certifications")} +

+
+ {trustCenter.audits.edges.map((audit) => ( + + ))} + {trustCenter.audits.edges.map((audit) => ( + + ))} + {trustCenter.audits.edges.map((audit) => ( + + ))} +
+
+ +
+ + {/* Actions */} + {!isAuthenticated && ( + + + + )} + {/* */} +
+ + ); +} + +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 new file mode 100644 index 000000000..8e378115c --- /dev/null +++ b/apps/trust/src/components/PDFPreview.tsx @@ -0,0 +1,130 @@ +import { Document, Page, pdfjs } from "react-pdf"; +import "react-pdf/dist/Page/TextLayer.css"; +import "react-pdf/dist/Page/AnnotationLayer.css"; +import { type ComponentProps, useRef, useState } from "react"; +import { + IconArrowInbox, + IconChevronLeft, + IconChevronRight, + IconPlusLarge, + Spinner, +} from "@probo/ui"; +import { times } from "@probo/helpers"; +import { IconMinusLarge } from "@probo/ui/src/Atoms/Icons/IconMinusLarge.tsx"; + +// 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 movePage = (direction: 1 | -1) => () => { + if (currentPage === 1 && direction === -1) { + return; + } + const newPage = currentPage + direction; + const page = documentRef.current?.pages.current[newPage - 1]; + if (!page) { + return; + } + page.scrollIntoView({ + behavior: "smooth", + block: "start", + inline: "center", + }); + setCurrentPage(newPage); + }; + + const resolveCurrentPage = () => { + 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) { + return setCurrentPage(i + 1); + } + } + }; + + 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 new file mode 100644 index 000000000..d4cbda36f --- /dev/null +++ b/apps/trust/src/components/PageError.tsx @@ -0,0 +1,88 @@ +import { useLocation, useRouteError } from "react-router"; +import { IconPageCross } from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { useEffect, useRef } from "react"; + +const classNames = { + wrapper: "py-10 text-center space-y-2 ", + title: "text-2xl flex gap-2 font-semibold items-center justify-center", + description: "text-base text-txt-tertiary", + detail: + "text-sm text-txt-tertiary font-mono text-start border border-border-low p-2 rounded bg-level-1 mt-2", +}; + +type Props = { + resetErrorBoundary?: () => void; + error?: string; +}; + +export function PageError({ resetErrorBoundary, error: propsError }: Props) { + const error = useRouteError() ?? propsError; + const { __ } = useTranslate(); + const location = useLocation(); + const baseLocation = useRef(location); + + // Reset error boundary on page change + useEffect(() => { + if ( + location.pathname !== baseLocation.current.pathname && + resetErrorBoundary + ) { + resetErrorBoundary(); + } + }, [location, resetErrorBoundary]); + + if (!error || (error && error.toString().includes("PAGE_NOT_FOUND"))) { + return ( +
+

+ + {__("Page not found")} +

+

+ {__("The page you are looking for does not exist")} +

+
+ ); + } + + if ( + error + .toString() + .toLowerCase() + .match(/(token|expired|invalid|401|unauthorized)/) + ) { + const isExpiredToken = error.toString().toLowerCase().includes("expired"); + const title = isExpiredToken + ? __("Expired token") + : __("Invalid Access Link"); + const description = isExpiredToken + ? __( + "This access link has expired. Trust center 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 ( +
+

+ + {title} +

+

{description}

+
+ ); + } + + return ( +
+

{__("Unexpected error :(")}

+
+ + {__("Something went wrong")} + +

{error.toString()}

+
+
+ ); +} diff --git a/apps/trust/src/components/RequestAccessDialog.tsx b/apps/trust/src/components/RequestAccessDialog.tsx new file mode 100644 index 000000000..f5e317a5e --- /dev/null +++ b/apps/trust/src/components/RequestAccessDialog.tsx @@ -0,0 +1,116 @@ +import { + Button, + Dialog, + DialogContent, + DialogFooter, + DialogTitle, + Field, + useDialogRef, + useToast, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { sprintf } from "@probo/helpers"; +import { z } from "zod"; +import { useFormWithSchema } from "/hooks/useFormWithSchema"; +import { graphql } from "relay-runtime"; +import { useMutationWithToasts } from "/hooks/useMutationWithToast"; +import { useTrustCenter } from "/hooks/useTrustCenter"; + +type Props = { + children: React.ReactNode; +}; + +const schema = z.object({ + name: z.string(), + email: z.string().email(), +}); + +const requestAccessMutation = graphql` + mutation RequestAccessDialogMutation($input: CreateTrustCenterAccessInput!) { + createTrustCenterAccess(input: $input) { + trustCenterAccess { + id + } + } + } +`; + +export function RequestAccessDialog({ children }: Props) { + const trustCenter = useTrustCenter(); + const { toast } = useToast(); + const { __ } = useTranslate(); + const { handleSubmit, register } = useFormWithSchema(schema, { + defaultValues: { + name: "", + email: "", + }, + }); + const dialogRef = useDialogRef(); + const [commitRequestAccess, isRequestingAccess] = useMutationWithToasts( + requestAccessMutation, + { + onSuccess: () => { + toast({ + title: __("Success"), + description: __("Access request submitted successfully"), + variant: "success", + }); + dialogRef.current?.close(); + }, + }, + ); + + const onSubmit = handleSubmit((data) => { + commitRequestAccess({ + variables: { + input: { + trustCenterId: trustCenter.id, + name: data.name, + email: data.email, + }, + }, + }); + }); + return ( + +
+ + {__("Request access to documentation")} + + +

+ {sprintf( + __( + "Request access to %s's Trust Center. Your request will be reviewed and you will receive an email notification with access instructions if approved.", + ), + trustCenter.organization.name, + )} +

+
+ + +
+
+ + + +
+
+ ); +} diff --git a/apps/trust/src/components/RowHeader.tsx b/apps/trust/src/components/RowHeader.tsx new file mode 100644 index 000000000..98172bd6f --- /dev/null +++ b/apps/trust/src/components/RowHeader.tsx @@ -0,0 +1,9 @@ +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 new file mode 100644 index 000000000..20e3f4528 --- /dev/null +++ b/apps/trust/src/components/Rows.tsx @@ -0,0 +1,18 @@ +import type { PropsWithChildren } from "react"; +import clsx from "clsx"; + +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 new file mode 100644 index 000000000..644eda575 --- /dev/null +++ b/apps/trust/src/components/Skeletons/MainSkeleton.tsx @@ -0,0 +1,25 @@ +import { Skeleton, TabLink, Tabs } from "@probo/ui"; +import { TabSkeleton } from "./TabSkeleton"; +import { useParams } from "react-router"; +import { useTranslate } from "@probo/i18n"; + +export function MainSkeleton() { + const { slug } = useParams<{ slug: string }>(); + const baseTabUrl = `/trust/${slug}`; + const { __ } = useTranslate(); + return ( +
+ +
+ + {__("Overview")} + {__("Documents")} + + {__("Subprocessors")} + + + +
+
+ ); +} diff --git a/apps/trust/src/components/Skeletons/TabSkeleton.tsx b/apps/trust/src/components/Skeletons/TabSkeleton.tsx new file mode 100644 index 000000000..619555748 --- /dev/null +++ b/apps/trust/src/components/Skeletons/TabSkeleton.tsx @@ -0,0 +1,11 @@ +import { Skeleton } from "@probo/ui"; + +export function TabSkeleton() { + return ( +
+ + + +
+ ); +} diff --git a/apps/trust/src/components/VendorRow.tsx b/apps/trust/src/components/VendorRow.tsx new file mode 100644 index 000000000..e24564c30 --- /dev/null +++ b/apps/trust/src/components/VendorRow.tsx @@ -0,0 +1,53 @@ +import { graphql } from "relay-runtime"; +import type { VendorRowFragment$key } from "./__generated__/VendorRowFragment.graphql"; +import { useFragment } from "react-relay"; +import { IconPin } from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { faviconUrl, getCountryName } from "@probo/helpers"; + +const vendorRowFragment = graphql` + fragment VendorRowFragment on Vendor { + id + name + category + websiteUrl + privacyPolicyUrl + countries + } +`; + +export function VendorRow(props: { vendor: VendorRowFragment$key }) { + const vendor = useFragment(vendorRowFragment, props.vendor); + const logo = faviconUrl(vendor.websiteUrl); + const { __ } = useTranslate(); + + return ( +
+ {logo ? ( + + ) : ( +
+ )} +
+
{vendor.name}
+ {vendor.privacyPolicyUrl && ( + + {vendor.privacyPolicyUrl.split("//").at(-1)} + + )} +
+ + + {vendor.countries + .map((country) => getCountryName(__, country)) + .join(", ")} + +
+
+
+ ); +} diff --git a/apps/trust/src/components/__generated__/AuditRowDownloadMutation.graphql.ts b/apps/trust/src/components/__generated__/AuditRowDownloadMutation.graphql.ts new file mode 100644 index 000000000..9853f3d2d --- /dev/null +++ b/apps/trust/src/components/__generated__/AuditRowDownloadMutation.graphql.ts @@ -0,0 +1,92 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type ExportReportPDFInput = { + reportId: string; +}; +export type AuditRowDownloadMutation$variables = { + input: ExportReportPDFInput; +}; +export type AuditRowDownloadMutation$data = { + readonly exportReportPDF: { + readonly data: string; + }; +}; +export type AuditRowDownloadMutation = { + response: AuditRowDownloadMutation$data; + variables: AuditRowDownloadMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "ExportReportPDFPayload", + "kind": "LinkedField", + "name": "exportReportPDF", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "data", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "AuditRowDownloadMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "AuditRowDownloadMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "79de6a9f2755587818dac20ec392b8e7", + "id": null, + "metadata": {}, + "name": "AuditRowDownloadMutation", + "operationKind": "mutation", + "text": "mutation AuditRowDownloadMutation(\n $input: ExportReportPDFInput!\n) {\n exportReportPDF(input: $input) {\n data\n }\n}\n" + } +}; +})(); + +(node as any).hash = "e3d7ceb7a0da979dad83b1b8289e192e"; + +export default node; diff --git a/apps/trust/src/components/__generated__/AuditRowFragment.graphql.ts b/apps/trust/src/components/__generated__/AuditRowFragment.graphql.ts new file mode 100644 index 000000000..c437da8c2 --- /dev/null +++ b/apps/trust/src/components/__generated__/AuditRowFragment.graphql.ts @@ -0,0 +1,89 @@ +/** + * @generated SignedSource<<5ad8bcd5ca3b7635248d13cef0a24edf>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type AuditRowFragment$data = { + readonly framework: { + readonly id: string; + readonly name: string; + }; + readonly report: { + readonly filename: string; + readonly id: string; + } | null | undefined; + readonly " $fragmentType": "AuditRowFragment"; +}; +export type AuditRowFragment$key = { + readonly " $data"?: AuditRowFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"AuditRowFragment">; +}; + +const node: ReaderFragment = (function(){ +var v0 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "AuditRowFragment", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Report", + "kind": "LinkedField", + "name": "report", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "filename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Framework", + "kind": "LinkedField", + "name": "framework", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Audit", + "abstractKey": null +}; +})(); + +(node as any).hash = "255e447eb5ac9b4cb889e7a8f0463902"; + +export default node; diff --git a/apps/trust/src/components/__generated__/DocumentRowDownloadMutation.graphql.ts b/apps/trust/src/components/__generated__/DocumentRowDownloadMutation.graphql.ts new file mode 100644 index 000000000..aff494c9f --- /dev/null +++ b/apps/trust/src/components/__generated__/DocumentRowDownloadMutation.graphql.ts @@ -0,0 +1,92 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type ExportDocumentPDFInput = { + documentId: string; +}; +export type DocumentRowDownloadMutation$variables = { + input: ExportDocumentPDFInput; +}; +export type DocumentRowDownloadMutation$data = { + readonly exportDocumentPDF: { + readonly data: string; + }; +}; +export type DocumentRowDownloadMutation = { + response: DocumentRowDownloadMutation$data; + variables: DocumentRowDownloadMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "ExportDocumentPDFPayload", + "kind": "LinkedField", + "name": "exportDocumentPDF", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "data", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "DocumentRowDownloadMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "DocumentRowDownloadMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "126681ef86a7a6aa5c831bdf53b7cf3e", + "id": null, + "metadata": {}, + "name": "DocumentRowDownloadMutation", + "operationKind": "mutation", + "text": "mutation DocumentRowDownloadMutation(\n $input: ExportDocumentPDFInput!\n) {\n exportDocumentPDF(input: $input) {\n data\n }\n}\n" + } +}; +})(); + +(node as any).hash = "8e48a364a7f9cf3d3a51a9db60ff792f"; + +export default node; diff --git a/apps/trust/src/components/__generated__/DocumentRowFragment.graphql.ts b/apps/trust/src/components/__generated__/DocumentRowFragment.graphql.ts new file mode 100644 index 000000000..b534b430c --- /dev/null +++ b/apps/trust/src/components/__generated__/DocumentRowFragment.graphql.ts @@ -0,0 +1,50 @@ +/** + * @generated SignedSource<<266bdec238fe7397f3cff10dc7da8fc6>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type DocumentRowFragment$data = { + readonly id: string; + readonly title: string; + readonly " $fragmentType": "DocumentRowFragment"; +}; +export type DocumentRowFragment$key = { + readonly " $data"?: DocumentRowFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"DocumentRowFragment">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "DocumentRowFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "title", + "storageKey": null + } + ], + "type": "Document", + "abstractKey": null +}; + +(node as any).hash = "437d68812bcc68724d2e347fea22b5e3"; + +export default node; diff --git a/apps/trust/src/components/__generated__/NDADialogSignMutation.graphql.ts b/apps/trust/src/components/__generated__/NDADialogSignMutation.graphql.ts new file mode 100644 index 000000000..c8b734ba7 --- /dev/null +++ b/apps/trust/src/components/__generated__/NDADialogSignMutation.graphql.ts @@ -0,0 +1,92 @@ +/** + * @generated SignedSource<> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type AcceptNonDisclosureAgreementInput = { + trustCenterId: string; +}; +export type NDADialogSignMutation$variables = { + input: AcceptNonDisclosureAgreementInput; +}; +export type NDADialogSignMutation$data = { + readonly acceptNonDisclosureAgreement: { + readonly success: boolean; + }; +}; +export type NDADialogSignMutation = { + response: NDADialogSignMutation$data; + variables: NDADialogSignMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "AcceptNonDisclosureAgreementPayload", + "kind": "LinkedField", + "name": "acceptNonDisclosureAgreement", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "success", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "NDADialogSignMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "NDADialogSignMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "130cfc307dca0525194e0103a0548bd0", + "id": null, + "metadata": {}, + "name": "NDADialogSignMutation", + "operationKind": "mutation", + "text": "mutation NDADialogSignMutation(\n $input: AcceptNonDisclosureAgreementInput!\n) {\n acceptNonDisclosureAgreement(input: $input) {\n success\n }\n}\n" + } +}; +})(); + +(node as any).hash = "1b9447e5cbb2ec7dce4f3f9c68493555"; + +export default node; diff --git a/apps/trust/src/components/__generated__/RequestAccessDialogMutation.graphql.ts b/apps/trust/src/components/__generated__/RequestAccessDialogMutation.graphql.ts new file mode 100644 index 000000000..4a6a65f37 --- /dev/null +++ b/apps/trust/src/components/__generated__/RequestAccessDialogMutation.graphql.ts @@ -0,0 +1,107 @@ +/** + * @generated SignedSource<<843902dd4fb6e2a5ee4d2d175ddcab03>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type CreateTrustCenterAccessInput = { + email: string; + name: string; + trustCenterId: string; +}; +export type RequestAccessDialogMutation$variables = { + input: CreateTrustCenterAccessInput; +}; +export type RequestAccessDialogMutation$data = { + readonly createTrustCenterAccess: { + readonly trustCenterAccess: { + readonly id: string; + }; + }; +}; +export type RequestAccessDialogMutation = { + response: RequestAccessDialogMutation$data; + variables: RequestAccessDialogMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "CreateTrustCenterAccessPayload", + "kind": "LinkedField", + "name": "createTrustCenterAccess", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "TrustCenterAccess", + "kind": "LinkedField", + "name": "trustCenterAccess", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "RequestAccessDialogMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "RequestAccessDialogMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "13fedcfe7c72292417b76b3624c5434f", + "id": null, + "metadata": {}, + "name": "RequestAccessDialogMutation", + "operationKind": "mutation", + "text": "mutation RequestAccessDialogMutation(\n $input: CreateTrustCenterAccessInput!\n) {\n createTrustCenterAccess(input: $input) {\n trustCenterAccess {\n id\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "18075ac4298dd3ca05bbcf8fb1717a9d"; + +export default node; diff --git a/apps/trust/src/components/__generated__/VendorRowFragment.graphql.ts b/apps/trust/src/components/__generated__/VendorRowFragment.graphql.ts new file mode 100644 index 000000000..463e62159 --- /dev/null +++ b/apps/trust/src/components/__generated__/VendorRowFragment.graphql.ts @@ -0,0 +1,84 @@ +/** + * @generated SignedSource<<4f486a2ab88b07376ece5f29705c2553>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +export type CountryCode = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW"; +export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL"; +import { FragmentRefs } from "relay-runtime"; +export type VendorRowFragment$data = { + readonly category: VendorCategory; + readonly countries: ReadonlyArray; + readonly id: string; + readonly name: string; + readonly privacyPolicyUrl: string | null | undefined; + readonly websiteUrl: string | null | undefined; + readonly " $fragmentType": "VendorRowFragment"; +}; +export type VendorRowFragment$key = { + readonly " $data"?: VendorRowFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "VendorRowFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "category", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "websiteUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "privacyPolicyUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "countries", + "storageKey": null + } + ], + "type": "Vendor", + "abstractKey": null +}; + +(node as any).hash = "eba669a2b65ef7b9990799516b7d9932"; + +export default node; diff --git a/apps/trust/src/helpers/documents.ts b/apps/trust/src/helpers/documents.ts new file mode 100644 index 000000000..9795ba288 --- /dev/null +++ b/apps/trust/src/helpers/documents.ts @@ -0,0 +1,10 @@ +export function documentTypeLabel(type: string, __: (s: string) => string) { + switch (type) { + case "POLICY": + return __("Policy"); + case "ISMS": + return __("Security"); + default: + return __("Other"); + } +} diff --git a/apps/trust/src/hooks/useDelayedEffect.ts b/apps/trust/src/hooks/useDelayedEffect.ts new file mode 100644 index 000000000..ee421db8a --- /dev/null +++ b/apps/trust/src/hooks/useDelayedEffect.ts @@ -0,0 +1,19 @@ +import { useEffect, useRef } from "react"; + +/** + * Hook to handle cleanup after a delay + * + * Used for disposing the graphQL query when the component unmounts + */ +export function useCleanup(callback: () => void, delay: number) { + const timer = useRef>(null); + + useEffect(() => { + if (timer.current) { + clearTimeout(timer.current); + } + return () => { + timer.current = setTimeout(callback, delay); + }; + }, [callback, delay]); +} diff --git a/apps/trust/src/hooks/useFormWithSchema.ts b/apps/trust/src/hooks/useFormWithSchema.ts new file mode 100644 index 000000000..6a7de80be --- /dev/null +++ b/apps/trust/src/hooks/useFormWithSchema.ts @@ -0,0 +1,13 @@ +import { useForm } from "react-hook-form"; +import type { z, ZodTypeAny } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; + +export function useFormWithSchema( + schema: T, + options: Parameters>>[0], +) { + return useForm>({ + ...options, + resolver: zodResolver(schema), + }); +} diff --git a/apps/trust/src/hooks/useIsAuthenticated.ts b/apps/trust/src/hooks/useIsAuthenticated.ts new file mode 100644 index 000000000..64537af87 --- /dev/null +++ b/apps/trust/src/hooks/useIsAuthenticated.ts @@ -0,0 +1,6 @@ +import { useContext } from "react"; +import { AuthContext } from "/providers/AuthProvider"; + +export function useIsAuthenticated(): boolean { + return useContext(AuthContext).isAuthenticated; +} diff --git a/apps/trust/src/hooks/useMutationWithToast.ts b/apps/trust/src/hooks/useMutationWithToast.ts new file mode 100644 index 000000000..acaff1096 --- /dev/null +++ b/apps/trust/src/hooks/useMutationWithToast.ts @@ -0,0 +1,63 @@ +import { useCallback } from "react"; +import { useMutation, type UseMutationConfig } from "react-relay"; +import { useToast } from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import type { MutationParameters, GraphQLTaggedNode } 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); + return; + } + options.onSuccess?.(response); + resolve(); + }, + onError: (error) => { + toast({ + title: __("Error"), + description: + options.errorMessage ?? __("Failed to commit this operation."), + variant: "error", + }); + reject(error); + }, + }) + ); + }, + [mutate] + ); + + return [mutateWithToast, isLoading] as const; +} diff --git a/apps/trust/src/hooks/useTrustCenter.ts b/apps/trust/src/hooks/useTrustCenter.ts new file mode 100644 index 000000000..931ffef8a --- /dev/null +++ b/apps/trust/src/hooks/useTrustCenter.ts @@ -0,0 +1,13 @@ +import { TrustCenterContext } from "/providers/TrustCenterProvider"; +import { useContext } from "react"; + +export function useTrustCenter(): { + id: string; + organization: { name: string }; +} { + const context = useContext(TrustCenterContext); + if (!context) { + throw new Error("useTrustCenter must be used within a TrustCenterProvider"); + } + return context; +} diff --git a/apps/trust/src/index.css b/apps/trust/src/index.css new file mode 100644 index 000000000..a4e4ea3fb --- /dev/null +++ b/apps/trust/src/index.css @@ -0,0 +1,10 @@ +@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 new file mode 100644 index 000000000..c87352264 --- /dev/null +++ b/apps/trust/src/layouts/MainLayout.tsx @@ -0,0 +1,67 @@ +import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; +import type { TrustGraphQuery } from "/queries/__generated__/TrustGraphQuery.graphql.ts"; +import { trustGraphQuery } from "/queries/TrustGraph.ts"; +import { Logo, TabLink, Tabs } from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { OrganizationSidebar } from "/components/OrganizationSidebar"; +import { Outlet } from "react-router"; +import { NDADialog } from "/components/NDADialog"; +import { AuthProvider } from "/providers/AuthProvider"; +import { TrustCenterProvider } from "/providers/TrustCenterProvider"; + +type Props = { + queryRef: PreloadedQuery; +}; + +export function MainLayout(props: Props) { + const { __ } = useTranslate(); + const trustCenter = usePreloadedQuery( + trustGraphQuery, + props.queryRef, + ).trustCenterBySlug; + + if (!trustCenter) { + return null; + } + + const baseTabUrl = `/trust/${trustCenter.slug}`; + const showNDADialog = + trustCenter.isUserAuthenticated && + !trustCenter.hasAcceptedNonDisclosureAgreement; + return ( + + + {showNDADialog && ( + + )} +
+ +
+ + {__("Overview")} + + {__("Documents")} + + + {__("Subprocessors")} + + + +
+
+ + + {__("Powered by")} + +
+
+ ); +} diff --git a/apps/trust/src/main.tsx b/apps/trust/src/main.tsx new file mode 100644 index 000000000..099511216 --- /dev/null +++ b/apps/trust/src/main.tsx @@ -0,0 +1,27 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import "./index.css"; +import { App } from "./App"; +import { RelayProvider } from "./providers/RelayProviders"; +import { TranslatorProvider } from "./providers/TranslatorProvider"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; + +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 new file mode 100644 index 000000000..dcc99adf2 --- /dev/null +++ b/apps/trust/src/module.d.ts @@ -0,0 +1,3 @@ +declare module "https://cdn.jsdelivr.net/npm/pdfjs-dist@5.4.149/+esm" { + export * from "pdfjs-dist"; +} diff --git a/apps/trust/src/pages/AccessPage.tsx b/apps/trust/src/pages/AccessPage.tsx new file mode 100644 index 000000000..1f9d93d3b --- /dev/null +++ b/apps/trust/src/pages/AccessPage.tsx @@ -0,0 +1,80 @@ +import { useTranslate } from "@probo/i18n"; +import { useEffect, useState } from "react"; +import { useNavigate, useParams, useSearchParams } from "react-router"; +import { buildEndpoint } from "/providers/RelayProviders"; +import { PageError } from "/components/PageError"; +import { Spinner } from "@probo/ui"; + +/** + * Page requested with an access token to authenticate the user for the Trust center + */ +export function AccessPage() { + const { __ } = useTranslate(); + const { slug } = useParams<{ slug: string }>(); + const [searchParams] = useSearchParams(); + const token = searchParams.get("token"); + const navigate = useNavigate(); + + const isValidRequest = !!(slug && token); + const [error, setError] = useState(() => { + if (!slug) { + return __("Invalid trust center"); + } + if (!token) { + return __("Invalid access token"); + } + return null; + }); + + // Initiate an authentication attempt + useEffect(() => { + if (!isValidRequest) { + return; + } + fetch(buildEndpoint("/api/trust/v1/auth/authenticate"), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + token, + }), + }) + .then((response) => { + // For invalid response throw an error + if (!response.ok) { + const defaultMessage = `HTTP ${response.status}: ${response.statusText}`; + return response + .json() + .then((json) => { + throw new Error(json.message ?? defaultMessage); + }) + .catch(() => { + throw new Error(defaultMessage); + }); + } + return response.json(); + }) + .then((data) => { + if (data.success) { + navigate(`/trust/${slug}`); + return; + } + throw new Error(data.message ?? __("Authentication failed")); + }) + .catch((error) => { + setError(error.message); + }); + }, [isValidRequest, slug, token, __, navigate]); + + if (error) { + return ; + } + + return ( +
+ + {__("Redirecting to trust center")} +
+ ); +} diff --git a/apps/trust/src/pages/DocumentsPage.tsx b/apps/trust/src/pages/DocumentsPage.tsx new file mode 100644 index 000000000..efcdde216 --- /dev/null +++ b/apps/trust/src/pages/DocumentsPage.tsx @@ -0,0 +1,42 @@ +import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; +import { trustDocumentsQuery } from "/queries/TrustGraph"; +import type { TrustGraphDocumentsQuery } from "/queries/__generated__/TrustGraphDocumentsQuery.graphql.ts"; +import { groupBy, objectEntries } from "@probo/helpers"; +import { documentTypeLabel } from "/helpers/documents"; +import { useTranslate } from "@probo/i18n"; +import { Fragment } from "react"; +import { DocumentRow } from "/components/DocumentRow"; +import { Rows } from "/components/Rows.tsx"; +import { RowHeader } from "/components/RowHeader.tsx"; + +type Props = { + queryRef: PreloadedQuery; +}; + +export function DocumentsPage({ queryRef }: Props) { + const { __ } = useTranslate(); + const data = usePreloadedQuery(trustDocumentsQuery, queryRef); + const documents = + data.trustCenterBySlug?.documents.edges.map((edge) => edge.node) ?? []; + const documentsPerType = groupBy(documents, (document) => + documentTypeLabel(document.documentType, __), + ); + return ( +
+

{__("Documents")}

+

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

+ + {objectEntries(documentsPerType).map(([label, documents]) => ( + + {label} + {documents.map((document) => ( + + ))} + + ))} + +
+ ); +} diff --git a/apps/trust/src/pages/OverviewPage.tsx b/apps/trust/src/pages/OverviewPage.tsx new file mode 100644 index 000000000..b0beeb572 --- /dev/null +++ b/apps/trust/src/pages/OverviewPage.tsx @@ -0,0 +1,147 @@ +import { useFragment } from "react-relay"; +import { graphql } from "relay-runtime"; +import type { OverviewFragment$key } from "./__generated__/OverviewFragment.graphql"; +import { Link, useOutletContext } from "react-router"; +import { groupBy, objectEntries, sprintf } from "@probo/helpers"; +import type { TrustGraphQuery$data } from "/queries/__generated__/TrustGraphQuery.graphql"; +import { useTranslate } from "@probo/i18n"; +import { Card, IconChevronRight } from "@probo/ui"; +import { AuditRow } from "/components/AuditRow"; +import { documentTypeLabel } from "/helpers/documents"; +import { Fragment } from "react"; +import { DocumentRow } from "/components/DocumentRow"; +import { VendorRow } from "/components/VendorRow"; +import { RowHeader } from "/components/RowHeader.tsx"; +import { Rows } from "/components/Rows.tsx"; + +const overviewFragment = graphql` + fragment OverviewFragment on TrustCenter { + references(first: 14) { + edges { + node { + id + name + logoUrl + websiteUrl + } + } + } + vendors(first: 3) { + edges { + node { + id + ...VendorRowFragment + } + } + } + documents(first: 5) { + edges { + node { + id + ...DocumentRowFragment + documentType + } + } + } + } +`; + +export function OverviewPage() { + const { trustCenter } = useOutletContext<{ + trustCenter: OverviewFragment$key & + TrustGraphQuery$data["trustCenterBySlug"]; + }>(); + const { __ } = useTranslate(); + const fragment = useFragment(overviewFragment, trustCenter); + const documentsPerType = groupBy( + fragment.documents.edges.map((edge) => edge.node), + (node) => documentTypeLabel(node.documentType, __), + ); + return ( +
+

{__("Documents")}

+

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

+ + {__("Certifications")} + {trustCenter.audits.edges.map((edge) => ( + + ))} + {objectEntries(documentsPerType).map(([label, documents]) => ( + + {label} + {documents.map((document) => ( + + ))} + + ))} + + {__("See all documents")} + + + + +

{__("Subprocessors")}

+

+ {sprintf( + __("Third-party subprocessors %s work with:"), + trustCenter.organization.name, + )} +

+ + {fragment.vendors.edges.map((edge) => ( + + ))} + + {__("See all subprocessors")} + + + + + edge.node)} + /> +
+ ); +} + +type Reference = { + name: string; + logoUrl: string; + websiteUrl: string; + id: string; +}; + +function References({ references }: { references: Reference[] }) { + const { __ } = useTranslate(); + 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 new file mode 100644 index 000000000..4bbc6cfb6 --- /dev/null +++ b/apps/trust/src/pages/SubprocessorsPage.tsx @@ -0,0 +1,34 @@ +import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; +import { trustVendorsQuery } from "/queries/TrustGraph"; +import { sprintf } from "@probo/helpers"; +import { useTranslate } from "@probo/i18n"; +import type { TrustGraphVendorsQuery } from "/queries/__generated__/TrustGraphVendorsQuery.graphql"; +import { VendorRow } from "/components/VendorRow"; +import { Rows } from "/components/Rows.tsx"; + +type Props = { + queryRef: PreloadedQuery; +}; + +export function SubprocessorsPage({ queryRef }: Props) { + const { __ } = useTranslate(); + const data = usePreloadedQuery(trustVendorsQuery, queryRef); + const vendors = + data.trustCenterBySlug?.vendors.edges.map((edge) => edge.node) ?? []; + return ( +
+

{__("Subprocessors")}

+

+ {sprintf( + __("Third-party subprocessors %s work with:"), + data.trustCenterBySlug?.organization.name ?? "", + )} +

+ + {vendors.map((vendor) => ( + + ))} + +
+ ); +} diff --git a/apps/trust/src/pages/__generated__/OverviewFragment.graphql.ts b/apps/trust/src/pages/__generated__/OverviewFragment.graphql.ts new file mode 100644 index 000000000..2299db14a --- /dev/null +++ b/apps/trust/src/pages/__generated__/OverviewFragment.graphql.ts @@ -0,0 +1,229 @@ +/** + * @generated SignedSource<<0767a7e9f6fb3f0464027b92a5239521>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +export type DocumentType = "ISMS" | "OTHER" | "POLICY"; +import { FragmentRefs } from "relay-runtime"; +export type OverviewFragment$data = { + readonly documents: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly documentType: DocumentType; + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"DocumentRowFragment">; + }; + }>; + }; + readonly references: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly logoUrl: string; + readonly name: string; + readonly websiteUrl: string; + }; + }>; + }; + readonly vendors: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">; + }; + }>; + }; + readonly " $fragmentType": "OverviewFragment"; +}; +export type OverviewFragment$key = { + readonly " $data"?: OverviewFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"OverviewFragment">; +}; + +const node: ReaderFragment = (function(){ +var v0 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "OverviewFragment", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 14 + } + ], + "concreteType": "TrustCenterReferenceConnection", + "kind": "LinkedField", + "name": "references", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "TrustCenterReferenceEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "TrustCenterReference", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "logoUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "websiteUrl", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "references(first:14)" + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 3 + } + ], + "concreteType": "VendorConnection", + "kind": "LinkedField", + "name": "vendors", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Vendor", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "VendorRowFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "vendors(first:3)" + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 5 + } + ], + "concreteType": "DocumentConnection", + "kind": "LinkedField", + "name": "documents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "DocumentRowFragment" + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "documentType", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "documents(first:5)" + } + ], + "type": "TrustCenter", + "abstractKey": null +}; +})(); + +(node as any).hash = "2f42031d2017248051c8dfea72b4e502"; + +export default node; diff --git a/apps/trust/src/providers/AuthProvider.tsx b/apps/trust/src/providers/AuthProvider.tsx new file mode 100644 index 000000000..cbe9b1293 --- /dev/null +++ b/apps/trust/src/providers/AuthProvider.tsx @@ -0,0 +1,13 @@ +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/RelayProviders.tsx b/apps/trust/src/providers/RelayProviders.tsx new file mode 100644 index 000000000..645593082 --- /dev/null +++ b/apps/trust/src/providers/RelayProviders.tsx @@ -0,0 +1,146 @@ +import { + Environment, + type FetchFunction, + Network, + RecordSource, + Store, +} from "relay-runtime"; +import { GraphQLError } from "graphql"; +import type { PropsWithChildren } from "react"; +import { RelayEnvironmentProvider } from "react-relay"; + +export class UnAuthenticatedError extends Error { + constructor() { + super("UNAUTHENTICATED"); + this.name = "UnAuthenticatedError"; + } +} + +export class InternalServerError extends Error { + constructor() { + super("INTERNAL_SERVER_ERROR"); + this.name = "InternalServerError"; + } +} + +export function buildEndpoint(path: string): string { + const host = import.meta.env.VITE_API_URL; + + if (!host) { + return path; + } + + const formattedHost = + host.startsWith("http://") || host.startsWith("https://") + ? host + : `https://${host}`; + + const url = new URL(formattedHost); + + if (path) { + url.pathname = path.startsWith("/") ? path : `/${path}`; + } + + return url.toString(); +} + +const hasUnauthenticatedError = (error: GraphQLError) => + error.extensions?.code == "UNAUTHENTICATED"; + +const fetchRelay: FetchFunction = async ( + request, + variables, + _, + uploadables, +) => { + const requestInit: RequestInit = { + method: "POST", + credentials: "include", + headers: {}, + }; + + if (uploadables) { + const formData = new FormData(); + formData.append( + "operations", + JSON.stringify({ + operationName: request.name, + query: request.text, + variables: variables, + }), + ); + + const uploadableMap: { + [key: string]: string[]; + } = {}; + + Object.keys(uploadables).forEach((key, index) => { + uploadableMap[index] = [`variables.${key}`]; + }); + + formData.append("map", JSON.stringify(uploadableMap)); + + Object.keys(uploadables).forEach((key, index) => { + formData.append(index.toString(), uploadables[key]); + }); + + requestInit.body = formData; + } else { + requestInit.headers = { + Accept: + "application/graphql-response+json; charset=utf-8, application/json; charset=utf-8", + "Content-Type": "application/json", + }; + + requestInit.body = JSON.stringify({ + operationName: request.name, + query: request.text, + variables, + }); + } + + const response = await fetch( + buildEndpoint("/api/trust/v1/graphql"), + requestInit, + ); + + if (response.status === 500) { + throw new InternalServerError(); + } + + const json = await response.json(); + + if (json.errors) { + const errors = json.errors as GraphQLError[]; + + if (errors.find(hasUnauthenticatedError)) { + throw new UnAuthenticatedError(); + } + + throw new Error(`Error fetching GraphQL query '${request.name}'`); + } + + return json; +}; + +const source = new RecordSource(); +const store = new Store(source, { + queryCacheExpirationTime: 1 * 60 * 1000, + gcReleaseBufferSize: 20, +}); + +export const relayEnvironment = new Environment({ + network: Network.create(fetchRelay), + 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 new file mode 100644 index 000000000..c32f80e65 --- /dev/null +++ b/apps/trust/src/providers/TranslatorProvider.tsx @@ -0,0 +1,18 @@ +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/providers/TrustCenterProvider.tsx b/apps/trust/src/providers/TrustCenterProvider.tsx new file mode 100644 index 000000000..daad3ad0f --- /dev/null +++ b/apps/trust/src/providers/TrustCenterProvider.tsx @@ -0,0 +1,20 @@ +import { createContext, type ReactNode } from "react"; +import type { TrustGraphQuery$data } from "/queries/__generated__/TrustGraphQuery.graphql"; + +export const TrustCenterContext = createContext< + TrustGraphQuery$data["trustCenterBySlug"] | null +>(null); + +export const TrustCenterProvider = ({ + children, + trustCenter, +}: { + children: ReactNode; + trustCenter: TrustGraphQuery$data["trustCenterBySlug"]; +}) => { + return ( + + {children} + + ); +}; diff --git a/apps/trust/src/queries/TrustGraph.ts b/apps/trust/src/queries/TrustGraph.ts new file mode 100644 index 000000000..2bfed290e --- /dev/null +++ b/apps/trust/src/queries/TrustGraph.ts @@ -0,0 +1,70 @@ +import { graphql } from "relay-runtime"; + +export const trustGraphQuery = graphql` + query TrustGraphQuery($slug: String!) { + trustCenterBySlug(slug: $slug) { + id + slug + isUserAuthenticated + hasAcceptedNonDisclosureAgreement + ndaFileName + ndaFileUrl + organization { + name + description + websiteUrl + logoUrl + email + headquarterAddress + } + ...OverviewFragment + audits(first: 50) { + edges { + node { + id + ...AuditRowFragment + } + } + } + } + } +`; + +export const trustDocumentsQuery = graphql` + query TrustGraphDocumentsQuery($slug: String!) { + trustCenterBySlug(slug: $slug) { + id + organization { + name + } + documents(first: 50) { + edges { + node { + id + documentType + ...DocumentRowFragment + } + } + } + } + } +`; + +export const trustVendorsQuery = graphql` + query TrustGraphVendorsQuery($slug: String!) { + trustCenterBySlug(slug: $slug) { + id + organization { + name + } + vendors(first: 50) { + edges { + node { + id + ...VendorRowFragment + } + } + } + } + } +`; diff --git a/apps/trust/src/queries/__generated__/TrustGraphDocumentsQuery.graphql.ts b/apps/trust/src/queries/__generated__/TrustGraphDocumentsQuery.graphql.ts new file mode 100644 index 000000000..f5d6f96fd --- /dev/null +++ b/apps/trust/src/queries/__generated__/TrustGraphDocumentsQuery.graphql.ts @@ -0,0 +1,245 @@ +/** + * @generated SignedSource<<55d256287ee091b57754d2d76080ad25>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type DocumentType = "ISMS" | "OTHER" | "POLICY"; +export type TrustGraphDocumentsQuery$variables = { + slug: string; +}; +export type TrustGraphDocumentsQuery$data = { + readonly trustCenterBySlug: { + readonly documents: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly documentType: DocumentType; + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"DocumentRowFragment">; + }; + }>; + }; + readonly id: string; + readonly organization: { + readonly name: string; + }; + } | null | undefined; +}; +export type TrustGraphDocumentsQuery = { + response: TrustGraphDocumentsQuery$data; + variables: TrustGraphDocumentsQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "slug" + } +], +v1 = [ + { + "kind": "Variable", + "name": "slug", + "variableName": "slug" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v4 = [ + { + "kind": "Literal", + "name": "first", + "value": 50 + } +], +v5 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "documentType", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TrustGraphDocumentsQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenterBySlug", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "organization", + "plural": false, + "selections": [ + (v3/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": (v4/*: any*/), + "concreteType": "DocumentConnection", + "kind": "LinkedField", + "name": "documents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + (v5/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "DocumentRowFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "documents(first:50)" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TrustGraphDocumentsQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenterBySlug", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "organization", + "plural": false, + "selections": [ + (v3/*: any*/), + (v2/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": (v4/*: any*/), + "concreteType": "DocumentConnection", + "kind": "LinkedField", + "name": "documents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + (v5/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "title", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "documents(first:50)" + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "71e1dc4102d19cdd2fb8d0ff60a391ca", + "id": null, + "metadata": {}, + "name": "TrustGraphDocumentsQuery", + "operationKind": "query", + "text": "query TrustGraphDocumentsQuery(\n $slug: String!\n) {\n trustCenterBySlug(slug: $slug) {\n id\n organization {\n name\n id\n }\n documents(first: 50) {\n edges {\n node {\n id\n documentType\n ...DocumentRowFragment\n }\n }\n }\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n}\n" + } +}; +})(); + +(node as any).hash = "9c56f70fca2afb316f4fd38d646ec545"; + +export default node; diff --git a/apps/trust/src/queries/__generated__/TrustGraphQuery.graphql.ts b/apps/trust/src/queries/__generated__/TrustGraphQuery.graphql.ts new file mode 100644 index 000000000..c54756d38 --- /dev/null +++ b/apps/trust/src/queries/__generated__/TrustGraphQuery.graphql.ts @@ -0,0 +1,525 @@ +/** + * @generated SignedSource<<669a97d59bae0528905d34c18586ce11>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type TrustGraphQuery$variables = { + slug: string; +}; +export type TrustGraphQuery$data = { + readonly trustCenterBySlug: { + readonly audits: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"AuditRowFragment">; + }; + }>; + }; + readonly hasAcceptedNonDisclosureAgreement: boolean; + readonly id: string; + readonly isUserAuthenticated: boolean; + readonly ndaFileName: string | null | undefined; + readonly ndaFileUrl: string | null | undefined; + readonly organization: { + readonly description: string | null | undefined; + readonly email: string | null | undefined; + readonly headquarterAddress: string | null | undefined; + readonly logoUrl: string | null | undefined; + readonly name: string; + readonly websiteUrl: string | null | undefined; + }; + readonly slug: string; + readonly " $fragmentSpreads": FragmentRefs<"OverviewFragment">; + } | null | undefined; +}; +export type TrustGraphQuery = { + response: TrustGraphQuery$data; + variables: TrustGraphQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "slug" + } +], +v1 = [ + { + "kind": "Variable", + "name": "slug", + "variableName": "slug" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "slug", + "storageKey": null +}, +v4 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "isUserAuthenticated", + "storageKey": null +}, +v5 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasAcceptedNonDisclosureAgreement", + "storageKey": null +}, +v6 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "ndaFileName", + "storageKey": null +}, +v7 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "ndaFileUrl", + "storageKey": null +}, +v8 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v9 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null +}, +v10 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "websiteUrl", + "storageKey": null +}, +v11 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "logoUrl", + "storageKey": null +}, +v12 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "email", + "storageKey": null +}, +v13 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "headquarterAddress", + "storageKey": null +}, +v14 = [ + { + "kind": "Literal", + "name": "first", + "value": 50 + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TrustGraphQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenterBySlug", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "organization", + "plural": false, + "selections": [ + (v8/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + (v11/*: any*/), + (v12/*: any*/), + (v13/*: any*/) + ], + "storageKey": null + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "OverviewFragment" + }, + { + "alias": null, + "args": (v14/*: any*/), + "concreteType": "AuditConnection", + "kind": "LinkedField", + "name": "audits", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "AuditEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "AuditRowFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "audits(first:50)" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TrustGraphQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenterBySlug", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "organization", + "plural": false, + "selections": [ + (v8/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + (v11/*: any*/), + (v12/*: any*/), + (v13/*: any*/), + (v2/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 14 + } + ], + "concreteType": "TrustCenterReferenceConnection", + "kind": "LinkedField", + "name": "references", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "TrustCenterReferenceEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "TrustCenterReference", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + (v8/*: any*/), + (v11/*: any*/), + (v10/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "references(first:14)" + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 3 + } + ], + "concreteType": "VendorConnection", + "kind": "LinkedField", + "name": "vendors", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Vendor", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + (v8/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "category", + "storageKey": null + }, + (v10/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "privacyPolicyUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "countries", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "vendors(first:3)" + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 5 + } + ], + "concreteType": "DocumentConnection", + "kind": "LinkedField", + "name": "documents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "title", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "documentType", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "documents(first:5)" + }, + { + "alias": null, + "args": (v14/*: any*/), + "concreteType": "AuditConnection", + "kind": "LinkedField", + "name": "audits", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "AuditEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Audit", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Report", + "kind": "LinkedField", + "name": "report", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "filename", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Framework", + "kind": "LinkedField", + "name": "framework", + "plural": false, + "selections": [ + (v2/*: any*/), + (v8/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "audits(first:50)" + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "00f2723e0dac553f037af3570903fb51", + "id": null, + "metadata": {}, + "name": "TrustGraphQuery", + "operationKind": "query", + "text": "query TrustGraphQuery(\n $slug: String!\n) {\n trustCenterBySlug(slug: $slug) {\n id\n slug\n isUserAuthenticated\n hasAcceptedNonDisclosureAgreement\n ndaFileName\n ndaFileUrl\n organization {\n name\n description\n websiteUrl\n logoUrl\n email\n headquarterAddress\n id\n }\n ...OverviewFragment\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n report {\n id\n filename\n }\n framework {\n id\n name\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n}\n\nfragment OverviewFragment on TrustCenter {\n references(first: 14) {\n edges {\n node {\n id\n name\n logoUrl\n websiteUrl\n }\n }\n }\n vendors(first: 3) {\n edges {\n node {\n id\n ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n" + } +}; +})(); + +(node as any).hash = "192a8d21a41871de201009a2dae65870"; + +export default node; diff --git a/apps/trust/src/queries/__generated__/TrustGraphVendorsQuery.graphql.ts b/apps/trust/src/queries/__generated__/TrustGraphVendorsQuery.graphql.ts new file mode 100644 index 000000000..cd913d5ce --- /dev/null +++ b/apps/trust/src/queries/__generated__/TrustGraphVendorsQuery.graphql.ts @@ -0,0 +1,256 @@ +/** + * @generated SignedSource<<43ebc34eede5683873c41a65f93e58b1>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type TrustGraphVendorsQuery$variables = { + slug: string; +}; +export type TrustGraphVendorsQuery$data = { + readonly trustCenterBySlug: { + readonly id: string; + readonly organization: { + readonly name: string; + }; + readonly vendors: { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">; + }; + }>; + }; + } | null | undefined; +}; +export type TrustGraphVendorsQuery = { + response: TrustGraphVendorsQuery$data; + variables: TrustGraphVendorsQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "slug" + } +], +v1 = [ + { + "kind": "Variable", + "name": "slug", + "variableName": "slug" + } +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v4 = [ + { + "kind": "Literal", + "name": "first", + "value": 50 + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TrustGraphVendorsQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenterBySlug", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "organization", + "plural": false, + "selections": [ + (v3/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": (v4/*: any*/), + "concreteType": "VendorConnection", + "kind": "LinkedField", + "name": "vendors", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Vendor", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "VendorRowFragment" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "vendors(first:50)" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TrustGraphVendorsQuery", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "TrustCenter", + "kind": "LinkedField", + "name": "trustCenterBySlug", + "plural": false, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "organization", + "plural": false, + "selections": [ + (v3/*: any*/), + (v2/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": (v4/*: any*/), + "concreteType": "VendorConnection", + "kind": "LinkedField", + "name": "vendors", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Vendor", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v2/*: any*/), + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "category", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "websiteUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "privacyPolicyUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "countries", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "vendors(first:50)" + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "1975e4b062f66fef036fc08bd7ff0b53", + "id": null, + "metadata": {}, + "name": "TrustGraphVendorsQuery", + "operationKind": "query", + "text": "query TrustGraphVendorsQuery(\n $slug: String!\n) {\n trustCenterBySlug(slug: $slug) {\n id\n organization {\n name\n id\n }\n vendors(first: 50) {\n edges {\n node {\n id\n ...VendorRowFragment\n }\n }\n }\n }\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n" + } +}; +})(); + +(node as any).hash = "b21c7b35a682aa1fc4210e1c717e55b4"; + +export default node; diff --git a/apps/trust/src/routes.tsx b/apps/trust/src/routes.tsx new file mode 100644 index 000000000..ea167c27b --- /dev/null +++ b/apps/trust/src/routes.tsx @@ -0,0 +1,153 @@ +import { + createBrowserRouter, + Navigate, + redirect, + type RouteObject, + useLoaderData, + useRouteError, +} from "react-router"; +import { type ComponentType, Fragment, Suspense } from "react"; +import { + relayEnvironment, + UnAuthenticatedError, +} from "./providers/RelayProviders"; +import { loadQuery, type PreloadedQuery } from "react-relay"; +import { useCleanup } from "./hooks/useDelayedEffect"; +import { PageError } from "./components/PageError"; +import { MainLayout } from "/layouts/MainLayout"; +import { + trustGraphQuery, + trustDocumentsQuery, + trustVendorsQuery, +} from "/queries/TrustGraph"; +import { OverviewPage } from "/pages/OverviewPage"; +import { DocumentsPage } from "/pages/DocumentsPage"; +import { SubprocessorsPage } from "/pages/SubprocessorsPage"; +import { AccessPage } from "./pages/AccessPage.tsx"; +import { TabSkeleton } from "./components/Skeletons/TabSkeleton"; +import { MainSkeleton } from "./components/Skeletons/MainSkeleton"; + +export type AppRoute = Omit & { + Component?: ComponentType; + children?: AppRoute[]; + fallback?: ComponentType; + queryLoader?: (params: any) => PreloadedQuery; +}; + +/** + * Top level error boundary + */ +function ErrorBoundary({ error: propsError }: { error?: string }) { + const error = useRouteError() ?? propsError; + + if (error instanceof UnAuthenticatedError) { + return ; + } + + return ; +} + +const routes = [ + { + path: "/", + Component: Fragment, + ErrorBoundary: ErrorBoundary, + }, + { + path: "/trust/:slug/access", + Component: AccessPage, + ErrorBoundary: ErrorBoundary, + }, + { + path: "/trust/:slug", + queryLoader: ({ slug }) => + loadQuery(relayEnvironment, trustGraphQuery, { slug: slug }), + Component: MainLayout, + fallback: MainSkeleton, + ErrorBoundary: ErrorBoundary, + children: [ + { + path: "", + loader: ({ params }) => { + throw redirect(`/trust/${params.slug}/overview`); + }, + }, + { + path: "overview", + fallback: TabSkeleton, + Component: OverviewPage, + }, + { + path: "documents", + fallback: TabSkeleton, + Component: DocumentsPage, + queryLoader: ({ slug }) => + loadQuery(relayEnvironment, trustDocumentsQuery, { slug: slug }), + }, + { + path: "subprocessors", + fallback: TabSkeleton, + Component: SubprocessorsPage, + queryLoader: ({ slug }) => + loadQuery(relayEnvironment, trustVendorsQuery, { slug: slug }), + }, + ], + }, + // Fallback URL to the NotFound Page + { + path: "*", + Component: PageError, + }, +] satisfies AppRoute[]; + +/** + * Wrap components with suspense to handle lazy loading & relay loading states + */ +function routeTransformer({ + fallback: FallbackComponent, + queryLoader, + ...route +}: AppRoute): RouteObject { + let result = { ...route }; + if (FallbackComponent && route.Component) { + const OriginalComponent = route.Component; + result = { + ...result, + Component: (props) => ( + }> + + + ), + }; + } + if (queryLoader && route.Component) { + const OriginalComponent = route.Component; + result = { + ...result, + loader: ({ params }) => { + const query = queryLoader(params as Record); + return { + queryRef: query, + dispose: query.dispose, + }; + }, + Component: () => { + const { queryRef, dispose } = useLoaderData(); + + useCleanup(dispose, 1000); + + return ( + : null}> + + + ); + }, + }; + } + return { + ...result, + children: route.children?.map(routeTransformer), + } as RouteObject; +} + +export const router = createBrowserRouter(routes.map(routeTransformer)); diff --git a/apps/trust/src/types.ts b/apps/trust/src/types.ts new file mode 100644 index 000000000..583413b93 --- /dev/null +++ b/apps/trust/src/types.ts @@ -0,0 +1,8 @@ +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 new file mode 100644 index 000000000..29c29a188 --- /dev/null +++ b/apps/trust/src/vite-env.d.ts @@ -0,0 +1,9 @@ +/// + +interface ImportMetaEnv { + readonly VITE_API_URL: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/apps/trust/tsconfig.app.json b/apps/trust/tsconfig.app.json new file mode 100644 index 000000000..40a8e8c55 --- /dev/null +++ b/apps/trust/tsconfig.app.json @@ -0,0 +1,31 @@ +{ + "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": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "baseUrl": ".", + "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 new file mode 100644 index 000000000..1ffef600d --- /dev/null +++ b/apps/trust/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/apps/trust/tsconfig.node.json b/apps/trust/tsconfig.node.json new file mode 100644 index 000000000..9728af2d8 --- /dev/null +++ b/apps/trust/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "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 new file mode 100644 index 000000000..068c8cdbd --- /dev/null +++ b/apps/trust/vite.config.ts @@ -0,0 +1,33 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import tailwindcss from "@tailwindcss/vite"; +import { fileURLToPath, URL } from "node:url"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react({ babel: { plugins: ["relay"] } }), tailwindcss()], + server: { + port: 5174, + proxy: { + "/api": { + target: "http://localhost:8080", + changeOrigin: true, + }, + }, + }, + resolve: { + alias: { + "/type": fileURLToPath(new URL("./src/type.ts", import.meta.url)), + "/components": fileURLToPath( + new URL("./src/components", import.meta.url) + ), + "/queries": fileURLToPath(new URL("./src/queries", import.meta.url)), + "/helpers": fileURLToPath(new URL("./src/helpers", import.meta.url)), + "/hooks": fileURLToPath(new URL("./src/hooks", import.meta.url)), + "/layouts": fileURLToPath(new URL("./src/layouts", import.meta.url)), + "/pages": fileURLToPath(new URL("./src/pages", import.meta.url)), + "/routes": fileURLToPath(new URL("./src/routes", import.meta.url)), + "/providers": fileURLToPath(new URL("./src/providers", import.meta.url)), + }, + }, +}); diff --git a/package-lock.json b/package-lock.json index 0ee39c472..0d60de96f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,6 +68,50 @@ "vite": "^6.3.6" } }, + "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/ui": "1.0.0", + "clsx": "^2.1.1", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-error-boundary": "^6.0.0", + "react-hook-form": "^7.56.4", + "react-pdf": "^10.1.0", + "react-relay": "^19.0.0", + "react-router": "^7.6.0", + "relay-runtime": "^19.0.0", + "usehooks-ts": "^3.1.1", + "zod": "^3.25.71" + }, + "devDependencies": { + "@eslint/js": "^9.25.0", + "@tailwindcss/vite": "^4.1.7", + "@types/node": "^22.15.21", + "@types/react": "^19.1.2", + "@types/react-dom": "^19.1.2", + "@types/react-relay": "^18.2.1", + "@types/relay-runtime": "^19.0.1", + "@vitejs/plugin-react": "^4.4.1", + "babel-plugin-relay": "^19.0.0", + "eslint": "^9.25.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^16.0.0", + "graphql": "^16.11.0", + "prettier": "^3.5.3", + "relay-compiler": "^19.0.0", + "tailwindcss": "^4.1.7", + "typescript": "~5.8.3", + "typescript-eslint": "^8.30.1", + "vite": "^6.3.6" + } + }, "node_modules/@adobe/css-tools": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz", @@ -1305,6 +1349,191 @@ "react": ">=16" } }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.80.tgz", + "integrity": "sha512-DxuT1ClnIPts1kQx8FBmkk4BQDTfI5kIzywAaMjQSXfNnra5UFU9PwurXrl+Je3bJ6BGsp/zmshVVFbCmyI+ww==", + "license": "MIT", + "optional": true, + "workspaces": [ + "e2e/*" + ], + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.80", + "@napi-rs/canvas-darwin-arm64": "0.1.80", + "@napi-rs/canvas-darwin-x64": "0.1.80", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.80", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.80", + "@napi-rs/canvas-linux-arm64-musl": "0.1.80", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-musl": "0.1.80", + "@napi-rs/canvas-win32-x64-msvc": "0.1.80" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.80.tgz", + "integrity": "sha512-sk7xhN/MoXeuExlggf91pNziBxLPVUqF2CAVnB57KLG/pz7+U5TKG8eXdc3pm0d7Od0WreB6ZKLj37sX9muGOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz", + "integrity": "sha512-O64APRTXRUiAz0P8gErkfEr3lipLJgM6pjATwavZ22ebhjYl/SUbpgM0xcWPQBNMP1n29afAC/Us5PX1vg+JNQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz", + "integrity": "sha512-FqqSU7qFce0Cp3pwnTjVkKjjOtxMqRe6lmINxpIZYaZNnVI0H5FtsaraZJ36SiTHNjZlUB69/HhxNDT1Aaa9vA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz", + "integrity": "sha512-eyWz0ddBDQc7/JbAtY4OtZ5SpK8tR4JsCYEZjCE3dI8pqoWUC8oMwYSBGCYfsx2w47cQgQCgMVRVTFiiO38hHQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz", + "integrity": "sha512-qwA63t8A86bnxhuA/GwOkK3jvb+XTQaTiVML0vAWoHyoZYTjNs7BzoOONDgTnNtr8/yHrq64XXzUoLqDzU+Uuw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz", + "integrity": "sha512-1XbCOz/ymhj24lFaIXtWnwv/6eFHXDrjP0jYkc6iHQ9q8oXKzUX1Lc6bu+wuGiLhGh2GS/2JlfORC5ZcXimRcg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz", + "integrity": "sha512-XTzR125w5ZMs0lJcxRlS1K3P5RaZ9RmUsPtd1uGt+EfDyYMu4c6SEROYsxyatbbu/2+lPe7MPHOO/0a0x7L/gw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz", + "integrity": "sha512-BeXAmhKg1kX3UCrJsYbdQd3hIMDH/K6HnP/pG2LuITaXhXBiNdh//TVVVVCBbJzVQaV5gK/4ZOCMrQW9mvuTqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz", + "integrity": "sha512-x0XvZWdHbkgdgucJsRxprX/4o4sEed7qo9rCQA9ugiS9qE2QvP0RIiEugtZhfLH3cyI+jIRFJHV4Fuz+1BHHMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz", + "integrity": "sha512-Z8jPsM6df5V8B1HrCHB05+bDiCxjE9QA//3YrkKIdVDEwn5RKaqOxCJDRJkl48cJbylcrJbW4HxZbTte8juuPg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1389,6 +1618,10 @@ "resolved": "packages/react-lazy", "link": true }, + "node_modules/@probo/trust": { + "resolved": "apps/trust", + "link": true + }, "node_modules/@probo/tsconfig": { "resolved": "packages/tsconfig", "link": true @@ -7179,6 +7412,15 @@ "source-map-js": "^1.2.0" } }, + "node_modules/make-cancellable-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-2.0.0.tgz", + "integrity": "sha512-3SEQqTpV9oqVsIWqAcmDuaNeo7yBO3tqPtqGRcKkEo0lrzD3wqbKG9mkxO65KoOgXqj+zH2phJ2LiAsdzlogSw==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -7208,6 +7450,15 @@ "node": ">=10" } }, + "node_modules/make-event-props": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-2.0.0.tgz", + "integrity": "sha512-G/hncXrl4Qt7mauJEXSg3AcdYzmpkIITTNl5I+rH9sog5Yw0kK6vseJjCaPfOXqOqQuPUP89Rkhfz5kPS8ijtw==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" + } + }, "node_modules/map-or-similar": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", @@ -7527,6 +7778,23 @@ "map-or-similar": "^1.5.0" } }, + "node_modules/merge-refs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-2.0.0.tgz", + "integrity": "sha512-3+B21mYK2IqUWnd2EivABLT7ueDhb0b8/dGK8LoFQPrU61YITeCMn14F7y7qZafWNZhUEKb24cJdiT5Wxs3prg==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -8522,6 +8790,18 @@ "node": ">= 14.16" } }, + "node_modules/pdfjs-dist": { + "version": "5.3.93", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.3.93.tgz", + "integrity": "sha512-w3fQKVL1oGn8FRyx5JUG5tnbblggDqyx2XzA5brsJ5hSuS+I0NdnJANhmeWKLjotdbPQucLBug5t0MeWr0AAdg==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.16.0 || >=22.3.0" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^0.1.71" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -8952,6 +9232,35 @@ "react": ">=18" } }, + "node_modules/react-pdf": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-10.1.0.tgz", + "integrity": "sha512-iUI1YqWgwwZcsXjrehTp3Yi8nT/bvTaWULaRMMyJWvoqqSlopk4LQQ9GDqUnDtX3gzT2glrqrLbjIPl56a+Q3w==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "dequal": "^2.0.3", + "make-cancellable-promise": "^2.0.0", + "make-event-props": "^2.0.0", + "merge-refs": "^2.0.0", + "pdfjs-dist": "5.3.93", + "tiny-invariant": "^1.0.0", + "warning": "^4.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-pdf?sponsor=1" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", @@ -9852,7 +10161,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", - "dev": true, "license": "MIT" }, "node_modules/tinybench": { @@ -10782,6 +11090,15 @@ "node": ">=14.0.0" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/web-namespaces": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", @@ -10994,20 +11311,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 221919490..951c46353 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,6 @@ "license": "MIT", "packageManager": "npm@11.1.0", "volta": { - "node": "v24.4.0" + "node": "24.4.0" } } diff --git a/packages/helpers/src/index.ts b/packages/helpers/src/index.ts index 3f355ff9a..58e91da17 100644 --- a/packages/helpers/src/index.ts +++ b/packages/helpers/src/index.ts @@ -1,5 +1,5 @@ export { objectKeys, objectEntries, cleanFormData } from "./object"; -export { sprintf, faviconUrl, slugify } from "./string"; +export { sprintf, faviconUrl, slugify, domain } from "./string"; export { getTreatment, getRiskImpacts, @@ -12,14 +12,37 @@ export { randomInt } from "./number"; export { getMeasureStateLabel, measureStates } from "./measure"; export { getRole, getRoles, peopleRoles } from "./people"; export { certificationCategoryLabel, certifications } from "./certifications"; -export { getCountryName, getCountryOptions, getCountryLabel, countries, type CountryCode } from "./countries"; +export { + getCountryName, + getCountryOptions, + getCountryLabel, + countries, + type CountryCode, +} from "./countries"; export { availableFrameworks } from "./frameworks"; export { getDocumentTypeLabel, documentTypes } from "./documents"; export { getAssetTypeVariant, getCriticityVariant } from "./assets"; -export { getSnapshotTypeLabel, getSnapshotTypeUrlPath, snapshotTypes, validateSnapshotConsistency } from "./snapshots"; -export { getAuditStateLabel, getAuditStateVariant, auditStates } from "./audits"; -export { getStatusVariant, getStatusLabel, getStatusOptions } from "./registryStatus"; -export { getObligationStatusVariant, getObligationStatusLabel, getObligationStatusOptions } from "./obligationStatus"; +export { + getSnapshotTypeLabel, + getSnapshotTypeUrlPath, + snapshotTypes, + validateSnapshotConsistency, +} from "./snapshots"; +export { + getAuditStateLabel, + getAuditStateVariant, + auditStates, +} from "./audits"; +export { + getStatusVariant, + getStatusLabel, + getStatusOptions, +} from "./registryStatus"; +export { + getObligationStatusVariant, + getObligationStatusLabel, + getObligationStatusOptions, +} from "./obligationStatus"; export { promisifyMutation } from "./relay"; export { fileType, fileSize } from "./file"; export { formatDatetime, formatDate } from "./date"; diff --git a/packages/helpers/src/string.ts b/packages/helpers/src/string.ts index e026a644d..7af9f542f 100644 --- a/packages/helpers/src/string.ts +++ b/packages/helpers/src/string.ts @@ -30,3 +30,11 @@ export function slugify(str: string): string { .replace(/[^a-z0-9 ]/g, "") // remove all chars not letters, numbers and spaces (to be replaced) .replace(/\s+/g, "-"); } + +export function domain(url: string): string { + const parts = url.split("//"); + if (parts.length > 1) { + url = parts[1]; + } + return url.split("/")[0]; +} diff --git a/packages/ui/src/Atoms/Icons/Frame-1.svg b/packages/ui/src/Atoms/Icons/Frame-1.svg deleted file mode 100644 index c68462645..000000000 --- a/packages/ui/src/Atoms/Icons/Frame-1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/Frame-2.svg b/packages/ui/src/Atoms/Icons/Frame-2.svg deleted file mode 100644 index 0b2a32f6e..000000000 --- a/packages/ui/src/Atoms/Icons/Frame-2.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/Frame.svg b/packages/ui/src/Atoms/Icons/Frame.svg deleted file mode 100644 index c53d1c0c8..000000000 --- a/packages/ui/src/Atoms/Icons/Frame.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/IconMail.tsx b/packages/ui/src/Atoms/Icons/IconMail.tsx new file mode 100644 index 000000000..13d1df5cc --- /dev/null +++ b/packages/ui/src/Atoms/Icons/IconMail.tsx @@ -0,0 +1,19 @@ +import type { IconProps } from "./type.ts"; + +export function IconMail({ size = 24, className }: IconProps) { + return ( + + + + ); +} diff --git a/packages/ui/src/Atoms/Icons/IconMedal.tsx b/packages/ui/src/Atoms/Icons/IconMedal.tsx new file mode 100644 index 000000000..d641a43c9 --- /dev/null +++ b/packages/ui/src/Atoms/Icons/IconMedal.tsx @@ -0,0 +1,21 @@ +import type { IconProps } from "./type.ts"; + +export function IconMedal({ size = 24, className }: IconProps) { + return ( + + + + ); +} diff --git a/packages/ui/src/Atoms/Icons/IconMinusLarge.tsx b/packages/ui/src/Atoms/Icons/IconMinusLarge.tsx new file mode 100644 index 000000000..fe1450ab8 --- /dev/null +++ b/packages/ui/src/Atoms/Icons/IconMinusLarge.tsx @@ -0,0 +1,19 @@ +import type {IconProps} from "./type.ts"; + +export function IconMinusLarge({size = 16, className}: IconProps) { + return ( + + + + ); +} diff --git a/packages/ui/src/Atoms/Icons/IconPin.tsx b/packages/ui/src/Atoms/Icons/IconPin.tsx new file mode 100644 index 000000000..0b29889d7 --- /dev/null +++ b/packages/ui/src/Atoms/Icons/IconPin.tsx @@ -0,0 +1,27 @@ +import type { IconProps } from "./type.ts"; + +export function IconPin({ size = 24, className }: IconProps) { + return ( + + + + + ); +} diff --git a/packages/ui/src/Atoms/Icons/Image.svg b/packages/ui/src/Atoms/Icons/Image.svg deleted file mode 100644 index 44440122c..000000000 --- a/packages/ui/src/Atoms/Icons/Image.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/ui/src/Atoms/Icons/Send.svg b/packages/ui/src/Atoms/Icons/Send.svg deleted file mode 100644 index 97eb34760..000000000 --- a/packages/ui/src/Atoms/Icons/Send.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/arrow-box-left.svg b/packages/ui/src/Atoms/Icons/arrow-box-left.svg deleted file mode 100644 index 1e4bc130a..000000000 --- a/packages/ui/src/Atoms/Icons/arrow-box-left.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/arrow-corner-down-left.svg b/packages/ui/src/Atoms/Icons/arrow-corner-down-left.svg deleted file mode 100644 index f9fa083f7..000000000 --- a/packages/ui/src/Atoms/Icons/arrow-corner-down-left.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/arrow-down.svg b/packages/ui/src/Atoms/Icons/arrow-down.svg deleted file mode 100644 index 9348a7a53..000000000 --- a/packages/ui/src/Atoms/Icons/arrow-down.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/arrow-inbox-1.svg b/packages/ui/src/Atoms/Icons/arrow-inbox-1.svg deleted file mode 100644 index bc36e8844..000000000 --- a/packages/ui/src/Atoms/Icons/arrow-inbox-1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/arrow-inbox.svg b/packages/ui/src/Atoms/Icons/arrow-inbox.svg deleted file mode 100644 index 7c9f76e24..000000000 --- a/packages/ui/src/Atoms/Icons/arrow-inbox.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/arrow-link.svg b/packages/ui/src/Atoms/Icons/arrow-link.svg deleted file mode 100644 index 75a2eb34c..000000000 --- a/packages/ui/src/Atoms/Icons/arrow-link.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/arrow-up.svg b/packages/ui/src/Atoms/Icons/arrow-up.svg deleted file mode 100644 index e8208a8c0..000000000 --- a/packages/ui/src/Atoms/Icons/arrow-up.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/bank.svg b/packages/ui/src/Atoms/Icons/bank.svg deleted file mode 100644 index c4aedb364..000000000 --- a/packages/ui/src/Atoms/Icons/bank.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/bell-2.svg b/packages/ui/src/Atoms/Icons/bell-2.svg deleted file mode 100644 index 8f692ce24..000000000 --- a/packages/ui/src/Atoms/Icons/bell-2.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/block-1.svg b/packages/ui/src/Atoms/Icons/block-1.svg deleted file mode 100644 index 4580b79d3..000000000 --- a/packages/ui/src/Atoms/Icons/block-1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/block.svg b/packages/ui/src/Atoms/Icons/block.svg deleted file mode 100644 index c55d24462..000000000 --- a/packages/ui/src/Atoms/Icons/block.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/book.svg b/packages/ui/src/Atoms/Icons/book.svg deleted file mode 100644 index 96695a558..000000000 --- a/packages/ui/src/Atoms/Icons/book.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/calendar-1.svg b/packages/ui/src/Atoms/Icons/calendar-1.svg deleted file mode 100644 index a533ac85d..000000000 --- a/packages/ui/src/Atoms/Icons/calendar-1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/calendar-2.svg b/packages/ui/src/Atoms/Icons/calendar-2.svg deleted file mode 100644 index 12ae0009c..000000000 --- a/packages/ui/src/Atoms/Icons/calendar-2.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/checkmark-1.svg b/packages/ui/src/Atoms/Icons/checkmark-1.svg deleted file mode 100644 index 6fe15fe43..000000000 --- a/packages/ui/src/Atoms/Icons/checkmark-1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/checkmark-2-small.svg b/packages/ui/src/Atoms/Icons/checkmark-2-small.svg deleted file mode 100644 index a8264ebe0..000000000 --- a/packages/ui/src/Atoms/Icons/checkmark-2-small.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/chevron-down.svg b/packages/ui/src/Atoms/Icons/chevron-down.svg deleted file mode 100644 index 6077bd3e2..000000000 --- a/packages/ui/src/Atoms/Icons/chevron-down.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/chevron-grabber-vertical.svg b/packages/ui/src/Atoms/Icons/chevron-grabber-vertical.svg deleted file mode 100644 index a0ab5ddb2..000000000 --- a/packages/ui/src/Atoms/Icons/chevron-grabber-vertical.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/chevron-left.svg b/packages/ui/src/Atoms/Icons/chevron-left.svg deleted file mode 100644 index e5145d888..000000000 --- a/packages/ui/src/Atoms/Icons/chevron-left.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/chevron-right.svg b/packages/ui/src/Atoms/Icons/chevron-right.svg deleted file mode 100644 index 53861cf1b..000000000 --- a/packages/ui/src/Atoms/Icons/chevron-right.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/chevron-triangle-down-small.svg b/packages/ui/src/Atoms/Icons/chevron-triangle-down-small.svg deleted file mode 100644 index afae78b2c..000000000 --- a/packages/ui/src/Atoms/Icons/chevron-triangle-down-small.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/chevron-up.svg b/packages/ui/src/Atoms/Icons/chevron-up.svg deleted file mode 100644 index 97a5b333f..000000000 --- a/packages/ui/src/Atoms/Icons/chevron-up.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/circle-check-1.svg b/packages/ui/src/Atoms/Icons/circle-check-1.svg deleted file mode 100644 index 7ffc640eb..000000000 --- a/packages/ui/src/Atoms/Icons/circle-check-1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/circle-check.svg b/packages/ui/src/Atoms/Icons/circle-check.svg deleted file mode 100644 index be7466163..000000000 --- a/packages/ui/src/Atoms/Icons/circle-check.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/circle-info.svg b/packages/ui/src/Atoms/Icons/circle-info.svg deleted file mode 100644 index df970b8b9..000000000 --- a/packages/ui/src/Atoms/Icons/circle-info.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/circle-progress.svg b/packages/ui/src/Atoms/Icons/circle-progress.svg deleted file mode 100644 index 06cf12749..000000000 --- a/packages/ui/src/Atoms/Icons/circle-progress.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/circle-questionmark-1.svg b/packages/ui/src/Atoms/Icons/circle-questionmark-1.svg deleted file mode 100644 index 9fb1c05a3..000000000 --- a/packages/ui/src/Atoms/Icons/circle-questionmark-1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/circle-questionmark-solid.svg b/packages/ui/src/Atoms/Icons/circle-questionmark-solid.svg deleted file mode 100644 index bb71a709f..000000000 --- a/packages/ui/src/Atoms/Icons/circle-questionmark-solid.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/circle-questionmark.svg b/packages/ui/src/Atoms/Icons/circle-questionmark.svg deleted file mode 100644 index 24eba8cad..000000000 --- a/packages/ui/src/Atoms/Icons/circle-questionmark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/ui/src/Atoms/Icons/circle-x.svg b/packages/ui/src/Atoms/Icons/circle-x.svg deleted file mode 100644 index 934dc263e..000000000 --- a/packages/ui/src/Atoms/Icons/circle-x.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/clock.svg b/packages/ui/src/Atoms/Icons/clock.svg deleted file mode 100644 index 7bfb28be5..000000000 --- a/packages/ui/src/Atoms/Icons/clock.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/collapse.svg b/packages/ui/src/Atoms/Icons/collapse.svg deleted file mode 100644 index 1c1c899aa..000000000 --- a/packages/ui/src/Atoms/Icons/collapse.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/cross-large-x.svg b/packages/ui/src/Atoms/Icons/cross-large-x.svg deleted file mode 100644 index 7e966c9a4..000000000 --- a/packages/ui/src/Atoms/Icons/cross-large-x.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/dot-grid-1x3-horizontal.svg b/packages/ui/src/Atoms/Icons/dot-grid-1x3-horizontal.svg deleted file mode 100644 index ea7d6b883..000000000 --- a/packages/ui/src/Atoms/Icons/dot-grid-1x3-horizontal.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/ui/src/Atoms/Icons/expand.svg b/packages/ui/src/Atoms/Icons/expand.svg deleted file mode 100644 index e7edcc6dd..000000000 --- a/packages/ui/src/Atoms/Icons/expand.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/ui/src/Atoms/Icons/filter.svg b/packages/ui/src/Atoms/Icons/filter.svg deleted file mode 100644 index ce12d347d..000000000 --- a/packages/ui/src/Atoms/Icons/filter.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/ui/src/Atoms/Icons/fire-3.svg b/packages/ui/src/Atoms/Icons/fire-3.svg deleted file mode 100644 index 45bb911f3..000000000 --- a/packages/ui/src/Atoms/Icons/fire-3.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/folder-2.svg b/packages/ui/src/Atoms/Icons/folder-2.svg deleted file mode 100644 index de4b55f99..000000000 --- a/packages/ui/src/Atoms/Icons/folder-2.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/folder-upload.svg b/packages/ui/src/Atoms/Icons/folder-upload.svg deleted file mode 100644 index dc9ee5dde..000000000 --- a/packages/ui/src/Atoms/Icons/folder-upload.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/generator.ts b/packages/ui/src/Atoms/Icons/generator.ts deleted file mode 100644 index a3d5e411f..000000000 --- a/packages/ui/src/Atoms/Icons/generator.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* -Generates Icon components from SVG files - */ - -import fs from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const svgFiles = fs - .readdirSync(path.join(__dirname)) - .filter((file) => file.endsWith(".svg")); - -function camelCase(s: string) { - return s.replace(/-([a-z0-9])/g, (g) => g[1].toUpperCase()); -} - -function capitalize(s: string) { - return s.charAt(0).toUpperCase() + s.slice(1); -} - -const exports = []; - -for (const svgFile of svgFiles) { - const iconName = svgFile.replace(".svg", ""); - const componentName = capitalize(camelCase(iconName)); - let svgContent = fs.readFileSync(path.join(__dirname, svgFile), "utf-8"); - - svgContent = svgContent.replace(/width="[^"]*"/, "width={size}"); - svgContent = svgContent.replace(/height="[^"]*"/, "height={size}"); - svgContent = svgContent.replace(/fill="[^"]*"/g, 'fill="currentColor"'); - svgContent = svgContent.replace(/xmlns=/g, "className={className} xmlns="); - svgContent = svgContent.replace(/([a-z]+-[a-z]+)="/g, function (_, attr) { - return `${camelCase(attr)}="`; - }); - - const componentContent = `import type {IconProps} from "./type.ts"; - -export function Icon${componentName}({size = 24, className}: IconProps) { - return ${svgContent} -}`; - - fs.writeFileSync( - path.join(__dirname, `Icon${componentName}.tsx`), - componentContent, - ); - exports.push( - `export { Icon${componentName} } from "./Icon${componentName}.tsx"`, - ); -} - -// Write exports in the index.ts file -fs.writeFileSync( - path.join(__dirname, "index.tsx"), - `${exports.join(";\n")};\n`, -); diff --git a/packages/ui/src/Atoms/Icons/group-1-1.svg b/packages/ui/src/Atoms/Icons/group-1-1.svg deleted file mode 100644 index b05a4b80a..000000000 --- a/packages/ui/src/Atoms/Icons/group-1-1.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/ui/src/Atoms/Icons/group-1.svg b/packages/ui/src/Atoms/Icons/group-1.svg deleted file mode 100644 index bf045ad96..000000000 --- a/packages/ui/src/Atoms/Icons/group-1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/home.svg b/packages/ui/src/Atoms/Icons/home.svg deleted file mode 100644 index 9d8b1f824..000000000 --- a/packages/ui/src/Atoms/Icons/home.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/import-2.svg b/packages/ui/src/Atoms/Icons/import-2.svg deleted file mode 100644 index 1f5f6632a..000000000 --- a/packages/ui/src/Atoms/Icons/import-2.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/in-progress.svg b/packages/ui/src/Atoms/Icons/in-progress.svg deleted file mode 100644 index 1d7c9c114..000000000 --- a/packages/ui/src/Atoms/Icons/in-progress.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/inbox-empty.svg b/packages/ui/src/Atoms/Icons/inbox-empty.svg deleted file mode 100644 index ebf243e12..000000000 --- a/packages/ui/src/Atoms/Icons/inbox-empty.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/index.tsx b/packages/ui/src/Atoms/Icons/index.tsx index 9bf21bb9b..ad7415554 100644 --- a/packages/ui/src/Atoms/Icons/index.tsx +++ b/packages/ui/src/Atoms/Icons/index.tsx @@ -1,6 +1,8 @@ export { IconArrowUp } from "./IconArrowUp.tsx"; export { IconBox } from "./IconBox.tsx"; export { IconBell2 } from "./IconBell2.tsx"; +export { IconMedal } from "./IconMedal.tsx"; +export { IconMail } from "./IconMail.tsx"; export { IconArrowInbox1 } from "./IconArrowInbox1.tsx"; export { IconCircleX } from "./IconCircleX.tsx"; export { IconFire3 } from "./IconFire3.tsx"; @@ -79,3 +81,5 @@ export { IconBlock } from "./IconBlock.tsx"; export { IconChevronDown } from "./IconChevronDown.tsx"; export { IconPageCross } from "./IconPageCross.tsx"; export { IconRotateCw } from "./IconRotateCw.tsx"; +export { IconPin } from "./IconPin.tsx"; +export { IconMinusLarge } from "./IconMinusLarge.tsx"; diff --git a/packages/ui/src/Atoms/Icons/list-stack.svg b/packages/ui/src/Atoms/Icons/list-stack.svg deleted file mode 100644 index 726542168..000000000 --- a/packages/ui/src/Atoms/Icons/list-stack.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/ui/src/Atoms/Icons/magnifying-glass.svg b/packages/ui/src/Atoms/Icons/magnifying-glass.svg deleted file mode 100644 index 18450cf2d..000000000 --- a/packages/ui/src/Atoms/Icons/magnifying-glass.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/not-started.svg b/packages/ui/src/Atoms/Icons/not-started.svg deleted file mode 100644 index b848ce9f1..000000000 --- a/packages/ui/src/Atoms/Icons/not-started.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/page-check-1.svg b/packages/ui/src/Atoms/Icons/page-check-1.svg deleted file mode 100644 index 52600bb3a..000000000 --- a/packages/ui/src/Atoms/Icons/page-check-1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/page-check.svg b/packages/ui/src/Atoms/Icons/page-check.svg deleted file mode 100644 index b1a7be091..000000000 --- a/packages/ui/src/Atoms/Icons/page-check.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/page-cross.svg b/packages/ui/src/Atoms/Icons/page-cross.svg deleted file mode 100644 index daa32892e..000000000 --- a/packages/ui/src/Atoms/Icons/page-cross.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/page-text-line.svg b/packages/ui/src/Atoms/Icons/page-text-line.svg deleted file mode 100644 index c6abed23f..000000000 --- a/packages/ui/src/Atoms/Icons/page-text-line.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/page-text-solid.svg b/packages/ui/src/Atoms/Icons/page-text-solid.svg deleted file mode 100644 index 19dc06415..000000000 --- a/packages/ui/src/Atoms/Icons/page-text-solid.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/pencil.svg b/packages/ui/src/Atoms/Icons/pencil.svg deleted file mode 100644 index cd510b65e..000000000 --- a/packages/ui/src/Atoms/Icons/pencil.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/people-add-2-line.svg b/packages/ui/src/Atoms/Icons/people-add-2-line.svg deleted file mode 100644 index 06adfdd29..000000000 --- a/packages/ui/src/Atoms/Icons/people-add-2-line.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/people-add.svg b/packages/ui/src/Atoms/Icons/people-add.svg deleted file mode 100644 index 45fbe26a3..000000000 --- a/packages/ui/src/Atoms/Icons/people-add.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/ui/src/Atoms/Icons/plus-large.svg b/packages/ui/src/Atoms/Icons/plus-large.svg deleted file mode 100644 index 38fe572a5..000000000 --- a/packages/ui/src/Atoms/Icons/plus-large.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/plus-small.svg b/packages/ui/src/Atoms/Icons/plus-small.svg deleted file mode 100644 index 4cf246917..000000000 --- a/packages/ui/src/Atoms/Icons/plus-small.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/priority.svg b/packages/ui/src/Atoms/Icons/priority.svg deleted file mode 100644 index 0d2d59422..000000000 --- a/packages/ui/src/Atoms/Icons/priority.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/ui/src/Atoms/Icons/radio-unchecked.svg b/packages/ui/src/Atoms/Icons/radio-unchecked.svg deleted file mode 100644 index 2b36ecc96..000000000 --- a/packages/ui/src/Atoms/Icons/radio-unchecked.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/rec-keyframe.svg b/packages/ui/src/Atoms/Icons/rec-keyframe.svg deleted file mode 100644 index 7f8e0656c..000000000 --- a/packages/ui/src/Atoms/Icons/rec-keyframe.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/settings-gear-2.svg b/packages/ui/src/Atoms/Icons/settings-gear-2.svg deleted file mode 100644 index 2ad9ac8fe..000000000 --- a/packages/ui/src/Atoms/Icons/settings-gear-2.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/shield.svg b/packages/ui/src/Atoms/Icons/shield.svg deleted file mode 100644 index c460d1af9..000000000 --- a/packages/ui/src/Atoms/Icons/shield.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/signature.svg b/packages/ui/src/Atoms/Icons/signature.svg deleted file mode 100644 index 56893cd5f..000000000 --- a/packages/ui/src/Atoms/Icons/signature.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/square-behind-square-2.svg b/packages/ui/src/Atoms/Icons/square-behind-square-2.svg deleted file mode 100644 index 758f95a38..000000000 --- a/packages/ui/src/Atoms/Icons/square-behind-square-2.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/store.svg b/packages/ui/src/Atoms/Icons/store.svg deleted file mode 100644 index c15fa61e0..000000000 --- a/packages/ui/src/Atoms/Icons/store.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages/ui/src/Atoms/Icons/sun.svg b/packages/ui/src/Atoms/Icons/sun.svg deleted file mode 100644 index 815ae9d39..000000000 --- a/packages/ui/src/Atoms/Icons/sun.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/packages/ui/src/Atoms/Icons/todo.svg b/packages/ui/src/Atoms/Icons/todo.svg deleted file mode 100644 index 4e9f88b64..000000000 --- a/packages/ui/src/Atoms/Icons/todo.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/todo2.svg b/packages/ui/src/Atoms/Icons/todo2.svg deleted file mode 100644 index 642d0e48b..000000000 --- a/packages/ui/src/Atoms/Icons/todo2.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/packages/ui/src/Atoms/Icons/trash-can-solid.svg b/packages/ui/src/Atoms/Icons/trash-can-solid.svg deleted file mode 100644 index 580f06ea5..000000000 --- a/packages/ui/src/Atoms/Icons/trash-can-solid.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/ui/src/Atoms/Icons/trash-can.svg b/packages/ui/src/Atoms/Icons/trash-can.svg deleted file mode 100644 index b31f128d1..000000000 --- a/packages/ui/src/Atoms/Icons/trash-can.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/packages/ui/src/Atoms/Icons/upload.svg b/packages/ui/src/Atoms/Icons/upload.svg deleted file mode 100644 index 7fde469d4..000000000 --- a/packages/ui/src/Atoms/Icons/upload.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/ui/src/Atoms/Icons/warning.svg b/packages/ui/src/Atoms/Icons/warning.svg deleted file mode 100644 index d11e0f793..000000000 --- a/packages/ui/src/Atoms/Icons/warning.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/ui/src/Atoms/Logo/Logo.tsx b/packages/ui/src/Atoms/Logo/Logo.tsx index 74f4c892d..34cc65192 100644 --- a/packages/ui/src/Atoms/Logo/Logo.tsx +++ b/packages/ui/src/Atoms/Logo/Logo.tsx @@ -1,8 +1,73 @@ +import clsx from "clsx"; +import { useId } from "react"; + type Props = { className?: string; + withPicto?: boolean; }; -export function Logo({ className }: Props) { +export function Logo({ className, withPicto }: Props) { + const id = useId(); + if (withPicto) { + return ( + + + + + + + + + + + + + + + + + + + ); + } return ( ) { return ( - + {children} ); diff --git a/packages/ui/src/Molecules/Badge/FrameworkLogo.stories.tsx b/packages/ui/src/Molecules/Badge/FrameworkLogo.stories.tsx new file mode 100644 index 000000000..182660359 --- /dev/null +++ b/packages/ui/src/Molecules/Badge/FrameworkLogo.stories.tsx @@ -0,0 +1,17 @@ +import { FrameworkLogo } from "./FrameworkLogo"; +import type { Meta, StoryObj } from "@storybook/react"; + +export default { + title: "Molecules/Badges/FrameworkLogo", + component: FrameworkLogo, + argTypes: {}, +} satisfies Meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + name: "SOC 2", + className: "size-12", + }, +}; diff --git a/packages/ui/src/Molecules/Badge/FrameworkLogo.tsx b/packages/ui/src/Molecules/Badge/FrameworkLogo.tsx new file mode 100644 index 000000000..f3c7f711b --- /dev/null +++ b/packages/ui/src/Molecules/Badge/FrameworkLogo.tsx @@ -0,0 +1,23 @@ +import { availableFrameworks } from "@probo/helpers"; +import { Avatar } from "../../Atoms/Avatar/Avatar.tsx"; + +const availableLogos = new Map( + availableFrameworks.map((framework) => [framework.name, framework.logo]), +); + +export function FrameworkLogo({ + name, + alt, + className, +}: { + name: string; + alt?: string; + className?: string; +}) { + const logo = availableLogos.get(name); + return logo ? ( + {alt} + ) : ( + + ); +} diff --git a/packages/ui/src/Molecules/Dialog/Dialog.tsx b/packages/ui/src/Molecules/Dialog/Dialog.tsx index 4179c43c7..e4262ee37 100644 --- a/packages/ui/src/Molecules/Dialog/Dialog.tsx +++ b/packages/ui/src/Molecules/Dialog/Dialog.tsx @@ -91,11 +91,13 @@ export function Dialog({ } }; - const contentProps = closable ? {} : { - onEscapeKeyDown: (e: Event) => e.preventDefault(), - onPointerDownOutside: (e: Event) => e.preventDefault(), - onInteractOutside: (e: Event) => e.preventDefault(), - }; + const contentProps = closable + ? {} + : { + onEscapeKeyDown: (e: Event) => e.preventDefault(), + onPointerDownOutside: (e: Event) => e.preventDefault(), + onInteractOutside: (e: Event) => e.preventDefault(), + }; return ( @@ -142,14 +144,16 @@ export function Dialog({ export function DialogFooter({ children, exitLabel, + className, }: { children?: ReactNode; exitLabel?: string; + className?: string; }) { const { __ } = useTranslate(); const { footer } = dialog(); return ( -
+
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 939ae3889..f672dbc8a 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -69,6 +69,7 @@ export { DocumentTypeBadge } from "./Molecules/Badge/DocumentTypeBadge"; export { SentitivityOptions } from "./Molecules/Select/SentitivityOptions"; export { ImpactOptions } from "./Molecules/Select/ImpactOptions"; export { DurationPicker } from "./Molecules/DurationPicker/DurationPicker"; +export { FrameworkLogo } from "./Molecules/Badge/FrameworkLogo"; // Hooks export { useToast, Toasts } from "./Atoms/Toasts/Toasts"; diff --git a/pkg/server/api/trust/v1/schema.graphql b/pkg/server/api/trust/v1/schema.graphql index c7177d1a4..057710656 100644 --- a/pkg/server/api/trust/v1/schema.graphql +++ b/pkg/server/api/trust/v1/schema.graphql @@ -552,6 +552,7 @@ type AcceptNonDisclosureAgreementPayload{ } type Query { + node(id: ID!): Node! trustCenterBySlug(slug: String!): TrustCenter @mustBeAuthenticated(role: NONE) }