diff options
Diffstat (limited to 'packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx')
-rw-r--r-- | packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx | 220 |
1 files changed, 138 insertions, 82 deletions
diff --git a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx index 0dfdb39f3..9f8fb72bc 100644 --- a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx +++ b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx @@ -1,112 +1,156 @@ -import { AbsoluteTime, HttpStatusCode, TalerCorebankApi, TalerError, TalerErrorCode, TranslatedString } from "@gnu-taler/taler-util"; -import { Loading, LocalNotificationBanner, notifyInfo, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser"; +/* + This file is part of GNU Taler + (C) 2022-2024 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { + AbsoluteTime, + HttpStatusCode, + TalerCorebankApi, + TalerError, + TalerErrorCode, + TranslatedString, + assertUnreachable, +} from "@gnu-taler/taler-util"; +import { + Loading, + LocalNotificationBanner, + notifyInfo, + useLocalNotification, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { useBankCoreApiContext } from "../../context/config.js"; import { useAccountDetails } from "../../hooks/access.js"; import { useBackendState } from "../../hooks/backend.js"; +import { useBankState } from "../../hooks/bank-state.js"; +import { RouteDefinition } from "../../route.js"; import { LoginForm } from "../LoginForm.js"; import { ProfileNavigation } from "../ProfileNavigation.js"; -import { assertUnreachable } from "../WithdrawalOperationPage.js"; import { AccountForm } from "../admin/AccountForm.js"; -import { useBankState } from "../../hooks/bank-state.js"; export function ShowAccountDetails({ account, - onClear, + routeClose, onUpdateSuccess, onAuthorizationRequired, }: { - onClear?: () => void; + routeClose: RouteDefinition<Record<string, never>>; onUpdateSuccess: () => void; - onAuthorizationRequired: () => void, + onAuthorizationRequired: () => void; account: string; }): VNode { const { i18n } = useTranslationContext(); const { state: credentials } = useBackendState(); - const creds = credentials.status !== "loggedIn" ? undefined : credentials - const { api } = useBankCoreApiContext() - const accountIsTheCurrentUser = credentials.status === "loggedIn" ? - credentials.username === account : false + const creds = credentials.status !== "loggedIn" ? undefined : credentials; + const { api } = useBankCoreApiContext(); + const accountIsTheCurrentUser = + credentials.status === "loggedIn" + ? credentials.username === account + : false; const [update, setUpdate] = useState(false); - const [submitAccount, setSubmitAccount] = useState<TalerCorebankApi.AccountReconfiguration | undefined>(); - const [notification, notify, handleError] = useLocalNotification() - const [, updateBankState] = useBankState() + const [submitAccount, setSubmitAccount] = useState< + TalerCorebankApi.AccountReconfiguration | undefined + >(); + const [notification, notify, handleError] = useLocalNotification(); + const [, updateBankState] = useBankState(); const result = useAccountDetails(account); if (!result) { - return <Loading /> + return <Loading />; } if (result instanceof TalerError) { - return <ErrorLoadingWithDebug error={result} /> + return <ErrorLoadingWithDebug error={result} />; } if (result.type === "fail") { switch (result.case) { case HttpStatusCode.Unauthorized: - case HttpStatusCode.NotFound: return <LoginForm currentUser={account} /> - default: assertUnreachable(result) + case HttpStatusCode.NotFound: + return <LoginForm currentUser={account} />; + default: + assertUnreachable(result); } } async function doUpdate() { if (!update || !submitAccount || !creds) return; await handleError(async () => { - const resp = await api.updateAccount({ - token: creds.token, - username: account, - }, submitAccount); + const resp = await api.updateAccount( + { + token: creds.token, + username: account, + }, + submitAccount, + ); if (resp.type === "ok") { notifyInfo(i18n.str`Account updated`); onUpdateSuccess(); } else { switch (resp.case) { - case HttpStatusCode.Unauthorized: return notify({ - type: "error", - title: i18n.str`The rights to change the account are not sufficient`, - description: resp.detail.hint as TranslatedString, - debug: resp.detail, - }) - case HttpStatusCode.NotFound: return notify({ - type: "error", - title: i18n.str`The username was not found`, - description: resp.detail.hint as TranslatedString, - debug: resp.detail, - }) - case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_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 TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: 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, - }) - case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT: return notify({ - type: "error", - title: i18n.str`You can't change the cashout address, please contact the your account administrator.`, - description: resp.detail.hint as TranslatedString, - debug: resp.detail, - }) - case TalerErrorCode.BANK_MISSING_TAN_INFO: return notify({ - type: "error", - title: i18n.str`No information for the selected authentication channel.`, - description: resp.detail.hint as TranslatedString, - debug: resp.detail, - }) + case HttpStatusCode.Unauthorized: + return notify({ + type: "error", + title: i18n.str`The rights to change the account are not sufficient`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }); + case HttpStatusCode.NotFound: + return notify({ + type: "error", + title: i18n.str`The username was not found`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_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 TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: + 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, + }); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT: + return notify({ + type: "error", + title: i18n.str`You can't change the cashout address, please contact the your account administrator.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }); + case TalerErrorCode.BANK_MISSING_TAN_INFO: + return notify({ + type: "error", + title: i18n.str`No information for the selected authentication channel.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }); case HttpStatusCode.Accepted: { updateBankState("currentChallenge", { operation: "update-account", id: String(resp.body.challenge_id), sent: AbsoluteTime.never(), request: submitAccount, - }) - return onAuthorizationRequired() + }); + return onAuthorizationRequired(); } case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: { return notify({ @@ -116,39 +160,53 @@ export function ShowAccountDetails({ debug: resp.detail, }); } - default: assertUnreachable(resp) + default: + assertUnreachable(resp); } } - }) - + }); } return ( <Fragment> <LocalNotificationBanner notification={notification} showDebug={true} /> - {accountIsTheCurrentUser ? + {accountIsTheCurrentUser ? ( <ProfileNavigation current="details" /> - : + ) : ( <h1 class="text-base font-semibold leading-6 text-gray-900"> <i18n.Translate>Account "{account}"</i18n.Translate> </h1> - - } + )} <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg"> <div class="px-4 sm:px-0"> <h2 class="text-base font-semibold leading-7 text-gray-900"> <div class="flex items-center justify-between"> <span class="flex flex-grow flex-col"> - <span class="text-sm text-black font-semibold leading-6 " id="availability-label"> + <span + class="text-sm text-black font-semibold leading-6 " + id="availability-label" + > <i18n.Translate>Change details</i18n.Translate> </span> </span> - <button type="button" data-enabled={!update} class="bg-indigo-600 data-[enabled=true]:bg-gray-200 relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer rounded-full ring-2 border-gray-600 transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" + <button + type="button" + data-enabled={!update} + class="bg-indigo-600 data-[enabled=true]:bg-gray-200 relative inline-flex h-5 w-10 flex-shrink-0 cursor-pointer rounded-full ring-2 border-gray-600 transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" + role="switch" + aria-checked="false" + aria-labelledby="availability-label" + aria-describedby="availability-description" onClick={() => { - setUpdate(!update) - }}> - <span aria-hidden="true" data-enabled={!update} class="translate-x-5 data-[enabled=true]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"></span> + setUpdate(!update); + }} + > + <span + aria-hidden="true" + data-enabled={!update} + class="translate-x-5 data-[enabled=true]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out" + ></span> </button> </div> </h2> @@ -162,15 +220,14 @@ export function ShowAccountDetails({ onChange={(a) => setSubmitAccount(a)} > <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8"> - {onClear ? - <button type="button" class="text-sm font-semibold leading-6 text-gray-900" - onClick={onClear} - > - <i18n.Translate>Cancel</i18n.Translate> - </button> - : <div /> - } - <button type="submit" + <a + href={routeClose.url({})} + class="text-sm font-semibold leading-6 text-gray-900" + > + <i18n.Translate>Cancel</i18n.Translate> + </a> + <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={!update || !submitAccount} onClick={doUpdate} @@ -183,4 +240,3 @@ export function ShowAccountDetails({ </Fragment> ); } - |