/*
This file is part of GNU Taler
(C) 2022 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
*/
import { TranslatedString } from "@gnu-taler/taler-util";
import { Notification, useLocalNotification, useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useEffect, useRef, 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 { bankUiSettings } from "../settings.js";
import { undefinedIfEmpty, withRuntimeErrorHandling } from "../utils.js";
import { assertUnreachable } from "./WithdrawalOperationPage.js";
import { doAutoFocus } from "./PaytoWireTransferForm.js";
import { Attention } from "@gnu-taler/web-util/browser";
import { ShowLocalNotification } from "@gnu-taler/web-util/browser";
/**
* Collect and submit login data.
*/
export function LoginForm({ reason, onRegister }: { reason?: "not-found" | "forbidden", onRegister?: () => void }): VNode {
const backend = useBackendState();
const currentUser = backend.state.status !== "loggedOut" ? backend.state.username : undefined
const [username, setUsername] = useState(currentUser);
const [password, setPassword] = useState();
const { i18n } = useTranslationContext();
const { api } = useBankCoreApiContext();
const [notification, notify, handleError] = useLocalNotification()
/**
* Register form may be shown in the initialization step.
* If no register handler then this is invoke
* to show a session expired or unauthorized
*/
const isLogginAgain = !onRegister
const ref = useRef(null);
useEffect(function focusInput() {
if (isLogginAgain && backend.state.status !== "expired") {
backend.expired()
window.location.reload()
}
ref.current?.focus();
}, []);
const [busy, setBusy] = useState>()
const errors = undefinedIfEmpty({
username: !username
? i18n.str`Missing username`
// : !USERNAME_REGEX.test(username)
// ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
: undefined,
password: !password ? i18n.str`Missing password` : undefined,
}) ?? busy;
async function doLogout() {
backend.logOut()
}
async function doLogin() {
if (!username || !password) return;
setBusy({})
await handleError(async () => {
const resp = await api.getAuthenticationAPI(username).createAccessToken(password, {
// scope: "readwrite" as "write", //FIX: different than merchant
scope: "readwrite",
duration: {
d_us: "forever" //FIX: should return shortest
// d_us: 60 * 60 * 24 * 7 * 1000 * 1000
},
refreshable: true,
})
if (resp.type === "ok") {
backend.logIn({ username, token: resp.body.access_token });
} else {
switch (resp.case) {
case "wrong-credentials": return notify({
type: "error",
title: i18n.str`Wrong credentials for "${username}"`,
description: resp.detail.hint as TranslatedString,
debug: resp.detail,
})
case "not-found": return notify({
type: "error",
title: i18n.str`Account not found`,
description: resp.detail.hint as TranslatedString,
debug: resp.detail,
})
default: assertUnreachable(resp)
}
}
})
setPassword(undefined);
setBusy(undefined)
}
return (