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 | |
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')
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) } } |