diff options
author | Sebastian <sebasjm@gmail.com> | 2023-12-01 14:50:13 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2023-12-01 14:50:13 -0300 |
commit | 685f747b6a24ae0d25f2bb458074c955e5acdbc4 (patch) | |
tree | 317b3738e532e1d993aca617181c69aa137c21ba /packages/demobank-ui/src | |
parent | 6b1bee3fe0e933b3c7421fc6d3d0425a01c41e30 (diff) | |
download | wallet-core-685f747b6a24ae0d25f2bb458074c955e5acdbc4.tar.xz |
sync demobank with new libeufin API, still missing when the withdrawal operation is not the same user that created the transfer
Diffstat (limited to 'packages/demobank-ui/src')
10 files changed, 116 insertions, 68 deletions
diff --git a/packages/demobank-ui/src/hooks/access.ts b/packages/demobank-ui/src/hooks/access.ts index da9812ffa..1e09c444a 100644 --- a/packages/demobank-ui/src/hooks/access.ts +++ b/packages/demobank-ui/src/hooks/access.ts @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { AccessToken, TalerCoreBankResultByMethod, TalerHttpError } from "@gnu-taler/taler-util"; +import { AccessToken, TalerBankIntegrationResultByMethod, TalerCoreBankResultByMethod, TalerHttpError } from "@gnu-taler/taler-util"; import { useState } from "preact/hooks"; import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils.js"; import { useBackendState } from "./backend.js"; @@ -62,10 +62,10 @@ export function useWithdrawalDetails(wid: string) { const { api } = useBankCoreApiContext(); async function fetcher([wid]: [string]) { - return await api.getWithdrawalById(wid) + return await api.getIntegrationAPI().getWithdrawalOperationById(wid) } - const { data, error } = useSWR<TalerCoreBankResultByMethod<"getWithdrawalById">, TalerHttpError>( + const { data, error } = useSWR<TalerBankIntegrationResultByMethod<"getWithdrawalOperationById">, TalerHttpError>( [wid, "getWithdrawalById"], fetcher, { refreshInterval: 1000, refreshWhenHidden: false, @@ -110,12 +110,12 @@ export function useTransactionDetails(account: string, tid: number) { return undefined; } -export function usePublicAccounts(initial?: number) { +export function usePublicAccounts(filterAccount: string |undefined ,initial?: number) { const [offset, setOffset] = useState<number | undefined>(initial); const { api } = useBankCoreApiContext(); - async function fetcher([txid]: [number | undefined]) { - return await api.getPublicAccounts({ + async function fetcher([account, txid]: [string | undefined , number | undefined]) { + return await api.getPublicAccounts({account},{ limit: MAX_RESULT_SIZE, offset: txid ? String(txid) : undefined, order: "asc" @@ -123,7 +123,7 @@ export function usePublicAccounts(initial?: number) { } const { data, error } = useSWR<TalerCoreBankResultByMethod<"getPublicAccounts">, TalerHttpError>( - [offset, "getPublicAccounts"], fetcher, { + [filterAccount, offset, "getPublicAccounts"], fetcher, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, diff --git a/packages/demobank-ui/src/pages/OperationState/index.ts b/packages/demobank-ui/src/pages/OperationState/index.ts index 120fd7b45..0776bbed5 100644 --- a/packages/demobank-ui/src/pages/OperationState/index.ts +++ b/packages/demobank-ui/src/pages/OperationState/index.ts @@ -83,8 +83,8 @@ export namespace State { } export interface NeedConfirmation { status: "need-confirmation", - onAbort: () => Promise<TalerCoreBankErrorsByMethod<"abortWithdrawalById"> | undefined>; - onConfirm: () => Promise<TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined>; + onAbort: undefined | (() => Promise<TalerCoreBankErrorsByMethod<"abortWithdrawalById"> | undefined>); + onConfirm: undefined | (() => Promise<TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined>); error: undefined; busy: boolean, } diff --git a/packages/demobank-ui/src/pages/OperationState/state.ts b/packages/demobank-ui/src/pages/OperationState/state.ts index 30f7419f0..da924104a 100644 --- a/packages/demobank-ui/src/pages/OperationState/state.ts +++ b/packages/demobank-ui/src/pages/OperationState/state.ts @@ -74,7 +74,8 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive const wid = withdrawalOperationId async function doAbort() { - const resp = await api.abortWithdrawalById(wid); + if (!creds) return; + const resp = await api.abortWithdrawalById(creds, wid); if (resp.type === "ok") { updateSettings("currentWithdrawalOperationId", undefined) onClose(); @@ -84,8 +85,9 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive } async function doConfirm(): Promise<TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined> { + if (!creds) return; setBusy({}) - const resp = await api.confirmWithdrawalById(wid); + const resp = await api.confirmWithdrawalById(creds, wid); setBusy(undefined) if (resp.type === "ok") { mutate(() => true)//clean withdrawal state @@ -142,23 +144,12 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive }, } } - case "invalid-id": { - return { - status: "aborted", - error: undefined, - onClose: async () => { - updateSettings("currentWithdrawalOperationId", undefined) - onClose() - }, - } - - } - default: assertUnreachable(result) + default: assertUnreachable(result.case) } } const { body: data } = result; - if (data.aborted) { + if (data.status === "aborted") { return { status: "aborted", error: undefined, @@ -169,7 +160,7 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive } } - if (data.confirmation_done) { + if (data.status === "confirmed") { if (!settings.showWithdrawalSuccess) { updateSettings("currentWithdrawalOperationId", undefined) onClose() @@ -184,12 +175,15 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive } } - if (!data.selection_done) { + if (data.status === "pending") { return { status: "ready", error: undefined, uri: parsedUri, - onClose: doAbort, + onClose: !creds ? (async () => { + onClose(); + return undefined + }) : doAbort, } } @@ -216,9 +210,9 @@ export function useComponentState({ currency, onClose }: Props): utils.Recursive return { status: "need-confirmation", error: undefined, - onAbort: doAbort, + onAbort: !creds ? undefined : doAbort, busy: !!busy, - onConfirm: doConfirm + onConfirm: !creds ? undefined : doConfirm } } diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx b/packages/demobank-ui/src/pages/OperationState/views.tsx index a06147039..a3b30c179 100644 --- a/packages/demobank-ui/src/pages/OperationState/views.tsx +++ b/packages/demobank-ui/src/pages/OperationState/views.tsx @@ -69,6 +69,7 @@ export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: doCon async function onCancel() { errorHandler(async () => { + if (!doAbort) return; const resp = await doAbort() if (!resp) return; switch (resp.case) { @@ -97,6 +98,7 @@ export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: doCon async function onConfirm() { errorHandler(async () => { + if (!doConfirm) return; const hasError = await doConfirm() if (!hasError) { if (!settings.showWithdrawalSuccess) { @@ -186,26 +188,34 @@ export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: doCon <ShowInputErrorLabel message={errors?.answer} isDirty={captchaAnswer !== undefined} /> </div> </div> - <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> - <button type="button" class="text-sm font-semibold leading-6 text-gray-900" - onClick={(e) => { - e.preventDefault() - onCancel() - }} - > - <i18n.Translate>Cancel</i18n.Translate></button> - <button type="submit" - class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" - disabled={!!errors} - onClick={(e) => { - e.preventDefault() - onConfirm() - }} - > - <i18n.Translate>Transfer</i18n.Translate> - </button> - </div> + {!doAbort || !doConfirm ? + <Attention type="warning" title={i18n.str`not logged in`}> + <i18n.Translate> + You need to log in as pepito to complete the operation + </i18n.Translate> + </Attention> + : + <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> + <button type="button" class="text-sm font-semibold leading-6 text-gray-900" + onClick={(e) => { + e.preventDefault() + onCancel() + }} + > + <i18n.Translate>Cancel</i18n.Translate></button> + <button type="submit" + class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + disabled={!!errors} + onClick={(e) => { + e.preventDefault() + onConfirm() + }} + > + <i18n.Translate>Transfer</i18n.Translate> + </button> + </div> + } </form> </div> <div class="px-4 mt-4 "> diff --git a/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx b/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx index 7d93e7222..eb6f6fd27 100644 --- a/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx +++ b/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx @@ -32,7 +32,8 @@ interface Props { } export function PublicHistoriesPage({ }: Props): VNode { const { i18n } = useTranslationContext(); - const result = usePublicAccounts(); + //TODO: implemented filter by account name + const result = usePublicAccounts(undefined); const firstAccount = result && !(result instanceof TalerError) && result.data.public_accounts.length > 0 ? result.data.public_accounts[0].account_name : undefined; diff --git a/packages/demobank-ui/src/pages/QrCodeSection.tsx b/packages/demobank-ui/src/pages/QrCodeSection.tsx index f1394b3f6..60beb012e 100644 --- a/packages/demobank-ui/src/pages/QrCodeSection.tsx +++ b/packages/demobank-ui/src/pages/QrCodeSection.tsx @@ -30,6 +30,7 @@ import { useBankCoreApiContext } from "../context/config.js"; import { withRuntimeErrorHandling } from "../utils.js"; import { assertUnreachable } from "./WithdrawalOperationPage.js"; import { LocalNotificationBanner } from "@gnu-taler/web-util/browser"; +import { useBackendState } from "../hooks/backend.js"; export function QrCodeSection({ withdrawUri, @@ -40,6 +41,9 @@ export function QrCodeSection({ }): VNode { const { i18n } = useTranslationContext(); const talerWithdrawUri = stringifyWithdrawUri(withdrawUri); + const { state: credentials } = useBackendState(); + const creds = credentials.status !== "loggedIn" ? undefined : credentials + useEffect(() => { //Taler Wallet WebExtension is listening to headers response and tab updates. //In the SPA there is no header response with the Taler URI so @@ -58,7 +62,8 @@ export function QrCodeSection({ async function doAbort() { await handleError(async () => { - const resp = await api.abortWithdrawalById(withdrawUri.withdrawalOperationId); + if (!creds) return; + const resp = await api.abortWithdrawalById(creds, withdrawUri.withdrawalOperationId); if (resp.type === "ok") { onAborted(); } else { diff --git a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx index bfb118c6c..e21c0917b 100644 --- a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx +++ b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx @@ -20,10 +20,13 @@ import { PaytoUri, PaytoUriIBAN, PaytoUriTalerBank, + TalerError, TranslatedString, WithdrawUriResult } from "@gnu-taler/taler-util"; import { + ErrorLoading, + Loading, notifyInfo, useLocalNotification, useTranslationContext @@ -38,6 +41,10 @@ import { undefinedIfEmpty, withRuntimeErrorHandling } from "../utils.js"; import { RenderAmount } from "./PaytoWireTransferForm.js"; import { assertUnreachable } from "./WithdrawalOperationPage.js"; import { LocalNotificationBanner } from "@gnu-taler/web-util/browser"; +import { useBackendState } from "../hooks/backend.js"; +import { useWithdrawalDetails } from "../hooks/access.js"; +import { OperationState } from "./OperationState/index.js"; +import { OperationNotFound } from "./WithdrawalQRCode.js"; const logger = new Logger("WithdrawalConfirmationQuestion"); @@ -60,8 +67,23 @@ export function WithdrawalConfirmationQuestion({ withdrawUri, }: Props): VNode { const { i18n } = useTranslationContext(); - const [settings, updateSettings] = usePreferences() - + const [settings] = usePreferences() + const { state: credentials } = useBackendState(); + const creds = credentials.status !== "loggedIn" ? undefined : credentials + const withdrawalInfo = useWithdrawalDetails(withdrawUri.withdrawalOperationId) + if (!withdrawalInfo) { + return <Loading /> + } + if (withdrawalInfo instanceof TalerError) { + return <ErrorLoading error={withdrawalInfo} /> + } + if (withdrawalInfo.type === "fail") { + switch(withdrawalInfo.case) { + case "not-found": return <OperationNotFound onClose={onAborted} /> + default: assertUnreachable(withdrawalInfo.case) + } + } + const captchaNumbers = useMemo(() => { return { a: Math.floor(Math.random() * 10), @@ -87,7 +109,8 @@ export function WithdrawalConfirmationQuestion({ async function doTransfer() { setBusy({}) await handleError(async () => { - const resp = await api.confirmWithdrawalById(withdrawUri.withdrawalOperationId); + if (!creds) return; + const resp = await api.confirmWithdrawalById(creds, withdrawUri.withdrawalOperationId); if (resp.type === "ok") { mutate(() => true)// clean any info that we have if (!settings.showWithdrawalSuccess) { @@ -135,7 +158,8 @@ export function WithdrawalConfirmationQuestion({ async function doCancel() { setBusy({}) await handleError(async () => { - const resp = await api.abortWithdrawalById(withdrawUri.withdrawalOperationId); + if (!creds) return; + const resp = await api.abortWithdrawalById(creds, withdrawUri.withdrawalOperationId); if (resp.type === "ok") { onAborted(); } else { @@ -217,6 +241,7 @@ export function WithdrawalConfirmationQuestion({ <ShowInputErrorLabel message={errors?.answer} isDirty={captchaAnswer !== undefined} /> </div> </div> + <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> <button type="button" class="text-sm font-semibold leading-6 text-gray-900" onClick={doCancel} diff --git a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx index 52e3c63ee..0c3d83c3b 100644 --- a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx +++ b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx @@ -58,14 +58,13 @@ export function WithdrawalQRCode({ if (result.type === "fail") { switch (result.case) { case "not-found": return <OperationNotFound onClose={onClose} /> - case "invalid-id": return <OperationNotFound onClose={onClose} /> - default: assertUnreachable(result) + default: assertUnreachable(result.case) } } const { body: data } = result; - if (data.aborted) { + if (data.status === "aborted") { return <section id="main" class="content"> <h1 class="nav">{i18n.str`Operation aborted`}</h1> <section> @@ -93,7 +92,7 @@ export function WithdrawalQRCode({ </section> } - if (data.confirmation_done) { + if (data.status === "confirmed") { return <div class="relative ml-auto mr-auto transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6"> <div> <div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100"> @@ -128,7 +127,7 @@ export function WithdrawalQRCode({ } - if (!data.selection_done) { + if (data.status === "pending") { return ( <QrCodeSection withdrawUri={withdrawUri} @@ -173,7 +172,7 @@ export function WithdrawalQRCode({ } -function OperationNotFound({ onClose }: { onClose: () => void }): VNode { +export function OperationNotFound({ onClose }: { onClose: () => void }): VNode { const { i18n } = useTranslationContext(); return <div class="relative ml-auto mr-auto transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6"> <div> diff --git a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx index 4332284e8..b5579c199 100644 --- a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx +++ b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx @@ -82,9 +82,21 @@ export function ShowAccountDetails({ description: resp.detail.hint as TranslatedString, debug: resp.detail, }) - case "cant-change-legal-name-or-admin": return notify({ + case "admin-cant-be-exchange": return notify({ type: "error", - title: i18n.str`Can't change legal name`, + title: i18n.str`This is an administration account, changing to exchange account is denied.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }) + case "user-cant-change-name": return notify({ + type: "error", + title: i18n.str`You can't change the legal name, please contact the your account administrator.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }) + case "user-cant-change-debt": return notify({ + type: "error", + title: i18n.str`You can't change the debt limit, please contact the your account administrator.`, description: resp.detail.hint as TranslatedString, debug: resp.detail, }) diff --git a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx index 3c00ad1b8..eef2a0692 100644 --- a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx +++ b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx @@ -61,16 +61,18 @@ export function UpdateAccountPassword({ type: "error", title: i18n.str`Not authorized to change the password, maybe the session is invalid.` }) - case "old-password-invalid-or-not-allowed": return notify({ - type: "error", - title: current ? - i18n.str`This user have no right on to change the password.` : - i18n.str`This user have no right on to change the password or the old password doesn't match.` - }) case "not-found": return notify({ type: "error", title: i18n.str`Account not found` }) + case "user-require-old-password": return notify({ + type: "error", + title: i18n.str`Old password need to be provided in order to change new one. If you don't have it contact your account administrator.` + }) + case "wrong-old-password": return notify({ + type: "error", + title: i18n.str`Your current password doesn't match, can't change to a new password.` + }) default: assertUnreachable(resp) } } |