aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-08-27 18:20:54 -0300
committerSebastian <sebasjm@gmail.com>2024-08-27 18:21:28 -0300
commit94cb658024a17084da5de310bc5104cff6fd8337 (patch)
tree37c8459d8f7ba1262ac866de904a40d8cc6688e0 /packages
parent3e834cd10187a488b19b8f809b55cc443cd3c675 (diff)
freeze account
Diffstat (limited to 'packages')
-rw-r--r--packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx9
-rw-r--r--packages/aml-backoffice-ui/src/Routing.tsx17
-rw-r--r--packages/aml-backoffice-ui/src/hooks/decisions.ts12
-rw-r--r--packages/aml-backoffice-ui/src/pages/CaseDetails.tsx421
-rw-r--r--packages/aml-backoffice-ui/src/pages/Cases.tsx89
5 files changed, 452 insertions, 96 deletions
diff --git a/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
index 7dc36e7f6..44cd0ce82 100644
--- a/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
+++ b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
@@ -33,7 +33,7 @@ import {
getLabelForPreferences,
usePreferences,
} from "./hooks/preferences.js";
-import { HomeIcon } from "./pages/Cases.js";
+import { HomeIcon, PeopleIcon, ToInvestigateIcon } from "./pages/Cases.js";
/**
* mapping route to view
@@ -208,7 +208,7 @@ export function ExchangeAmlFrame({
<div class="-mt-32 flex grow ">
{officer?.state !== "ready" ? undefined : <Navigation />}
<div class="flex mx-auto my-4">
- <main class="rounded-lg bg-white px-5 py-6 shadow">{children}</main>
+ <main class="block rounded-lg bg-white px-5 py-6 shadow " style={{minWidth: 300}} >{children}</main>
</div>
</div>
@@ -224,8 +224,9 @@ export function ExchangeAmlFrame({
function Navigation(): VNode {
const { i18n } = useTranslationContext();
const pageList = [
- { route: privatePages.account, Icon: HomeIcon, label: i18n.str`Account` },
- { route: privatePages.cases, Icon: HomeIcon, label: i18n.str`Cases` },
+ { route: privatePages.profile, Icon: PeopleIcon, label: i18n.str`Profile` },
+ { route: privatePages.investigation, Icon: ToInvestigateIcon, label: i18n.str`Investigation` },
+ { route: privatePages.active, Icon: HomeIcon, label: i18n.str`Active` },
];
const { path } = useNavigationContext();
return (
diff --git a/packages/aml-backoffice-ui/src/Routing.tsx b/packages/aml-backoffice-ui/src/Routing.tsx
index 4000cac00..082dc8ab5 100644
--- a/packages/aml-backoffice-ui/src/Routing.tsx
+++ b/packages/aml-backoffice-ui/src/Routing.tsx
@@ -94,8 +94,9 @@ function PublicRounting(): VNode {
}
export const privatePages = {
- account: urlPattern(/\/account/, () => "#/account"),
- cases: urlPattern(/\/cases/, () => "#/cases"),
+ profile: urlPattern(/\/profile/, () => "#/profile"),
+ investigation: urlPattern(/\/investigation/, () => "#/investigation"),
+ active: urlPattern(/\/active/, () => "#/active"),
caseUpdate: urlPattern<{ cid: string; type: string }>(
/\/case\/(?<cid>[a-zA-Z0-9]+)\/new\/(?<type>[a-zA-Z0-9_.]+)/,
({ cid, type }) => `#/case/${cid}/new/${type}`,
@@ -114,8 +115,9 @@ function PrivateRouting(): VNode {
const { navigateTo } = useNavigationContext();
const location = useCurrentLocation(privatePages);
useEffect(() => {
- if (location === undefined) {
- navigateTo(privatePages.account.url({}));
+ if (location.name === undefined) {
+ console.log("asd")
+ navigateTo(privatePages.profile.url({}));
}
}, [location]);
@@ -123,7 +125,7 @@ function PrivateRouting(): VNode {
case undefined: {
return <Fragment />;
}
- case "account": {
+ case "profile": {
return <Officer />;
}
case "caseDetails": {
@@ -137,7 +139,10 @@ function PrivateRouting(): VNode {
case "caseNew": {
return <SelectForm account={location.values.cid} />;
}
- case "cases": {
+ case "investigation": {
+ return <Cases filtered/>;
+ }
+ case "active": {
return <Cases />;
}
default:
diff --git a/packages/aml-backoffice-ui/src/hooks/decisions.ts b/packages/aml-backoffice-ui/src/hooks/decisions.ts
index e652f233e..de8f1637e 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() {
+export function useCurrentDecisions(filtered?: boolean) {
const officer = useOfficer();
const session = officer.state === "ready" ? officer.account : undefined;
const {
@@ -46,13 +46,15 @@ export function useCurrentDecisions() {
const [offset, setOffset] = useState<string>();
- async function fetcher([officer, offset]: [
+ async function fetcher([officer, offset, investigation]: [
OfficerAccount,
string | undefined,
+ boolean | undefined
]) {
return await api.getAmlDecisions(officer, {
- order: "asc",
+ order: "dec",
offset,
+ investigation,
active: true,
limit: PAGINATED_LIST_REQUEST,
});
@@ -62,7 +64,7 @@ export function useCurrentDecisions() {
TalerExchangeResultByMethod<"getAmlDecisions">,
TalerHttpError
>(
- !session ? undefined : [session, offset, "getAmlDecisions"],
+ !session ? undefined : [session, offset, filtered ? true : filtered, "getAmlDecisions"],
fetcher,
);
@@ -95,7 +97,7 @@ export function useAccountDecisions(accountStr: string) {
string | undefined,
]) {
return await api.getAmlDecisions(officer, {
- order: "asc",
+ order: "dec",
offset,
account,
limit: PAGINATED_LIST_REQUEST,
diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
index b26e6f430..b421bd8c5 100644
--- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
@@ -51,6 +51,7 @@ import { preloadedForms } from "../forms/index.js";
import { useAccountInformation } from "../hooks/account.js";
import { useAccountDecisions } from "../hooks/decisions.js";
import { ShowConsolidated } from "./ShowConsolidated.js";
+import { useOfficer } from "../hooks/officer.js";
export type AmlEvent =
| AmlFormEvent
@@ -175,6 +176,10 @@ export function CaseDetails({ account }: { account: string }) {
justification: Justification;
metadata: FormMetadata;
}>();
+ const { config, lib } = useExchangeApiContext()
+ const officer = useOfficer();
+ const session = officer.state === "ready" ? officer.account : undefined;
+
const { i18n } = useTranslationContext();
const details = useAccountInformation(account);
@@ -215,7 +220,8 @@ export function CaseDetails({ account }: { account: string }) {
}
}
const { details: accountDetails } = details.body;
- const activeDesicion = history.body.find(d => d.is_active)
+ const activeDecision = history.body.find(d => d.is_active)
+ const restDecisions = !activeDecision ? history.body : history.body.filter(d => d.rowid !== activeDecision.rowid)
const events = getEventsFromAmlHistory(
accountDetails,
@@ -243,30 +249,9 @@ export function CaseDetails({ account }: { account: string }) {
</DefaultForm>
);
}
- return (
- <div>
- <a
- // href={privatePages.caseNew.url({ cid: account })}
- href="#"
- class="m-4 block rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
- >
- <i18n.Translate>Freeze account</i18n.Translate>
- </a>
- <a
- // href={privatePages.caseNew.url({ cid: account })}
- href="#"
- class="m-4 block rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
- >
- <i18n.Translate>New threshold</i18n.Translate>
- </a>
- <a
- // href={privatePages.caseNew.url({ cid: account })}
- href="#"
- class="m-4 block rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
- >
- <i18n.Translate>Ask more information</i18n.Translate>
- </a>
+ return (
+ <div class="min-w-60">
<header class="flex items-center justify-between border-b border-white/5 px-4 py-4 sm:px-6 sm:py-6 lg:px-8">
<h1 class="text-base font-semibold leading-7 text-black">
<i18n.Translate>
@@ -275,10 +260,112 @@ export function CaseDetails({ account }: { account: string }) {
</i18n.Translate>
</h1>
</header>
- {!activeDesicion ? <Attention title={i18n.str`No active decision found`} type="warning" /> : <Fragment>
- {!activeDesicion.to_investigate ? undefined : <Attention title={i18n.str`Requires investigation`} type="warning" />}
- <ShowActiveDecision decision={activeDesicion} />
+
+ {!activeDecision || !activeDecision.to_investigate ? undefined : <Attention title={i18n.str`Under investigation`} type="warning" >
+ <i18n.Translate>This account requires a manual review and is waiting for a decision to be made.</i18n.Translate>
+ </Attention>}
+
+ <div>
+ <button
+ onClick={async () => {
+ if (!session) return;
+ lib.exchange.makeAmlDesicion(session, {
+ decision_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()),
+ h_payto: account,
+ justification: "",
+ keep_investigating: false,
+ properties: {},
+ new_rules: {
+ custom_measures: {},
+ expiration_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
+ rules: FREEZE_RULES(config.currency),
+ successor_measure: "verboten",
+ },
+ })
+ }}
+ class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ >
+ <i18n.Translate>Freeze account</i18n.Translate>
+ </button>
+ <button
+ onClick={async () => {
+ if (!session) return;
+ lib.exchange.makeAmlDesicion(session, {
+ decision_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()),
+ h_payto: account,
+ justification: "",
+ keep_investigating: false,
+ properties: {},
+ new_rules: {
+ custom_measures: {},
+ expiration_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
+ rules: THRESHOLD_100_HOUR(config.currency),
+ successor_measure: "verboten",
+ },
+ })
+ }}
+
+ class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ >
+ <i18n.Translate>Set threshold to 100 / hour</i18n.Translate>
+ </button>
+ <button
+ onClick={async () => {
+ if (!session) return;
+ lib.exchange.makeAmlDesicion(session, {
+ decision_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()),
+ h_payto: account,
+ justification: "",
+ keep_investigating: false,
+ properties: {},
+ new_rules: {
+ custom_measures: {},
+ expiration_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
+ rules: THRESHOLD_2000_WEEK(config.currency),
+ successor_measure: "verboten",
+ },
+ })
+ }}
+
+ class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ >
+ <i18n.Translate>Set threshold to 2000 / week</i18n.Translate>
+ </button>
+ <button
+ onClick={async () => {
+ if (!session) return;
+ lib.exchange.makeAmlDesicion(session, {
+ decision_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()),
+ h_payto: account,
+ justification: "",
+ keep_investigating: false,
+ properties: {},
+ new_measure: "onlyTalers",
+ new_rules: {
+ custom_measures: {},
+ expiration_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
+ rules: FREEZE_RULES(config.currency),
+ successor_measure: "verboten",
+ },
+ })
+ }}
+
+ class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ >
+ <i18n.Translate>Ask for more information</i18n.Translate>
+ </button>
+ </div>
+
+ {!activeDecision ? <Attention title={i18n.str`No active decision found`} type="warning" /> : <Fragment>
+ <h1 class="my-4 text-base font-semibold leading-6 text-black">
+ <i18n.Translate>Current active rules</i18n.Translate>
+ </h1>
+
+ <ShowDecisionInfo decision={activeDecision} />
</Fragment>}
+ <h1 class="my-4 text-base font-semibold leading-6 text-black">
+ <i18n.Translate>KYC collection events</i18n.Translate>
+ </h1>
<ShowTimeline
history={events}
onSelect={(e) => {
@@ -299,25 +386,55 @@ export function CaseDetails({ account }: { account: string }) {
/>
{/* {selected && <ShowEventDetails event={selected} />} */}
{selected && <ShowConsolidated history={events} until={selected} />}
+ {restDecisions.length > 0 ?
+ <Fragment>
+ <h1 class="my-4 text-base font-semibold leading-6 text-black">
+ <i18n.Translate>Previous AML decisions</i18n.Translate>
+ </h1>
+ {restDecisions.map(d => {
+ return <ShowDecisionInfo decision={d} />
+ })}
+
+ </Fragment> : <div />}
</div>
);
}
-function ShowActiveDecision({ decision }: { decision: TalerExchangeApi.AmlDecision }): VNode {
+function ShowDecisionInfo({ decision }: { decision: TalerExchangeApi.AmlDecision }): VNode {
const { i18n } = useTranslationContext();
const { config } = useExchangeApiContext()
return <Fragment>
- <h1 class="mt-4 text-base font-semibold leading-6 text-black">
- <i18n.Translate>Current active rules</i18n.Translate>
- </h1>
<div class="sm:col-span-5">
<label
for="amount"
class="block text-sm font-medium leading-6 text-gray-900"
>
- <b>Expiration time</b>
+ <b><i18n.Translate>Since</i18n.Translate></b>
+ <div class="flex 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="p-4 disabled:bg-gray-200 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>
+
+
+ </label>
+ </div>
+
+ <div class="sm:col-span-5">
+ <label
+ for="amount"
+ class="block text-sm font-medium leading-6 text-gray-900"
+ >
+ {AbsoluteTime.isExpired(AbsoluteTime.fromProtocolTimestamp(decision.limits.expiration_time)) ?
+ <b><i18n.Translate>Expired at</i18n.Translate></b> :
+ <b><i18n.Translate>Expires at</i18n.Translate></b>
+ }
<div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
<div
@@ -631,3 +748,243 @@ function parseJustification(
};
}
}
+
+const THRESHOLD_2000_WEEK: (currency: string) => TalerExchangeApi.KycRule[] = (currency) => [{
+ "operation_type": "WITHDRAW",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "DEPOSIT",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "AGGREGATE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "MERGE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "BALANCE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "CLOSE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "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}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "DEPOSIT",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "AGGREGATE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "MERGE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "BALANCE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "CLOSE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "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"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "DEPOSIT",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "AGGREGATE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "MERGE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "BALANCE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "CLOSE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "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 9a569cd60..d79ce9006 100644
--- a/packages/aml-backoffice-ui/src/pages/Cases.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Cases.tsx
@@ -36,6 +36,7 @@ import { FormErrors, RecursivePartial, useFormState } from "../hooks/form.js";
import { undefinedIfEmpty } from "./CreateAccount.js";
import { Officer } from "./Officer.js";
import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js";
+import { useState } from "preact/hooks";
type FormType = {
// state: TalerExchangeApi.AmlState;
@@ -43,15 +44,13 @@ type FormType = {
export function CasesUI({
records,
- // filter,
- // onChangeFilter,
onFirstPage,
onNext,
+ filtered,
}: {
+ filtered: boolean,
onFirstPage?: () => void;
onNext?: () => void;
- // filter: TalerExchangeApi.AmlState;
- // onChangeFilter: (f: TalerExchangeApi.AmlState) => void;
records: TalerExchangeApi.AmlDecision[];
}): VNode {
const { i18n } = useTranslationContext();
@@ -94,38 +93,27 @@ export function CasesUI({
return (
<div>
<div class="sm:flex sm:items-center">
- <div class="px-2 sm:flex-auto">
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Cases</i18n.Translate>
- </h1>
- <p class="mt-2 text-sm text-gray-700 w-80">
- <i18n.Translate>
- A list of all the account with the status
- </i18n.Translate>
- </p>
- </div>
- <div class="px-2">
- {/* <InputChoiceHorizontal<FormType, "state">
- name="state"
- label={i18n.str`Filter`}
- handler={form.state}
- converter={amlStateConverter}
- choices={[
- {
- label: i18n.str`Pending`,
- value: "pending",
- },
- {
- label: i18n.str`Frozen`,
- value: "frozen",
- },
- {
- label: i18n.str`Normal`,
- value: "normal",
- },
- ]}
- /> */}
- </div>
+ {filtered ?
+ <div class="px-2 sm:flex-auto">
+ <h1 class="text-base font-semibold leading-6 text-gray-900">
+ <i18n.Translate>Cases under investigation</i18n.Translate>
+ </h1>
+ <p class="mt-2 text-sm text-gray-700 w-80">
+ <i18n.Translate>
+ A list of all the accounts which are waiting for a deicison to be made.
+ </i18n.Translate>
+ </p>
+ </div> : <div class="px-2 sm:flex-auto">
+ <h1 class="text-base font-semibold leading-6 text-gray-900">
+ <i18n.Translate>Cases</i18n.Translate>
+ </h1>
+ <p class="mt-2 text-sm text-gray-700 w-80">
+ <i18n.Translate>
+ A list of all the known account by the exchange.
+ </i18n.Translate>
+ </p>
+ </div>
+ }
</div>
<div class="mt-8 flow-root">
<div class="overflow-x-auto">
@@ -167,7 +155,7 @@ export function CasesUI({
</div>
</td>
<td class="whitespace-nowrap px-3 py-5 text-sm text-gray-900">
- {r.to_investigate ? <ToInvestigateIcon /> : undefined}
+ {r.to_investigate ? <span title="require investigation"><ToInvestigateIcon /></span> : undefined}
</td>
</tr>
);
@@ -182,19 +170,9 @@ export function CasesUI({
</div>
);
}
-function ToInvestigateIcon(): VNode {
- return <svg title="requires investigation" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 w-6">
- <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" />
- </svg>
-}
-
-export function Cases() {
- // const [stateFilter, setStateFilter] = useState(
- // TalerExchangeApi.AmlState.pending,
- // );
-
- const list = useCurrentDecisions();
+export function Cases({ filtered }: { filtered?: boolean }) {
+ const list = useCurrentDecisions(filtered);
const { i18n } = useTranslationContext();
if (!list) {
@@ -251,6 +229,7 @@ export function Cases() {
return (
<CasesUI
+ filtered={!!filtered}
records={list.body}
onFirstPage={list.isFirstPage ? undefined : list.loadFirst}
onNext={list.isLastPage ? undefined : list.loadNext}
@@ -262,6 +241,18 @@ export function Cases() {
);
}
+// function ToInvestigateIcon(): VNode {
+// return <svg title="requires investigation" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 w-6">
+// <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" />
+// </svg>
+// }
+export const ToInvestigateIcon = () => (
+ <svg title="requires investigation" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 w-6">
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" />
+ </svg>
+);
+
+
export const PeopleIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"