diff options
Diffstat (limited to 'packages/bank-ui/src/pages/admin/CreateNewAccount.tsx')
-rw-r--r-- | packages/bank-ui/src/pages/admin/CreateNewAccount.tsx | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/packages/bank-ui/src/pages/admin/CreateNewAccount.tsx b/packages/bank-ui/src/pages/admin/CreateNewAccount.tsx new file mode 100644 index 000000000..7d2d449b0 --- /dev/null +++ b/packages/bank-ui/src/pages/admin/CreateNewAccount.tsx @@ -0,0 +1,217 @@ +/* + 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, + TalerErrorCode, + TranslatedString, + assertUnreachable, +} from "@gnu-taler/taler-util"; +import { + Attention, + LocalNotificationBanner, + notifyInfo, + useLocalNotification, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; +import { Fragment, VNode, h } from "preact"; +import { useState } from "preact/hooks"; +import { useBankCoreApiContext } from "@gnu-taler/web-util/browser"; +import { useSessionState } from "../../hooks/session.js"; +import { RouteDefinition } from "@gnu-taler/web-util/browser"; +import { AccountForm } from "./AccountForm.js"; + +export function CreateNewAccount({ + routeCancel, + onCreateSuccess, +}: { + routeCancel: RouteDefinition; + onCreateSuccess: () => void; +}): VNode { + const { i18n } = useTranslationContext(); + const { state: credentials } = useSessionState(); + const token = + credentials.status !== "loggedIn" ? undefined : credentials.token; + const { + lib: { bank: api }, + } = useBankCoreApiContext(); + + const [submitAccount, setSubmitAccount] = useState< + TalerCorebankApi.RegisterAccountRequest | undefined + >(); + const [notification, notify, handleError] = useLocalNotification(); + + async function doCreate() { + if (!submitAccount || !token) return; + await handleError(async () => { + const resp = await api.createAccount(token, submitAccount); + if (resp.type === "ok") { + notifyInfo( + i18n.str`Account created with password "${submitAccount.password}".`, + ); + onCreateSuccess(); + } else { + switch (resp.case) { + case HttpStatusCode.BadRequest: + return notify({ + type: "error", + title: i18n.str`Server replied that phone or email is invalid`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + when: AbsoluteTime.now(), + }); + case HttpStatusCode.Unauthorized: + return notify({ + type: "error", + title: i18n.str`The rights to perform the operation are not sufficient`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + when: AbsoluteTime.now(), + }); + case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE: + return notify({ + type: "error", + title: i18n.str`Account username is already taken`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + when: AbsoluteTime.now(), + }); + case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE: + return notify({ + type: "error", + title: i18n.str`Account id is already taken`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + when: AbsoluteTime.now(), + }); + case TalerErrorCode.BANK_UNALLOWED_DEBIT: + return notify({ + type: "error", + title: i18n.str`Bank ran out of bonus credit.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + when: AbsoluteTime.now(), + }); + case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: + return notify({ + type: "error", + title: i18n.str`Account username can't be used because is reserved`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + when: AbsoluteTime.now(), + }); + case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: + return notify({ + type: "error", + title: i18n.str`Only admin is allow to set debt limit.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + when: AbsoluteTime.now(), + }); + 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, + when: AbsoluteTime.now(), + }); + case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: + return notify({ + type: "error", + title: i18n.str`Authentication channel is not supported.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + when: AbsoluteTime.now(), + }); + case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL: + return notify({ + type: "error", + title: i18n.str`Only admin can create accounts with second factor authentication.`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + when: AbsoluteTime.now(), + }); + default: + assertUnreachable(resp); + } + } + }); + } + + if (!(credentials.status === "loggedIn" && credentials.isUserAdministrator)) { + return ( + <Fragment> + <Attention type="warning" title={i18n.str`Can't create accounts`}> + <i18n.Translate> + Only system admin can create accounts. + </i18n.Translate> + </Attention> + <div class="mt-5 sm:mt-6"> + <a + href={routeCancel.url({})} + name="close" + class="inline-flex w-full justify-center 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" + > + <i18n.Translate>Close</i18n.Translate> + </a> + </div> + </Fragment> + ); + } + + return ( + <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg"> + <LocalNotificationBanner notification={notification} /> + + <div class="px-4 sm:px-0"> + <h2 class="text-base font-semibold leading-7 text-gray-900"> + <i18n.Translate>New bank account</i18n.Translate> + </h2> + </div> + <AccountForm + template={undefined} + purpose="create" + 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"> + <a + href={routeCancel.url({})} + name="cancel" + class="text-sm font-semibold leading-6 text-gray-900" + > + <i18n.Translate>Cancel</i18n.Translate> + </a> + <button + type="submit" + name="create" + 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={!submitAccount} + onClick={(e) => { + e.preventDefault(); + doCreate(); + }} + > + <i18n.Translate>Create</i18n.Translate> + </button> + </div> + </AccountForm> + </div> + ); +} |