aboutsummaryrefslogtreecommitdiff
path: root/packages/merchant-backoffice-ui/src/paths/login/index.tsx
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-09-11 15:07:55 -0300
committerSebastian <sebasjm@gmail.com>2023-09-11 15:08:08 -0300
commit8c20f4b27946679267bb44255721a9f14ae1077a (patch)
tree389d7dac804af0e17652240094947e710f503dd3 /packages/merchant-backoffice-ui/src/paths/login/index.tsx
parente2422b68ebb2a29fb2e4d86f8a8cf9ec2a33e099 (diff)
downloadwallet-core-8c20f4b27946679267bb44255721a9f14ae1077a.tar.xz
new login token
Diffstat (limited to 'packages/merchant-backoffice-ui/src/paths/login/index.tsx')
-rw-r--r--packages/merchant-backoffice-ui/src/paths/login/index.tsx299
1 files changed, 294 insertions, 5 deletions
diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
index caa63c714..9948307e4 100644
--- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
@@ -18,12 +18,301 @@
*
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { h, VNode } from "preact";
-import { LoginModal } from "../../components/exception/login.js";
+
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { ComponentChildren, h, VNode } from "preact";
+import { useCallback, useEffect, useState } from "preact/hooks";
+import { useBackendContext } from "../../context/backend.js";
+import { useInstanceContext } from "../../context/instance.js";
+import { AccessToken, LoginToken } from "../../declaration.js";
+import { useCredentialsChecker } from "../../hooks/backend.js";
+import { useBackendURL } from "../../hooks/index.js";
interface Props {
- onConfirm: (url: string, token?: string) => void;
+ onConfirm: (token: LoginToken | undefined) => void;
+}
+
+function getTokenValuePart(t: string): string {
+ if (!t) return t;
+ const match = /secret-token:(.*)/.exec(t);
+ if (!match || !match[1]) return "";
+ return match[1];
}
-export default function LoginPage({ onConfirm }: Props): VNode {
- return <LoginModal onConfirm={onConfirm} />;
+
+function normalizeToken(r: string): AccessToken {
+ return `secret-token:${r}` as AccessToken;
+}
+
+function cleanUp(s: string): string {
+ let result = s;
+ if (result.indexOf("webui/") !== -1) {
+ result = result.substring(0, result.indexOf("webui/"));
+ }
+ return result;
}
+
+export function LoginPage({ onConfirm }: Props): VNode {
+ const { url: backendURL, changeBackend } = useBackendContext();
+ const { admin, id } = useInstanceContext();
+ const { requestNewLoginToken } = useCredentialsChecker();
+ const [token, setToken] = useState("");
+
+ const { i18n } = useTranslationContext();
+
+
+ const doLogin = useCallback(async function doLoginImpl() {
+ const secretToken = normalizeToken(token);
+ const baseUrl = id === undefined ? backendURL : `${backendURL}/instances/${id}`
+ const result = await requestNewLoginToken(baseUrl, secretToken);
+ if (result.valid) {
+ const { token, expiration } = result
+ onConfirm({ token, expiration });
+ } else {
+ onConfirm(undefined);
+ }
+ }, [backendURL, id, token])
+
+ async function changeServer() {
+ changeBackend("")
+ }
+
+ console.log(admin, id)
+ if (admin && id !== "default") {
+ //admin trying to access another instance
+ return (<div class="columns is-centered" style={{ margin: "auto" }}>
+ <div class="column is-two-thirds ">
+ <div class="modal-card" style={{ width: "100%", margin: 0 }}>
+ <header
+ class="modal-card-head"
+ style={{ border: "1px solid", borderBottom: 0 }}
+ >
+ <p class="modal-card-title">{i18n.str`Login required`}</p>
+ </header>
+ <section
+ class="modal-card-body"
+ style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
+ >
+ <p>
+ <i18n.Translate>Need the access token for the instance.</i18n.Translate>
+ </p>
+ <div class="field is-horizontal">
+ <div class="field-label is-normal">
+ <label class="label">
+ <i18n.Translate>Access Token</i18n.Translate>
+ </label>
+ </div>
+ <div class="field-body">
+ <div class="field">
+ <p class="control is-expanded">
+ <input
+ class="input"
+ type="password"
+ placeholder={"current access token"}
+ name="token"
+ onKeyPress={(e) =>
+ e.keyCode === 13
+ ? doLogin()
+ : null
+ }
+ value={token}
+ onInput={(e): void => setToken(e?.currentTarget.value)}
+ />
+ </p>
+ </div>
+ </div>
+ </div>
+ </section>
+ <footer
+ class="modal-card-foot "
+ style={{
+ justifyContent: "flex-end",
+ border: "1px solid",
+ borderTop: 0,
+ }}
+ >
+ <AsyncButton
+ onClick={doLogin}
+ >
+ <i18n.Translate>Confirm</i18n.Translate>
+ </AsyncButton>
+ </footer>
+ </div>
+ </div>
+ </div>)
+ }
+
+ return (
+ <div class="columns is-centered" style={{ margin: "auto" }}>
+ <div class="column is-two-thirds ">
+ <div class="modal-card" style={{ width: "100%", margin: 0 }}>
+ <header
+ class="modal-card-head"
+ style={{ border: "1px solid", borderBottom: 0 }}
+ >
+ <p class="modal-card-title">{i18n.str`Login required`}</p>
+ </header>
+ <section
+ class="modal-card-body"
+ style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
+ >
+ <i18n.Translate>Please enter your access token.</i18n.Translate>
+ <div class="field is-horizontal">
+ <div class="field-label is-normal">
+ <label class="label">URL</label>
+ </div>
+ <div class="field-body">
+ <div class="field">
+ <p class="control is-expanded">
+ <input
+ class="input"
+ type="text"
+ placeholder="set new url"
+ name="id"
+ value={backendURL}
+ disabled
+ readOnly
+ />
+ </p>
+ </div>
+ </div>
+ </div>
+ <div class="field is-horizontal">
+ <div class="field-label is-normal">
+ <label class="label">
+ <i18n.Translate>Access Token</i18n.Translate>
+ </label>
+ </div>
+ <div class="field-body">
+ <div class="field">
+ <p class="control is-expanded">
+ <input
+ class="input"
+ type="password"
+ placeholder={"current access token"}
+ name="token"
+ onKeyPress={(e) =>
+ e.keyCode === 13
+ ? doLogin()
+ : null
+ }
+ value={token}
+ onInput={(e): void => setToken(e?.currentTarget.value)}
+ />
+ </p>
+ </div>
+ </div>
+ </div>
+ </section>
+ <footer
+ class="modal-card-foot "
+ style={{
+ justifyContent: "space-between",
+ border: "1px solid",
+ borderTop: 0,
+ }}
+ >
+ <AsyncButton
+
+ onClick={changeServer}
+ >
+ <i18n.Translate>Change server</i18n.Translate>
+ </AsyncButton>
+
+ <AsyncButton
+ type="is-info"
+ onClick={doLogin}
+ >
+ <i18n.Translate>Confirm</i18n.Translate>
+ </AsyncButton>
+ </footer>
+ </div>
+ </div>
+ </div>
+ );
+}
+
+function AsyncButton({ onClick, disabled, type = "", children }: { type?: string, disabled?: boolean, onClick: () => Promise<void>, children: ComponentChildren }): VNode {
+ const [running, setRunning] = useState(false)
+ return <button class={"button " + type} disabled={disabled || running} onClick={() => {
+ setRunning(true)
+ onClick().then(() => {
+ setRunning(false)
+ }).catch(() => {
+ setRunning(false)
+ })
+ }}>
+ {children}
+ </button>
+}
+
+
+export function ConnectionPage({ onConfirm }: { onConfirm: (s: string) => void }): VNode {
+ const { url: backendURL } = useBackendContext()
+
+ const [url, setURL] = useState(cleanUp(backendURL));
+ const { i18n } = useTranslationContext();
+
+ async function doConnect() {
+ onConfirm(url)
+ }
+
+ return (
+ <div class="columns is-centered" style={{ margin: "auto" }}>
+ <div class="column is-two-thirds ">
+ <div class="modal-card" style={{ width: "100%", margin: 0 }}>
+ <header
+ class="modal-card-head"
+ style={{ border: "1px solid", borderBottom: 0 }}
+ >
+ <p class="modal-card-title">{i18n.str`Connect to backend`}</p>
+ </header>
+ <section
+ class="modal-card-body"
+ style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
+ >
+ <i18n.Translate>Location of the backend server</i18n.Translate>
+ <div class="field is-horizontal">
+ <div class="field-label is-normal">
+ <label class="label">URL</label>
+ </div>
+ <div class="field-body">
+ <div class="field">
+ <p class="control is-expanded">
+ <input
+ class="input"
+ type="text"
+ placeholder="set new url"
+ name="id"
+ value={url ?? ""}
+ onKeyPress={(e) =>
+ e.keyCode === 13
+ ? doConnect()
+ : null
+ }
+ onInput={(e): void => setURL(e?.currentTarget.value)}
+ />
+ </p>
+ </div>
+ </div>
+ </div>
+ </section>
+ <footer
+ class="modal-card-foot "
+ style={{
+ justifyContent: "flex-end",
+ border: "1px solid",
+ borderTop: 0,
+ }}
+ >
+ <AsyncButton
+ disabled={backendURL === url}
+ onClick={doConnect}
+ >
+ <i18n.Translate>Try again</i18n.Translate>
+ </AsyncButton>
+ </footer>
+ </div>
+ </div>
+ </div>
+ );
+} \ No newline at end of file