diff options
Diffstat (limited to 'packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx')
-rw-r--r-- | packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx | 145 |
1 files changed, 90 insertions, 55 deletions
diff --git a/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx b/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx index de634c9e0..9552f2b0c 100644 --- a/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx +++ b/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx @@ -13,81 +13,116 @@ 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 { TranslatedString, UnwrapKeyError } from "@gnu-taler/taler-util"; -import { createNewForm, notifyError, notifyInfo, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { + Button, + InputLine, + LocalNotificationBanner, + useLocalNotificationHandler, + useTranslationContext +} from "@gnu-taler/web-util/browser"; import { VNode, h } from "preact"; +import { FormErrors, useFormState } from "../hooks/form.js"; +import { useOfficer } from "../hooks/officer.js"; +import { undefinedIfEmpty } from "./CreateAccount.js"; -export function UnlockAccount({ - onAccountUnlocked, - onRemoveAccount, -}: { - onAccountUnlocked: (password: string) => Promise<void>; - onRemoveAccount: () => void; -}): VNode { - const { i18n } = useTranslationContext() - const Form = createNewForm<{ - password: string; - }>(); +type FormType = { + password: string; +}; + +export function UnlockAccount(): VNode { + const { i18n } = useTranslationContext(); + + const officer = useOfficer(); + const [notification, withErrorHandler] = useLocalNotificationHandler(); + + const [form, status] = useFormState<FormType>( + { + password: undefined, + }, + (state) => { + const errors = undefinedIfEmpty<FormErrors<FormType>>({ + password: !state.password ? i18n.str`required` : undefined, + }); + if (errors === undefined) { + return { + status: "ok", + result: state as FormType, + errors, + }; + } + return { + status: "fail", + result: state, + errors, + }; + }, + ); + + const unlockHandler = + status.status === "fail" || officer.state !== "locked" + ? undefined + : withErrorHandler( + async () => officer.tryUnlock(form.password!.value!), + () => {}, + ); + + const forgetHandler = + status.status === "fail" || officer.state !== "locked" + ? undefined + : withErrorHandler( + async () => officer.forget(), + () => {}, + ); return ( <div class="flex min-h-full flex-col "> + <LocalNotificationBanner notification={notification} /> + <div class="sm:mx-auto sm:w-full sm:max-w-md"> <h1 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900"> <i18n.Translate>Account locked</i18n.Translate> </h1> <p class="mt-6 text-lg leading-8 text-gray-600"> - <i18n.Translate>Your account is normally locked anytime you reload. To unlock type - your password again.</i18n.Translate> + <i18n.Translate> + Your account is normally locked anytime you reload. To unlock type + your password again. + </i18n.Translate> </p> </div> <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px] "> <div class="bg-gray-100 px-6 py-6 shadow sm:rounded-lg sm:px-12"> - <Form.Provider - onSubmit={async (v) => { - try { - await onAccountUnlocked(v.password!); - notifyInfo(i18n.str`Account unlocked`); - } catch (e) { - if (e instanceof UnwrapKeyError) { - notifyError( - i18n.str`Could not unlock account`, - e.message as TranslatedString, - ); - } else { - throw e; - } - } - }} - > - <div class="mb-4"> - <Form.InputLine - label={i18n.str`Password`} - name="password" - type="password" - required - /> - </div> - <div class="mt-8"> - <button - type="submit" - class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 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" - > - <i18n.Translate>Unlock</i18n.Translate> - </button> - </div> - </Form.Provider> + <div class="mb-4"> + <InputLine<FormType, "password"> + label={i18n.str`Password`} + name="password" + type="password" + required + handler={form.password} + /> + </div> + + <div class="mt-8"> + <Button + type="submit" + handler={unlockHandler} + disabled={!unlockHandler} + class="disabled:opacity-50 disabled:cursor-default flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 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" + > + <i18n.Translate>Unlock</i18n.Translate> + </Button> + </div> + </div> - <button + <Button type="button" - onClick={() => { - onRemoveAccount(); - }} - class="m-4 block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 " + handler={forgetHandler} + disabled={!forgetHandler} + class="disabled:opacity-50 disabled:cursor-default m-4 block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 " > <i18n.Translate>Forget account</i18n.Translate> - </button> + </Button> </div> </div> ); |