Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/hooks/compliance.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export interface ComplianceSearchResult {
export interface UserSearchResult {
id: number;
kycStatus: KycStatus;
kycLevel?: number;
accountType?: AccountType;
mail?: string;
name?: string;
Expand Down
46 changes: 43 additions & 3 deletions src/screens/compliance-user.screen.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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<string>();
const [data, setData] = useState<ComplianceUserData>();
const [isDownloading, setIsDownloading] = useState(false);
const [preview, setPreview] = useState<{ url: string; contentType: string; name: string }>();
const [activeTab, setActiveTab] = useState<TabType>('transactions');
const [expandedBankTxId, setExpandedBankTxId] = useState<number>();
Expand Down Expand Up @@ -100,6 +108,7 @@ export default function ComplianceUserScreen(): JSX.Element {
}

async function openFile(file: KycFile): Promise<void> {
setError(undefined);
try {
const { content, contentType } = await getFile(file.uid);
if (!content || content.type !== 'Buffer' || !Array.isArray(content.data)) {
Expand All @@ -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]);
Expand All @@ -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[] = [
Expand All @@ -172,6 +192,26 @@ export default function ComplianceUserScreen(): JSX.Element {

return (
<div className="w-full flex flex-col gap-4">
{isComplianceRole && (
<div className="flex justify-end items-center gap-2">
<button
className="px-3 py-1.5 text-sm font-medium text-white rounded transition-colors bg-dfxBlue-800 hover:bg-dfxBlue-800/80"
onClick={() => navigate(`/compliance/user/${numericUserDataId}/kyc`)}
>
{translate('screens/compliance', 'KYC')}
</button>
<StyledIconButton
icon={IconVariant.FILE}
color={IconColor.BLUE}
size={IconSize.MD}
onClick={handleDownload}
isLoading={isDownloading}
/>
</div>
)}

{error && <ErrorHint message={error} />}

{/* Top Section: (User Data | Middle Panels) | Splitter | (File Preview | Support Overview) */}
<div ref={containerRef} className="flex min-h-[400px]">
<div style={{ width: `${showRightPanel ? splitPercent : 100}%` }} className="flex gap-4 min-w-0 pr-2">
Expand Down
34 changes: 8 additions & 26 deletions src/screens/compliance.screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -50,7 +50,6 @@ export default function ComplianceScreen(): JSX.Element {
const [dashboardError, setDashboardError] = useState<string>();
const [searchResult, setSearchResult] = useState<ComplianceSearchResult>();
const [showInfo, setShowInfo] = useState(false);
const [downloadingUserId, setDownloadingUserId] = useState<number>();
const [pendingReviews, setPendingReviews] = useState<PendingReviewSummaryEntry[]>([]);
const [pendingTransactions, setPendingTransactions] = useState<PendingTransactionInfo[]>([]);
const [callQueues, setCallQueues] = useState<CallQueueSummaryEntry[]>([]);
Expand Down Expand Up @@ -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 = [
Expand Down Expand Up @@ -139,31 +129,23 @@ 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: '',
cellClassName: 'whitespace-nowrap',
render: (u: UserSearchResult) => (
<div className="flex gap-2 justify-end items-center">
<StyledIconButton
icon={IconVariant.FILE}
icon={IconVariant.FORWARD}
color={IconColor.BLUE}
size={IconSize.SM}
onClick={() => handleDownloadUserData(u.id)}
isLoading={downloadingUserId === u.id}
/>
<button
className="px-2 py-1 text-xs font-medium text-white rounded transition-colors bg-dfxBlue-800 hover:bg-dfxBlue-800/80"
onClick={() => navigate(`compliance/user/${u.id}/kyc`)}
>
KYC
</button>
<button
className="px-2 py-1 text-xs font-medium bg-dfxBlue-800 text-white rounded hover:bg-dfxBlue-800/80 transition-colors"
onClick={() => navigate(`compliance/user/${u.id}`)}
>
Details
</button>
/>
</div>
),
},
Expand Down
1 change: 1 addition & 0 deletions src/translations/languages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions src/translations/languages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions src/translations/languages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading