taler-typescript-core

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

commit fdab1b9a323da944de456c31cd404f118e93412d
parent 381a18530f16570de843f04dda1c1f78fa34d68a
Author: Sebastian <sebasjm@gmail.com>
Date:   Thu,  8 May 2025 17:38:07 -0300

adding log of dec req

Diffstat:
Mpackages/aml-backoffice-ui/src/Routing.tsx | 8++++----
Mpackages/aml-backoffice-ui/src/hooks/decision-request.ts | 41++++++++++++++++++++++++++---------------
Mpackages/aml-backoffice-ui/src/pages/CaseDetails.tsx | 4+---
Mpackages/aml-backoffice-ui/src/pages/NewMeasure.tsx | 18++++++++----------
Mpackages/aml-backoffice-ui/src/pages/Search.tsx | 10+++-------
Mpackages/aml-backoffice-ui/src/pages/decision/Events.tsx | 3+--
Mpackages/aml-backoffice-ui/src/pages/decision/Information.tsx | 7++-----
Mpackages/aml-backoffice-ui/src/pages/decision/Justification.tsx | 3+--
Mpackages/aml-backoffice-ui/src/pages/decision/Measures.tsx | 3+--
Mpackages/aml-backoffice-ui/src/pages/decision/Properties.tsx | 3+--
Mpackages/aml-backoffice-ui/src/pages/decision/Rules.tsx | 22+++++++++++-----------
Mpackages/aml-backoffice-ui/src/pages/decision/Summary.tsx | 7+++----
12 files changed, 62 insertions(+), 67 deletions(-)

