aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-09-11 12:18:02 -0300
committerSebastian <sebasjm@gmail.com>2024-09-11 12:18:16 -0300
commite2ede9ff4f5df733fc89e10d5b61f3867b0479ae (patch)
treeb34c906799bab26b3a56d414ef096953b3e50c34
parentf401ab076bb037e46c4b12e371dfe13a777bf582 (diff)
fix #9156
-rw-r--r--packages/aml-backoffice-ui/src/Routing.tsx17
-rw-r--r--packages/aml-backoffice-ui/src/pages/CaseDetails.tsx438
-rw-r--r--packages/aml-backoffice-ui/src/pages/Cases.tsx2
-rw-r--r--packages/aml-backoffice-ui/src/pages/Search.tsx147
-rw-r--r--packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx2
-rw-r--r--packages/web-util/src/utils/route.ts8
6 files changed, 382 insertions, 232 deletions
diff --git a/packages/aml-backoffice-ui/src/Routing.tsx b/packages/aml-backoffice-ui/src/Routing.tsx
index c7f9a40fe..d69b47184 100644
--- a/packages/aml-backoffice-ui/src/Routing.tsx
+++ b/packages/aml-backoffice-ui/src/Routing.tsx
@@ -15,6 +15,7 @@
*/
import {
+ decodeCrockFromURI,
urlPattern,
useCurrentLocation,
useNavigationContext,
@@ -22,7 +23,7 @@ import {
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
-import { assertUnreachable } from "@gnu-taler/taler-util";
+import { assertUnreachable, parsePaytoUri, PaytoString } from "@gnu-taler/taler-util";
import { useEffect } from "preact/hooks";
import { ExchangeAmlFrame } from "./ExchangeAmlFrame.js";
import { useOfficer } from "./hooks/officer.js";
@@ -107,6 +108,10 @@ export const privatePages = {
/\/case\/(?<cid>[a-zA-Z0-9]+)\/new/,
({ cid }) => `#/case/${cid}/new`,
),
+ caseDetailsNewAccount: urlPattern<{ cid: string, payto: string }>(
+ /\/case\/(?<cid>[a-zA-Z0-9]+)\/(?<payto>[a-zA-Z0-9]+)/,
+ ({ cid, payto }) => `#/case/${cid}/${payto}`,
+ ),
caseDetails: urlPattern<{ cid: string }>(
/\/case\/(?<cid>[a-zA-Z0-9]+)/,
({ cid }) => `#/case/${cid}`,
@@ -129,12 +134,18 @@ function PrivateRouting(): VNode {
case "profile": {
return <Officer />;
}
+ case "caseUpdate": {
+ return (
+ <CaseUpdate account={location.values.cid} type={location.values.type} />
+ );
+ }
case "caseDetails": {
return <CaseDetails account={location.values.cid} />;
}
- case "caseUpdate": {
+ case "caseDetailsNewAccount": {
+ console.log(location.values)
return (
- <CaseUpdate account={location.values.cid} type={location.values.type} />
+ <CaseDetails account={location.values.cid} paytoString={decodeCrockFromURI(location.values.payto)} />
);
}
case "caseNew": {
diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
index 54f979846..88366c1d0 100644
--- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
@@ -22,6 +22,7 @@ import {
HttpStatusCode,
OperationFail,
OperationOk,
+ PaytoString,
TalerError,
TalerErrorDetail,
TalerExchangeApi,
@@ -171,7 +172,7 @@ export function getEventsFromAmlHistory(
return ke.sort(selectSooner);
}
-export function CaseDetails({ account }: { account: string }) {
+export function CaseDetails({ account, paytoString }: { account: string, paytoString?: PaytoString }) {
const [selected, setSelected] = useState<AbsoluteTime>(AbsoluteTime.now());
const [showForm, setShowForm] = useState<{
justification: Justification;
@@ -273,6 +274,7 @@ export function CaseDetails({ account }: { account: string }) {
onClick={async () => {
if (!session) return;
lib.exchange.makeAmlDesicion(session, {
+ payto_uri: paytoString,
decision_time: AbsoluteTime.toProtocolTimestamp(
AbsoluteTime.now(),
),
@@ -298,6 +300,7 @@ export function CaseDetails({ account }: { account: string }) {
onClick={async () => {
if (!session) return;
lib.exchange.makeAmlDesicion(session, {
+ payto_uri: paytoString,
decision_time: AbsoluteTime.toProtocolTimestamp(
AbsoluteTime.now(),
),
@@ -323,6 +326,7 @@ export function CaseDetails({ account }: { account: string }) {
onClick={async () => {
if (!session) return;
lib.exchange.makeAmlDesicion(session, {
+ payto_uri: paytoString,
decision_time: AbsoluteTime.toProtocolTimestamp(
AbsoluteTime.now(),
),
@@ -348,6 +352,7 @@ export function CaseDetails({ account }: { account: string }) {
onClick={async () => {
if (!session) return;
lib.exchange.makeAmlDesicion(session, {
+ payto_uri: paytoString,
decision_time: AbsoluteTime.toProtocolTimestamp(
AbsoluteTime.now(),
),
@@ -385,24 +390,28 @@ export function CaseDetails({ account }: { account: string }) {
<h1 class="my-4 text-base font-semibold leading-6 text-black">
<i18n.Translate>KYC collection events</i18n.Translate>
</h1>
- <ShowTimeline
- history={events}
- onSelect={(e) => {
- switch (e.type) {
- case "aml-form": {
- // const { justification, metadata } = e;
- // setShowForm({ justification, metadata });
- break;
+ {events.length === 0 ?
+ <Attention title={i18n.str`No events found`} type="warning" />
+ :
+ <ShowTimeline
+ history={events}
+ onSelect={(e) => {
+ switch (e.type) {
+ case "aml-form": {
+ // const { justification, metadata } = e;
+ // setShowForm({ justification, metadata });
+ break;
+ }
+ case "kyc-collection":
+ case "kyc-expiration": {
+ setSelected(e.when);
+ break;
+ }
+ case "aml-form-error":
}
- case "kyc-collection":
- case "kyc-expiration": {
- setSelected(e.when);
- break;
- }
- case "aml-form-error":
- }
- }}
- />
+ }}
+ />
+ }
{/* {selected && <ShowEventDetails event={selected} />} */}
{selected && <ShowConsolidated history={events} until={selected} />}
{restDecisions.length > 0 ? (
@@ -415,7 +424,10 @@ export function CaseDetails({ account }: { account: string }) {
})}
</Fragment>
) : (
- <div />
+ !activeDecision ?
+ <div class="ty-4">
+ <Attention title={i18n.str`No aml history found`} type="warning" />
+ </div> : undefined
)}
</div>
);
@@ -569,11 +581,11 @@ function ShowDecisionInfo({
{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
@@ -808,13 +820,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);
@@ -852,9 +864,9 @@ function parseJustification(
listOfAllKnownForms: FormMetadata[],
):
| OperationOk<{
- justification: Justification;
- metadata: FormMetadata;
- }>
+ justification: Justification;
+ metadata: FormMetadata;
+ }>
| OperationFail<ParseJustificationFail> {
try {
const justification = JSON.parse(s);
@@ -902,212 +914,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,
+ {
+ 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,
},
- 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: "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: "AGGREGATE",
- 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: "MERGE",
- 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: "BALANCE",
- 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: "CLOSE",
- 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,
- },
-];
+ ];
const THRESHOLD_100_HOUR: (currency: string) => TalerExchangeApi.KycRule[] = (
currency,
) => [
- {
- operation_type: "WITHDRAW",
- threshold: `${currency}:100`,
- timeframe: {
- d_us: 1 * 60 * 60 * 1000 * 1000,
+ {
+ 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,
},
- 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: "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: "AGGREGATE",
- 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: "MERGE",
- 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: "BALANCE",
- 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: "CLOSE",
- 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,
- },
-];
+ ];
const FREEZE_RULES: (currency: string) => TalerExchangeApi.KycRule[] = (
currency,
) => [
- {
- operation_type: "WITHDRAW",
- threshold: `${currency}:0`,
- timeframe: {
- d_us: "forever",
+ {
+ operation_type: "WITHDRAW",
+ 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: "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: "AGGREGATE",
- 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: "MERGE",
- 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: "BALANCE",
- 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: "CLOSE",
- 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,
- },
-];
+ ];
diff --git a/packages/aml-backoffice-ui/src/pages/Cases.tsx b/packages/aml-backoffice-ui/src/pages/Cases.tsx
index c274cbcb0..278d4bac2 100644
--- a/packages/aml-backoffice-ui/src/pages/Cases.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Cases.tsx
@@ -387,7 +387,7 @@ export const SearchIcon = () => (
</svg>
);
-function Pagination({
+export function Pagination({
onFirstPage,
onNext,
}: {
diff --git a/packages/aml-backoffice-ui/src/pages/Search.tsx b/packages/aml-backoffice-ui/src/pages/Search.tsx
index f9612c025..2bca86310 100644
--- a/packages/aml-backoffice-ui/src/pages/Search.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Search.tsx
@@ -14,6 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
+ AbsoluteTime,
assertUnreachable,
buildPayto,
encodeCrock,
@@ -28,10 +29,12 @@ import {
import {
Attention,
convertUiField,
+ encodeCrockForURI,
getConverterById,
InternationalizationAPI,
Loading,
RenderAllFieldsByUiConfig,
+ Time,
UIFormElementConfig,
UIHandlerId,
useTranslationContext,
@@ -51,6 +54,9 @@ import { undefinedIfEmpty } from "./CreateAccount.js";
import { HandleAccountNotReady } from "./HandleAccountNotReady.js";
import { useAccountInformation } from "../hooks/account.js";
import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js";
+import { useAccountDecisions } from "../hooks/decisions.js";
+import { privatePages } from "../Routing.js";
+import { Pagination, ToInvestigateIcon } from "./Cases.js";
export function Search() {
const officer = useOfficer();
@@ -108,18 +114,19 @@ export function Search() {
}
function ShowResult({ payto }: { payto: PaytoUri }): VNode {
- const account = encodeCrock(hashPaytoUri(payto));
+ const paytoStr = stringifyPaytoUri(payto)
+ const account = encodeCrock(hashPaytoUri(paytoStr));
const { i18n } = useTranslationContext();
- const details = useAccountInformation(account);
- if (!details) {
+ const history = useAccountDecisions(account);
+ if (!history) {
return <Loading />
}
- if (details instanceof TalerError) {
- return <ErrorLoadingWithDebug error={details} />;
+ if (history instanceof TalerError) {
+ return <ErrorLoadingWithDebug error={history} />;
}
- if (details.type === "fail") {
- switch (details.case) {
+ if (history.type === "fail") {
+ switch (history.case) {
case HttpStatusCode.Forbidden: {
return (
<Fragment>
@@ -155,13 +162,123 @@ function ShowResult({ payto }: { payto: PaytoUri }): VNode {
);
}
default: {
- assertUnreachable(details)
+ assertUnreachable(history)
}
}
}
-
- return <div >
- found {JSON.stringify(details.body.details, undefined, 2)}
+
+ if (history.body.length) {
+ return <div class="mt-8">
+ <div class="mb-2">
+ <a
+ href={privatePages.caseDetails.url({
+ cid: account,
+ })}
+ class="text-indigo-600 hover:text-indigo-900"
+ >
+ <i18n.Translate>
+ Check account details
+ </i18n.Translate>
+ </a>
+ </div>
+ <div class="sm:flex sm:items-center">
+ <div class="sm:flex-auto">
+ <div>
+ <h1 class="text-base font-semibold leading-6 text-gray-900">
+ <i18n.Translate>Account most recent decisions</i18n.Translate>
+ </h1>
+ </div>
+ </div>
+ </div>
+
+ <div class="flow-root">
+ <div class="overflow-x-auto">
+ {!history.body.length ? (
+ <div>empty result </div>
+ ) : (
+ <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
+ <table class="min-w-full divide-y divide-gray-300">
+ <thead>
+ <tr>
+ <th
+ scope="col"
+ class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-80"
+ >
+ <i18n.Translate>When</i18n.Translate>
+ </th>
+ <th
+ scope="col"
+ class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-80"
+ >
+ <i18n.Translate>Justification</i18n.Translate>
+ </th>
+ <th
+ scope="col"
+ class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-40"
+ >
+ <i18n.Translate>Status</i18n.Translate>
+ </th>
+ </tr>
+ </thead>
+ <tbody class="divide-y divide-gray-200 bg-white">
+ {history.body.map((r, idx) => {
+ return (
+ <tr key={r.h_payto} class="hover:bg-gray-100 ">
+ <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500 ">
+ <Time format="dd/MM/yyyy HH:mm" timestamp={AbsoluteTime.fromProtocolTimestamp(r.decision_time)} />
+ </td>
+ <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500 ">
+ {r.justification}
+ </td>
+ <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-900">
+
+
+ {idx === 0 ? <span class="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10">
+ <i18n.Translate>LATEST</i18n.Translate>
+ </span> : undefined}
+ {r.is_active ? <span class="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10">
+ <i18n.Translate>ACTIVE</i18n.Translate>
+ </span> : undefined}
+ {r.decision_time ? (
+ <span title="require investigation">
+ <ToInvestigateIcon />
+ </span>
+ ) : undefined}
+ </td>
+ </tr>
+ );
+ })}
+ </tbody>
+ </table>
+ <Pagination
+ onFirstPage={history.isFirstPage ? undefined : history.loadFirst}
+ onNext={history.isLastPage ? undefined : history.loadNext} />
+ </div>
+ )}
+ </div>
+ </div>
+ </div>
+ }
+ // const detailsUrl = new URL(, window.location.href)
+ // detailsUrl.searchParams.set("payto", encodeCrockForURI(paytoStr))
+ return <div class="mt-4">
+ <Attention title={i18n.str`Account not found`} type="warning">
+ <i18n.Translate>
+ There is no history known for this account yet.
+ </i18n.Translate>
+ &nbsp;
+ <a
+ href={privatePages.caseDetailsNewAccount.url({
+ cid: account,
+ payto: encodeCrockForURI(paytoStr),
+ })}
+ class="text-indigo-600 hover:text-indigo-900"
+ >
+ <i18n.Translate>
+ You can make a decision for this account anyway.
+ </i18n.Translate>
+ </a>
+ </Attention>
</div>
}
@@ -210,7 +327,7 @@ function XTalerBankForm({
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>
);
@@ -224,7 +341,11 @@ function IbanForm({
const fields = ibanFields(i18n);
const form = useFormState(
getShapeFromFields(fields),
- {},
+ {
+ account: "DE6985463381715",
+ name: "alice",
+ bic: "SANDBOX"
+ },
createIbanPaytoValidator(i18n),
);
const paytoUri =
diff --git a/packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx b/packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx
index 2866755c2..fcec8609a 100644
--- a/packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx
+++ b/packages/aml-backoffice-ui/src/pages/ShowConsolidated.tsx
@@ -98,7 +98,7 @@ export function ShowConsolidated({
return (
<Fragment>
- <div class="space-y-10 divide-y -mt-5 divide-gray-900/10">
+ <div class="space-y-10 divide-y divide-gray-900/10">
{formConfig.design.map((section, i) => {
if (!section) return <Fragment />;
return (
diff --git a/packages/web-util/src/utils/route.ts b/packages/web-util/src/utils/route.ts
index cbac8851a..fbbbfebd1 100644
--- a/packages/web-util/src/utils/route.ts
+++ b/packages/web-util/src/utils/route.ts
@@ -25,7 +25,13 @@ export type AppLocation = string & {
};
export type EmptyObject = Record<string, never>;
-
+/**
+ * FIXME: receive parameters
+ * maybe return URL for reverse function instead of string
+ * @param pattern
+ * @param reverse
+ * @returns
+ */
export function urlPattern<
T extends Record<string, string | undefined> = EmptyObject,
>(pattern: RegExp, reverse: (p: T) => string): RouteDefinition<T> {