diff --git a/e2e/screenshots/baseline/compliance.spec.ts-compliance-02-search-results-chromium-darwin.png b/e2e/screenshots/baseline/compliance.spec.ts-compliance-02-search-results-chromium-darwin.png index c64b2fec..4f9badad 100644 Binary files a/e2e/screenshots/baseline/compliance.spec.ts-compliance-02-search-results-chromium-darwin.png and b/e2e/screenshots/baseline/compliance.spec.ts-compliance-02-search-results-chromium-darwin.png differ diff --git a/e2e/screenshots/baseline/compliance.spec.ts-compliance-user-01-overview-chromium-darwin.png b/e2e/screenshots/baseline/compliance.spec.ts-compliance-user-01-overview-chromium-darwin.png index 4b2230f3..c99faaf8 100644 Binary files a/e2e/screenshots/baseline/compliance.spec.ts-compliance-user-01-overview-chromium-darwin.png and b/e2e/screenshots/baseline/compliance.spec.ts-compliance-user-01-overview-chromium-darwin.png differ diff --git a/src/hooks/compliance.hook.ts b/src/hooks/compliance.hook.ts index e4838a2a..1b004962 100644 --- a/src/hooks/compliance.hook.ts +++ b/src/hooks/compliance.hook.ts @@ -93,6 +93,7 @@ export interface ComplianceSearchResult { export interface UserSearchResult { id: number; kycStatus: KycStatus; + kycLevel?: number; accountType?: AccountType; mail?: string; name?: string; diff --git a/src/screens/compliance-user.screen.tsx b/src/screens/compliance-user.screen.tsx index a10b765b..afb5b819 100644 --- a/src/screens/compliance-user.screen.tsx +++ b/src/screens/compliance-user.screen.tsx @@ -1,5 +1,12 @@ import { useAuthContext, UserRole, useKyc } from '@dfx.swiss/react'; -import { SpinnerSize, StyledLoadingSpinner } from '@dfx.swiss/react-components'; +import { + IconColor, + IconSize, + IconVariant, + SpinnerSize, + StyledIconButton, + StyledLoadingSpinner, +} from '@dfx.swiss/react-components'; import { useCallback, useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { @@ -57,12 +64,13 @@ export default function ComplianceUserScreen(): JSX.Element { const { translate } = useSettingsContext(); const { id: userDataId } = useParams(); - const { getUserData } = useCompliance(); + const { getUserData, downloadUserFiles } = useCompliance(); const { getFile } = useKyc(); const navigate = useNavigate(); const [error, setError] = useState(); const [data, setData] = useState(); + const [isDownloading, setIsDownloading] = useState(false); const [preview, setPreview] = useState<{ url: string; contentType: string; name: string }>(); const [activeTab, setActiveTab] = useState('transactions'); const [expandedBankTxId, setExpandedBankTxId] = useState(); @@ -100,6 +108,7 @@ export default function ComplianceUserScreen(): JSX.Element { } async function openFile(file: KycFile): Promise { + setError(undefined); try { const { content, contentType } = await getFile(file.uid); if (!content || content.type !== 'Buffer' || !Array.isArray(content.data)) { @@ -121,11 +130,21 @@ export default function ComplianceUserScreen(): JSX.Element { setError('No ID provided'); return; } + setError(undefined); getUserData(+userDataId) .then(setData) .catch((e: unknown) => setError(e instanceof Error ? e.message : 'Unknown error')); }, [userDataId, getUserData]); + function handleDownload(): void { + if (!userDataId) return; + setIsDownloading(true); + setError(undefined); + downloadUserFiles([+userDataId]) + .catch((e: unknown) => setError(e instanceof Error ? e.message : 'Unknown error')) + .finally(() => setIsDownloading(false)); + } + useEffect(() => { loadData(); }, [loadData]); @@ -150,7 +169,8 @@ export default function ComplianceUserScreen(): JSX.Element { const numericUserDataId = +userDataId; const isSupport = role === UserRole.SUPPORT; - const canCopyKycLinks = role === UserRole.ADMIN || role === UserRole.COMPLIANCE; + const isComplianceRole = role === UserRole.ADMIN || role === UserRole.COMPLIANCE; + const canCopyKycLinks = isComplianceRole; const showRightPanel = data.permissions.viewKycFiles || isSupport; const tabs: TabConfig[] = [ @@ -172,6 +192,26 @@ export default function ComplianceUserScreen(): JSX.Element { return (
+ {isComplianceRole && ( +
+ + +
+ )} + + {error && } + {/* Top Section: (User Data | Middle Panels) | Splitter | (File Preview | Support Overview) */}
diff --git a/src/screens/compliance.screen.tsx b/src/screens/compliance.screen.tsx index 2465215a..0e99c6cd 100644 --- a/src/screens/compliance.screen.tsx +++ b/src/screens/compliance.screen.tsx @@ -41,7 +41,7 @@ export default function ComplianceScreen(): JSX.Element { useComplianceGuard(); const { translate, translateError } = useSettingsContext(); - const { search, downloadUserFiles, getPendingReviews, getPendingTransactions, getCallQueues } = useCompliance(); + const { search, getPendingReviews, getPendingTransactions, getCallQueues } = useCompliance(); const { navigate } = useNavigation(); const { search: query } = useLocation(); @@ -50,7 +50,6 @@ export default function ComplianceScreen(): JSX.Element { const [dashboardError, setDashboardError] = useState(); const [searchResult, setSearchResult] = useState(); const [showInfo, setShowInfo] = useState(false); - const [downloadingUserId, setDownloadingUserId] = useState(); const [pendingReviews, setPendingReviews] = useState([]); const [pendingTransactions, setPendingTransactions] = useState([]); const [callQueues, setCallQueues] = useState([]); @@ -93,15 +92,6 @@ export default function ComplianceScreen(): JSX.Element { if (paramSearch) onSubmit({ key: paramSearch }); }, [paramSearch, onSubmit]); - function handleDownloadUserData(userId: number) { - setDownloadingUserId(userId); - setError(undefined); - - downloadUserFiles([userId]) - .catch((e) => setError(e.message)) - .finally(() => setDownloadingUserId(undefined)); - } - const rules = Utils.createRules({ key: Validations.Required }); const searchExamples = [ @@ -139,6 +129,11 @@ export default function ComplianceScreen(): JSX.Element { cellClassName: 'break-all', render: (u: UserSearchResult) => u.mail ?? '-', }, + { + key: 'kycLevel', + label: translate('screens/compliance', 'KYC Level'), + render: (u: UserSearchResult) => u.kycLevel ?? '-', + }, { key: 'actions', label: '', @@ -146,24 +141,11 @@ export default function ComplianceScreen(): JSX.Element { render: (u: UserSearchResult) => (
handleDownloadUserData(u.id)} - isLoading={downloadingUserId === u.id} - /> - - + />
), }, diff --git a/src/translations/languages/de.json b/src/translations/languages/de.json index afb97c7b..04e04908 100644 --- a/src/translations/languages/de.json +++ b/src/translations/languages/de.json @@ -396,6 +396,7 @@ "No entries found": "Keine Einträge gefunden", "found by {{type}}": "gefunden per {{type}}", "Customers": "Kunden", + "KYC Level": "KYC-Level", "Bank Transactions": "Banktransaktionen", "AmlCheck": "AmlCheck", "No change": "keine Änderung", diff --git a/src/translations/languages/fr.json b/src/translations/languages/fr.json index 6b729cd6..919cc78a 100644 --- a/src/translations/languages/fr.json +++ b/src/translations/languages/fr.json @@ -396,6 +396,7 @@ "No entries found": "Aucune entrée trouvée", "found by {{type}}": "trouvés par {{type}}", "Customers": "Clients", + "KYC Level": "Niveau KYC", "Bank Transactions": "Transactions bancaires", "AmlCheck": "AmlCheck", "No change": "aucun changement", diff --git a/src/translations/languages/it.json b/src/translations/languages/it.json index bb0adbff..98f13312 100644 --- a/src/translations/languages/it.json +++ b/src/translations/languages/it.json @@ -396,6 +396,7 @@ "No entries found": "Nessuna voce trovata", "found by {{type}}": "trovati tramite {{type}}", "Customers": "Clienti", + "KYC Level": "Livello KYC", "Bank Transactions": "Transazioni bancarie", "AmlCheck": "AmlCheck", "No change": "nessuna modifica",