diff options
9 files changed, 48 insertions, 171 deletions
| diff --git a/packages/merchant-backoffice-ui/src/Application.tsx b/packages/merchant-backoffice-ui/src/Application.tsx index c871b1633..82329974f 100644 --- a/packages/merchant-backoffice-ui/src/Application.tsx +++ b/packages/merchant-backoffice-ui/src/Application.tsx @@ -26,7 +26,6 @@ import {    useTranslationContext,  } from "@gnu-taler/web-util/browser";  import { Fragment, VNode, h } from "preact"; -import { route } from "preact-router";  import { useMemo } from "preact/hooks";  import { ApplicationReadyRoutes } from "./ApplicationReadyRoutes.js";  import { Loading } from "./components/exception/loading.js"; @@ -41,8 +40,7 @@ import {  import { ConfigContextProvider } from "./context/config.js";  import { useBackendConfig } from "./hooks/backend.js";  import { strings } from "./i18n/strings.js"; -import { ConnectionPage, LoginPage } from "./paths/login/index.js"; -import { LoginToken } from "./declaration.js"; +import { LoginPage } from "./paths/login/index.js";  export function Application(): VNode {    return ( @@ -60,7 +58,6 @@ export function Application(): VNode {   * @returns    */  function ApplicationStatusRoutes(): VNode { -  const { changeBackend, selected: backendSelected } = useBackendContext();    const result = useBackendConfig();    const { i18n } = useTranslationContext(); @@ -69,15 +66,6 @@ function ApplicationStatusRoutes(): VNode {      : { currency: "unknown", version: "unknown" };    const ctx = useMemo(() => ({ currency, version }), [currency, version]); -  if (!backendSelected) { -    return ( -      <Fragment> -        <NotConnectedAppMenu title="Welcome!" /> -        <ConnectionPage onConfirm={changeBackend} /> -      </Fragment> -    ); -  } -    if (!result.ok) {      if (result.loading) return <Loading />;      if ( @@ -87,7 +75,13 @@ function ApplicationStatusRoutes(): VNode {        return (          <Fragment>            <NotConnectedAppMenu title="Login" /> -          <ConnectionPage onConfirm={changeBackend} /> +          <NotificationCard +            notification={{ +              message: i18n.str`Checking the /config endpoint got authorization error`, +              type: "ERROR", +              description: `The /config endpoint of the backend server should be accesible`, +            }} +          />          </Fragment>        );      } @@ -100,12 +94,11 @@ function ApplicationStatusRoutes(): VNode {            <NotConnectedAppMenu title="Error" />            <NotificationCard              notification={{ -              message: i18n.str`Server not found`, +              message: i18n.str`Could not find /config enpoint on this URL`,                type: "ERROR", -              description: `Check your url`, +              description: `Check the URL or contact the system administrator.`,              }}            /> -          <ConnectionPage onConfirm={changeBackend} />          </Fragment>        );      } @@ -119,7 +112,6 @@ function ApplicationStatusRoutes(): VNode {              description: i18n.str`Got message "${result.message}" from ${result.info?.url}`,            }}          /> -        <ConnectionPage onConfirm={changeBackend} />        </Fragment>;      }      if (result.type === ErrorType.UNREADABLE) { @@ -132,7 +124,6 @@ function ApplicationStatusRoutes(): VNode {              description: i18n.str`Got message "${result.message}" from ${result.info?.url}`,            }}          /> -        <ConnectionPage onConfirm={changeBackend} />        </Fragment>;      }      return ( @@ -145,7 +136,6 @@ function ApplicationStatusRoutes(): VNode {              description: i18n.str`Got message "${result.message}" from ${result.info?.url}`,            }}          /> -        <ConnectionPage onConfirm={changeBackend} />        </Fragment>      );    } @@ -164,9 +154,7 @@ function ApplicationStatusRoutes(): VNode {            description: i18n.str`Merchant backend server version ${result.data.version} is not compatible with the supported version ${SUPPORTED_VERSION}`,          }}        /> -      <ConnectionPage onConfirm={changeBackend} />      </Fragment> -    }    return ( diff --git a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx b/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx index ebfa2b6d6..55accd989 100644 --- a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx +++ b/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx @@ -26,13 +26,14 @@ import { Route, Router, route } from "preact-router";  import { useState } from "preact/hooks";  import { InstanceRoutes } from "./InstanceRoutes.js";  import { +  NotConnectedAppMenu,    NotYetReadyAppMenu,    NotificationCard,  } from "./components/menu/index.js";  import { useBackendContext } from "./context/backend.js";  import { LoginToken } from "./declaration.js";  import { useBackendInstancesTestForAdmin } from "./hooks/backend.js"; -import { ConnectionPage, LoginPage } from "./paths/login/index.js"; +import { LoginPage } from "./paths/login/index.js";  import { Settings } from "./paths/settings/index.js";  import { INSTANCE_ID_LOOKUP } from "./utils/constants.js"; @@ -42,10 +43,11 @@ import { INSTANCE_ID_LOOKUP } from "./utils/constants.js";   */  export function ApplicationReadyRoutes(): VNode {    const { i18n } = useTranslationContext(); -  const { url: backendURL, changeBackend } = useBackendContext()    const [unauthorized, setUnauthorized] = useState(false)    const { +    url: backendURL,      updateToken, +    alreadyTriedLogin,    } = useBackendContext();    function updateLoginStatus(token: LoginToken | undefined) { @@ -64,6 +66,15 @@ export function ApplicationReadyRoutes(): VNode {      && result.type === ErrorType.CLIENT      && result.status === HttpStatusCode.Unauthorized; +  if (!alreadyTriedLogin) { +    return ( +      <Fragment> +        <NotConnectedAppMenu title="Welcome!" /> +        <LoginPage onConfirm={updateToken} /> +      </Fragment> +    ); +  } +    if (showSettings) {      return <Fragment>        <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="UI Settings" onLogout={clearTokenAndGoToRoot} isPasswordOk={false} /> @@ -100,7 +111,7 @@ export function ApplicationReadyRoutes(): VNode {                type: "ERROR",              }}            /> -          <ConnectionPage onConfirm={changeBackend} /> +          {/* <ConnectionPage onConfirm={changeBackend} /> */}          </Fragment>        );      } diff --git a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx index 95be49c9d..5d33655ff 100644 --- a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx +++ b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx @@ -205,7 +205,7 @@ export function InstanceRoutes({        <NotificationCard          notification={{            message: i18n.str`Access denied`, -          description: i18n.str`Redirecting to login page.`, +          description: i18n.str`Session expired or password changed.`,            type: "ERROR",          }}        /> diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx index 6905cb4d0..d6c4ce4b2 100644 --- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx +++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx @@ -49,7 +49,7 @@ export function Sidebar({    isPasswordOk  }: Props): VNode {    const config = useConfigContext(); -  const { url: backendURL, resetBackend } = useBackendContext() +  const { url: backendURL } = useBackendContext()    const { i18n } = useTranslationContext();    const kycStatus = useInstanceKYCDetails();    const needKYC = kycStatus.ok && kycStatus.data.type === "redirect"; @@ -283,21 +283,8 @@ export function Sidebar({                    <i18n.Translate>Log out</i18n.Translate>                  </span>                </a> -            </li> : -            <li> -            <a -              class="has-icon is-state-info is-hoverable" -              onClick={(): void => resetBackend()} -            > -              <span class="icon"> -                <i class="mdi mdi-logout default" /> -              </span> -              <span class="menu-item-label"> -                <i18n.Translate>Change server</i18n.Translate> -              </span> -            </a> -          </li> -        } +            </li> : undefined +          }          </ul>        </div>      </aside> diff --git a/packages/merchant-backoffice-ui/src/context/backend.ts b/packages/merchant-backoffice-ui/src/context/backend.ts index d4a9abd5f..9b1a37be6 100644 --- a/packages/merchant-backoffice-ui/src/context/backend.ts +++ b/packages/merchant-backoffice-ui/src/context/backend.ts @@ -19,56 +19,39 @@   * @author Sebastian Javier Marchano (sebasjm)   */ +import { useMemoryStorage } from "@gnu-taler/web-util/browser";  import { createContext, h, VNode } from "preact"; -import { useContext, useState } from "preact/hooks"; +import { useContext } from "preact/hooks";  import { LoginToken } from "../declaration.js";  import { useBackendDefaultToken, useBackendURL } from "../hooks/index.js"; -import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser"; -import { codecForBoolean } from "@gnu-taler/taler-util";  interface BackendContextType {    url: string, -  selected: boolean; +  alreadyTriedLogin: boolean;    token?: LoginToken;    updateToken: (token: LoginToken | undefined) => void; -  changeBackend: (url: string) => void; -  resetBackend: () => void;  }  const BackendContext = createContext<BackendContextType>({    url: "", -  selected: false, +  alreadyTriedLogin: false,    token: undefined,    updateToken: () => null, -  changeBackend: () => null, -  resetBackend: () => null,  }); -const BACKEND_SELECTED = buildStorageKey("backend-selected", codecForBoolean()); -  function useBackendContextState(    defaultUrl?: string,  ): BackendContextType { -  const [url, changeBackend2] = useBackendURL(defaultUrl); +  const [url] = useBackendURL(defaultUrl);    const [token, updateToken] = useBackendDefaultToken(); -  const {value, update} = useLocalStorage(BACKEND_SELECTED) - -  function changeBackend(s:string) { -    changeBackend2(s) -    update(true) -  } -  function resetBackend() { -    update(false) -  } +  console.log(JSON.stringify(token))    return {      url,      token, -    selected: value ?? false, +    alreadyTriedLogin: token !== undefined,      updateToken, -    changeBackend, -    resetBackend    };  } diff --git a/packages/merchant-backoffice-ui/src/hooks/backend.ts b/packages/merchant-backoffice-ui/src/hooks/backend.ts index 4515f0557..054c074f1 100644 --- a/packages/merchant-backoffice-ui/src/hooks/backend.ts +++ b/packages/merchant-backoffice-ui/src/hooks/backend.ts @@ -345,7 +345,7 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {          //and avoid network          return Promise.resolve({            ok: true, -          data: {orders:[]} as T, +          data: { orders: [] } as T,          })        }        return requestHandler<T>(baseUrl, endpoint, { params, token }); @@ -398,7 +398,7 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {          //and avoid network          return Promise.resolve({            ok: true, -          data: {transfers:[]} as T, +          data: { transfers: [] } as T,          })        }        if (delta !== undefined) { @@ -424,7 +424,7 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {          //and avoid network          return Promise.resolve({            ok: true, -          data: {templates:[]} as T, +          data: { templates: [] } as T,          })        }        if (delta !== undefined) { @@ -450,7 +450,7 @@ export function useBackendInstanceRequest(): useBackendInstanceRequestType {          //and avoid network          return Promise.resolve({            ok: true, -          data: {webhooks:[]} as T, +          data: { webhooks: [] } as T,          })        }        if (delta !== undefined) { diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx index e37ef4bef..1c98b7c9b 100644 --- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx @@ -36,7 +36,7 @@ function normalizeToken(r: string): AccessToken {  }  export function LoginPage({ onConfirm }: Props): VNode { -  const { url: backendURL, changeBackend, resetBackend } = useBackendContext(); +  const { url: backendURL } = useBackendContext();    const { admin, id } = useInstanceContext();    const { requestNewLoginToken } = useCredentialsChecker();    const [token, setToken] = useState(""); @@ -54,11 +54,7 @@ export function LoginPage({ onConfirm }: Props): VNode {      } else {        onConfirm(undefined);      } -  }, [backendURL, id, token]) - -  async function changeServer() { -    resetBackend() -  } +  }, [id, token])    if (admin && id !== "default") {      //admin trying to access another instance @@ -139,26 +135,7 @@ export function LoginPage({ onConfirm }: Props): VNode {              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"> @@ -194,10 +171,7 @@ export function LoginPage({ onConfirm }: Props): VNode {                borderTop: 0,              }}            > -            <AsyncButton onClick={changeServer}> -              <i18n.Translate>Change server</i18n.Translate> -            </AsyncButton> - +            <div />              <AsyncButton                type="is-info"                onClick={doLogin} @@ -226,73 +200,3 @@ function AsyncButton({ onClick, disabled, type = "", children }: { type?: string  } -export function ConnectionPage({ onConfirm }: { onConfirm: (s: string) => void }): VNode { -  const { url: backendURL } = useBackendContext() - -  const [error, setError] = useState<string>(); -  const [url, setURL] = useState(backendURL ?? ""); -  const { i18n } = useTranslationContext(); - -  async function doConnect() { -    const withHttp = url.startsWith("http") ? url : "https://" + url -     -    onConfirm(withHttp) -  } - -  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 onClick={doConnect}> -              <i18n.Translate>Connect</i18n.Translate> -            </AsyncButton> -          </footer> -        </div> -      </div> -    </div> -  ); -}
\ No newline at end of file diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index cf2006406..72c67b153 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -1291,10 +1291,12 @@ export async function getTransactions(    const txNotPending = transactions.filter((x) => !isPending(x));    const txCmp = (h1: Transaction, h2: Transaction) => { -    const tsCmp = AbsoluteTime.cmp( +    // Order transactions by timestamp.  Newest transactions come first. +    const tsCmp = -AbsoluteTime.cmp(        AbsoluteTime.fromPreciseTimestamp(h1.timestamp),        AbsoluteTime.fromPreciseTimestamp(h2.timestamp),      ); +    // If the timestamp is exactly the same, order by transaction type.      if (tsCmp === 0) {        return Math.sign(txOrder[h1.type] - txOrder[h2.type]);      } diff --git a/packages/web-util/src/live-reload.ts b/packages/web-util/src/live-reload.ts index 407ef9e84..cd3a7540d 100644 --- a/packages/web-util/src/live-reload.ts +++ b/packages/web-util/src/live-reload.ts @@ -1,6 +1,8 @@  /* eslint-disable no-undef */  function setupLiveReload(): void { +  const stopWs = localStorage.getItem("stop-ws") +  if (!!stopWs) return;    const protocol = window.location.protocol === "http:" ? "ws:" : "wss:";    const ws = new WebSocket(`${protocol}//${window.location.hostname}:${window.location.port}/ws`); | 
