From 554b6d8790dbeffac9e6604fe98a1e1b7ca329ef Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Fri, 6 Feb 2026 06:02:32 +0100 Subject: [PATCH] Fix date picker causing page reload in compliance transaction list (#953) * Fix date picker causing page reload in compliance transaction list The useEffect triggered on every date change, setting isLoading=true which replaced the entire page with a spinner, making date inputs unusable. Now the API call is only triggered via a Search button, and loading state is shown inline. * Add kycFileId column and fix CHF volume formatting to 2 decimals Use toFixed(2) instead of Math.round() in both TX list and KYC files details to match exact DB precision. Add KycFileId column and filter checkbox to transaction list. --- src/hooks/compliance.hook.ts | 1 + .../compliance-kyc-files-details.screen.tsx | 2 +- .../compliance-transaction-list.screen.tsx | 224 ++++++++++-------- 3 files changed, 131 insertions(+), 96 deletions(-) diff --git a/src/hooks/compliance.hook.ts b/src/hooks/compliance.hook.ts index 4ececadb..c23bee08 100644 --- a/src/hooks/compliance.hook.ts +++ b/src/hooks/compliance.hook.ts @@ -156,6 +156,7 @@ export interface TransactionListEntry { id: number; type?: string; accountId?: number; + kycFileId?: number; name?: string; domicile?: string; created?: string; diff --git a/src/screens/compliance-kyc-files-details.screen.tsx b/src/screens/compliance-kyc-files-details.screen.tsx index aaf53c8a..feb9ce7a 100644 --- a/src/screens/compliance-kyc-files-details.screen.tsx +++ b/src/screens/compliance-kyc-files-details.screen.tsx @@ -46,7 +46,7 @@ export default function ComplianceKycFilesDetailsScreen(): JSX.Element { function formatVolume(volume?: number): string { if (volume == null) return '-'; - return Math.round(volume).toLocaleString('de-CH'); + return volume.toFixed(2); } function getStatus(entry: KycFileListEntry): string { diff --git a/src/screens/compliance-transaction-list.screen.tsx b/src/screens/compliance-transaction-list.screen.tsx index 4c8fb76d..a3207509 100644 --- a/src/screens/compliance-transaction-list.screen.tsx +++ b/src/screens/compliance-transaction-list.screen.tsx @@ -8,7 +8,7 @@ import { StyledLoadingSpinner, StyledVerticalStack, } from '@dfx.swiss/react-components'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { ErrorHint } from 'src/components/error-hint'; import { useSettingsContext } from 'src/contexts/settings.context'; import { TransactionListEntry, useCompliance } from 'src/hooks/compliance.hook'; @@ -35,6 +35,12 @@ export default function ComplianceTransactionListScreen(): JSX.Element { const [createdTo, setCreatedTo] = useState(today); const [outputFrom, setOutputFrom] = useState(threeDaysAgo); const [outputTo, setOutputTo] = useState(today); + const [onlyWithKycFile, setOnlyWithKycFile] = useState(false); + + const filteredData = useMemo( + () => (onlyWithKycFile ? data.filter((e) => e.kycFileId && e.kycFileId > 0) : data), + [data, onlyWithKycFile], + ); function formatDate(dateString?: string): string { if (!dateString) return '-'; @@ -47,7 +53,7 @@ export default function ComplianceTransactionListScreen(): JSX.Element { function formatChf(value?: number): string { if (value == null) return '-'; - return Math.round(value).toLocaleString('de-CH'); + return value.toFixed(2); } function exportCsv() { @@ -55,6 +61,7 @@ export default function ComplianceTransactionListScreen(): JSX.Element { 'Id', 'Type', 'AccountId', + 'KycFileId', 'Name', 'Domizil', 'Created', @@ -64,10 +71,11 @@ export default function ComplianceTransactionListScreen(): JSX.Element { 'CHF Value', 'TMER', ]; - const rows = data.map((entry) => [ + const rows = filteredData.map((entry) => [ entry.id, entry.type ?? '', entry.accountId ?? '', + entry.kycFileId ?? '', entry.name ?? '', entry.domicile ?? '', formatDate(entry.created), @@ -91,7 +99,7 @@ export default function ComplianceTransactionListScreen(): JSX.Element { URL.revokeObjectURL(url); } - useEffect(() => { + const loadData = useCallback(() => { if (!isLoggedIn) return; setIsLoading(true); @@ -110,15 +118,11 @@ export default function ComplianceTransactionListScreen(): JSX.Element { .finally(() => setIsLoading(false)); }, [isLoggedIn, getTransactionList, createdFrom, createdTo, outputFrom, outputTo]); - useLayoutOptions({ title: translate('screens/compliance', 'Transaction List'), noMaxWidth: true }); - - if (isLoading) { - return ; - } + useEffect(() => { + loadData(); + }, [isLoggedIn]); - if (error) { - return ; - } + useLayoutOptions({ title: translate('screens/compliance', 'Transaction List'), noMaxWidth: true }); return ( @@ -173,106 +177,136 @@ export default function ComplianceTransactionListScreen(): JSX.Element {
  - +
+ + +
+
+ +
+   +
- {data.length} {translate('screens/compliance', 'entries')} + {filteredData.length} {translate('screens/compliance', 'entries')}
-
- - - - - - - - - - - - - - - - - - {data.length > 0 ? ( - data.map((entry) => ( - entry.accountId && navigate(`compliance/user/${entry.accountId}`)} - > - - - - - - - - - - - +
- {translate('screens/compliance', 'Id')} - - {translate('screens/compliance', 'Type')} - - {translate('screens/compliance', 'AccountId')} - - {translate('screens/compliance', 'Name')} - - {translate('screens/compliance', 'Domizil')} - - {translate('screens/compliance', 'Created')} - - {translate('screens/compliance', 'Transaktionsdatum')} - - {translate('screens/compliance', 'Output Datum')} - - {translate('screens/compliance', 'Assets')} - - {translate('screens/compliance', 'CHF Value')} - - {translate('screens/compliance', 'TMER')} -
{entry.id}{entry.type ?? '-'}{entry.accountId ?? '-'}{entry.name ?? '-'}{entry.domicile ?? '-'}{formatDate(entry.created)}{formatDate(entry.eventDate)}{formatDate(entry.outputDate)}{entry.assets ?? '-'}{formatChf(entry.amountInChf)} - {entry.highRisk ? 'Ja' : 'Nein'} + {error && } + + {isLoading && data.length === 0 ? ( + + ) : ( +
+ + + + + + + + + + + + + + + + + + + {filteredData.length > 0 ? ( + filteredData.map((entry) => ( + entry.accountId && navigate(`compliance/user/${entry.accountId}`)} + > + + + + + + + + + + + + + + )) + ) : ( + + - )) - ) : ( - - - - )} - -
+ {translate('screens/compliance', 'Id')} + + {translate('screens/compliance', 'Type')} + + {translate('screens/compliance', 'AccountId')} + + {translate('screens/compliance', 'KycFileId')} + + {translate('screens/compliance', 'Name')} + + {translate('screens/compliance', 'Domizil')} + + {translate('screens/compliance', 'Created')} + + {translate('screens/compliance', 'Transaktionsdatum')} + + {translate('screens/compliance', 'Output Datum')} + + {translate('screens/compliance', 'Assets')} + + {translate('screens/compliance', 'CHF Value')} + + {translate('screens/compliance', 'TMER')} +
{entry.id}{entry.type ?? '-'}{entry.accountId ?? '-'}{entry.kycFileId ?? '-'}{entry.name ?? '-'}{entry.domicile ?? '-'}{formatDate(entry.created)}{formatDate(entry.eventDate)}{formatDate(entry.outputDate)}{entry.assets ?? '-'}{formatChf(entry.amountInChf)}{entry.highRisk ? 'Ja' : 'Nein'}
+ {translate('screens/compliance', 'No entries found')}
- {translate('screens/compliance', 'No entries found')} -
-
+ )} +
+
+ )}
); }