amliq-dashboard 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (492) hide show
  1. package/.env.example +3 -0
  2. package/.env.production +1 -0
  3. package/Dockerfile +26 -0
  4. package/QUICK_START.md +267 -0
  5. package/README.md +161 -0
  6. package/TESTING_GUIDE.md +322 -0
  7. package/dist/.well-known/ai-plugin.json +15 -0
  8. package/dist/_headers +8 -0
  9. package/dist/_redirects +1 -0
  10. package/dist/assets/APIKeys-BvwFauIs.js +6 -0
  11. package/dist/assets/APIKeys-DaMSBZQL.js +1 -0
  12. package/dist/assets/AdverseMedia-DckXfMzS.js +4 -0
  13. package/dist/assets/AlertDetailPage-Bc2_zwu_.js +1 -0
  14. package/dist/assets/AlertQueue-DFtBiRoM.js +8 -0
  15. package/dist/assets/Analytics-DtruB5lQ.js +1 -0
  16. package/dist/assets/AuditTrail-BK68ePu0.js +1 -0
  17. package/dist/assets/AuthDivider-gRHEt7gx.js +1 -0
  18. package/dist/assets/Badge-B9VFkofy.js +1 -0
  19. package/dist/assets/BatchJobs-Bz6KFnXD.js +6 -0
  20. package/dist/assets/BillingPage-R9nQ5nFb.js +11 -0
  21. package/dist/assets/Card-Cw-T_-oU.js +1 -0
  22. package/dist/assets/CaseDetail-DYs7Zg_y.js +7 -0
  23. package/dist/assets/CaseManagement-B1Q4Dp1Y.js +1 -0
  24. package/dist/assets/ComplianceReport-Dhssqc9T.js +1 -0
  25. package/dist/assets/Configuration-B92kl9T0.js +1 -0
  26. package/dist/assets/CryptoScreening-C7yFlskC.js +1 -0
  27. package/dist/assets/Dashboard-w4-Nhv9q.js +17 -0
  28. package/dist/assets/DataSources-u3-Ri_5_.js +3 -0
  29. package/dist/assets/EDDWorkflow-CFzlEO0e.js +1 -0
  30. package/dist/assets/EmptyState-Do0xJAT9.js +6 -0
  31. package/dist/assets/ForgotPassword-BPYyQFQp.js +1 -0
  32. package/dist/assets/LandingPage-CjaP0zw4.js +41 -0
  33. package/dist/assets/ListsMarketplace-CG6KkT9B.js +6 -0
  34. package/dist/assets/Login-677LEGP1.js +1 -0
  35. package/dist/assets/MFASetup-BxqCPvui.js +1 -0
  36. package/dist/assets/Monitoring-9TN9MK4y.js +1 -0
  37. package/dist/assets/Onboarding-Cf0Y83lX.js +1 -0
  38. package/dist/assets/Operations-CcXwc2xw.js +10 -0
  39. package/dist/assets/Overview-B_Ky0VWV.js +1 -0
  40. package/dist/assets/PEPScreening-pUQjTH9c.js +1 -0
  41. package/dist/assets/PageHeader-BObHFn0i.js +1 -0
  42. package/dist/assets/PrivacyPolicy-DZ2xrKir.js +1 -0
  43. package/dist/assets/ResetPassword-AtxtpIG1.js +1 -0
  44. package/dist/assets/RiskAssessment-Dzuh1Usv.js +1 -0
  45. package/dist/assets/SARForm-D8w2ZGe-.js +1 -0
  46. package/dist/assets/SanctionsLists-CPA3UH2v.js +1 -0
  47. package/dist/assets/ScheduledTasks-Dsjk-6UR.js +1 -0
  48. package/dist/assets/ScreenEntity-D1U0YL7v.js +3 -0
  49. package/dist/assets/ScreeningProgress-BW49PzoB.js +66 -0
  50. package/dist/assets/SearchField-CulFKdiI.js +1 -0
  51. package/dist/assets/Signup-C0FmFOo_.js +1 -0
  52. package/dist/assets/SystemHealth-B_8u4eva.js +1 -0
  53. package/dist/assets/TaskHistory-BCmEM89q.js +3 -0
  54. package/dist/assets/Team-CUo_FlU7.js +1 -0
  55. package/dist/assets/TenantDetail-CgZQHUY8.js +1 -0
  56. package/dist/assets/Tenants-RB9E9ick.js +2 -0
  57. package/dist/assets/TermsOfService-BfL-kndX.js +1 -0
  58. package/dist/assets/TransactionMonitoring-DGh_T22s.js +14 -0
  59. package/dist/assets/TxnScreening-B7cm2-eh.js +1 -0
  60. package/dist/assets/UBOChain-falXAsCo.js +1 -0
  61. package/dist/assets/Users-Doakpg9c.js +1 -0
  62. package/dist/assets/Webhooks-BZpAfaxv.js +1 -0
  63. package/dist/assets/alert-triangle-YCFVm7B_.js +6 -0
  64. package/dist/assets/alerts-COUnTwWY.js +1 -0
  65. package/dist/assets/arrow-left-9ApLqP95.js +6 -0
  66. package/dist/assets/check-VTcvVtIU.js +6 -0
  67. package/dist/assets/check-circle-2-Dn-lG5YQ.js +6 -0
  68. package/dist/assets/code-DIJRWFVv.js +6 -0
  69. package/dist/assets/fingerprint-C0MGVtax.js +6 -0
  70. package/dist/assets/flag-B8_Gwxh6.js +6 -0
  71. package/dist/assets/index-CfdYcqRM.js +289 -0
  72. package/dist/assets/index-HPU_Rhdu.css +1 -0
  73. package/dist/assets/layers-zHz2o4vo.js +6 -0
  74. package/dist/assets/loader-B9_dNihg.js +6 -0
  75. package/dist/assets/mail-BijL2qwp.js +6 -0
  76. package/dist/assets/plus-i0oBIIPS.js +6 -0
  77. package/dist/assets/refresh-cw-CSuAwutt.js +6 -0
  78. package/dist/assets/useAnalytics-Bj8IONcw.js +72 -0
  79. package/dist/assets/x-circle-DLGKvijE.js +6 -0
  80. package/dist/favicon.svg +15 -0
  81. package/dist/index.html +51 -0
  82. package/dist/llms.txt +28 -0
  83. package/dist/logo.png +0 -0
  84. package/dist/logo.svg +17 -0
  85. package/dist/manifest.json +44 -0
  86. package/dist/robots.txt +15 -0
  87. package/dist/schema.json +13 -0
  88. package/dist/sitemap.xml +28 -0
  89. package/dist/sw.js +67 -0
  90. package/e2e/auth-setup.ts +20 -0
  91. package/e2e/billing.spec.ts +50 -0
  92. package/e2e/cases.spec.ts +53 -0
  93. package/e2e/compliance.spec.ts +65 -0
  94. package/e2e/config.spec.ts +56 -0
  95. package/e2e/dashboard.spec.ts +47 -0
  96. package/e2e/fixtures.ts +33 -0
  97. package/e2e/lists.spec.ts +43 -0
  98. package/e2e/login.spec.ts +64 -0
  99. package/e2e/media.spec.ts +48 -0
  100. package/e2e/mocks.ts +51 -0
  101. package/e2e/monitoring.spec.ts +44 -0
  102. package/e2e/navigation.spec.ts +56 -0
  103. package/e2e/onboarding.spec.ts +49 -0
  104. package/e2e/responsive.spec.ts +40 -0
  105. package/e2e/risk.spec.ts +61 -0
  106. package/e2e/screening.spec.ts +76 -0
  107. package/e2e/team.spec.ts +53 -0
  108. package/index.html +50 -0
  109. package/package.json +47 -0
  110. package/playwright.config.ts +35 -0
  111. package/postcss.config.js +6 -0
  112. package/public/.well-known/ai-plugin.json +15 -0
  113. package/public/_headers +8 -0
  114. package/public/_redirects +1 -0
  115. package/public/favicon.svg +15 -0
  116. package/public/llms.txt +28 -0
  117. package/public/logo.png +0 -0
  118. package/public/logo.svg +17 -0
  119. package/public/manifest.json +44 -0
  120. package/public/robots.txt +15 -0
  121. package/public/schema.json +13 -0
  122. package/public/sitemap.xml +28 -0
  123. package/public/sw.js +67 -0
  124. package/scripts/test-runner.sh +152 -0
  125. package/src/App.tsx +48 -0
  126. package/src/api/alerts.ts +19 -0
  127. package/src/api/analytics.ts +6 -0
  128. package/src/api/audit.ts +11 -0
  129. package/src/api/auth.ts +26 -0
  130. package/src/api/billing.ts +54 -0
  131. package/src/api/cases.ts +48 -0
  132. package/src/api/client.ts +50 -0
  133. package/src/api/config.ts +30 -0
  134. package/src/api/edd.ts +25 -0
  135. package/src/api/enforcement.ts +33 -0
  136. package/src/api/lists.ts +24 -0
  137. package/src/api/monitoring.ts +82 -0
  138. package/src/api/pep.ts +30 -0
  139. package/src/api/risk.ts +26 -0
  140. package/src/api/screening.ts +37 -0
  141. package/src/api/team.ts +27 -0
  142. package/src/api/transactions.ts +37 -0
  143. package/src/components/admin/TenantCards.tsx +51 -0
  144. package/src/components/alerts/AlertActions.test.tsx +80 -0
  145. package/src/components/alerts/AlertActions.tsx +68 -0
  146. package/src/components/alerts/AlertCard.test.tsx +86 -0
  147. package/src/components/alerts/AlertCard.tsx +60 -0
  148. package/src/components/alerts/AlertDetailSidebar.tsx +63 -0
  149. package/src/components/alerts/AlertFilters.test.tsx +73 -0
  150. package/src/components/alerts/AlertFilters.tsx +88 -0
  151. package/src/components/alerts/EntityDetailsCard.test.tsx +61 -0
  152. package/src/components/alerts/EntityDetailsCard.tsx +37 -0
  153. package/src/components/alerts/NotesCard.test.tsx +39 -0
  154. package/src/components/alerts/NotesCard.tsx +28 -0
  155. package/src/components/auth/AuthDivider.tsx +18 -0
  156. package/src/components/auth/LoginForm.tsx +62 -0
  157. package/src/components/auth/LoginLeftPanel.tsx +43 -0
  158. package/src/components/auth/PasswordStrength.tsx +26 -0
  159. package/src/components/auth/SignInButtons.tsx +46 -0
  160. package/src/components/auth/SignupLeftPanel.tsx +35 -0
  161. package/src/components/auth/countries.ts +17 -0
  162. package/src/components/charts/AreaChart.tsx +45 -0
  163. package/src/components/charts/BarChart.tsx +48 -0
  164. package/src/components/charts/DonutChart.tsx +47 -0
  165. package/src/components/compliance/CaseActions.tsx +74 -0
  166. package/src/components/compliance/CaseTimeline.tsx +68 -0
  167. package/src/components/compliance/MediaResultCard.tsx +87 -0
  168. package/src/components/compliance/PEPResultCard.tsx +78 -0
  169. package/src/components/config/MatchingModesCard.test.tsx +75 -0
  170. package/src/components/config/MatchingModesCard.tsx +40 -0
  171. package/src/components/config/ScreeningLayersCard.test.tsx +57 -0
  172. package/src/components/config/ScreeningLayersCard.tsx +36 -0
  173. package/src/components/config/ThresholdsCard.test.tsx +79 -0
  174. package/src/components/config/ThresholdsCard.tsx +51 -0
  175. package/src/components/dashboard/ActivityFeed.tsx +93 -0
  176. package/src/components/dashboard/DashboardGreeting.tsx +23 -0
  177. package/src/components/dashboard/DashboardSkeleton.tsx +35 -0
  178. package/src/components/dashboard/QuickActions.tsx +52 -0
  179. package/src/components/dashboard/TopEntitiesTable.tsx +63 -0
  180. package/src/components/data/ComplianceMetrics.test.tsx +32 -0
  181. package/src/components/data/ComplianceMetrics.tsx +40 -0
  182. package/src/components/data/ConfidenceScore.test.tsx +62 -0
  183. package/src/components/data/ConfidenceScore.tsx +27 -0
  184. package/src/components/data/StatCard.test.tsx +72 -0
  185. package/src/components/data/StatCard.tsx +63 -0
  186. package/src/components/data/StatusBadge.test.tsx +63 -0
  187. package/src/components/data/StatusBadge.tsx +39 -0
  188. package/src/components/layout/AppShell.tsx +48 -0
  189. package/src/components/layout/Breadcrumbs.tsx +48 -0
  190. package/src/components/layout/CommandPalette.tsx +81 -0
  191. package/src/components/layout/DashboardLayout.tsx +19 -0
  192. package/src/components/layout/MobileHeader.tsx +30 -0
  193. package/src/components/layout/NavGroup.test.tsx +63 -0
  194. package/src/components/layout/NavGroup.tsx +64 -0
  195. package/src/components/layout/NotificationBell.tsx +89 -0
  196. package/src/components/layout/PageHeader.test.tsx +61 -0
  197. package/src/components/layout/PageHeader.tsx +19 -0
  198. package/src/components/layout/ProtectedRoute.tsx +31 -0
  199. package/src/components/layout/PublicLayout.tsx +17 -0
  200. package/src/components/layout/Sidebar.test.tsx +67 -0
  201. package/src/components/layout/Sidebar.tsx +92 -0
  202. package/src/components/layout/Toolbar.test.tsx +47 -0
  203. package/src/components/layout/Toolbar.tsx +68 -0
  204. package/src/components/layout/navItems.ts +94 -0
  205. package/src/components/lists/ListCard.tsx +78 -0
  206. package/src/components/lists/ListMarketplaceCard.tsx +77 -0
  207. package/src/components/screening/CircularConfidence.tsx +38 -0
  208. package/src/components/screening/LimitReachedBanner.tsx +31 -0
  209. package/src/components/screening/ListSelector.tsx +64 -0
  210. package/src/components/screening/MatchDetailHeader.tsx +64 -0
  211. package/src/components/screening/MatchEntityInfo.tsx +56 -0
  212. package/src/components/screening/MatchEvidenceBars.tsx +65 -0
  213. package/src/components/screening/MatchMetadata.tsx +95 -0
  214. package/src/components/screening/ScreenResults.tsx +49 -0
  215. package/src/components/screening/ScreeningForm.test.tsx +83 -0
  216. package/src/components/screening/ScreeningForm.tsx +100 -0
  217. package/src/components/screening/ScreeningLayersList.test.tsx +33 -0
  218. package/src/components/screening/ScreeningLayersList.tsx +46 -0
  219. package/src/components/screening/ScreeningProgress.tsx +91 -0
  220. package/src/components/screening/ScreeningQuotaBanner.tsx +64 -0
  221. package/src/components/screening/ScreeningResultCard.tsx +47 -0
  222. package/src/components/screening/ScreeningResultRow.tsx +45 -0
  223. package/src/components/screening/ScreeningResults.test.tsx +37 -0
  224. package/src/components/screening/ScreeningResults.tsx +33 -0
  225. package/src/components/screening/ShareResults.tsx +103 -0
  226. package/src/components/screening/ThresholdSlider.tsx +23 -0
  227. package/src/components/transactions/WebhookCTA.tsx +63 -0
  228. package/src/components/ui/Avatar.test.tsx +47 -0
  229. package/src/components/ui/Avatar.tsx +35 -0
  230. package/src/components/ui/Badge.test.tsx +49 -0
  231. package/src/components/ui/Badge.tsx +33 -0
  232. package/src/components/ui/Button.test.tsx +56 -0
  233. package/src/components/ui/Button.tsx +46 -0
  234. package/src/components/ui/Card.test.tsx +61 -0
  235. package/src/components/ui/Card.tsx +29 -0
  236. package/src/components/ui/ConfirmModal.tsx +67 -0
  237. package/src/components/ui/Divider.test.tsx +24 -0
  238. package/src/components/ui/Divider.tsx +5 -0
  239. package/src/components/ui/EmptyState.test.tsx +49 -0
  240. package/src/components/ui/EmptyState.tsx +22 -0
  241. package/src/components/ui/ErrorBoundary.tsx +44 -0
  242. package/src/components/ui/ExportMenu.tsx +71 -0
  243. package/src/components/ui/LanguageSwitcher.tsx +37 -0
  244. package/src/components/ui/LoadingSpinner.test.tsx +41 -0
  245. package/src/components/ui/LoadingSpinner.tsx +21 -0
  246. package/src/components/ui/MetricCard.tsx +63 -0
  247. package/src/components/ui/ScoreRing.tsx +51 -0
  248. package/src/components/ui/SearchField.test.tsx +55 -0
  249. package/src/components/ui/SearchField.tsx +31 -0
  250. package/src/components/ui/SeverityBadge.tsx +57 -0
  251. package/src/components/ui/ThemeToggle.tsx +37 -0
  252. package/src/components/ui/Toast.test.tsx +79 -0
  253. package/src/components/ui/Toast.tsx +75 -0
  254. package/src/components/ui/Toggle.test.tsx +85 -0
  255. package/src/components/ui/Toggle.tsx +46 -0
  256. package/src/context/AuthContext.tsx +71 -0
  257. package/src/data/pepProfiles.ts +76 -0
  258. package/src/data/pepProfilesExtra.ts +58 -0
  259. package/src/hooks/useAlerts.ts +36 -0
  260. package/src/hooks/useAnalytics.ts +23 -0
  261. package/src/hooks/useApi.test.ts +79 -0
  262. package/src/hooks/useApi.ts +33 -0
  263. package/src/hooks/useAudit.ts +28 -0
  264. package/src/hooks/useBilling.ts +38 -0
  265. package/src/hooks/useConfig.ts +35 -0
  266. package/src/hooks/useDebounce.test.ts +84 -0
  267. package/src/hooks/useDebounce.ts +15 -0
  268. package/src/hooks/useDirection.ts +15 -0
  269. package/src/hooks/useLists.ts +34 -0
  270. package/src/hooks/useMediaQuery.test.ts +97 -0
  271. package/src/hooks/useMediaQuery.ts +28 -0
  272. package/src/hooks/useScreening.ts +33 -0
  273. package/src/hooks/useSidebar.ts +18 -0
  274. package/src/hooks/useUsage.ts +27 -0
  275. package/src/i18n/config.ts +33 -0
  276. package/src/i18n/locales/ar/admin.json +19 -0
  277. package/src/i18n/locales/ar/alerts.json +52 -0
  278. package/src/i18n/locales/ar/analytics.json +9 -0
  279. package/src/i18n/locales/ar/audit.json +12 -0
  280. package/src/i18n/locales/ar/auth.json +60 -0
  281. package/src/i18n/locales/ar/batch.json +5 -0
  282. package/src/i18n/locales/ar/billing.json +41 -0
  283. package/src/i18n/locales/ar/common.json +65 -0
  284. package/src/i18n/locales/ar/compliance.json +83 -0
  285. package/src/i18n/locales/ar/config.json +13 -0
  286. package/src/i18n/locales/ar/dashboard.json +19 -0
  287. package/src/i18n/locales/ar/errors.json +9 -0
  288. package/src/i18n/locales/ar/index.ts +29 -0
  289. package/src/i18n/locales/ar/legal.json +10 -0
  290. package/src/i18n/locales/ar/lists.json +6 -0
  291. package/src/i18n/locales/ar/marketing.json +110 -0
  292. package/src/i18n/locales/ar/monitoring.json +15 -0
  293. package/src/i18n/locales/ar/nav.json +35 -0
  294. package/src/i18n/locales/ar/onboarding.json +25 -0
  295. package/src/i18n/locales/ar/platform.json +23 -0
  296. package/src/i18n/locales/ar/screening.json +26 -0
  297. package/src/i18n/locales/ar/team.json +11 -0
  298. package/src/i18n/locales/en/admin.json +21 -0
  299. package/src/i18n/locales/en/alerts.json +52 -0
  300. package/src/i18n/locales/en/analytics.json +9 -0
  301. package/src/i18n/locales/en/audit.json +12 -0
  302. package/src/i18n/locales/en/auth.json +60 -0
  303. package/src/i18n/locales/en/batch.json +5 -0
  304. package/src/i18n/locales/en/billing.json +87 -0
  305. package/src/i18n/locales/en/common.json +65 -0
  306. package/src/i18n/locales/en/compliance.json +83 -0
  307. package/src/i18n/locales/en/config.json +29 -0
  308. package/src/i18n/locales/en/dashboard.json +23 -0
  309. package/src/i18n/locales/en/errors.json +9 -0
  310. package/src/i18n/locales/en/index.ts +29 -0
  311. package/src/i18n/locales/en/legal.json +114 -0
  312. package/src/i18n/locales/en/lists.json +6 -0
  313. package/src/i18n/locales/en/marketing.json +174 -0
  314. package/src/i18n/locales/en/monitoring.json +15 -0
  315. package/src/i18n/locales/en/nav.json +35 -0
  316. package/src/i18n/locales/en/onboarding.json +31 -0
  317. package/src/i18n/locales/en/platform.json +25 -0
  318. package/src/i18n/locales/en/screening.json +26 -0
  319. package/src/i18n/locales/en/team.json +12 -0
  320. package/src/i18n/locales/he/admin.json +19 -0
  321. package/src/i18n/locales/he/alerts.json +52 -0
  322. package/src/i18n/locales/he/analytics.json +9 -0
  323. package/src/i18n/locales/he/audit.json +12 -0
  324. package/src/i18n/locales/he/auth.json +60 -0
  325. package/src/i18n/locales/he/batch.json +5 -0
  326. package/src/i18n/locales/he/billing.json +41 -0
  327. package/src/i18n/locales/he/common.json +65 -0
  328. package/src/i18n/locales/he/compliance.json +83 -0
  329. package/src/i18n/locales/he/config.json +13 -0
  330. package/src/i18n/locales/he/dashboard.json +19 -0
  331. package/src/i18n/locales/he/errors.json +9 -0
  332. package/src/i18n/locales/he/index.ts +29 -0
  333. package/src/i18n/locales/he/legal.json +10 -0
  334. package/src/i18n/locales/he/lists.json +6 -0
  335. package/src/i18n/locales/he/marketing.json +110 -0
  336. package/src/i18n/locales/he/monitoring.json +15 -0
  337. package/src/i18n/locales/he/nav.json +35 -0
  338. package/src/i18n/locales/he/onboarding.json +25 -0
  339. package/src/i18n/locales/he/platform.json +23 -0
  340. package/src/i18n/locales/he/screening.json +26 -0
  341. package/src/i18n/locales/he/team.json +11 -0
  342. package/src/index.css +112 -0
  343. package/src/main.tsx +15 -0
  344. package/src/pages/APIKeys.tsx +120 -0
  345. package/src/pages/AddMonitorModal.tsx +30 -0
  346. package/src/pages/AdverseMedia.test.tsx +18 -0
  347. package/src/pages/AdverseMedia.tsx +89 -0
  348. package/src/pages/AlertDetailPage.tsx +64 -0
  349. package/src/pages/AlertQueue.test.tsx +48 -0
  350. package/src/pages/AlertQueue.tsx +63 -0
  351. package/src/pages/Analytics.tsx +50 -0
  352. package/src/pages/AuditTrail.tsx +64 -0
  353. package/src/pages/BatchJobs.tsx +79 -0
  354. package/src/pages/CaseDetail.tsx +72 -0
  355. package/src/pages/CaseManagement.test.tsx +31 -0
  356. package/src/pages/CaseManagement.tsx +92 -0
  357. package/src/pages/Configuration.test.tsx +96 -0
  358. package/src/pages/Configuration.tsx +123 -0
  359. package/src/pages/CryptoScreening.tsx +109 -0
  360. package/src/pages/Dashboard.test.tsx +51 -0
  361. package/src/pages/Dashboard.tsx +66 -0
  362. package/src/pages/EDDWorkflow.test.tsx +29 -0
  363. package/src/pages/EDDWorkflow.tsx +73 -0
  364. package/src/pages/ForgotPassword.test.tsx +49 -0
  365. package/src/pages/ForgotPassword.tsx +67 -0
  366. package/src/pages/ListsMarketplace.tsx +102 -0
  367. package/src/pages/Login.test.tsx +100 -0
  368. package/src/pages/Login.tsx +57 -0
  369. package/src/pages/MFASetup.tsx +114 -0
  370. package/src/pages/MonitorProfileCard.tsx +27 -0
  371. package/src/pages/Monitoring.tsx +68 -0
  372. package/src/pages/Onboarding.test.tsx +36 -0
  373. package/src/pages/Onboarding.tsx +60 -0
  374. package/src/pages/PEPScreening.test.tsx +15 -0
  375. package/src/pages/PEPScreening.tsx +100 -0
  376. package/src/pages/ResetPassword.tsx +81 -0
  377. package/src/pages/RiskAssessment.test.tsx +15 -0
  378. package/src/pages/RiskAssessment.tsx +108 -0
  379. package/src/pages/SanctionsLists.tsx +74 -0
  380. package/src/pages/ScreenEntity.test.tsx +82 -0
  381. package/src/pages/ScreenEntity.tsx +76 -0
  382. package/src/pages/Signup.test.tsx +98 -0
  383. package/src/pages/Signup.tsx +92 -0
  384. package/src/pages/TaskHistory.tsx +183 -0
  385. package/src/pages/Team.test.tsx +15 -0
  386. package/src/pages/Team.tsx +140 -0
  387. package/src/pages/TransactionMonitoring.test.tsx +18 -0
  388. package/src/pages/TransactionMonitoring.tsx +118 -0
  389. package/src/pages/TxnScreening.tsx +125 -0
  390. package/src/pages/UBOChain.test.tsx +35 -0
  391. package/src/pages/UBOChain.tsx +65 -0
  392. package/src/pages/Webhooks.tsx +137 -0
  393. package/src/pages/admin/DataSources.tsx +230 -0
  394. package/src/pages/admin/Operations.tsx +103 -0
  395. package/src/pages/admin/ScheduledTasks.tsx +155 -0
  396. package/src/pages/admin/SystemHealth.tsx +58 -0
  397. package/src/pages/admin/TenantDetail.tsx +62 -0
  398. package/src/pages/admin/Tenants.test.tsx +20 -0
  399. package/src/pages/admin/Tenants.tsx +63 -0
  400. package/src/pages/admin/opsRunners.ts +81 -0
  401. package/src/pages/admin/opsTerminal.tsx +63 -0
  402. package/src/pages/billing/ActiveSubscriptions.tsx +41 -0
  403. package/src/pages/billing/AddProductModal.tsx +99 -0
  404. package/src/pages/billing/BillingPage.test.tsx +30 -0
  405. package/src/pages/billing/BillingPage.tsx +67 -0
  406. package/src/pages/billing/CurrentPlan.tsx +50 -0
  407. package/src/pages/billing/InvoiceList.tsx +104 -0
  408. package/src/pages/billing/InvoiceRow.tsx +37 -0
  409. package/src/pages/billing/LemonSqueezySetup.tsx +51 -0
  410. package/src/pages/billing/PaymentAlert.tsx +33 -0
  411. package/src/pages/billing/PlanComparison.tsx +53 -0
  412. package/src/pages/billing/ProductUsage.tsx +43 -0
  413. package/src/pages/billing/PromoCodeInput.tsx +58 -0
  414. package/src/pages/billing/SeatManager.tsx +80 -0
  415. package/src/pages/billing/SeatRow.tsx +32 -0
  416. package/src/pages/billing/SubscriptionCard.tsx +73 -0
  417. package/src/pages/billing/UpgradeModal.tsx +53 -0
  418. package/src/pages/billing/UsageHistory.tsx +37 -0
  419. package/src/pages/billing/UsageMeter.tsx +26 -0
  420. package/src/pages/billing/UsageOverview.tsx +38 -0
  421. package/src/pages/legal/PrivacyPolicy.tsx +25 -0
  422. package/src/pages/legal/TermsOfService.tsx +25 -0
  423. package/src/pages/marketing/BundleCallout.tsx +24 -0
  424. package/src/pages/marketing/CTASection.tsx +48 -0
  425. package/src/pages/marketing/CaseStudy.tsx +37 -0
  426. package/src/pages/marketing/ComparisonTable.tsx +66 -0
  427. package/src/pages/marketing/CompetitiveEdge.tsx +55 -0
  428. package/src/pages/marketing/DataCoverage.tsx +54 -0
  429. package/src/pages/marketing/DataRain.tsx +30 -0
  430. package/src/pages/marketing/EnterpriseCTA.tsx +26 -0
  431. package/src/pages/marketing/FAQItem.tsx +27 -0
  432. package/src/pages/marketing/FAQSchema.tsx +43 -0
  433. package/src/pages/marketing/FAQSection.tsx +19 -0
  434. package/src/pages/marketing/FeatureDetail.tsx +19 -0
  435. package/src/pages/marketing/FeaturesGrid.tsx +60 -0
  436. package/src/pages/marketing/FeaturesSpotlight.tsx +68 -0
  437. package/src/pages/marketing/FooterSection.tsx +92 -0
  438. package/src/pages/marketing/GradientOrbs.tsx +26 -0
  439. package/src/pages/marketing/HeroSearch.tsx +113 -0
  440. package/src/pages/marketing/HeroSection.tsx +72 -0
  441. package/src/pages/marketing/LandingPage.tsx +45 -0
  442. package/src/pages/marketing/LogoCloud.tsx +31 -0
  443. package/src/pages/marketing/LogoMarquee.tsx +45 -0
  444. package/src/pages/marketing/MarketingNav.tsx +80 -0
  445. package/src/pages/marketing/MatchingLayers.tsx +78 -0
  446. package/src/pages/marketing/MobileMenu.tsx +45 -0
  447. package/src/pages/marketing/PricingCard.tsx +57 -0
  448. package/src/pages/marketing/PricingFeatureRow.tsx +16 -0
  449. package/src/pages/marketing/PricingSection.tsx +103 -0
  450. package/src/pages/marketing/PricingToggle.tsx +40 -0
  451. package/src/pages/marketing/ProductPricingCards.tsx +23 -0
  452. package/src/pages/marketing/ProductShowcase.tsx +81 -0
  453. package/src/pages/marketing/ProductTabs.tsx +45 -0
  454. package/src/pages/marketing/QuoteRotator.tsx +56 -0
  455. package/src/pages/marketing/StatsBar.tsx +81 -0
  456. package/src/pages/marketing/StatsSection.tsx +44 -0
  457. package/src/pages/marketing/TestimonialCard.tsx +38 -0
  458. package/src/pages/marketing/TestimonialsSection.tsx +32 -0
  459. package/src/pages/marketing/animations.tsx +56 -0
  460. package/src/pages/onboarding/CountryStep.tsx +38 -0
  461. package/src/pages/onboarding/ListsStep.tsx +44 -0
  462. package/src/pages/onboarding/StepIndicator.tsx +34 -0
  463. package/src/pages/onboarding/ThresholdStep.tsx +49 -0
  464. package/src/pages/platform/APIKeys.tsx +102 -0
  465. package/src/pages/platform/Overview.tsx +58 -0
  466. package/src/pages/platform/Users.tsx +110 -0
  467. package/src/pages/reporting/ComplianceReport.tsx +99 -0
  468. package/src/pages/reporting/SARForm.tsx +99 -0
  469. package/src/routes/appRoutes.tsx +60 -0
  470. package/src/routes/compliance.tsx +28 -0
  471. package/src/routes/lazyCompliance.ts +34 -0
  472. package/src/routes/lazyPages.ts +35 -0
  473. package/src/routes/lazyPlatform.ts +5 -0
  474. package/src/routes/platform.tsx +15 -0
  475. package/src/styles/effects.css +76 -0
  476. package/src/test/setup.ts +25 -0
  477. package/src/test/utils.tsx +49 -0
  478. package/src/types/alert.ts +31 -0
  479. package/src/types/analytics.ts +16 -0
  480. package/src/types/audit.ts +11 -0
  481. package/src/types/billing.ts +60 -0
  482. package/src/types/common.ts +15 -0
  483. package/src/types/config.ts +19 -0
  484. package/src/types/entity.ts +34 -0
  485. package/src/types/index.ts +8 -0
  486. package/src/types/list.ts +15 -0
  487. package/src/types/screening.ts +32 -0
  488. package/src/vite-env.d.ts +1 -0
  489. package/tailwind.config.js +65 -0
  490. package/tsconfig.json +22 -0
  491. package/vite.config.ts +11 -0
  492. package/vitest.config.ts +19 -0
@@ -0,0 +1,58 @@
1
+ import { useState, useEffect } from 'react'
2
+ import { useTranslation } from 'react-i18next'
3
+ import { PageHeader } from '../../components/layout/PageHeader'
4
+ import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
5
+ import { api } from '../../api/client'
6
+
7
+ interface PlatformStats {
8
+ total_tenants: number
9
+ total_screenings: number
10
+ }
11
+
12
+ export default function PlatformOverview() {
13
+ const { t } = useTranslation('platform')
14
+ const [stats, setStats] = useState<PlatformStats | null>(null)
15
+ const [loading, setLoading] = useState(true)
16
+ const [error, setError] = useState('')
17
+
18
+ useEffect(() => {
19
+ api.get<PlatformStats>('/platform/overview')
20
+ .then(d => setStats(d ?? null))
21
+ .catch((err) => setError(err?.message || 'Failed to load'))
22
+ .finally(() => setLoading(false))
23
+ }, [])
24
+
25
+ if (loading) {
26
+ return <div className="flex items-center justify-center h-96"><LoadingSpinner /></div>
27
+ }
28
+
29
+ if (error) {
30
+ return (
31
+ <div className="p-xl text-center">
32
+ <p className="sf-body text-apple-red mb-md">{error}</p>
33
+ <p className="sf-caption text-apple-label-secondary">
34
+ This page requires admin access.
35
+ </p>
36
+ </div>
37
+ )
38
+ }
39
+
40
+ return (
41
+ <div>
42
+ <PageHeader title={t('overview.title')} />
43
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-lg">
44
+ <StatCard label={t('overview.total_tenants')} value={stats?.total_tenants ?? 0} />
45
+ <StatCard label={t('overview.total_screenings')} value={stats?.total_screenings ?? 0} />
46
+ </div>
47
+ </div>
48
+ )
49
+ }
50
+
51
+ function StatCard({ label, value }: { label: string; value: number }) {
52
+ return (
53
+ <div className="card-vibrancy p-xl">
54
+ <p className="sf-caption mb-xs">{label}</p>
55
+ <p className="text-3xl font-bold">{value.toLocaleString()}</p>
56
+ </div>
57
+ )
58
+ }
@@ -0,0 +1,110 @@
1
+ import { useState, useEffect } from 'react'
2
+ import { useTranslation } from 'react-i18next'
3
+ import { Shield, Mail, User } from 'lucide-react'
4
+ import { PageHeader } from '../../components/layout/PageHeader'
5
+ import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
6
+ import { Badge } from '../../components/ui/Badge'
7
+ import { SearchField } from '../../components/ui/SearchField'
8
+ import { api } from '../../api/client'
9
+
10
+ interface PlatformUser {
11
+ id: string
12
+ email: string
13
+ name?: string
14
+ role: string
15
+ tenant_id?: string
16
+ }
17
+
18
+ const roleColor: Record<string, 'red' | 'blue' | 'green' | 'orange' | 'gray'> = {
19
+ admin: 'red', analyst: 'blue', auditor: 'orange', viewer: 'gray',
20
+ }
21
+
22
+ export default function PlatformUsers() {
23
+ const { t } = useTranslation('platform')
24
+ const [users, setUsers] = useState<PlatformUser[]>([])
25
+ const [search, setSearch] = useState('')
26
+ const [loading, setLoading] = useState(true)
27
+
28
+ useEffect(() => {
29
+ api.get<{ users: PlatformUser[] }>('/platform/users')
30
+ .then(d => setUsers(d?.users ?? []))
31
+ .catch(() => setUsers([]))
32
+ .finally(() => setLoading(false))
33
+ }, [])
34
+
35
+ if (loading) return <div className="flex items-center justify-center h-96"><LoadingSpinner /></div>
36
+
37
+ const q = search.toLowerCase()
38
+ const filtered = users.filter(u =>
39
+ (u.email ?? '').toLowerCase().includes(q) ||
40
+ (u.name ?? '').toLowerCase().includes(q)
41
+ )
42
+
43
+ return (
44
+ <div>
45
+ <PageHeader title={t('users.title')} description={`${users.length} users`} />
46
+ <div className="mb-lg">
47
+ <SearchField placeholder={t('users.search_placeholder')} value={search} onChange={setSearch} />
48
+ </div>
49
+
50
+ {/* Desktop table */}
51
+ <div className="hidden md:block">
52
+ <UsersTable users={filtered} t={t} />
53
+ </div>
54
+
55
+ {/* Mobile cards */}
56
+ <div className="md:hidden space-y-sm">
57
+ {filtered.map(u => <UserCard key={u.id} user={u} />)}
58
+ </div>
59
+
60
+ {filtered.length === 0 && (
61
+ <p className="text-center py-xl text-apple-label-tertiary sf-body">No users found</p>
62
+ )}
63
+ </div>
64
+ )
65
+ }
66
+
67
+ function UsersTable({ users, t }: { users: PlatformUser[]; t: (k: string) => string }) {
68
+ return (
69
+ <div className="glass-panel rounded-apple-lg overflow-hidden">
70
+ <table className="w-full text-sm">
71
+ <thead>
72
+ <tr className="text-left text-apple-label-secondary border-b border-white/10">
73
+ <th className="px-lg py-md">{t('users.email')}</th>
74
+ <th className="px-lg py-md">Name</th>
75
+ <th className="px-lg py-md">{t('users.role')}</th>
76
+ </tr>
77
+ </thead>
78
+ <tbody>
79
+ {users.map(u => (
80
+ <tr key={u.id} className="border-b border-white/5 hover:bg-white/5 transition-colors">
81
+ <td className="px-lg py-md sf-body text-white">{u.email}</td>
82
+ <td className="px-lg py-md sf-body text-white">{u.name ?? '—'}</td>
83
+ <td className="px-lg py-md">
84
+ <Badge size="sm" color={roleColor[u.role] ?? 'gray'}>{u.role}</Badge>
85
+ </td>
86
+ </tr>
87
+ ))}
88
+ </tbody>
89
+ </table>
90
+ </div>
91
+ )
92
+ }
93
+
94
+ function UserCard({ user }: { user: PlatformUser }) {
95
+ const initials = (user.name ?? user.email).slice(0, 2).toUpperCase()
96
+ return (
97
+ <div className="glass-panel rounded-apple-lg p-lg">
98
+ <div className="flex items-center gap-md">
99
+ <div className="flex-shrink-0 w-10 h-10 rounded-full bg-apple-blue/20 flex items-center justify-center">
100
+ <span className="text-sm font-semibold text-apple-blue">{initials}</span>
101
+ </div>
102
+ <div className="min-w-0 flex-1">
103
+ <p className="sf-body text-white font-medium truncate">{user.name ?? '—'}</p>
104
+ <p className="sf-caption text-apple-label-secondary truncate">{user.email}</p>
105
+ </div>
106
+ <Badge size="sm" color={roleColor[user.role] ?? 'gray'}>{user.role}</Badge>
107
+ </div>
108
+ </div>
109
+ )
110
+ }
@@ -0,0 +1,99 @@
1
+ import { useState, useEffect } from 'react'
2
+ import { api } from '../../api/client'
3
+
4
+ interface Metrics {
5
+ screenings_performed: number
6
+ alerts_generated: number
7
+ cases_opened: number
8
+ cases_closed: number
9
+ sars_filed: number
10
+ false_positive_rate: number
11
+ avg_resolution_hours: number
12
+ }
13
+
14
+ const defaultMetrics: Metrics = {
15
+ screenings_performed: 0, alerts_generated: 0,
16
+ cases_opened: 0, cases_closed: 0, sars_filed: 0,
17
+ false_positive_rate: 0, avg_resolution_hours: 0,
18
+ }
19
+
20
+ export function ComplianceReport() {
21
+ const [metrics, setMetrics] = useState<Metrics>(defaultMetrics)
22
+ const [loading, setLoading] = useState(true)
23
+
24
+ useEffect(() => {
25
+ api.get<Metrics>('/reports/dashboard')
26
+ .then(d => setMetrics(d ?? defaultMetrics))
27
+ .catch(() => setMetrics(defaultMetrics))
28
+ .finally(() => setLoading(false))
29
+ }, [])
30
+
31
+ const cards = [
32
+ { label: 'Screenings Performed', value: metrics.screenings_performed },
33
+ { label: 'Alerts Generated', value: metrics.alerts_generated },
34
+ { label: 'Cases Opened', value: metrics.cases_opened },
35
+ { label: 'Cases Closed', value: metrics.cases_closed },
36
+ { label: 'SARs Filed', value: metrics.sars_filed },
37
+ { label: 'False Positive Rate', value: `${(metrics.false_positive_rate * 100).toFixed(1)}%` },
38
+ { label: 'Avg Resolution (hrs)', value: metrics.avg_resolution_hours.toFixed(1) },
39
+ ]
40
+
41
+ const handleExport = () => {
42
+ window.print()
43
+ }
44
+
45
+ if (loading) {
46
+ return (
47
+ <div className="px-md py-lg sm:p-8 max-w-6xl mx-auto">
48
+ <p className="text-apple-label-secondary text-center py-12">Loading report...</p>
49
+ </div>
50
+ )
51
+ }
52
+
53
+ return (
54
+ <div className="px-md py-lg sm:p-8 max-w-6xl mx-auto">
55
+ <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-md mb-6">
56
+ <h1 className="text-xl sm:text-2xl font-semibold">Monthly Compliance Report</h1>
57
+ <button className="btn-apple-secondary w-full sm:w-auto" onClick={handleExport}>
58
+ Export as PDF
59
+ </button>
60
+ </div>
61
+ <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-8">
62
+ {cards.map(c => (
63
+ <div key={c.label} className="card-vibrancy p-4">
64
+ <p className="text-sm text-apple-label-secondary">{c.label}</p>
65
+ <p className="text-2xl font-bold mt-1">{c.value}</p>
66
+ </div>
67
+ ))}
68
+ </div>
69
+ <div className="card-vibrancy p-6 mb-6">
70
+ <h2 className="text-lg font-medium mb-4">Screening Trend</h2>
71
+ <div className="h-32 flex items-end gap-1">
72
+ {Array.from({ length: 12 }, (_, i) => {
73
+ const h = Math.max(8, Math.random() * 100)
74
+ return (
75
+ <div key={i} className="flex-1 bg-apple-blue/60 rounded-t"
76
+ style={{ height: `${h}%` }}
77
+ title={`Month ${i + 1}`} />
78
+ )
79
+ })}
80
+ </div>
81
+ <div className="flex justify-between text-xs text-apple-label-secondary mt-2">
82
+ <span>Jan</span><span>Jun</span><span>Dec</span>
83
+ </div>
84
+ </div>
85
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
86
+ <div className="card-vibrancy p-6">
87
+ <h2 className="text-lg font-medium mb-3">Alert Volume</h2>
88
+ <p className="text-3xl font-bold">{metrics.alerts_generated}</p>
89
+ <p className="text-sm text-apple-label-secondary mt-1">Total this period</p>
90
+ </div>
91
+ <div className="card-vibrancy p-6">
92
+ <h2 className="text-lg font-medium mb-3">Resolution Time</h2>
93
+ <p className="text-3xl font-bold">{metrics.avg_resolution_hours.toFixed(1)}h</p>
94
+ <p className="text-sm text-apple-label-secondary mt-1">Average per case</p>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ )
99
+ }
@@ -0,0 +1,99 @@
1
+ import { useState } from 'react'
2
+ import { api } from '../../api/client'
3
+
4
+ const activityTypes = [
5
+ { value: 'structuring', label: 'Structuring' },
6
+ { value: 'money_laundering', label: 'Money Laundering' },
7
+ { value: 'terrorist_financing', label: 'Terrorist Financing' },
8
+ { value: 'fraud', label: 'Fraud' },
9
+ { value: 'identity_theft', label: 'Identity Theft' },
10
+ ]
11
+
12
+ const regulators = ['FinCEN', 'FCA', 'MAS']
13
+
14
+ const statusColors: Record<string, string> = {
15
+ draft: 'bg-apple-gray/20 text-apple-gray',
16
+ review: 'bg-apple-orange/20 text-apple-orange',
17
+ filed: 'bg-apple-green/20 text-apple-green',
18
+ acknowledged: 'bg-apple-blue/20 text-apple-blue',
19
+ }
20
+
21
+ export function SARForm() {
22
+ const [caseId, setCaseId] = useState('')
23
+ const [subject, setSubject] = useState('')
24
+ const [subjectType, setSubjectType] = useState('individual')
25
+ const [activity, setActivity] = useState('structuring')
26
+ const [regulator, setRegulator] = useState('FinCEN')
27
+ const [narrative, setNarrative] = useState('')
28
+ const [status, setStatus] = useState('draft')
29
+ const [loading, setLoading] = useState(false)
30
+
31
+ const handleSubmit = async (e: React.FormEvent) => {
32
+ e.preventDefault()
33
+ setLoading(true)
34
+ try {
35
+ const res = await api.post<{ sar: { id: string; filing_status: string } }>(
36
+ '/reports/sar',
37
+ { case_id: caseId, subject_name: subject, subject_type: subjectType, activity_type: activity, regulator },
38
+ )
39
+ setStatus(res?.sar?.filing_status ?? 'draft')
40
+ } catch { /* handled by client */ }
41
+ setLoading(false)
42
+ }
43
+
44
+ return (
45
+ <div className="px-md py-lg sm:p-8 max-w-3xl mx-auto">
46
+ <h1 className="text-xl sm:text-2xl font-semibold mb-6">Suspicious Activity Report</h1>
47
+ <div className="mb-4 flex items-center gap-2">
48
+ <span className="text-sm">Status:</span>
49
+ <span className={`px-2 py-1 text-xs rounded-full ${statusColors[status] ?? ''}`}>
50
+ {status.toUpperCase()}
51
+ </span>
52
+ </div>
53
+ <form onSubmit={handleSubmit} className="space-y-4">
54
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
55
+ <label className="block">
56
+ <span className="text-sm text-apple-label-secondary">Case ID</span>
57
+ <input className="input-apple w-full" value={caseId} onChange={e => setCaseId(e.target.value)} required />
58
+ </label>
59
+ <label className="block">
60
+ <span className="text-sm text-apple-label-secondary">Subject Name</span>
61
+ <input className="input-apple w-full" value={subject} onChange={e => setSubject(e.target.value)} required />
62
+ </label>
63
+ <label className="block">
64
+ <span className="text-sm text-apple-label-secondary">Subject Type</span>
65
+ <select className="input-apple w-full" value={subjectType} onChange={e => setSubjectType(e.target.value)}>
66
+ <option value="individual">Individual</option>
67
+ <option value="entity">Entity</option>
68
+ </select>
69
+ </label>
70
+ <label className="block">
71
+ <span className="text-sm text-apple-label-secondary">Activity Type</span>
72
+ <select className="input-apple w-full" value={activity} onChange={e => setActivity(e.target.value)}>
73
+ {activityTypes.map(at => <option key={at.value} value={at.value}>{at.label}</option>)}
74
+ </select>
75
+ </label>
76
+ <label className="block">
77
+ <span className="text-sm text-apple-label-secondary">Regulatory Body</span>
78
+ <select className="input-apple w-full" value={regulator} onChange={e => setRegulator(e.target.value)}>
79
+ {regulators.map(r => <option key={r} value={r}>{r}</option>)}
80
+ </select>
81
+ </label>
82
+ </div>
83
+ <label className="block">
84
+ <span className="text-sm text-apple-label-secondary">Narrative Summary</span>
85
+ <textarea className="input-apple w-full h-32" value={narrative} onChange={e => setNarrative(e.target.value)}
86
+ placeholder="AI-generated narrative will appear here. You can edit before filing." />
87
+ </label>
88
+ <div className="flex flex-col sm:flex-row gap-3">
89
+ <button type="submit" className="btn-apple-primary w-full sm:w-auto" disabled={loading}>
90
+ {loading ? 'Generating...' : 'Generate SAR'}
91
+ </button>
92
+ <button type="button" className="btn-apple-secondary w-full sm:w-auto" onClick={() => setStatus('review')}>
93
+ Submit for Review
94
+ </button>
95
+ </div>
96
+ </form>
97
+ </div>
98
+ )
99
+ }
@@ -0,0 +1,60 @@
1
+ import React from 'react'
2
+ import { Route } from 'react-router-dom'
3
+ import { ProtectedRoute } from '../components/layout/ProtectedRoute'
4
+ import {
5
+ Dashboard, AlertQueue, AlertDetailPage, ScreenEntity,
6
+ Configuration, Analytics, AuditTrail, Monitoring,
7
+ BatchJobs, SanctionsLists, ListsMarketplace, Login, Signup,
8
+ LandingPage, BillingPage, Onboarding,
9
+ AdminTenants, TenantDetail, SystemHealth, DataSources,
10
+ AdminOperations, AdminScheduledTasks,
11
+ Team, TermsOfService, PrivacyPolicy, ForgotPassword,
12
+ APIKeysPage, WebhooksPage, CryptoScreening, TxnScreening,
13
+ MFASetup, ResetPassword, TaskHistory,
14
+ } from './lazyPages'
15
+
16
+ type PWrapper = ({ children }: { children: React.ReactNode }) => JSX.Element
17
+
18
+ export function appRoutes(
19
+ P: PWrapper,
20
+ PublicLayout: React.ComponentType<{ children: React.ReactNode }>,
21
+ DashboardLayout: React.ComponentType<{ children: React.ReactNode }>,
22
+ ) {
23
+ return (
24
+ <>
25
+ <Route path="/" element={<PublicLayout><LandingPage /></PublicLayout>} />
26
+ <Route path="/login" element={<Login />} />
27
+ <Route path="/signup" element={<Signup />} />
28
+ <Route path="/forgot-password" element={<ForgotPassword />} />
29
+ <Route path="/terms" element={<PublicLayout><TermsOfService /></PublicLayout>} />
30
+ <Route path="/privacy" element={<PublicLayout><PrivacyPolicy /></PublicLayout>} />
31
+ <Route path="/dashboard" element={<P><Dashboard /></P>} />
32
+ <Route path="/alerts" element={<P><AlertQueue /></P>} />
33
+ <Route path="/alerts/:id" element={<P><AlertDetailPage /></P>} />
34
+ <Route path="/screen" element={<P><ScreenEntity /></P>} />
35
+ <Route path="/config" element={<P><Configuration /></P>} />
36
+ <Route path="/analytics" element={<P><Analytics /></P>} />
37
+ <Route path="/audit" element={<P><AuditTrail /></P>} />
38
+ <Route path="/monitoring" element={<P><Monitoring /></P>} />
39
+ <Route path="/batch" element={<P><BatchJobs /></P>} />
40
+ <Route path="/lists" element={<P><SanctionsLists /></P>} />
41
+ <Route path="/lists/marketplace" element={<P><ListsMarketplace /></P>} />
42
+ <Route path="/billing" element={
43
+ <ProtectedRoute><DashboardLayout><BillingPage /></DashboardLayout></ProtectedRoute>
44
+ } />
45
+ <Route path="/onboarding" element={<ProtectedRoute><Onboarding /></ProtectedRoute>} />
46
+ <Route path="/admin/tenants" element={<P><AdminTenants /></P>} />
47
+ <Route path="/admin/tenants/:id" element={<P><TenantDetail /></P>} />
48
+ <Route path="/admin/health" element={<P><SystemHealth /></P>} />
49
+ <Route path="/admin/data-sources" element={<P><DataSources /></P>} />
50
+ <Route path="/admin/operations" element={<P><AdminOperations /></P>} />
51
+ <Route path="/admin/tasks" element={<P><AdminScheduledTasks /></P>} />
52
+ <Route path="/team" element={<P><Team /></P>} />
53
+ <Route path="/keys" element={<P><APIKeysPage /></P>} />
54
+ <Route path="/webhooks" element={<P><WebhooksPage /></P>} />
55
+ <Route path="/settings/mfa" element={<P><MFASetup /></P>} />
56
+ <Route path="/tasks" element={<P><TaskHistory /></P>} />
57
+ <Route path="/reset-password" element={<ResetPassword />} />
58
+ </>
59
+ )
60
+ }
@@ -0,0 +1,28 @@
1
+ import React from 'react'
2
+ import { Route } from 'react-router-dom'
3
+ import {
4
+ CaseManagement, CaseDetail, RiskAssessment, UBOChain,
5
+ EDDWorkflow, TransactionMonitoring, AdverseMedia, PEPScreening,
6
+ SARForm, ComplianceReport, CryptoScreeningPage, TxnScreeningPage,
7
+ } from './lazyCompliance'
8
+
9
+ type PWrapper = ({ children }: { children: React.ReactNode }) => JSX.Element
10
+
11
+ export function complianceRoutes(P: PWrapper) {
12
+ return (
13
+ <>
14
+ <Route path="/compliance/cases" element={<P><CaseManagement /></P>} />
15
+ <Route path="/compliance/cases/:id" element={<P><CaseDetail /></P>} />
16
+ <Route path="/compliance/risk" element={<P><RiskAssessment /></P>} />
17
+ <Route path="/compliance/ubo/:id" element={<P><UBOChain /></P>} />
18
+ <Route path="/compliance/edd/:id" element={<P><EDDWorkflow /></P>} />
19
+ <Route path="/compliance/txn" element={<P><TransactionMonitoring /></P>} />
20
+ <Route path="/compliance/media" element={<P><AdverseMedia /></P>} />
21
+ <Route path="/compliance/pep" element={<P><PEPScreening /></P>} />
22
+ <Route path="/compliance/sar" element={<P><SARForm /></P>} />
23
+ <Route path="/compliance/report" element={<P><ComplianceReport /></P>} />
24
+ <Route path="/compliance/crypto" element={<P><CryptoScreeningPage /></P>} />
25
+ <Route path="/compliance/txn-screen" element={<P><TxnScreeningPage /></P>} />
26
+ </>
27
+ )
28
+ }
@@ -0,0 +1,34 @@
1
+ import { lazy } from 'react'
2
+
3
+ export const CaseManagement = lazy(() =>
4
+ import('../pages/CaseManagement').then(m => ({ default: m.CaseManagement }))
5
+ )
6
+ export const CaseDetail = lazy(() =>
7
+ import('../pages/CaseDetail').then(m => ({ default: m.CaseDetail }))
8
+ )
9
+ export const RiskAssessment = lazy(() =>
10
+ import('../pages/RiskAssessment').then(m => ({ default: m.RiskAssessment }))
11
+ )
12
+ export const UBOChain = lazy(() =>
13
+ import('../pages/UBOChain').then(m => ({ default: m.UBOChain }))
14
+ )
15
+ export const EDDWorkflow = lazy(() =>
16
+ import('../pages/EDDWorkflow').then(m => ({ default: m.EDDWorkflow }))
17
+ )
18
+ export const TransactionMonitoring = lazy(() =>
19
+ import('../pages/TransactionMonitoring').then(m => ({ default: m.TransactionMonitoring }))
20
+ )
21
+ export const AdverseMedia = lazy(() =>
22
+ import('../pages/AdverseMedia').then(m => ({ default: m.AdverseMedia }))
23
+ )
24
+ export const PEPScreening = lazy(() =>
25
+ import('../pages/PEPScreening').then(m => ({ default: m.PEPScreening }))
26
+ )
27
+ export const SARForm = lazy(() =>
28
+ import('../pages/reporting/SARForm').then(m => ({ default: m.SARForm }))
29
+ )
30
+ export const ComplianceReport = lazy(() =>
31
+ import('../pages/reporting/ComplianceReport').then(m => ({ default: m.ComplianceReport }))
32
+ )
33
+ export const CryptoScreeningPage = lazy(() => import('../pages/CryptoScreening'))
34
+ export const TxnScreeningPage = lazy(() => import('../pages/TxnScreening'))
@@ -0,0 +1,35 @@
1
+ import { lazy } from 'react'
2
+
3
+ export const Dashboard = lazy(() => import('../pages/Dashboard').then(m => ({ default: m.Dashboard })))
4
+ export const AlertQueue = lazy(() => import('../pages/AlertQueue').then(m => ({ default: m.AlertQueue })))
5
+ export const AlertDetailPage = lazy(() => import('../pages/AlertDetailPage').then(m => ({ default: m.AlertDetailPage })))
6
+ export const ScreenEntity = lazy(() => import('../pages/ScreenEntity').then(m => ({ default: m.ScreenEntity })))
7
+ export const Configuration = lazy(() => import('../pages/Configuration').then(m => ({ default: m.Configuration })))
8
+ export const Analytics = lazy(() => import('../pages/Analytics').then(m => ({ default: m.Analytics })))
9
+ export const AuditTrail = lazy(() => import('../pages/AuditTrail').then(m => ({ default: m.AuditTrail })))
10
+ export const Monitoring = lazy(() => import('../pages/Monitoring').then(m => ({ default: m.Monitoring })))
11
+ export const BatchJobs = lazy(() => import('../pages/BatchJobs').then(m => ({ default: m.BatchJobs })))
12
+ export const SanctionsLists = lazy(() => import('../pages/SanctionsLists').then(m => ({ default: m.SanctionsLists })))
13
+ export const Login = lazy(() => import('../pages/Login').then(m => ({ default: m.Login })))
14
+ export const Signup = lazy(() => import('../pages/Signup').then(m => ({ default: m.Signup })))
15
+ export const LandingPage = lazy(() => import('../pages/marketing/LandingPage'))
16
+ export const BillingPage = lazy(() => import('../pages/billing/BillingPage'))
17
+ export const Onboarding = lazy(() => import('../pages/Onboarding'))
18
+ export const AdminTenants = lazy(() => import('../pages/admin/Tenants'))
19
+ export const TenantDetail = lazy(() => import('../pages/admin/TenantDetail'))
20
+ export const SystemHealth = lazy(() => import('../pages/admin/SystemHealth'))
21
+ export const DataSources = lazy(() => import('../pages/admin/DataSources'))
22
+ export const AdminOperations = lazy(() => import('../pages/admin/Operations'))
23
+ export const AdminScheduledTasks = lazy(() => import('../pages/admin/ScheduledTasks'))
24
+ export const Team = lazy(() => import('../pages/Team'))
25
+ export const TermsOfService = lazy(() => import('../pages/legal/TermsOfService'))
26
+ export const PrivacyPolicy = lazy(() => import('../pages/legal/PrivacyPolicy'))
27
+ export const ForgotPassword = lazy(() => import('../pages/ForgotPassword'))
28
+ export const ListsMarketplace = lazy(() => import('../pages/ListsMarketplace').then(m => ({ default: m.ListsMarketplace })))
29
+ export const APIKeysPage = lazy(() => import('../pages/APIKeys'))
30
+ export const WebhooksPage = lazy(() => import('../pages/Webhooks'))
31
+ export const CryptoScreening = lazy(() => import('../pages/CryptoScreening'))
32
+ export const TxnScreening = lazy(() => import('../pages/TxnScreening'))
33
+ export const MFASetup = lazy(() => import('../pages/MFASetup'))
34
+ export const ResetPassword = lazy(() => import('../pages/ResetPassword'))
35
+ export const TaskHistory = lazy(() => import('../pages/TaskHistory'))
@@ -0,0 +1,5 @@
1
+ import { lazy } from 'react'
2
+
3
+ export const PlatformOverview = lazy(() => import('../pages/platform/Overview'))
4
+ export const PlatformUsers = lazy(() => import('../pages/platform/Users'))
5
+ export const PlatformAPIKeys = lazy(() => import('../pages/platform/APIKeys'))
@@ -0,0 +1,15 @@
1
+ import React from 'react'
2
+ import { Route } from 'react-router-dom'
3
+ import { PlatformOverview, PlatformUsers, PlatformAPIKeys } from './lazyPlatform'
4
+
5
+ type PWrapper = ({ children }: { children: React.ReactNode }) => JSX.Element
6
+
7
+ export function platformRoutes(P: PWrapper) {
8
+ return (
9
+ <>
10
+ <Route path="/platform/overview" element={<P><PlatformOverview /></P>} />
11
+ <Route path="/platform/users" element={<P><PlatformUsers /></P>} />
12
+ <Route path="/platform/keys" element={<P><PlatformAPIKeys /></P>} />
13
+ </>
14
+ )
15
+ }
@@ -0,0 +1,76 @@
1
+ /* Animations */
2
+ @keyframes spin-smooth { to { transform: rotate(360deg); } }
3
+ .spinner { animation: spin-smooth 1s linear infinite; }
4
+
5
+ @keyframes fade-in {
6
+ from { opacity: 0; transform: translateY(8px); }
7
+ to { opacity: 1; transform: translateY(0); }
8
+ }
9
+ .animate-fade-in { animation: fade-in 0.3s ease-out both; }
10
+
11
+ @keyframes glow-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } }
12
+
13
+ @keyframes marquee { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } }
14
+ .marquee-track { animation: marquee 30s linear infinite; }
15
+
16
+ @keyframes shimmer {
17
+ 0% { background-position: -200% 0; }
18
+ 100% { background-position: 200% 0; }
19
+ }
20
+
21
+ @keyframes border-glow-pulse {
22
+ 0%, 100% { border-color: rgba(10,132,255,0.2); }
23
+ 50% { border-color: rgba(10,132,255,0.5); }
24
+ }
25
+
26
+ /* Glass surfaces */
27
+ .glass {
28
+ backdrop-filter: blur(16px);
29
+ background: rgba(255,255,255,0.03);
30
+ border: 1px solid rgba(255,255,255,0.06);
31
+ }
32
+
33
+ .glass-panel {
34
+ backdrop-filter: blur(24px) saturate(180%);
35
+ background: rgba(18, 18, 26, 0.6);
36
+ border: 1px solid rgba(255,255,255,0.06);
37
+ border-radius: 16px;
38
+ box-shadow: 0 8px 32px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.04);
39
+ }
40
+
41
+ /* Glow effects */
42
+ .glow-blue { box-shadow: 0 0 20px rgba(10,132,255,0.15), 0 0 40px rgba(10,132,255,0.05); }
43
+ .glow-green { box-shadow: 0 0 20px rgba(48,209,88,0.15), 0 0 40px rgba(48,209,88,0.05); }
44
+ .glow-accent { box-shadow: 0 0 20px rgba(0,212,170,0.15), 0 0 40px rgba(0,212,170,0.05); }
45
+ .glow-red { box-shadow: 0 0 30px rgba(255,69,58,0.15), 0 0 60px rgba(255,69,58,0.05); }
46
+ .glow-orange { box-shadow: 0 0 30px rgba(255,159,10,0.15), 0 0 60px rgba(255,159,10,0.05); }
47
+
48
+ /* Stat card glow */
49
+ .stat-glow {
50
+ box-shadow: 0 0 0 1px rgba(255,255,255,0.04), 0 0 30px rgba(10,132,255,0.08);
51
+ transition: box-shadow 0.3s ease;
52
+ }
53
+ .stat-glow:hover {
54
+ box-shadow: 0 0 0 1px rgba(10,132,255,0.2), 0 0 40px rgba(10,132,255,0.12);
55
+ }
56
+
57
+ /* Gradient text */
58
+ .gradient-text {
59
+ background: linear-gradient(135deg, #fff 0%, rgba(255,255,255,0.6) 100%);
60
+ -webkit-background-clip: text;
61
+ -webkit-text-fill-color: transparent;
62
+ background-clip: text;
63
+ }
64
+
65
+ /* Shimmer loading effect */
66
+ .shimmer {
67
+ background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.04) 50%, transparent 100%);
68
+ background-size: 200% 100%;
69
+ animation: shimmer 2s ease-in-out infinite;
70
+ }
71
+
72
+ /* Animated border glow */
73
+ .border-glow {
74
+ border: 1px solid rgba(10,132,255,0.2);
75
+ animation: border-glow-pulse 3s ease-in-out infinite;
76
+ }
@@ -0,0 +1,25 @@
1
+ import { vi } from 'vitest'
2
+ import '@testing-library/jest-dom/vitest'
3
+ import '../i18n/config'
4
+
5
+ // Mock window.matchMedia
6
+ Object.defineProperty(window, 'matchMedia', {
7
+ writable: true,
8
+ value: vi.fn().mockImplementation(query => ({
9
+ matches: false,
10
+ media: query,
11
+ onchange: null,
12
+ addListener: vi.fn(),
13
+ removeListener: vi.fn(),
14
+ addEventListener: vi.fn(),
15
+ removeEventListener: vi.fn(),
16
+ dispatchEvent: vi.fn(),
17
+ })),
18
+ })
19
+
20
+ // Mock ResizeObserver
21
+ global.ResizeObserver = vi.fn().mockImplementation(() => ({
22
+ observe: vi.fn(),
23
+ unobserve: vi.fn(),
24
+ disconnect: vi.fn(),
25
+ }))