commit a8542fb65a0676ae55d74b49a9dda573accec82b
parent 9a7dee809ec56bdc2aa4b33c425e3f5970692bc8
Author: Sebastian <sebasjm@gmail.com>
Date: Wed, 9 Oct 2024 11:14:28 -0300
simple form with name and type of field
Diffstat:
4 files changed, 130 insertions(+), 70 deletions(-)
diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
@@ -184,9 +184,11 @@ export function getEventsFromAmlHistory(
return ke.sort(selectSooner);
}
+type NewDecision = { request: Omit<Omit<AmlDecisionRequest, "justification">, "officer_sig">, askInformation: boolean }
+
export function CaseDetails({ account, paytoString }: { account: string, paytoString?: PaytoString }) {
const [selected, setSelected] = useState<AbsoluteTime>(AbsoluteTime.now());
- const [request, setDesicionRequest] = useState<Omit<AmlDecisionRequest, "officer_sig"> | undefined>(undefined)
+ const [request, setDesicionRequest] = useState<NewDecision | undefined>(undefined)
const { config } = useExchangeApiContext();
const { i18n } = useTranslationContext();
@@ -238,7 +240,7 @@ export function CaseDetails({ account, paytoString }: { account: string, paytoSt
if (request) {
- return <SubmitNewDecision request={request} onComplete={() => {
+ return <SubmitNewDecision decision={request} onComplete={() => {
setDesicionRequest(undefined)
}} />
}
@@ -267,22 +269,24 @@ export function CaseDetails({ account, paytoString }: { account: string, paytoSt
<button
onClick={async () => {
setDesicionRequest({
- payto_uri: paytoString,
- decision_time: AbsoluteTime.toProtocolTimestamp(
- AbsoluteTime.now(),
- ),
- h_payto: account,
- justification: "",
- keep_investigating: false,
- properties: {},
- new_rules: {
- custom_measures: {},
- expiration_time: AbsoluteTime.toProtocolTimestamp(
- AbsoluteTime.never(),
+ request: {
+ payto_uri: paytoString,
+ decision_time: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.now(),
),
- rules: FREEZE_RULES(config.currency),
- successor_measure: "verboten",
+ h_payto: account,
+ keep_investigating: false,
+ properties: {},
+ new_rules: {
+ custom_measures: {},
+ expiration_time: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.never(),
+ ),
+ rules: FREEZE_RULES(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"
@@ -292,22 +296,24 @@ export function CaseDetails({ account, paytoString }: { account: string, paytoSt
<button
onClick={async () => {
setDesicionRequest({
- payto_uri: paytoString,
- decision_time: AbsoluteTime.toProtocolTimestamp(
- AbsoluteTime.now(),
- ),
- h_payto: account,
- justification: "",
- keep_investigating: false,
- properties: {},
- new_rules: {
- custom_measures: {},
- expiration_time: AbsoluteTime.toProtocolTimestamp(
- AbsoluteTime.never(),
+ request: {
+ payto_uri: paytoString,
+ decision_time: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.now(),
),
- rules: THRESHOLD_100_HOUR(config.currency),
- successor_measure: "verboten",
+ h_payto: account,
+ keep_investigating: false,
+ properties: {},
+ new_rules: {
+ custom_measures: {},
+ expiration_time: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.never(),
+ ),
+ rules: THRESHOLD_100_HOUR(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"
@@ -317,22 +323,24 @@ export function CaseDetails({ account, paytoString }: { account: string, paytoSt
<button
onClick={async () => {
setDesicionRequest({
- payto_uri: paytoString,
- decision_time: AbsoluteTime.toProtocolTimestamp(
- AbsoluteTime.now(),
- ),
- h_payto: account,
- justification: "",
- keep_investigating: false,
- properties: {},
- new_rules: {
- custom_measures: {},
- expiration_time: AbsoluteTime.toProtocolTimestamp(
- AbsoluteTime.never(),
+ request: {
+ payto_uri: paytoString,
+ decision_time: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.now(),
),
- rules: THRESHOLD_2000_WEEK(config.currency),
- successor_measure: "verboten",
+ h_payto: account,
+ keep_investigating: false,
+ properties: {},
+ new_rules: {
+ custom_measures: {},
+ expiration_time: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.never(),
+ ),
+ rules: THRESHOLD_2000_WEEK(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"
@@ -342,23 +350,27 @@ export function CaseDetails({ account, paytoString }: { account: string, paytoSt
<button
onClick={async () => {
setDesicionRequest({
- payto_uri: paytoString,
- decision_time: AbsoluteTime.toProtocolTimestamp(
- AbsoluteTime.now(),
- ),
- h_payto: account,
- justification: "",
- keep_investigating: false,
- properties: {},
- new_measures: "m2",
- new_rules: {
- custom_measures: {},
- expiration_time: AbsoluteTime.toProtocolTimestamp(
- AbsoluteTime.never(),
+ request: {
+ payto_uri: paytoString,
+ decision_time: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.now(),
),
- rules: FREEZE_RULES(config.currency),
- successor_measure: "verboten",
+ h_payto: account,
+ keep_investigating: false,
+ properties: {
+ "pepe": "text",
+ },
+ new_measures: "ask",
+ new_rules: {
+ custom_measures: {},
+ expiration_time: AbsoluteTime.toProtocolTimestamp(
+ AbsoluteTime.never(),
+ ),
+ rules: FREEZE_RULES(config.currency),
+ successor_measure: "verboten",
+ },
},
+ 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"
@@ -442,7 +454,7 @@ export function CaseDetails({ account, paytoString }: { account: string, paytoSt
}
-function SubmitNewDecision({ request, onComplete }: { onComplete: () => void; request: Omit<AmlDecisionRequest, "officer_sig"> }): VNode {
+function SubmitNewDecision({ decision, onComplete }: { onComplete: () => void; decision: NewDecision }): VNode {
const { i18n } = useTranslationContext();
const { lib } = useExchangeApiContext();
const [notification, withErrorHandler] = useLocalNotificationHandler();
@@ -453,9 +465,46 @@ function SubmitNewDecision({ request, onComplete }: { onComplete: () => void; re
required: true,
label: i18n.str`Justification`,
}]
+
+ if (decision.askInformation) {
+ formDesign.push({
+ type: "caption",
+ label: i18n.str`Form definition`,
+ help: i18n.str`The user will need to complete this form.`,
+ })
+ formDesign.push({
+ id: "fields" as UIHandlerId,
+ type: "array",
+ required: true,
+ label: i18n.str`Fields`,
+ fields: [{
+ id: "name" as UIHandlerId,
+ type: "text",
+ required: true,
+ label: i18n.str`Name`,
+ help:i18n.str`Name of the field in the form`,
+ },{
+ id: "type" as UIHandlerId,
+ type: "choiceStacked",
+ required: true,
+ label: i18n.str`Type`,
+ help:i18n.str`Type of information being asked`,
+ choices: [{
+ value: "number",
+ label: i18n.str`Number`,
+ description:i18n.str`Numeric information`,
+ },{
+ value: "text",
+ label: i18n.str`Text`,
+ description:i18n.str`Free form text input`,
+ }]
+ }],
+ labelFieldId: "name" as UIHandlerId,
+ })
+ }
const officer = useOfficer();
const session = officer.state === "ready" ? officer.account : undefined;
- const decisionForm = useFormState<{ justification: string }>(
+ const decisionForm = useFormState<{ justification: string, fields: object }>(
getShapeFromFields(formDesign),
{ justification: "" },
(d) => {
@@ -473,7 +522,14 @@ function SubmitNewDecision({ request, onComplete }: { onComplete: () => void; re
? undefined
: withErrorHandler(
() => {
- request.justification = decisionForm.status.result.justification ?? "empty"
+ const request: Omit<AmlDecisionRequest, "officer_sig"> = {
+ ...decision.request,
+ properties: {
+ ...decision.request.properties,
+ fields: decisionForm.status.result.fields,
+ },
+ justification: decisionForm.status.result.justification ?? "empty",
+ }
return lib.exchange.makeAmlDesicion(session, request);
},
onComplete,
@@ -542,16 +598,20 @@ function SubmitNewDecision({ request, onComplete }: { onComplete: () => void; re
</form>
+ <h1 class="my-2 text-xl font-bold tracking-tight text-gray-900 ">
+ <i18n.Translate>New rules to submit</i18n.Translate>
+ </h1>
+
<ShowDecisionLimitInfo
since={AbsoluteTime.fromProtocolTimestamp(
- request.decision_time,
+ decision.request.decision_time,
)}
until={AbsoluteTime.fromProtocolTimestamp(
- request.new_rules.expiration_time,
+ decision.request.new_rules.expiration_time,
)}
- ruleSet={request.new_rules}
-
- startOpen />
+ ruleSet={decision.request.new_rules}
+ startOpen
+ />
</div>
diff --git a/packages/aml-backoffice-ui/src/pages/Search.tsx b/packages/aml-backoffice-ui/src/pages/Search.tsx
@@ -369,7 +369,7 @@ function IbanForm({
class="disabled:bg-gray-100 disabled:text-gray-500 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"
onClick={() => onSearch(paytoUri)}
>
- Search
+ <i18n.Translate>Search</i18n.Translate>
</button>
</form>
);
diff --git a/packages/web-util/src/forms/Caption.tsx b/packages/web-util/src/forms/Caption.tsx
@@ -13,7 +13,7 @@ interface Props {
export function Caption({ before, after, label, tooltip, help }: Props): VNode {
return (
- <div class="sm:col-span-6 flex">
+ <div class="sm:col-span-6">
{before !== undefined && <RenderAddon addon={before} />}
<LabelWithTooltipMaybeRequired label={label} tooltip={tooltip} />
{after !== undefined && <RenderAddon addon={after} />}
diff --git a/packages/web-util/src/forms/InputArray.tsx b/packages/web-util/src/forms/InputArray.tsx
@@ -128,7 +128,7 @@ export function InputArray<T extends object, K extends keyof T>(
{!state.disabled && (
<div class="pt-2">
<Option
- label={"Add..." as TranslatedString}
+ label={"Add new..." as TranslatedString}
isSelected={selectedIndex === list.length}
isLast
isFirst