diff options
Diffstat (limited to 'packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx')
-rw-r--r-- | packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx | 173 |
1 files changed, 105 insertions, 68 deletions
diff --git a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx index 32e100e43..3b35c1fe1 100644 --- a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx +++ b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx @@ -1,45 +1,76 @@ -import { 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, + TalerErrorCode, + assertUnreachable, +} from "@gnu-taler/taler-util"; +import { + LocalNotificationBanner, + ShowInputErrorLabel, + notifyInfo, + useLocalNotification, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; -import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser"; import { useBankCoreApiContext } from "../../context/config.js"; import { useBackendState } from "../../hooks/backend.js"; -import { undefinedIfEmpty, withRuntimeErrorHandling } from "../../utils.js"; +import { useBankState } from "../../hooks/bank-state.js"; +import { RouteDefinition } from "../../route.js"; +import { undefinedIfEmpty } from "../../utils.js"; import { doAutoFocus } from "../PaytoWireTransferForm.js"; import { ProfileNavigation } from "../ProfileNavigation.js"; -import { assertUnreachable } from "../WithdrawalOperationPage.js"; -import { LocalNotificationBanner } from "@gnu-taler/web-util/browser"; -import { AbsoluteTime, HttpStatusCode, TalerErrorCode } from "@gnu-taler/taler-util"; -import { useBankState } from "../../hooks/bank-state.js"; export function UpdateAccountPassword({ account: accountName, - onCancel, + routeClose, onUpdateSuccess, onAuthorizationRequired, focus, }: { - onCancel: () => void; - focus?: boolean, - onAuthorizationRequired: () => void, + routeClose: RouteDefinition<Record<string, never>>; + focus?: boolean; + onAuthorizationRequired: () => void; onUpdateSuccess: () => void; account: string; }): VNode { const { i18n } = useTranslationContext(); const { state: credentials } = useBackendState(); - const token = credentials.status !== "loggedIn" ? undefined : credentials.token + const token = + credentials.status !== "loggedIn" ? undefined : credentials.token; const { api } = useBankCoreApiContext(); const [current, setCurrent] = useState<string | undefined>(); const [password, setPassword] = useState<string | undefined>(); const [repeat, setRepeat] = useState<string | undefined>(); - const [, updateBankState] = useBankState() + const [, updateBankState] = useBankState(); - const accountIsTheCurrentUser = credentials.status === "loggedIn" ? - credentials.username === accountName : false + const accountIsTheCurrentUser = + credentials.status === "loggedIn" + ? credentials.username === accountName + : false; const errors = undefinedIfEmpty({ - current: !accountIsTheCurrentUser ? undefined : !current ? i18n.str`required` : undefined, + current: !accountIsTheCurrentUser + ? undefined + : !current + ? i18n.str`required` + : undefined, password: !password ? i18n.str`required` : undefined, repeat: !repeat ? i18n.str`required` @@ -47,8 +78,7 @@ export function UpdateAccountPassword({ ? i18n.str`password doesn't match` : undefined, }); - const [notification, notify, handleError] = useLocalNotification() - + const [notification, notify, handleError] = useLocalNotification(); async function doChangePassword() { if (!!errors || !password || !token) return; @@ -56,54 +86,62 @@ export function UpdateAccountPassword({ const request = { old_password: current, new_password: password, - } - const resp = await api.updatePassword({ username: accountName, token }, request); + }; + const resp = await api.updatePassword( + { username: accountName, token }, + request, + ); if (resp.type === "ok") { notifyInfo(i18n.str`Password changed`); onUpdateSuccess(); } else { switch (resp.case) { - case HttpStatusCode.Unauthorized: return notify({ - type: "error", - title: i18n.str`Not authorized to change the password, maybe the session is invalid.` - }) - case HttpStatusCode.NotFound: return notify({ - type: "error", - title: i18n.str`Account not found` - }) - case TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD: return notify({ - type: "error", - title: i18n.str`You need to provide the old password. If you don't have it contact your account administrator.` - }) - case TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD: return notify({ - type: "error", - title: i18n.str`Your current password doesn't match, can't change to a new password.` - }) + case HttpStatusCode.Unauthorized: + return notify({ + type: "error", + title: i18n.str`Not authorized to change the password, maybe the session is invalid.`, + }); + case HttpStatusCode.NotFound: + return notify({ + type: "error", + title: i18n.str`Account not found`, + }); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD: + return notify({ + type: "error", + title: i18n.str`You need to provide the old password. If you don't have it contact your account administrator.`, + }); + case TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD: + return notify({ + type: "error", + title: i18n.str`Your current password doesn't match, can't change to a new password.`, + }); case HttpStatusCode.Accepted: { updateBankState("currentChallenge", { operation: "update-password", id: String(resp.body.challenge_id), sent: AbsoluteTime.never(), request, - }) - return onAuthorizationRequired() + }); + return onAuthorizationRequired(); } - default: assertUnreachable(resp) + default: + assertUnreachable(resp); } } - }) + }); } return ( <Fragment> <LocalNotificationBanner notification={notification} /> - {accountIsTheCurrentUser ? - <ProfileNavigation current="credentials" /> : + {accountIsTheCurrentUser ? ( + <ProfileNavigation current="credentials" /> + ) : ( <h1 class="text-base font-semibold leading-6 text-gray-900"> <i18n.Translate>Account "{accountName}"</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"> @@ -115,8 +153,8 @@ export function UpdateAccountPassword({ class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2" autoCapitalize="none" autoCorrect="off" - onSubmit={e => { - e.preventDefault() + onSubmit={(e) => { + e.preventDefault(); }} > <div class="px-4 py-6 sm:p-8"> @@ -138,7 +176,7 @@ export function UpdateAccountPassword({ data-error={!!errors?.password && password !== undefined} value={password ?? ""} onChange={(e) => { - setPassword(e.currentTarget.value) + setPassword(e.currentTarget.value); }} autocomplete="off" /> @@ -165,7 +203,7 @@ export function UpdateAccountPassword({ data-error={!!errors?.repeat && repeat !== undefined} value={repeat ?? ""} onChange={(e) => { - setRepeat(e.currentTarget.value) + setRepeat(e.currentTarget.value); }} // placeholder="" autocomplete="off" @@ -175,12 +213,12 @@ export function UpdateAccountPassword({ isDirty={repeat !== undefined} /> </div> - <p class="mt-2 text-sm text-gray-500" > + <p class="mt-2 text-sm text-gray-500"> <i18n.Translate>repeat the same password</i18n.Translate> </p> </div> - {accountIsTheCurrentUser ? + {accountIsTheCurrentUser ? ( <div class="sm:col-span-5"> <label class="block text-sm font-medium leading-6 text-gray-900" @@ -197,7 +235,7 @@ export function UpdateAccountPassword({ data-error={!!errors?.current && current !== undefined} value={current ?? ""} onChange={(e) => { - setCurrent(e.currentTarget.value) + setCurrent(e.currentTarget.value); }} autocomplete="off" /> @@ -206,29 +244,29 @@ export function UpdateAccountPassword({ isDirty={current !== undefined} /> </div> - <p class="mt-2 text-sm text-gray-500" > - <i18n.Translate>your current password, for security</i18n.Translate> + <p class="mt-2 text-sm text-gray-500"> + <i18n.Translate> + your current password, for security + </i18n.Translate> </p> </div> - : undefined} - + ) : 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"> - {onCancel ? - <button type="button" class="text-sm font-semibold leading-6 text-gray-900" - onClick={onCancel} - > - <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={!!errors} onClick={(e) => { - e.preventDefault() - doChangePassword() + e.preventDefault(); + doChangePassword(); }} > <i18n.Translate>Change</i18n.Translate> @@ -237,6 +275,5 @@ export function UpdateAccountPassword({ </form> </div> </Fragment> - ); -}
\ No newline at end of file +} |