taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit a2011cb08bfbea3d82b0ec680a6836a6e09c8e19
parent e9e12687488be1350f708daa7dc3f51bc4907df2
Author: Sebastian <sebasjm@gmail.com>
Date:   Wed,  5 Feb 2025 14:13:12 -0300

using error summary in kyc

Diffstat:
Mpackages/aml-backoffice-ui/src/pages/CaseDetails.tsx | 179-------------------------------------------------------------------------------
Mpackages/kyc-ui/src/pages/FillForm.tsx | 4+++-
Mpackages/web-util/src/forms/fields/InputSelectMultiple.tsx | 69++++++++++++++++++++++++++++++++++++---------------------------------
Mpackages/web-util/src/forms/forms-ui.tsx | 4++--
4 files changed, 41 insertions(+), 215 deletions(-)

diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx @@ -199,56 +199,6 @@ export function CaseDetails({ const events = getEventsFromAmlHistory(accountDetails, i18n, allForms); - // if (selectMeasure) { - // return ( - // <ShowMeasuresToSelect - // onSelect={(d) => { - // setSelectMeasure(false); - // setDesicionRequest({ - // request: { - // // payto_uri: paytoString, - // decision_time: AbsoluteTime.toProtocolTimestamp( - // AbsoluteTime.now(), - // ), - // h_payto: account, - // keep_investigating: false, - // properties: {}, - // // the custom measure with context - // new_measures: d.name, - // new_rules: { - // // this value is going to be overridden - // custom_measures: {}, - // expiration_time: AbsoluteTime.toProtocolTimestamp( - // AbsoluteTime.never(), - // ), - // rules: FREEZE_RULES(config.config.currency), - // }, - // }, - // askInformation: false, - // }); - // }} - // /> - // ); - // } - // if (request) { - // return ( - // <SubmitNewDecision - // decision={request} - // onComplete={() => { - // setDesicionRequest(undefined); - // }} - // /> - // ); - // } - // if (decisionWizardStep) { - // return ( - // <AmlDecisionRequestWizard - // step={decisionWizardStep} - // onMove={(step) => setDecisionWizardStep(step)} - // /> - // ); - // } - function ShortcutActionButtons(): VNode { return ( <div> @@ -271,126 +221,6 @@ export function CaseDetails({ > <i18n.Translate>New decision</i18n.Translate> </button> - {/* - <button - onClick={async () => { - setDesicionRequest({ - request: { - // payto_uri: paytoString, - decision_time: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.now(), - ), - h_payto: account, - keep_investigating: false, - properties: {}, - new_rules: { - custom_measures: {}, - expiration_time: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.never(), - ), - rules: FREEZE_RULES(config.config.currency), - successor_measure: "verboten", - }, - }, - askInformation: false, - }); - }} - 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 () => { - setDesicionRequest({ - request: { - // payto_uri: paytoString, - decision_time: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.now(), - ), - h_payto: account, - keep_investigating: false, - properties: {}, - new_rules: { - custom_measures: {}, - expiration_time: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.never(), - ), - rules: THRESHOLD_100_HOUR(config.config.currency), - successor_measure: "verboten", - }, - }, - askInformation: false, - }); - }} - 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 () => { - setDesicionRequest({ - request: { - // payto_uri: paytoString, - decision_time: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.now(), - ), - h_payto: account, - keep_investigating: false, - properties: {}, - new_rules: { - custom_measures: {}, - expiration_time: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.never(), - ), - rules: THRESHOLD_2000_WEEK(config.config.currency), - successor_measure: "verboten", - }, - }, - askInformation: false, - }); - }} - 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 () => { - setDesicionRequest({ - request: { - // payto_uri: paytoString, - decision_time: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.now(), - ), - h_payto: account, - keep_investigating: false, - properties: {}, - // the custom measure with context - new_measures: "askMoreInfo", - new_rules: { - // this value is going to be overridden - custom_measures: {}, - expiration_time: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.never(), - ), - rules: FREEZE_RULES(config.config.currency), - }, - }, - askInformation: true, - }); - }} - 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> */} - - {/* <button - onClick={async () => { - setSelectMeasure(true); - }} - 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 predefined measure</i18n.Translate> - </button> */} </div> ); } @@ -827,15 +657,6 @@ export function ShowDecisionLimitInfo({ /> )} </svg> - {/* <svg - 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 h-6" - > - </svg> */} </div> )} </div> diff --git a/packages/kyc-ui/src/pages/FillForm.tsx b/packages/kyc-ui/src/pages/FillForm.tsx @@ -24,6 +24,7 @@ import { } from "@gnu-taler/taler-util"; import { Button, + ErrorsSummary, FormMetadata, FormUI, InternationalizationAPI, @@ -158,7 +159,7 @@ export function FillForm({ ) : ( <Fragment /> )} - <div class="mt-6 flex items-center justify-end gap-x-6"> + <div class="my-6 flex items-center justify-end gap-x-6"> <button onClick={onComplete} class="text-sm font-semibold leading-6 text-gray-900" @@ -174,6 +175,7 @@ export function FillForm({ <i18n.Translate>Submit</i18n.Translate> </Button> </div> + {!status.errors ? undefined : <ErrorsSummary errors={status.errors} />} </div> ); } diff --git a/packages/web-util/src/forms/fields/InputSelectMultiple.tsx b/packages/web-util/src/forms/fields/InputSelectMultiple.tsx @@ -29,6 +29,7 @@ export function InputSelectMultiple<T extends object, K extends keyof T>( props.handler ?? noHandlerPropsAndNoContextForField(props.name); const [filter, setFilter] = useState<string | undefined>(undefined); + const [dirty, setDirty] = useState<boolean>(); const regex = new RegExp(`.*${filter}.*`, "i"); const choiceMap = choices.reduce( (prev, curr) => { @@ -54,38 +55,6 @@ export function InputSelectMultiple<T extends object, K extends keyof T>( tooltip={tooltip} name={props.name as string} /> - {list.map((v, idx) => { - return ( - <span - key={idx} - class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 p-1 mr-2 text-xs font-medium text-gray-600" - > - {choiceMap[v]} - <button - type="button" - disabled={state.disabled} - onClick={() => { - const newValue = [...list]; - newValue.splice(idx, 1); - onChange(newValue as any); - setFilter(undefined); - }} - class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20" - > - <span class="sr-only"> - <i18n.Translate>Remove</i18n.Translate> - </span> - <svg - viewBox="0 0 14 14" - class="h-5 w-5 stroke-gray-700/50 group-hover:stroke-gray-700/75" - > - <path d="M4 4l6 6m0-6l-6 6" /> - </svg> - <span class="absolute -inset-1"></span> - </button> - </span> - ); - })} {!state.disabled && ( <div class="relative mt-2"> @@ -95,6 +64,7 @@ export function InputSelectMultiple<T extends object, K extends keyof T>( value={filter ?? ""} onChange={(e) => { setFilter(e.currentTarget.value); + setDirty(true); }} placeholder={placeholder} class="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" @@ -107,6 +77,7 @@ export function InputSelectMultiple<T extends object, K extends keyof T>( disabled={state.disabled} onClick={() => { setFilter(filter === undefined ? "" : undefined); + setDirty(true); }} class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none" > @@ -124,7 +95,7 @@ export function InputSelectMultiple<T extends object, K extends keyof T>( </svg> </button> - {!filter ? undefined : filteredChoices === undefined || + {filter === undefined ? undefined : filteredChoices === undefined || !filteredChoices.length ? ( <ul class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm" @@ -172,6 +143,38 @@ export function InputSelectMultiple<T extends object, K extends keyof T>( )} </div> )} + {list.map((v, idx) => { + return ( + <span + key={idx} + class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 p-1 mt-2 mr-2 text-xs font-medium text-gray-600" + > + {choiceMap[v]} + <button + type="button" + disabled={state.disabled} + onClick={() => { + const newValue = [...list]; + newValue.splice(idx, 1); + onChange(newValue as any); + setFilter(undefined); + }} + class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20" + > + <span class="sr-only"> + <i18n.Translate>Remove</i18n.Translate> + </span> + <svg + viewBox="0 0 14 14" + class="h-5 w-5 stroke-gray-700/50 group-hover:stroke-gray-700/75" + > + <path d="M4 4l6 6m0-6l-6 6" /> + </svg> + <span class="absolute -inset-1"></span> + </button> + </span> + ); + })} {help && ( <p class="mt-2 text-sm text-gray-500" id="email-description"> {help} diff --git a/packages/web-util/src/forms/forms-ui.tsx b/packages/web-util/src/forms/forms-ui.tsx @@ -178,7 +178,7 @@ export function RenderAllFieldsByUiConfig({ ); } -function ErrorsSummary<T>({ +export function ErrorsSummary<T>({ errors, formName = DEFAULT_FORM_UI_NAME, startOpen, @@ -221,7 +221,7 @@ function ErrorsSummary<T>({ viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" - class="size-4" + class="size-4 h-4 w-4" > {opened ? ( <path