aboutsummaryrefslogtreecommitdiff
path: root/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/aml-backoffice-ui/src/pages/CaseDetails.tsx')
-rw-r--r--packages/aml-backoffice-ui/src/pages/CaseDetails.tsx579
1 files changed, 303 insertions, 276 deletions
diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
index 8b54c1861..cf6922e1a 100644
--- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
@@ -227,26 +227,26 @@ export function CaseDetails({ account }: { account: string }) {
const events = getEventsFromAmlHistory(accountDetails, i18n, allForms);
- if (showForm !== undefined) {
- return (
- <DefaultForm
- readOnly={true}
- initial={showForm.justification.value}
- form={showForm.metadata as any} // FIXME: HERE
- >
- <div class="mt-6 flex items-center justify-end gap-x-6">
- <button
- class="text-sm font-semibold leading-6 text-gray-900"
- onClick={() => {
- setShowForm(undefined);
- }}
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
- </div>
- </DefaultForm>
- );
- }
+ // if (showForm !== undefined) {
+ // return (
+ // <DefaultForm
+ // readOnly={true}
+ // initial={showForm.justification.value}
+ // form={showForm.metadata as any} // FIXME: HERE
+ // >
+ // <div class="mt-6 flex items-center justify-end gap-x-6">
+ // <button
+ // class="text-sm font-semibold leading-6 text-gray-900"
+ // onClick={() => {
+ // setShowForm(undefined);
+ // }}
+ // >
+ // <i18n.Translate>Cancel</i18n.Translate>
+ // </button>
+ // </div>
+ // </DefaultForm>
+ // );
+ // }
return (
<div class="min-w-60">
@@ -390,8 +390,8 @@ export function CaseDetails({ account }: { account: string }) {
onSelect={(e) => {
switch (e.type) {
case "aml-form": {
- const { justification, metadata } = e;
- setShowForm({ justification, metadata });
+ // const { justification, metadata } = e;
+ // setShowForm({ justification, metadata });
break;
}
case "kyc-collection":
@@ -423,87 +423,104 @@ export function CaseDetails({ account }: { account: string }) {
function ShowDecisionInfo({
decision,
- startOpen
+ startOpen,
}: {
decision: TalerExchangeApi.AmlDecision;
- startOpen?: boolean,
+ startOpen?: boolean;
}): VNode {
const { i18n } = useTranslationContext();
const { config } = useExchangeApiContext();
- const [opened, setOpened] = useState(startOpen ?? false)
-
+ const [opened, setOpened] = useState(startOpen ?? false);
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,
- )}
- />
+ 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>
- </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 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>
- </div>
- </li>
- </ul>
+ </li>
+ </ul>
+ );
}
if (!opened) {
- return <div class="mt-4 cursor-pointer" onClick={() => setOpened(true)}>
- <Header />
- </div>
+ return (
+ <div class="mt-4 cursor-pointer" onClick={() => setOpened(true)}>
+ <Header />
+ </div>
+ );
}
- const balanceLimit = decision.limits.rules.find(r => r.operation_type === "BALANCE")
+ 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 :
+ {!decision.justification ? undefined : (
<div>
- <label for="comment" class="block text-sm font-medium leading-6 text-gray-900">Description</label>
+ <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">
+ <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>
- }
+ )}
- {!balanceLimit ? undefined :
+ {!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">
@@ -514,21 +531,30 @@ function ShowDecisionInfo({
value={Amounts.parseOrThrow(balanceLimit.threshold)}
spec={config.currency_specification}
/>
-
</div>
</div>
</div>
-
- }
+ )}
<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>
+ <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">
@@ -536,16 +562,18 @@ function ShowDecisionInfo({
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 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,
- }),
- )}
+ intervalToDuration({
+ start: 0,
+ end: r.timeframe.d_us / 1000,
+ }),
+ )}
</td>
<td class=" relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 text-right">
<RenderAmount
@@ -559,7 +587,6 @@ function ShowDecisionInfo({
</tbody>
</table>
</div>
-
</div>
);
}
@@ -781,13 +808,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);
@@ -825,9 +852,9 @@ function parseJustification(
listOfAllKnownForms: FormMetadata[],
):
| OperationOk<{
- justification: Justification;
- metadata: FormMetadata;
- }>
+ justification: Justification;
+ metadata: FormMetadata;
+ }>
| OperationFail<ParseJustificationFail> {
try {
const justification = JSON.parse(s);
@@ -875,212 +902,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,
- },
- measures: ["verboten"],
- display_priority: 1,
- exposed: true,
- is_and_combinator: true,
+ {
+ operation_type: "WITHDRAW",
+ 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: "DEPOSIT",
+ 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: "AGGREGATE",
+ 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: "MERGE",
+ 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: "BALANCE",
+ 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,
+ },
+ {
+ 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,
+ },
+];
const THRESHOLD_100_HOUR: (currency: string) => TalerExchangeApi.KycRule[] = (
currency,
) => [
- {
- 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,
+ {
+ operation_type: "WITHDRAW",
+ 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: "DEPOSIT",
+ 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: "AGGREGATE",
+ 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: "MERGE",
+ 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: "BALANCE",
+ 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,
+ },
+ {
+ 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,
+ },
+];
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: "WITHDRAW",
+ 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: "DEPOSIT",
+ 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: "AGGREGATE",
+ 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: "MERGE",
+ 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: "BALANCE",
+ 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,
+ },
+ {
+ operation_type: "CLOSE",
+ threshold: `${currency}:0`,
+ timeframe: {
+ d_us: "forever",
},
- ];
+ measures: ["verboten"],
+ display_priority: 1,
+ exposed: true,
+ is_and_combinator: true,
+ },
+];