diff options
Diffstat (limited to 'packages/aml-backoffice-ui/src/pages/CaseDetails.tsx')
-rw-r--r-- | packages/aml-backoffice-ui/src/pages/CaseDetails.tsx | 579 |
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, + }, +]; |