diff options
| author | Sebastian <sebasjm@gmail.com> | 2023-10-04 14:36:03 -0300 | 
|---|---|---|
| committer | Sebastian <sebasjm@gmail.com> | 2023-10-04 14:36:03 -0300 | 
| commit | 851b2da39c3297ede3d267f3d2534cac213261c1 (patch) | |
| tree | 51ee03238cb7d87d21e57c0cdf245a0bc04681f0 /packages/merchant-backoffice-ui | |
| parent | 535b990215bdd861df5cf6215a5f72a47576f89b (diff) | |
fixing issues reported by Christian, wip
Diffstat (limited to 'packages/merchant-backoffice-ui')
21 files changed, 181 insertions, 81 deletions
| diff --git a/packages/merchant-backoffice-ui/src/Application.tsx b/packages/merchant-backoffice-ui/src/Application.tsx index 1a7617643..f0a7de53b 100644 --- a/packages/merchant-backoffice-ui/src/Application.tsx +++ b/packages/merchant-backoffice-ui/src/Application.tsx @@ -60,7 +60,7 @@ export function Application(): VNode {   * @returns    */  function ApplicationStatusRoutes(): VNode { -  const { url: backendURL, updateToken, changeBackend } = useBackendContext(); +  const { changeBackend, selected: backendSelected } = useBackendContext();    const result = useBackendConfig();    const { i18n } = useTranslationContext(); @@ -69,7 +69,7 @@ function ApplicationStatusRoutes(): VNode {      : { currency: "unknown", version: "unknown" };    const ctx = useMemo(() => ({ currency, version }), [currency, version]); -  if (!backendURL) { +  if (!backendSelected) {      return (        <Fragment>          <NotConnectedAppMenu title="Welcome!" /> diff --git a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx index c2a9d3b18..f5372db8d 100644 --- a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx +++ b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx @@ -87,9 +87,9 @@ export enum InstancePaths {    bank_update = "/bank/:bid/update",    bank_new = "/bank/new", -  product_list = "/products", -  product_update = "/product/:pid/update", -  product_new = "/product/new", +  inventory_list = "/inventory", +  inventory_update = "/inventory/:pid/update", +  inventory_new = "/inventory/new",    order_list = "/orders",    order_new = "/order/new", @@ -347,42 +347,42 @@ export function InstanceRoutes({            onLoadError={ServerErrorRedirectTo(InstancePaths.error)}          />          {/** -         * Product pages +         * Inventory pages           */}          <Route -          path={InstancePaths.product_list} +          path={InstancePaths.inventory_list}            component={ProductListPage}            onUnauthorized={LoginPageAccessDenied}            onLoadError={ServerErrorRedirectTo(InstancePaths.server)}            onCreate={() => { -            route(InstancePaths.product_new); +            route(InstancePaths.inventory_new);            }}            onSelect={(id: string) => { -            route(InstancePaths.product_update.replace(":pid", id)); +            route(InstancePaths.inventory_update.replace(":pid", id));            }}            onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}          />          <Route -          path={InstancePaths.product_update} +          path={InstancePaths.inventory_update}            component={ProductUpdatePage}            onUnauthorized={LoginPageAccessDenied} -          onLoadError={ServerErrorRedirectTo(InstancePaths.product_list)} +          onLoadError={ServerErrorRedirectTo(InstancePaths.inventory_list)}            onConfirm={() => { -            route(InstancePaths.product_list); +            route(InstancePaths.inventory_list);            }}            onBack={() => { -            route(InstancePaths.product_list); +            route(InstancePaths.inventory_list);            }}            onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}          />          <Route -          path={InstancePaths.product_new} +          path={InstancePaths.inventory_new}            component={ProductCreatePage}            onConfirm={() => { -            route(InstancePaths.product_list); +            route(InstancePaths.inventory_list);            }}            onBack={() => { -            route(InstancePaths.product_list); +            route(InstancePaths.inventory_list);            }}          />          {/** @@ -405,7 +405,7 @@ export function InstanceRoutes({            path={InstancePaths.bank_update}            component={BankAccountUpdatePage}            onUnauthorized={LoginPageAccessDenied} -          onLoadError={ServerErrorRedirectTo(InstancePaths.product_list)} +          onLoadError={ServerErrorRedirectTo(InstancePaths.inventory_list)}            onConfirm={() => {              route(InstancePaths.bank_list);            }} diff --git a/packages/merchant-backoffice-ui/src/components/form/InputStock.tsx b/packages/merchant-backoffice-ui/src/components/form/InputStock.tsx index 012d14977..1d18685c5 100644 --- a/packages/merchant-backoffice-ui/src/components/form/InputStock.tsx +++ b/packages/merchant-backoffice-ui/src/components/form/InputStock.tsx @@ -212,10 +212,7 @@ export function InputStock<T>({                withTimestampSupport              /> -            <InputGroup<Entity> -              name="address" -              label={i18n.str`Delivery address`} -            > +            <InputGroup<Entity> name="address" label={i18n.str`Warehouse address`}>                <InputLocation name="address" />              </InputGroup>            </FormProvider> diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx index 3d5f20c85..402134096 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 } = useBackendContext() +  const { url: backendURL, resetBackend } = useBackendContext()    const { i18n } = useTranslationContext();    const kycStatus = useInstanceKYCDetails();    const needKYC = kycStatus.ok && kycStatus.data.type === "redirect"; @@ -80,7 +80,7 @@ export function Sidebar({          </div>        </div>        <div class="menu is-menu-main"> -        {isPasswordOk && instance ? ( +        {instance ? (            <Fragment>              <ul class="menu-list">                <li> @@ -94,12 +94,12 @@ export function Sidebar({                  </a>                </li>                <li> -                <a href={"/products"} class="has-icon"> +                <a href={"/inventory"} class="has-icon">                    <span class="icon">                      <i class="mdi mdi-shopping" />                    </span>                    <span class="menu-item-label"> -                    <i18n.Translate>Products</i18n.Translate> +                    <i18n.Translate>Inventory</i18n.Translate>                    </span>                  </a>                </li> @@ -243,7 +243,7 @@ export function Sidebar({                </span>              </div>            </li> -          {isPasswordOk && admin && !mimic && ( +          {admin && !mimic && (              <Fragment>                <p class="menu-label">                  <i18n.Translate>Instances</i18n.Translate> @@ -270,7 +270,7 @@ export function Sidebar({                </li>              </Fragment>            )} -          {isPasswordOk && +          {isPasswordOk ?              <li>                <a                  class="has-icon is-state-info is-hoverable" @@ -283,8 +283,21 @@ export function Sidebar({                    <i18n.Translate>Log out</i18n.Translate>                  </span>                </a> -            </li> -          } +            </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> +        }          </ul>        </div>      </aside> diff --git a/packages/merchant-backoffice-ui/src/components/menu/index.tsx b/packages/merchant-backoffice-ui/src/components/menu/index.tsx index cb318906f..b8ac2c9ab 100644 --- a/packages/merchant-backoffice-ui/src/components/menu/index.tsx +++ b/packages/merchant-backoffice-ui/src/components/menu/index.tsx @@ -30,11 +30,11 @@ function getInstanceTitle(path: string, id: string): string {        return `${id}: Orders`;      case InstancePaths.order_new:        return `${id}: New order`; -    case InstancePaths.product_list: -      return `${id}: Products`; -    case InstancePaths.product_new: +    case InstancePaths.inventory_list: +      return `${id}: Inventory`; +    case InstancePaths.inventory_new:        return `${id}: New product`; -    case InstancePaths.product_update: +    case InstancePaths.inventory_update:        return `${id}: Update product`;      case InstancePaths.reserves_new:        return `${id}: New reserve`; diff --git a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx index 8bebbd298..e91e8c876 100644 --- a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx +++ b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx @@ -146,9 +146,9 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) {          />          <InputNumber<Entity>            name="minimum_age" -          label={i18n.str`Age restricted`} +          label={i18n.str`Age restriction`}            tooltip={i18n.str`is this product restricted for customer below certain age?`} -          help={i18n.str`can be overridden by the order configuration`} +          help={i18n.str`minimum age of the buyer`}          />          <Input<Entity>            name="unit" @@ -165,7 +165,7 @@ export function ProductForm({ onSubscribe, initial, alreadyExist }: Props) {            name="stock"            label={i18n.str`Stock`}            alreadyExist={alreadyExist} -          tooltip={i18n.str`product inventory for products with finite supply (for internal use only)`} +          tooltip={i18n.str`inventory for products with finite supply (for internal use only)`}          />          <InputTaxes<Entity>            name="taxes" diff --git a/packages/merchant-backoffice-ui/src/context/backend.ts b/packages/merchant-backoffice-ui/src/context/backend.ts index 056f9a192..d4a9abd5f 100644 --- a/packages/merchant-backoffice-ui/src/context/backend.ts +++ b/packages/merchant-backoffice-ui/src/context/backend.ts @@ -20,35 +20,55 @@   */  import { createContext, h, VNode } from "preact"; -import { useContext } from "preact/hooks"; +import { useContext, useState } 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;    token?: LoginToken;    updateToken: (token: LoginToken | undefined) => void;    changeBackend: (url: string) => void; +  resetBackend: () => void;  }  const BackendContext = createContext<BackendContextType>({    url: "", +  selected: false,    token: undefined,    updateToken: () => null,    changeBackend: () => null, +  resetBackend: () => null,  }); +const BACKEND_SELECTED = buildStorageKey("backend-selected", codecForBoolean()); +  function useBackendContextState(    defaultUrl?: string,  ): BackendContextType { -  const [url, changeBackend] = useBackendURL(defaultUrl); +  const [url, changeBackend2] = useBackendURL(defaultUrl);    const [token, updateToken] = useBackendDefaultToken(); +  const {value, update} = useLocalStorage(BACKEND_SELECTED) + +  function changeBackend(s:string) { +    changeBackend2(s) +    update(true) +  } + +  function resetBackend() { +    update(false) +  }    return {      url,      token, +    selected: value ?? false,      updateToken, -    changeBackend +    changeBackend, +    resetBackend    };  } diff --git a/packages/merchant-backoffice-ui/src/declaration.d.ts b/packages/merchant-backoffice-ui/src/declaration.d.ts index c3e6ea3da..dc53e3e83 100644 --- a/packages/merchant-backoffice-ui/src/declaration.d.ts +++ b/packages/merchant-backoffice-ui/src/declaration.d.ts @@ -1327,7 +1327,7 @@ export namespace MerchantBackend {        otp_device_id: string;        // Human-readable description for the device. -      otp_description: string; +      otp_device_description: string;        // A base64-encoded key        otp_key: string; @@ -1341,7 +1341,7 @@ export namespace MerchantBackend {      interface OtpDevicePatchDetails {        // Human-readable description for the device. -      otp_description: string; +      otp_device_description: string;        // A base64-encoded key        otp_key: string | undefined; diff --git a/packages/merchant-backoffice-ui/src/hooks/index.ts b/packages/merchant-backoffice-ui/src/hooks/index.ts index ee696779f..498e4eb78 100644 --- a/packages/merchant-backoffice-ui/src/hooks/index.ts +++ b/packages/merchant-backoffice-ui/src/hooks/index.ts @@ -31,7 +31,8 @@ const calculateRootPath = () => {      typeof window !== undefined        ? window.location.origin + window.location.pathname        : "/"; -  return rootPath; + +  return rootPath.replace("webui/","");  };  const loginTokenCodec = buildCodecForObject<LoginToken>() diff --git a/packages/merchant-backoffice-ui/src/hooks/otp.ts b/packages/merchant-backoffice-ui/src/hooks/otp.ts index 3544b4881..93eefeea5 100644 --- a/packages/merchant-backoffice-ui/src/hooks/otp.ts +++ b/packages/merchant-backoffice-ui/src/hooks/otp.ts @@ -30,13 +30,13 @@ const useSWR = _useSWR as unknown as SWRHook;  const MOCKED_DEVICES: Record<string, MerchantBackend.OTP.OtpDeviceAddDetails> = {    "1": { -    otp_description: "first device", +    otp_device_description: "first device",      otp_algorithm: 1,      otp_device_id: "1",      otp_key: "123",    },    "2": { -    otp_description: "second device", +    otp_device_description: "second device",      otp_algorithm: 0,      otp_device_id: "2",      otp_key: "456", diff --git a/packages/merchant-backoffice-ui/src/hooks/product.ts b/packages/merchant-backoffice-ui/src/hooks/product.ts index 8ecaefaa6..e06ea8ed8 100644 --- a/packages/merchant-backoffice-ui/src/hooks/product.ts +++ b/packages/merchant-backoffice-ui/src/hooks/product.ts @@ -26,6 +26,9 @@ import _useSWR, { SWRHook, useSWRConfig } from "swr";  const useSWR = _useSWR as unknown as SWRHook;  export interface ProductAPI { +  getProduct: ( +    id: string,   +  ) => Promise<void>;    createProduct: (      data: MerchantBackend.Products.ProductAddDetail,    ) => Promise<void>; @@ -66,7 +69,7 @@ export function useProductAPI(): ProductAPI {        data,      }); -    return await mutateAll(/.*"\/private\/products.*/); +    return await mutateAll(/.*\/private\/products.*/);    };    const deleteProduct = async (productId: string): Promise<void> => { @@ -88,7 +91,17 @@ export function useProductAPI(): ProductAPI {      return await mutateAll(/.*"\/private\/products.*/);    }; -  return { createProduct, updateProduct, deleteProduct, lockProduct }; +  const getProduct = async ( +    productId: string, +  ): Promise<void> => { +    await request(`/private/products/${productId}`, { +      method: "GET", +    }); + +    return +  }; + +  return { createProduct, updateProduct, deleteProduct, lockProduct, getProduct };  }  export function useInstanceProducts(): HttpResponse< diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx index cbfe1d573..db73217ed 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/Table.tsx @@ -66,7 +66,7 @@ export function CardTable({            <span class="icon">              <i class="mdi mdi-shopping" />            </span> -          <i18n.Translate>Products</i18n.Translate> +          <i18n.Translate>Inventory</i18n.Translate>          </p>          <div class="card-header-icon" aria-label="more options">            <span @@ -142,7 +142,7 @@ function Table({                <i18n.Translate>Taxes</i18n.Translate>              </th>              <th> -              <i18n.Translate>Profit</i18n.Translate> +              <i18n.Translate>Sales</i18n.Translate>              </th>              <th>                <i18n.Translate>Stock</i18n.Translate> @@ -190,18 +190,21 @@ function Table({                        src={i.image ? i.image : emptyImage}                        style={{                          border: "solid black 1px", -                        width: 100, -                        height: 100, +                        maxHeight: "2em", +                        width: "auto", +                        height: "auto",                        }}                      />                    </td>                    <td +                    class="has-tooltip-right"                     +                    data-tooltip={i.description}                      onClick={() =>                        rowSelection !== i.id && rowSelectionHandler(i.id)                      }                      style={{ cursor: "pointer" }}                    > -                    {i.description} +                    {i.description.length > 30  ? i.description.substring(0, 30) + "..." : i.description}                    </td>                    <td                      onClick={() => diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx index 85c50e5ed..274a7c2ea 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx @@ -53,7 +53,7 @@ export default function ProductList({    onNotFound,  }: Props): VNode {    const result = useInstanceProducts(); -  const { deleteProduct, updateProduct } = useProductAPI(); +  const { deleteProduct, updateProduct, getProduct } = useProductAPI();    const [deleting, setDeleting] =      useState<MerchantBackend.Products.ProductDetail & WithId | null>(null);    const [notif, setNotif] = useState<Notification | undefined>(undefined); @@ -74,11 +74,61 @@ export default function ProductList({        return onNotFound();      return onLoadError(result);    } +  const [errorId, setErrorId] = useState<string | undefined>( +    undefined, +  ); + +  const [productId, setProductId] = useState<string>() +  async function testIfProductExistAndSelect(orderId: string | undefined): Promise<void> { +    if (!orderId) { +      setErrorId(i18n.str`Enter a product id`); +      return; +    } +    try { +      await getProduct(orderId); +      onSelect(orderId); +      setErrorId(undefined); +    } catch { +      setErrorId(i18n.str`product not found`); +    } +  }    return (      <section class="section is-main-section">        <NotificationCard notification={notif} /> +      <div class="level"> +        <div class="level-left"> +          <div class="level-item"> +            <div class="field has-addons"> +              <div class="control"> +                <input +                  class={errorId ? "input is-danger" : "input"} +                  type="text" +                  value={productId ?? ""} +                  onChange={(e) => setProductId(e.currentTarget.value)} +                  placeholder={i18n.str`product id`} +                /> +                {errorId && <p class="help is-danger">{errorId}</p>} +              </div> +              <span +                class="has-tooltip-bottom" +                data-tooltip={i18n.str`jump to product with the given product ID`} +              > +                <button +                  class="button" +                  onClick={(e) => testIfProductExistAndSelect(productId)} +                > +                  <span class="icon"> +                    <i class="mdi mdi-arrow-right" /> +                  </span> +                </button> +              </span> +            </div> +          </div> +        </div> +      </div> +        <CardTable          instances={result.data}          onCreate={onCreate} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx index 2201e75a5..0d2bb2c30 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/create/CreatePage.tsx @@ -19,7 +19,7 @@   * @author Sebastian Javier Marchano (sebasjm)   */ -import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { HttpError, RequestError, useApiContext, useTranslationContext } from "@gnu-taler/web-util/browser";  import { Fragment, h, VNode } from "preact";  import { StateUpdater, useEffect, useState } from "preact/hooks";  import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; @@ -35,6 +35,7 @@ import {    PAYTO_WIRE_METHOD_LOOKUP,    URL_REGEX,  } from "../../../../utils/constants.js"; +import { useBackendBaseRequest } from "../../../../hooks/backend.js";  type Entity = MerchantBackend.Rewards.ReserveCreateRequest; @@ -65,6 +66,7 @@ function ViewStep({    setReserve,  }: ViewProps): VNode {    const { i18n } = useTranslationContext(); +  const {request} = useApiContext()    const [wireMethods, setWireMethods] = useState<Array<string>>([]);    const [exchangeQueryError, setExchangeQueryError] = useState<      string | undefined @@ -123,19 +125,26 @@ function ViewStep({              <AsyncButton                class="has-tooltip-left"                onClick={() => { -                return fetch(`${reserve.exchange_url}wire`) -                  .then((r) => r.json()) +                if (!reserve.exchange_url) { +                  return Promise.resolve(); +                } +                 +                return request<any>(reserve.exchange_url, "keys") //</div>fetch(`${reserve.exchange_url}wire`)                    .then((r) => { -                    const wireMethods = r.accounts.map((a: any) => { -                      const match = PAYTO_WIRE_METHOD_LOOKUP.exec(a.payto_uri); -                      return (match && match[1]) || ""; -                    }); +                    if (r.loading) return; +                    if (r.ok) { +                      const wireMethods = r.data.accounts.map((a: any) => { +                        const match = PAYTO_WIRE_METHOD_LOOKUP.exec(a.payto_uri); +                        return (match && match[1]) || ""; +                      });                      +                    }                      setWireMethods(wireMethods);                      setCurrentStep(Steps.WIRE_METHOD);                      return;                    }) -                  .catch((r: any) => { -                    setExchangeQueryError(r.message); +                  .catch((r: RequestError<{}>) => { +                    console.log(r.cause) +                    setExchangeQueryError(r.cause.message);                    });                }}                data-tooltip={ diff --git a/packages/merchant-backoffice-ui/src/paths/instance/validators/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/validators/create/CreatePage.tsx index bdc86d226..cebc1ade6 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/validators/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/validators/create/CreatePage.tsx @@ -70,8 +70,8 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {          : state.otp_key.length !== 32            ? i18n.str`size of the key should be 32`            : undefined, -    otp_description: !state.otp_description ? i18n.str`required` -      : !/[a-zA-Z0-9]*/.test(state.otp_description) +          otp_device_description: !state.otp_device_description ? i18n.str`required` +      : !/[a-zA-Z0-9]*/.test(state.otp_device_description)          ? i18n.str`no valid. only characters and numbers`          : undefined, @@ -103,7 +103,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {                  tooltip={i18n.str`Internal id on the system`}                />                <Input<Entity> -                name="otp_description" +                name="otp_device_description"                  label={i18n.str`Descripiton`}                  tooltip={i18n.str`Useful to identify the device physically`}                /> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/validators/create/CreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/paths/instance/validators/create/CreatedSuccessfully.tsx index 22ae55677..db3842711 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/validators/create/CreatedSuccessfully.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/validators/create/CreatedSuccessfully.tsx @@ -77,7 +77,7 @@ export function CreatedSuccessfully({                <input                  class="input"                  readonly -                value={entity.otp_description} +                value={entity.otp_device_description}                />              </p>            </div> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/validators/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/UpdatePage.tsx index 585c12e11..79be9802f 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/validators/update/UpdatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/UpdatePage.tsx @@ -87,7 +87,7 @@ export function UpdatePage({ device, onUpdate, onBack }: Props): VNode {                  errors={errors}                >                  <Input<Entity> -                  name="otp_description" +                  name="otp_device_description"                    label={i18n.str`Description`}                    tooltip={i18n.str`dddd`}                  /> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/validators/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/index.tsx index 9a27ccfee..52f6c6c29 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/validators/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/validators/update/index.tsx @@ -80,7 +80,7 @@ export default function UpdateValidator({          device={{            id: vid,            otp_algorithm: result.data.otp_algorithm, -          otp_description: result.data.device_description, +          otp_device_description: result.data.device_description,            otp_key: undefined,            otp_ctr: result.data.otp_ctr          }} diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx index 9948307e4..a9e3c3a1b 100644 --- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx @@ -52,7 +52,7 @@ function cleanUp(s: string): string {  }  export function LoginPage({ onConfirm }: Props): VNode { -  const { url: backendURL, changeBackend } = useBackendContext(); +  const { url: backendURL, changeBackend, resetBackend } = useBackendContext();    const { admin, id } = useInstanceContext();    const { requestNewLoginToken } = useCredentialsChecker();    const [token, setToken] = useState(""); @@ -73,10 +73,9 @@ export function LoginPage({ onConfirm }: Props): VNode {    }, [backendURL, id, token])    async function changeServer() { -    changeBackend("") +    resetBackend()    } -  console.log(admin, id)    if (admin && id !== "default") {      //admin trying to access another instance      return (<div class="columns is-centered" style={{ margin: "auto" }}> @@ -211,10 +210,7 @@ export function LoginPage({ onConfirm }: Props): VNode {                borderTop: 0,              }}            > -            <AsyncButton - -              onClick={changeServer} -            > +            <AsyncButton onClick={changeServer}>                <i18n.Translate>Change server</i18n.Translate>              </AsyncButton> @@ -304,11 +300,8 @@ export function ConnectionPage({ onConfirm }: { onConfirm: (s: string) => void }                borderTop: 0,              }}            > -            <AsyncButton -              disabled={backendURL === url} -              onClick={doConnect} -            > -              <i18n.Translate>Try again</i18n.Translate> +            <AsyncButton onClick={doConnect}> +              <i18n.Translate>Connect</i18n.Translate>              </AsyncButton>            </footer>          </div> diff --git a/packages/merchant-backoffice-ui/src/schemas/index.ts b/packages/merchant-backoffice-ui/src/schemas/index.ts index 4be77595b..c97d41204 100644 --- a/packages/merchant-backoffice-ui/src/schemas/index.ts +++ b/packages/merchant-backoffice-ui/src/schemas/index.ts @@ -22,6 +22,7 @@  import { isAfter, isFuture } from "date-fns";  import * as yup from "yup";  import { AMOUNT_REGEX, PAYTO_REGEX } from "../utils/constants.js"; +import { Amounts } from "@gnu-taler/taler-util";  yup.setLocale({    mixed: { @@ -38,7 +39,7 @@ function listOfPayToUrisAreValid(values?: (string | undefined)[]): boolean {  }  function currencyWithAmountIsValid(value?: string): boolean { -  return !!value && AMOUNT_REGEX.test(value); +  return !!value && Amounts.parse(value) !== undefined;  }  function currencyGreaterThan0(value?: string) {    if (value) { diff --git a/packages/merchant-backoffice-ui/src/utils/constants.ts b/packages/merchant-backoffice-ui/src/utils/constants.ts index fea9cb7e2..7c4e288b3 100644 --- a/packages/merchant-backoffice-ui/src/utils/constants.ts +++ b/packages/merchant-backoffice-ui/src/utils/constants.ts @@ -25,7 +25,7 @@ export const PAYTO_REGEX =  export const PAYTO_WIRE_METHOD_LOOKUP =    /payto:\/\/([a-zA-Z][a-zA-Z0-9-.]+)\/.*/; -export const AMOUNT_REGEX = /^[a-zA-Z][a-zA-Z]*:[0-9][0-9,]*\.?[0-9,]*$/; +export const AMOUNT_REGEX = /^[a-zA-Z][a-zA-Z]{1,11}:[0-9][0-9,]*\.?[0-9,]*$/;  export const INSTANCE_ID_LOOKUP = /\/instances\/([^/]*)\/?$/; | 
