diff options
author | Sebastian <sebasjm@gmail.com> | 2024-08-28 10:34:39 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2024-08-28 10:34:39 -0300 |
commit | f81151d4ecaa610578bd465461b478b0afc66e5b (patch) | |
tree | f8bfbe4852b1ba17d9f4be4c3ba6e4c10a66e9c9 | |
parent | ca4bccc5de2d92333267ced69535d4400c394fb9 (diff) |
ask for more info set meaure to m2
-rw-r--r-- | packages/aml-backoffice-ui/src/Routing.tsx | 4 | ||||
-rw-r--r-- | packages/aml-backoffice-ui/src/hooks/decisions.ts | 52 | ||||
-rw-r--r-- | packages/aml-backoffice-ui/src/pages/CaseDetails.tsx | 566 | ||||
-rw-r--r-- | packages/aml-backoffice-ui/src/pages/Cases.tsx | 77 |
4 files changed, 433 insertions, 266 deletions
diff --git a/packages/aml-backoffice-ui/src/Routing.tsx b/packages/aml-backoffice-ui/src/Routing.tsx index 082dc8ab5..b99314889 100644 --- a/packages/aml-backoffice-ui/src/Routing.tsx +++ b/packages/aml-backoffice-ui/src/Routing.tsx @@ -26,7 +26,7 @@ import { assertUnreachable } from "@gnu-taler/taler-util"; import { useEffect } from "preact/hooks"; import { ExchangeAmlFrame } from "./ExchangeAmlFrame.js"; import { useOfficer } from "./hooks/officer.js"; -import { Cases } from "./pages/Cases.js"; +import { Cases, CasesUnderInvestigation } from "./pages/Cases.js"; import { Officer } from "./pages/Officer.js"; import { CaseDetails } from "./pages/CaseDetails.js"; import { CaseUpdate, SelectForm } from "./pages/CaseUpdate.js"; @@ -140,7 +140,7 @@ function PrivateRouting(): VNode { return <SelectForm account={location.values.cid} />; } case "investigation": { - return <Cases filtered/>; + return <CasesUnderInvestigation />; } case "active": { return <Cases />; diff --git a/packages/aml-backoffice-ui/src/hooks/decisions.ts b/packages/aml-backoffice-ui/src/hooks/decisions.ts index eb861ae14..24941b29e 100644 --- a/packages/aml-backoffice-ui/src/hooks/decisions.ts +++ b/packages/aml-backoffice-ui/src/hooks/decisions.ts @@ -37,7 +37,7 @@ export const PAGINATED_LIST_REQUEST = PAGINATED_LIST_SIZE + 1; * @param args * @returns */ -export function useCurrentDecisions(filtered?: boolean) { +export function useCurrentDecisionsUnderInvestigation() { const officer = useOfficer(); const session = officer.state === "ready" ? officer.account : undefined; const { @@ -54,7 +54,7 @@ export function useCurrentDecisions(filtered?: boolean) { return await api.getAmlDecisions(officer, { order: "dec", offset, - investigation, + investigation: true, active: true, limit: PAGINATED_LIST_REQUEST, }); @@ -66,7 +66,53 @@ export function useCurrentDecisions(filtered?: boolean) { >( !session ? undefined - : [session, offset, filtered ? true : filtered, "getAmlDecisions"], + : [session, offset, "getAmlDecisions"], + fetcher, + ); + + if (error) return error; + if (data === undefined) return undefined; + if (data.type !== "ok") return data; + + return buildPaginatedResult(data.body.records, offset, setOffset, (d) => + String(d.rowid), + ); +} + +/** + * @param account + * @param args + * @returns + */ +export function useCurrentDecisions() { + const officer = useOfficer(); + const session = officer.state === "ready" ? officer.account : undefined; + const { + lib: { exchange: api }, + } = useExchangeApiContext(); + + const [offset, setOffset] = useState<string>(); + + async function fetcher([officer, offset]: [ + OfficerAccount, + string | undefined, + boolean | undefined, + ]) { + return await api.getAmlDecisions(officer, { + order: "dec", + offset, + active: true, + limit: PAGINATED_LIST_REQUEST, + }); + } + + const { data, error } = useSWR< + TalerExchangeResultByMethod<"getAmlDecisions">, + TalerHttpError + >( + !session + ? undefined + : [session, offset, "getAmlDecisions"], fetcher, ); diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx index a1c09025b..8b54c1861 100644 --- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx +++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx @@ -355,7 +355,7 @@ export function CaseDetails({ account }: { account: string }) { justification: "", keep_investigating: false, properties: {}, - new_measure: "onlyTalers", + new_measure: "m2", new_rules: { custom_measures: {}, expiration_time: AbsoluteTime.toProtocolTimestamp( @@ -379,7 +379,7 @@ export function CaseDetails({ account }: { account: string }) { <h1 class="my-4 text-base font-semibold leading-6 text-black"> <i18n.Translate>Current active rules</i18n.Translate> </h1> - <ShowDecisionInfo decision={activeDecision} /> + <ShowDecisionInfo decision={activeDecision} startOpen /> </Fragment> )} <h1 class="my-4 text-base font-semibold leading-6 text-black"> @@ -423,92 +423,144 @@ export function CaseDetails({ account }: { account: string }) { function ShowDecisionInfo({ decision, + startOpen }: { decision: TalerExchangeApi.AmlDecision; + startOpen?: boolean, }): VNode { const { i18n } = useTranslationContext(); const { config } = useExchangeApiContext(); + const [opened, setOpened] = useState(startOpen ?? false) - return ( - <Fragment> - <textarea>asdasdlaksdj</textarea> - <div class="flex col justify-between"> - <div class="flex mt-2 rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600"> - <div class="pointer-events-none bg-gray-200 inset-y-0 flex items-center px-3"> - <i18n.Translate>Since</i18n.Translate> + + function Header() { + return <ul role="list" class="divide-y divide-gray-100 overflow-hidden bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl"> + <li class="relative flex justify-between gap-x-6 px-4 py-5 hover:bg-gray-50 sm:px-6"> + <div class="flex min-w-0 gap-x-4"> + <div class="flex mt-2 rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600"> + <div class="pointer-events-none bg-gray-200 inset-y-0 flex items-center px-3"> + <i18n.Translate>Since</i18n.Translate> + </div> + <div class="p-2 disabled:bg-gray-200 text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900 placeholder:text-gray-400 sm:text-sm sm:leading-6"> + <Time + format="dd/MM/yyyy HH:mm:ss" + timestamp={AbsoluteTime.fromProtocolTimestamp( + decision.decision_time, + )} + /> + </div> </div> - <div class="p-2 disabled:bg-gray-200 text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900 placeholder:text-gray-400 sm:text-sm sm:leading-6"> - <Time - format="dd/MM/yyyy HH:mm:ss" - timestamp={AbsoluteTime.fromProtocolTimestamp( - decision.decision_time, + </div> + <div class="flex shrink-0 items-center gap-x-4"> + <div class="flex mt-2 rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600"> + <div class="pointer-events-none bg-gray-200 inset-y-0 flex items-center px-3"> + {AbsoluteTime.isExpired( + AbsoluteTime.fromProtocolTimestamp( + decision.limits.expiration_time, + ), + ) ? ( + <i18n.Translate>Expired</i18n.Translate> + ) : ( + <i18n.Translate>Expires</i18n.Translate> )} - /> + </div> + <div class="p-2 disabled:bg-gray-200 text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900 placeholder:text-gray-400 sm:text-sm sm:leading-6"> + <Time + format="dd/MM/yyyy HH:mm:ss" + timestamp={AbsoluteTime.fromProtocolTimestamp( + decision.limits.expiration_time, + )} + /> + </div> </div> </div> + </li> + </ul> + } - <div class="flex mt-2 rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600"> - <div class="pointer-events-none bg-gray-200 inset-y-0 flex items-center px-3"> - {AbsoluteTime.isExpired( - AbsoluteTime.fromProtocolTimestamp( - decision.limits.expiration_time, - ), - ) ? ( - <i18n.Translate>Expired</i18n.Translate> - ) : ( - <i18n.Translate>Expires</i18n.Translate> - )} + if (!opened) { + return <div class="mt-4 cursor-pointer" onClick={() => setOpened(true)}> + <Header /> + </div> + } + const balanceLimit = decision.limits.rules.find(r => r.operation_type === "BALANCE") + + return ( + <div> + + <div class="mt-4 cursor-pointer" onClick={() => setOpened(false)}> + <Header /> + </div> + + {!decision.justification ? undefined : + <div> + <label for="comment" class="block text-sm font-medium leading-6 text-gray-900">Description</label> + <div class="mt-2"> + <textarea rows={2} name="comment" id="comment" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"> + {decision.justification} + </textarea> </div> - <div class="p-2 disabled:bg-gray-200 text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900 placeholder:text-gray-400 sm:text-sm sm:leading-6"> - <Time - format="dd/MM/yyyy HH:mm:ss" - timestamp={AbsoluteTime.fromProtocolTimestamp( - decision.decision_time, - )} - /> + </div> + } + + {!balanceLimit ? undefined : + <div class="px-4"> + <div class="flex mt-2 rounded-md w-fit shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600"> + <div class="whitespace-nowrap pointer-events-none bg-gray-200 inset-y-0 items-center px-3 flex"> + <i18n.Translate>Max balance</i18n.Translate> + </div> + <div class="p-2 disabled:bg-gray-200 text-right rounded-md rounded-l-none data-[left=true]:text-left py-1.5 pl-3 text-gray-900 placeholder:text-gray-400 sm:text-sm sm:leading-6"> + <RenderAmount + value={Amounts.parseOrThrow(balanceLimit.threshold)} + spec={config.currency_specification} + /> + + </div> </div> </div> - </div> - <table class="w-full text-center m-4"> - <thead> - <tr> - <th>operation</th> - <th>timeframe</th> - <th>amount</th> - </tr> - </thead> - <tbody> - {decision.limits.rules.map((r) => { - const bySpec = Amounts.stringifyValueWithSpec( - Amounts.parseOrThrow(r.threshold), - config.currency_specification, - ); - return ( - <tr> - <td class="text-left">{r.operation_type}</td> - <td> - {r.timeframe.d_us === "forever" - ? "" - : formatDuration( + } + + <div class="w-full px-4 pt-4"> + + <table class="min-w-full divide-y divide-gray-300"> + <thead class="bg-gray-50"> + <tr> + <th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6"><i18n.Translate>Operation</i18n.Translate></th> + <th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"><i18n.Translate>Timeframe</i18n.Translate></th> + <th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6"><i18n.Translate>Amount</i18n.Translate></th> + </tr> + </thead> + <tbody class="divide-y divide-gray-200"> + {decision.limits.rules.map((r) => { + if (r.operation_type === "BALANCE") return; + return ( + <tr> + <td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 text-left">{r.operation_type}</td> + <td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500"> + {r.timeframe.d_us === "forever" + ? "" + : formatDuration( intervalToDuration({ start: 0, end: r.timeframe.d_us / 1000, }), )} - </td> - <td class="text-right"> - <RenderAmount - value={Amounts.parseOrThrow(r.threshold)} - spec={config.currency_specification} - /> - </td> - </tr> - ); - })} - </tbody> - </table> - </Fragment> + </td> + <td class=" relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 text-right"> + <RenderAmount + value={Amounts.parseOrThrow(r.threshold)} + spec={config.currency_specification} + /> + </td> + </tr> + ); + })} + </tbody> + </table> + </div> + + </div> ); } @@ -729,13 +781,13 @@ function InputAmount( if ( sep_pos !== -1 && l - sep_pos - 1 > - config.currency_specification.num_fractional_input_digits + config.currency_specification.num_fractional_input_digits ) { e.currentTarget.value = e.currentTarget.value.substring( 0, sep_pos + - config.currency_specification.num_fractional_input_digits + - 1, + config.currency_specification.num_fractional_input_digits + + 1, ); } onChange(e.currentTarget.value); @@ -773,9 +825,9 @@ function parseJustification( listOfAllKnownForms: FormMetadata[], ): | OperationOk<{ - justification: Justification; - metadata: FormMetadata; - }> + justification: Justification; + metadata: FormMetadata; + }> | OperationFail<ParseJustificationFail> { try { const justification = JSON.parse(s); @@ -823,212 +875,212 @@ function parseJustification( const THRESHOLD_2000_WEEK: (currency: string) => TalerExchangeApi.KycRule[] = ( currency, ) => [ - { - operation_type: "WITHDRAW", - threshold: `${currency}:2000`, - timeframe: { - d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + { + operation_type: "WITHDRAW", + threshold: `${currency}:2000`, + timeframe: { + d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "DEPOSIT", - threshold: `${currency}:2000`, - timeframe: { - d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + { + operation_type: "DEPOSIT", + threshold: `${currency}:2000`, + timeframe: { + d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "AGGREGATE", - threshold: `${currency}:2000`, - timeframe: { - d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + { + operation_type: "AGGREGATE", + threshold: `${currency}:2000`, + timeframe: { + d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "MERGE", - threshold: `${currency}:2000`, - timeframe: { - d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + { + operation_type: "MERGE", + threshold: `${currency}:2000`, + timeframe: { + d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "BALANCE", - threshold: `${currency}:2000`, - timeframe: { - d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + { + operation_type: "BALANCE", + threshold: `${currency}:2000`, + timeframe: { + d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "CLOSE", - threshold: `${currency}:2000`, - timeframe: { - d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + { + operation_type: "CLOSE", + threshold: `${currency}:2000`, + timeframe: { + d_us: 7 * 24 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, -]; + ]; const THRESHOLD_100_HOUR: (currency: string) => TalerExchangeApi.KycRule[] = ( currency, ) => [ - { - operation_type: "WITHDRAW", - threshold: `${currency}:100`, - timeframe: { - d_us: 1 * 60 * 60 * 1000 * 1000, + { + operation_type: "WITHDRAW", + threshold: `${currency}:100`, + timeframe: { + d_us: 1 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "DEPOSIT", - threshold: `${currency}:100`, - timeframe: { - d_us: 1 * 60 * 60 * 1000 * 1000, + { + operation_type: "DEPOSIT", + threshold: `${currency}:100`, + timeframe: { + d_us: 1 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "AGGREGATE", - threshold: `${currency}:100`, - timeframe: { - d_us: 1 * 60 * 60 * 1000 * 1000, + { + operation_type: "AGGREGATE", + threshold: `${currency}:100`, + timeframe: { + d_us: 1 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "MERGE", - threshold: `${currency}:100`, - timeframe: { - d_us: 1 * 60 * 60 * 1000 * 1000, + { + operation_type: "MERGE", + threshold: `${currency}:100`, + timeframe: { + d_us: 1 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "BALANCE", - threshold: `${currency}:100`, - timeframe: { - d_us: 1 * 60 * 60 * 1000 * 1000, + { + operation_type: "BALANCE", + threshold: `${currency}:100`, + timeframe: { + d_us: 1 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "CLOSE", - threshold: `${currency}:100`, - timeframe: { - d_us: 1 * 60 * 60 * 1000 * 1000, + { + operation_type: "CLOSE", + threshold: `${currency}:100`, + timeframe: { + d_us: 1 * 60 * 60 * 1000 * 1000, + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, -]; + ]; const FREEZE_RULES: (currency: string) => TalerExchangeApi.KycRule[] = ( currency, ) => [ - { - operation_type: "WITHDRAW", - threshold: `${currency}:0`, - timeframe: { - d_us: "forever", + { + operation_type: "WITHDRAW", + threshold: `${currency}:0`, + timeframe: { + d_us: "forever", + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "DEPOSIT", - threshold: `${currency}:0`, - timeframe: { - d_us: "forever", + { + operation_type: "DEPOSIT", + threshold: `${currency}:0`, + timeframe: { + d_us: "forever", + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "AGGREGATE", - threshold: `${currency}:0`, - timeframe: { - d_us: "forever", + { + operation_type: "AGGREGATE", + threshold: `${currency}:0`, + timeframe: { + d_us: "forever", + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "MERGE", - threshold: `${currency}:0`, - timeframe: { - d_us: "forever", + { + operation_type: "MERGE", + threshold: `${currency}:0`, + timeframe: { + d_us: "forever", + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "BALANCE", - threshold: `${currency}:0`, - timeframe: { - d_us: "forever", + { + operation_type: "BALANCE", + threshold: `${currency}:0`, + timeframe: { + d_us: "forever", + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, - { - operation_type: "CLOSE", - threshold: `${currency}:0`, - timeframe: { - d_us: "forever", + { + operation_type: "CLOSE", + threshold: `${currency}:0`, + timeframe: { + d_us: "forever", + }, + measures: ["verboten"], + display_priority: 1, + exposed: true, + is_and_combinator: true, }, - measures: ["verboten"], - display_priority: 1, - exposed: true, - is_and_combinator: true, - }, -]; + ]; diff --git a/packages/aml-backoffice-ui/src/pages/Cases.tsx b/packages/aml-backoffice-ui/src/pages/Cases.tsx index d79ce9006..c229850b1 100644 --- a/packages/aml-backoffice-ui/src/pages/Cases.tsx +++ b/packages/aml-backoffice-ui/src/pages/Cases.tsx @@ -29,7 +29,7 @@ import { useTranslationContext, } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; -import { useCurrentDecisions } from "../hooks/decisions.js"; +import { useCurrentDecisions, useCurrentDecisionsUnderInvestigation } from "../hooks/decisions.js"; import { privatePages } from "../Routing.js"; import { FormErrors, RecursivePartial, useFormState } from "../hooks/form.js"; @@ -171,8 +171,8 @@ export function CasesUI({ ); } -export function Cases({ filtered }: { filtered?: boolean }) { - const list = useCurrentDecisions(filtered); +export function Cases() { + const list = useCurrentDecisions(); const { i18n } = useTranslationContext(); if (!list) { @@ -229,7 +229,76 @@ export function Cases({ filtered }: { filtered?: boolean }) { return ( <CasesUI - filtered={!!filtered} + filtered={true} + records={list.body} + onFirstPage={list.isFirstPage ? undefined : list.loadFirst} + onNext={list.isLastPage ? undefined : list.loadNext} + // filter={stateFilter} + // onChangeFilter={(d) => { + // setStateFilter(d); + // }} + /> + ); +} +export function CasesUnderInvestigation() { + const list = useCurrentDecisionsUnderInvestigation(); + const { i18n } = useTranslationContext(); + + if (!list) { + return <Loading />; + } + if (list instanceof TalerError) { + return <ErrorLoadingWithDebug error={list} />; + } + + if (list.type === "fail") { + switch (list.case) { + case HttpStatusCode.Forbidden: { + return ( + <Fragment> + <Attention type="danger" title={i18n.str`Operation denied`}> + <i18n.Translate> + This account signature is wrong, contact administrator or create a new one. + </i18n.Translate> + </Attention> + <Officer /> + </Fragment> + ); + } + case HttpStatusCode.NotFound: { + return ( + <Fragment> + <Attention type="danger" title={i18n.str`Operation denied`}> + <i18n.Translate> + This account is not known. + </i18n.Translate> + </Attention> + <Officer /> + </Fragment> + ); + } + case HttpStatusCode.Conflict: { + return ( + <Fragment> + <Attention type="danger" title={i18n.str`Operation denied`}> + <i18n.Translate> + This account doesn't have access. Request account activation + sending your public key. + </i18n.Translate> + </Attention> + <Officer /> + </Fragment> + ); + } + return <Officer />; + default: + assertUnreachable(list); + } + } + + return ( + <CasesUI + filtered={false} records={list.body} onFirstPage={list.isFirstPage ? undefined : list.loadFirst} onNext={list.isLastPage ? undefined : list.loadNext} |