diff --git a/packages/aml-backoffice-ui/src/Routing.tsx b/packages/aml-backoffice-ui/src/Routing.tsx @@ -151,7 +151,7 @@ export const privatePages = { function PrivateRouting(): VNode { const { navigateTo } = useNavigationContext(); const location = useCurrentLocation(privatePages); - const [request, _, updateRequest] = useCurrentDecisionRequest(); + const [,, startNewRequest] = useCurrentDecisionRequest(); useEffect(() => { if (location.name === undefined) { navigateTo(privatePages.dashboard.url({})); @@ -300,7 +300,7 @@ function PrivateRouting(): VNode { account={location.values.cid} routeToShowCollectedInfo={privatePages.showCollectedInfo} onNewDecision={(r) => { - updateRequest(r); + startNewRequest(r); navigateTo( privatePages.decide.url({ cid: location.values.cid, @@ -316,8 +316,8 @@ function PrivateRouting(): VNode { case "search": { return ( <Search - onNewDecision={(request, account, payto) => { - updateRequest(request); + onNewDecision={(account, payto) => { + startNewRequest(); navigateTo( privatePages.decideNew.url({ cid: account, diff --git a/packages/aml-backoffice-ui/src/hooks/decision-request.ts b/packages/aml-backoffice-ui/src/hooks/decision-request.ts @@ -36,7 +36,7 @@ import { FormErrors, useLocalStorage, } from "@gnu-taler/web-util/browser"; - +import { useState } from "preact/hooks"; export interface AccountAttributes { data: object; formId: string | undefined; @@ -142,7 +142,7 @@ export const codecForDecisionRequest = (): Codec<DecisionRequest> => .property("onExpire_measure", codecOptional(codecForString())) .build("DecisionRequest"); -export const DECISION_REQUEST_EMPTY: DecisionRequest = { +const DECISION_REQUEST_EMPTY: DecisionRequest = { deadline: undefined, custom_properties: undefined, onExpire_measure: undefined, @@ -158,8 +158,6 @@ export const DECISION_REQUEST_EMPTY: DecisionRequest = { rules: undefined, }; -const defaultDecisionRequest: DecisionRequest = DECISION_REQUEST_EMPTY; - const DECISION_REQUEST_KEY = buildStorageKey( "aml-decision-request", codecForDecisionRequest(), @@ -167,24 +165,37 @@ const DECISION_REQUEST_KEY = buildStorageKey( /** * User preferences. * - * @returns tuple of [state, update()] */ export function useCurrentDecisionRequest(): [ Readonly<DecisionRequest>, - <T extends keyof DecisionRequest>(key: T, value: DecisionRequest[T]) => void, - (s: DecisionRequest) => void, + (s: Partial<DecisionRequest>) => void, + (s?: Partial<DecisionRequest>) => void, + () => void, ] { + const [currentDef, setDefault] = useState(DECISION_REQUEST_EMPTY); + const { value, update } = useLocalStorage( DECISION_REQUEST_KEY, - defaultDecisionRequest, + DECISION_REQUEST_EMPTY, ); - function updateField<T extends keyof DecisionRequest>( - k: T, - v: DecisionRequest[T], - ) { - const newValue = { ...value, [k]: v }; - update(newValue); + function updateValue(newValue: Partial<DecisionRequest>) { + const mergedValue = { ...value, ...newValue }; + console.log("UPDATING DECISON REQUEST", {old: value, mergedValue}) + update(mergedValue); } - return [value, updateField, update]; + + function start(d: Partial<DecisionRequest> | undefined) { + const v = d ?? DECISION_REQUEST_EMPTY + const newDef = {...DECISION_REQUEST_EMPTY, ...v} + setDefault(newDef); + console.log("STARTING NEW DECISION REQUEST", newDef) + updateValue(newDef); + } + function reset() { + console.log("RESETTING TO DEFAULT") + updateValue(currentDef); + } + + return [value, updateValue, start, reset]; } diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx @@ -55,7 +55,6 @@ import { useState } from "preact/hooks"; import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js"; import { useAccountInformation } from "../hooks/account.js"; import { - DECISION_REQUEST_EMPTY, DecisionRequest, } from "../hooks/decision-request.js"; import { useAccountDecisions } from "../hooks/decisions.js"; @@ -126,7 +125,7 @@ export function CaseDetails({ routeToShowCollectedInfo, onNewDecision, }: { - onNewDecision: (d: DecisionRequest) => void; + onNewDecision: (d: Partial<DecisionRequest>) => void; routeToShowCollectedInfo: RouteDefinition<{ cid: string; rowId: string }>; account: string; }) { @@ -186,7 +185,6 @@ export function CaseDetails({ // custom measures // FIXME add properties, limits, investigation state onNewDecision({ - ...DECISION_REQUEST_EMPTY, custom_measures: activeDecision?.limits.custom_measures, }); }} diff --git a/packages/aml-backoffice-ui/src/pages/NewMeasure.tsx b/packages/aml-backoffice-ui/src/pages/NewMeasure.tsx @@ -77,7 +77,7 @@ export function MeasureForm({ onCancel: () => void; }) { const { i18n } = useTranslationContext(); - const [request, _, update] = useCurrentDecisionRequest(); + const [request, updateRequest] = useCurrentDecisionRequest(); const names = { measures: Object.entries(summary.roots).map(([key, value]) => ({ @@ -165,8 +165,7 @@ export function MeasureForm({ {} as Record<string, string>, ), }; - update({ - ...request, + updateRequest({ custom_measures: currentMeasures, }); onCancel(); @@ -181,8 +180,9 @@ export function MeasureForm({ disabled={form.status.status === "fail"} onClick={() => { const newMeasure = form.status.result as MeasureDefinition; - const currentMeasures = { ...request.custom_measures }; - currentMeasures[name!] = { + + const CURRENT_MEASURES = { ...request.custom_measures }; + CURRENT_MEASURES[name!] = { check_name: newMeasure.check, prog_name: newMeasure.program, context: (newMeasure.context ?? []).reduce( @@ -193,9 +193,8 @@ export function MeasureForm({ {} as Record<string, string>, ), }; - update({ - ...request, - custom_measures: currentMeasures, + updateRequest({ + custom_measures: CURRENT_MEASURES, }); onCancel(); }} @@ -207,8 +206,7 @@ export function MeasureForm({ onClick={() => { const currentMeasures = { ...request.custom_measures }; delete currentMeasures[name!]; - update({ - ...request, + updateRequest({ custom_measures: currentMeasures, }); onCancel(); diff --git a/packages/aml-backoffice-ui/src/pages/Search.tsx b/packages/aml-backoffice-ui/src/pages/Search.tsx @@ -52,15 +52,12 @@ import { privatePages } from "../Routing.js"; import { Pagination, ToInvestigateIcon } from "./Cases.js"; import { HandleAccountNotReady } from "./HandleAccountNotReady.js"; import { Officer } from "./Officer.js"; -import { - DECISION_REQUEST_EMPTY, - DecisionRequest, -} from "../hooks/decision-request.js"; +import { DecisionRequest } from "../hooks/decision-request.js"; export function Search({ onNewDecision, }: { - onNewDecision: (d: DecisionRequest, account: string, payto: string) => void; + onNewDecision: (account: string, payto: string) => void; }) { const officer = useOfficer(); const { i18n } = useTranslationContext(); @@ -130,7 +127,7 @@ function ShowResult({ onNewDecision, }: { payto: PaytoUri; - onNewDecision: (d: DecisionRequest, account: string, payto: string) => void; + onNewDecision: (account: string, payto: string) => void; }): VNode { const paytoStr = stringifyPaytoUri(payto); const account = encodeCrock(hashNormalizedPaytoUri(paytoStr)); @@ -302,7 +299,6 @@ function ShowResult({ // })} onClick={async () => { onNewDecision( - DECISION_REQUEST_EMPTY, account, encodeCrockForURI(paytoStr), ); diff --git a/packages/aml-backoffice-ui/src/pages/decision/Events.tsx b/packages/aml-backoffice-ui/src/pages/decision/Events.tsx @@ -38,7 +38,7 @@ import { usePreferences } from "../../hooks/preferences.js"; export function Events({ account }: { account: string }): VNode { const activeDecision = useAccountActiveDecision(account); const { i18n } = useTranslationContext(); - const [request, _, updateRequest] = useCurrentDecisionRequest(); + const [request, updateRequest] = useCurrentDecisionRequest(); const [pref] = usePreferences(); const { config } = useExchangeApiContext(); @@ -87,7 +87,6 @@ export function Events({ account }: { account: string }): VNode { onComponentUnload(() => { updateRequest({ - ...request, custom_events: !form.status.result.custom ? [] : form.status.result.custom, diff --git a/packages/aml-backoffice-ui/src/pages/decision/Information.tsx b/packages/aml-backoffice-ui/src/pages/decision/Information.tsx @@ -67,7 +67,7 @@ function FillCustomerData({ theForm: FormMetadata; changeForm: () => void; }): VNode { - const [request, _, updateRequest] = useCurrentDecisionRequest(); + const [request, updateRequest] = useCurrentDecisionRequest(); const [expiration, setExpiration] = useState(request.attributes?.expiration); const expirationHandler: UIFieldHandler<any> = { onChange: setExpiration, @@ -90,7 +90,6 @@ function FillCustomerData({ onComponentUnload(() => { updateRequest({ - ...request, attributes: { data, expiration, @@ -156,7 +155,7 @@ function SelectForm({ }): VNode { const { i18n } = useTranslationContext(); const design = formDesign(i18n, forms); - const [request, _, updateRequest] = useCurrentDecisionRequest(); + const [request, updateRequest] = useCurrentDecisionRequest(); const form = useForm<SelectFormType>(design, { formId: undefined, @@ -170,7 +169,6 @@ function SelectForm({ onComponentUnload(() => { updateRequest({ - ...request, attributes: undefined, }); }); @@ -199,7 +197,6 @@ const formDesign = ( { id: "formId", type: "selectOne", - required: true, label: i18n.str`Form:`, choices: mi.map((f) => ({ label: f.label, diff --git a/packages/aml-backoffice-ui/src/pages/decision/Justification.tsx b/packages/aml-backoffice-ui/src/pages/decision/Justification.tsx @@ -43,7 +43,7 @@ export function Justification({ function JustificationForm({info, isNewAccount}:{info: AmlDecision | undefined, isNewAccount: boolean}):VNode { const { i18n } = useTranslationContext(); - const [request, _, updateRequest] = useCurrentDecisionRequest(); + const [request, updateRequest] = useCurrentDecisionRequest(); const design = formDesign(i18n, isNewAccount); const form = useForm<FormType>(design, { @@ -54,7 +54,6 @@ function JustificationForm({info, isNewAccount}:{info: AmlDecision | undefined, onComponentUnload(() => { updateRequest({ - ...request, keep_investigating: !!form.status.result.investigate, justification: form.status.result.justification ?? "", accountName: form.status.result.accountName ?? "", diff --git a/packages/aml-backoffice-ui/src/pages/decision/Measures.tsx b/packages/aml-backoffice-ui/src/pages/decision/Measures.tsx @@ -68,7 +68,7 @@ export function Measures({}: {}): VNode { function ActiveMeasureForm(): VNode { const { i18n } = useTranslationContext(); - const [request, _, updateRequest] = useCurrentDecisionRequest(); + const [request, updateRequest] = useCurrentDecisionRequest(); const measures = useServerMeasures(); const measureBody = @@ -92,7 +92,6 @@ function ActiveMeasureForm(): VNode { const form = useForm<FormType>(design, initValue); onComponentUnload(() => { updateRequest({ - ...request, new_measures: (form.status.result.measures ?? []) as string[], }); }); diff --git a/packages/aml-backoffice-ui/src/pages/decision/Properties.tsx b/packages/aml-backoffice-ui/src/pages/decision/Properties.tsx @@ -94,7 +94,7 @@ export function Properties({ account }: { account: string }): VNode { function ReloadForm({ merged }: { merged: any }): VNode { const { i18n } = useTranslationContext(); - const [request, _, updateRequest] = useCurrentDecisionRequest(); + const [request, updateRequest] = useCurrentDecisionRequest(); const design = propertiesForm(i18n, propertiesByDialect(i18n)); const form = useForm<PropertiesForm>(design, { defined: merged, @@ -107,7 +107,6 @@ function ReloadForm({ merged }: { merged: any }): VNode { onComponentUnload(() => { updateRequest({ - ...request, properties: (form.status.result.defined ?? {}) as Record<string, boolean>, custom_properties: (form.status.result.custom ?? []).reduce( (prev, cur) => { diff --git a/packages/aml-backoffice-ui/src/pages/decision/Rules.tsx b/packages/aml-backoffice-ui/src/pages/decision/Rules.tsx @@ -268,7 +268,7 @@ function UpdateRulesForm({ rootMeasures: AvailableMeasureSummary["roots"] | undefined; }): VNode { const { i18n } = useTranslationContext(); - const [request, updateRequestField, updateRequest] = + const [request, updateRequest] = useCurrentDecisionRequest(); const [showAddRuleForm, setShowAddRuleForm] = useState(false); const measureList = !rootMeasures ? [] : Object.keys(rootMeasures); @@ -277,6 +277,7 @@ function UpdateRulesForm({ ...measureList, ...customMeasures, ]); + const [rules, setRules] = useState<KycRule[]>([]); const expirationForm = useForm<ExpirationFormType>(expirationFormDesign, { expiration: request.deadline ?? @@ -293,7 +294,6 @@ function UpdateRulesForm({ : expirationForm.status.result.expiration; const doesntExpire = !deadline || AbsoluteTime.isNever(deadline); updateRequest({ - ...request, rules: currentRules, deadline, onExpire_measure: @@ -304,7 +304,7 @@ function UpdateRulesForm({ }); function addNewRule(nr: RuleFormType) { - const result = !request.rules ? [] : [...request.rules]; + const result = !rules ? [] : [...rules]; const clean = (nr.measures ?? []).filter((m) => !!m); const measures = !clean.length ? DEFAULT_MEASURE_IF_NONE : clean; result.push({ @@ -318,7 +318,7 @@ function UpdateRulesForm({ is_and_combinator: nr.all, measures, }); - updateRequestField("rules", result); + setRules(result); } const ruleInconsistency = @@ -411,7 +411,7 @@ function UpdateRulesForm({ onRemove={(r, idx) => { const nr = [...currentRules]; nr.splice(idx, 1); - updateRequestField("rules", nr); + setRules(nr); }} onNew={() => { setShowAddRuleForm(true); @@ -420,7 +420,7 @@ function UpdateRulesForm({ <button onClick={() => { - updateRequestField("rules", limits.rules); + setRules(limits.rules); }} 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 disabled:bg-gray-600" > @@ -428,7 +428,7 @@ function UpdateRulesForm({ </button> <button onClick={() => { - updateRequestField("rules", FREEZE_PLAN(config.currency, isWallet)); + setRules( FREEZE_PLAN(config.currency, isWallet)); }} 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 disabled:bg-gray-600" > @@ -436,7 +436,7 @@ function UpdateRulesForm({ </button> <button onClick={() => { - updateRequestField("rules", BASIC_PLAN(config.currency, isWallet)); + setRules( BASIC_PLAN(config.currency, isWallet)); }} 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 disabled:bg-gray-600" > @@ -444,7 +444,7 @@ function UpdateRulesForm({ </button> <button onClick={() => { - updateRequestField("rules", PREMIUM_PLAN(config.currency, isWallet)); + setRules( PREMIUM_PLAN(config.currency, isWallet)); }} 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 disabled:bg-gray-600" > @@ -452,7 +452,7 @@ function UpdateRulesForm({ </button> <button onClick={() => { - updateRequestField("rules", E_COMMERCE(config.currency, isWallet)); + setRules( E_COMMERCE(config.currency, isWallet)); }} 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 disabled:bg-gray-600" > @@ -460,7 +460,7 @@ function UpdateRulesForm({ </button> <button onClick={() => { - updateRequestField("rules", POINT_OF_SALE(config.currency, isWallet)); + setRules( POINT_OF_SALE(config.currency, isWallet)); }} 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 disabled:bg-gray-600" > diff --git a/packages/aml-backoffice-ui/src/pages/decision/Summary.tsx b/packages/aml-backoffice-ui/src/pages/decision/Summary.tsx @@ -21,8 +21,7 @@ import { import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { - DECISION_REQUEST_EMPTY, - useCurrentDecisionRequest, + useCurrentDecisionRequest } from "../../hooks/decision-request.js"; import { useOfficer } from "../../hooks/officer.js"; import { @@ -59,7 +58,7 @@ export function Summary({ onMove: (n: WizardSteps | undefined) => void; }): VNode { const { i18n } = useTranslationContext(); - const [decision, _, updateDecision] = useCurrentDecisionRequest(); + const [decision, updateRequest, cleanUpDecision] = useCurrentDecisionRequest(); const measures = useServerMeasures(); const [notification, withErrorHandler] = useLocalNotificationHandler(); const officer = useOfficer(); @@ -108,7 +107,7 @@ export function Summary({ INVALID_ATTRIBUTES; function clearUp() { - updateDecision(DECISION_REQUEST_EMPTY); + cleanUpDecision(); onMove(undefined); }