diff options
Diffstat (limited to 'packages/demobank-ui/src/pages/UpdateAccountPassword.tsx')
-rw-r--r-- | packages/demobank-ui/src/pages/UpdateAccountPassword.tsx | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx b/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx new file mode 100644 index 000000000..084a5b643 --- /dev/null +++ b/packages/demobank-ui/src/pages/UpdateAccountPassword.tsx @@ -0,0 +1,131 @@ +import { ErrorType, HttpResponsePaginated, RequestError, notify, notifyError, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useAdminAccountAPI, useBusinessAccountDetails } from "../hooks/circuit.js"; +import { useState } from "preact/hooks"; +import { HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util"; +import { VNode,h ,Fragment} from "preact"; +import { buildRequestErrorMessage, undefinedIfEmpty } from "../utils.js"; +import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js"; + +export function UpdateAccountPassword({ + account, + onClear, + onUpdateSuccess, + onLoadNotOk, + }: { + onLoadNotOk: <T>( + error: HttpResponsePaginated<T, SandboxBackend.SandboxError>, + ) => VNode; + onClear: () => void; + onUpdateSuccess: () => void; + account: string; + }): VNode { + const { i18n } = useTranslationContext(); + const result = useBusinessAccountDetails(account); + const { changePassword } = useAdminAccountAPI(); + const [password, setPassword] = useState<string | undefined>(); + const [repeat, setRepeat] = useState<string | undefined>(); + + if (!result.ok) { + if (result.loading || result.type === ErrorType.TIMEOUT) { + return onLoadNotOk(result); + } + if (result.status === HttpStatusCode.NotFound) { + return <div>account not found</div>; + } + return onLoadNotOk(result); + } + + const errors = undefinedIfEmpty({ + password: !password ? i18n.str`required` : undefined, + repeat: !repeat + ? i18n.str`required` + : password !== repeat + ? i18n.str`password doesn't match` + : undefined, + }); + + return ( + <div> + <div> + <h1 class="nav welcome-text"> + <i18n.Translate>Update password for {account}</i18n.Translate> + </h1> + </div> + + <div style={{ maxWidth: 600, overflowX: "hidden", margin: "auto" }}> + <form class="pure-form"> + <fieldset> + <label>{i18n.str`Password`}</label> + <input + type="password" + value={password ?? ""} + onChange={(e) => { + setPassword(e.currentTarget.value); + }} + /> + <ShowInputErrorLabel + message={errors?.password} + isDirty={password !== undefined} + /> + </fieldset> + <fieldset> + <label>{i18n.str`Repeat password`}</label> + <input + type="password" + value={repeat ?? ""} + onChange={(e) => { + setRepeat(e.currentTarget.value); + }} + /> + <ShowInputErrorLabel + message={errors?.repeat} + isDirty={repeat !== undefined} + /> + </fieldset> + </form> + <p> + <div style={{ display: "flex", justifyContent: "space-between" }}> + <div> + <input + class="pure-button" + type="submit" + value={i18n.str`Close`} + onClick={async (e) => { + e.preventDefault(); + onClear(); + }} + /> + </div> + <div> + <input + id="select-exchange" + class="pure-button pure-button-primary content" + disabled={!!errors} + type="submit" + value={i18n.str`Confirm`} + onClick={async (e) => { + e.preventDefault(); + if (!!errors || !password) return; + try { + const r = await changePassword(account, { + new_password: password, + }); + onUpdateSuccess(); + } catch (error) { + if (error instanceof RequestError) { + notify(buildRequestErrorMessage(i18n, error.cause)); + } else { + notifyError(i18n.str`Operation failed, please report`, (error instanceof Error + ? error.message + : JSON.stringify(error)) as TranslatedString) + } + } + }} + /> + </div> + </div> + </p> + </div> + </div> + ); + }
\ No newline at end of file |