gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant-backoffice] branch master updated: bank i18n: trying wit


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated: bank i18n: trying without 'useContext'
Date: Wed, 05 Jan 2022 21:07:48 +0100

This is an automated email from the git hooks/post-receive script.

ms pushed a commit to branch master
in repository merchant-backoffice.

The following commit(s) were added to refs/heads/master by this push:
     new e96a042  bank i18n: trying without 'useContext'
e96a042 is described below

commit e96a04250e110d12870044d35412a12645f41ec2
Author: ms <ms@taler.net>
AuthorDate: Wed Jan 5 21:06:34 2022 +0100

    bank i18n: trying without 'useContext'
---
 packages/bank/src/components/app.tsx               |   8 +-
 packages/bank/src/components/fields/DateInput.tsx  |  90 ------
 packages/bank/src/components/fields/EmailInput.tsx |  57 ----
 packages/bank/src/components/fields/FileInput.tsx  | 104 ------
 packages/bank/src/components/fields/ImageInput.tsx |  93 ------
 .../bank/src/components/fields/NumberInput.tsx     |  56 ----
 packages/bank/src/components/fields/TextInput.tsx  |  68 ----
 packages/bank/src/components/menu/LangSelector.tsx |  92 ------
 .../bank/src/components/menu/NavigationBar.tsx     |  79 -----
 packages/bank/src/components/menu/SideBar.tsx      |  73 -----
 packages/bank/src/components/menu/index.tsx        | 135 --------
 packages/bank/src/components/picker/DatePicker.tsx | 356 ---------------------
 .../components/picker/DurationPicker.stories.tsx   |  55 ----
 .../bank/src/components/picker/DurationPicker.tsx  | 211 ------------
 packages/bank/src/context/translation.ts           |  39 +--
 packages/bank/src/i18n/index.tsx                   | 167 +---------
 packages/bank/src/i18n/strings.ts                  |  30 +-
 packages/bank/src/pages/home/index.tsx             |  30 +-
 18 files changed, 61 insertions(+), 1682 deletions(-)

diff --git a/packages/bank/src/components/app.tsx 
b/packages/bank/src/components/app.tsx
index c111a1a..17325c0 100644
--- a/packages/bank/src/components/app.tsx
+++ b/packages/bank/src/components/app.tsx
@@ -1,14 +1,8 @@
 import { FunctionalComponent, h } from "preact";
-import { TranslationProvider } from "../context/translation";
 import { BankHome } from "../pages/home/index";
-import { Menu } from "./menu";
 
 const AppI18N: FunctionalComponent = () => {
-  return (
-    <TranslationProvider>
-      <BankHome />
-    </TranslationProvider>
-  );
+  return (<BankHome />);
 };
 
 const App = AppI18N;
diff --git a/packages/bank/src/components/fields/DateInput.tsx 
b/packages/bank/src/components/fields/DateInput.tsx
deleted file mode 100644
index 18ef899..0000000
--- a/packages/bank/src/components/fields/DateInput.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import { format, subYears } from "date-fns";
-import { h, VNode } from "preact";
-import { useLayoutEffect, useRef, useState } from "preact/hooks";
-import { DatePicker } from "../picker/DatePicker";
-
-export interface DateInputProps {
-  label: string;
-  grabFocus?: boolean;
-  tooltip?: string;
-  error?: string;
-  years?: Array<number>;
-  onConfirm?: () => void;
-  bind: [string, (x: string) => void];
-}
-
-export function DateInput(props: DateInputProps): VNode {
-  const inputRef = useRef<HTMLInputElement>(null);
-  useLayoutEffect(() => {
-    if (props.grabFocus) {
-      inputRef.current?.focus();
-    }
-  }, [props.grabFocus]);
-  const [opened, setOpened] = useState(false);
-
-  const value = props.bind[0] || "";
-  const [dirty, setDirty] = useState(false);
-  const showError = dirty && props.error;
-
-  const calendar = subYears(new Date(), 30);
-
-  return (
-    <div class="field">
-      <label class="label">
-        {props.label}
-        {props.tooltip && (
-          <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
-            <i class="mdi mdi-information" />
-          </span>
-        )}
-      </label>
-      <div class="control">
-        <div class="field has-addons">
-          <p class="control">
-            <input
-              type="text"
-              class={showError ? "input is-danger" : "input"}
-              value={value}
-              onKeyPress={(e) => {
-                if (e.key === 'Enter' && props.onConfirm) {
-                  props.onConfirm()
-                }
-              }}
-                  onInput={(e) => {
-                const text = e.currentTarget.value;
-                setDirty(true);
-                props.bind[1](text);
-              }}
-              ref={inputRef}
-            />
-          </p>
-          <p class="control">
-            <a
-              class="button"
-              onClick={() => {
-                setOpened(true);
-              }}
-            >
-              <span class="icon">
-                <i class="mdi mdi-calendar" />
-              </span>
-            </a>
-          </p>
-        </div>
-      </div>
-      <p class="help">Using the format yyyy-mm-dd</p>
-      {showError && <p class="help is-danger">{props.error}</p>}
-      <DatePicker
-        opened={opened}
-        initialDate={calendar}
-        years={props.years}
-        closeFunction={() => setOpened(false)}
-        dateReceiver={(d) => {
-          setDirty(true);
-          const v = format(d, "yyyy-MM-dd");
-          props.bind[1](v);
-        }}
-      />
-    </div>
-  );
-}
diff --git a/packages/bank/src/components/fields/EmailInput.tsx 
b/packages/bank/src/components/fields/EmailInput.tsx
deleted file mode 100644
index 4c35c06..0000000
--- a/packages/bank/src/components/fields/EmailInput.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import { h, VNode } from "preact";
-import { useLayoutEffect, useRef, useState } from "preact/hooks";
-
-export interface TextInputProps {
-  label: string;
-  grabFocus?: boolean;
-  error?: string;
-  placeholder?: string;
-  tooltip?: string;
-  onConfirm?: () => void;
-  bind: [string, (x: string) => void];
-}
-
-export function EmailInput(props: TextInputProps): VNode {
-  const inputRef = useRef<HTMLInputElement>(null);
-  useLayoutEffect(() => {
-    if (props.grabFocus) {
-      inputRef.current?.focus();
-    }
-  }, [props.grabFocus]);
-  const value = props.bind[0];
-  const [dirty, setDirty] = useState(false);
-  const showError = dirty && props.error;
-  return (
-    <div class="field">
-      <label class="label">
-        {props.label}
-        {props.tooltip && (
-          <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
-            <i class="mdi mdi-information" />
-          </span>
-        )}
-      </label>
-      <div class="control has-icons-right">
-        <input
-          value={value}
-          required
-          placeholder={props.placeholder}
-          type="email"
-          class={showError ? "input is-danger" : "input"}
-          onKeyPress={(e) => {
-            if (e.key === 'Enter' && props.onConfirm) {
-              props.onConfirm()
-            }
-          }}
-          onInput={(e) => {
-            setDirty(true);
-            props.bind[1]((e.target as HTMLInputElement).value);
-          }}
-          ref={inputRef}
-          style={{ display: "block" }}
-        />
-      </div>
-      {showError && <p class="help is-danger">{props.error}</p>}
-    </div>
-  );
-}
diff --git a/packages/bank/src/components/fields/FileInput.tsx 
b/packages/bank/src/components/fields/FileInput.tsx
deleted file mode 100644
index adf51af..0000000
--- a/packages/bank/src/components/fields/FileInput.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-import { h, VNode } from "preact";
-import { useLayoutEffect, useRef, useState } from "preact/hooks";
-
-const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
-
-export interface FileTypeContent {
-  content: string;
-  type: string;
-  name: string;
-}
-
-export interface FileInputProps {
-  label: string;
-  grabFocus?: boolean;
-  disabled?: boolean;
-  error?: string;
-  placeholder?: string;
-  tooltip?: string;
-  onChange: (v: FileTypeContent | undefined) => void;
-}
-
-export function FileInput(props: FileInputProps): VNode {
-  const inputRef = useRef<HTMLInputElement>(null);
-  useLayoutEffect(() => {
-    if (props.grabFocus) {
-      inputRef.current?.focus();
-    }
-  }, [props.grabFocus]);
-
-  const fileInputRef = useRef<HTMLInputElement>(null);
-  const [sizeError, setSizeError] = useState(false);
-  return (
-    <div class="field">
-      <label class="label">
-        <a class="button" onClick={(e) => fileInputRef.current?.click()}>
-          <div class="icon is-small ">
-            <i class="mdi mdi-folder" />
-          </div>
-          <span>
-            {props.label}
-          </span>
-        </a>
-        {props.tooltip && (
-          <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
-            <i class="mdi mdi-information" />
-          </span>
-        )}
-      </label>
-      <div class="control">
-        <input
-          ref={fileInputRef}
-          style={{ display: "none" }}
-          type="file"
-          // name={String(name)}
-          onChange={(e) => {
-            const f: FileList | null = e.currentTarget.files;
-            if (!f || f.length != 1) {
-              return props.onChange(undefined);
-            }
-            console.log(f)
-            if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
-              setSizeError(true);
-              return props.onChange(undefined);
-            }
-            setSizeError(false);
-            return f[0].arrayBuffer().then((b) => {
-              const b64 = btoa(
-                new Uint8Array(b).reduce(
-                  (data, byte) => data + String.fromCharCode(byte),
-                  "",
-                ),
-              );
-              return props.onChange({content: 
`data:${f[0].type};base64,${b64}`, name: f[0].name, type: f[0].type});
-            });
-          }}
-        />
-        {props.error && <p class="help is-danger">{props.error}</p>}
-        {sizeError && (
-          <p class="help is-danger">File should be smaller than 1 MB</p>
-        )}
-      </div>
-    </div>
-  );
-}
diff --git a/packages/bank/src/components/fields/ImageInput.tsx 
b/packages/bank/src/components/fields/ImageInput.tsx
deleted file mode 100644
index 3f8cc58..0000000
--- a/packages/bank/src/components/fields/ImageInput.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-import { h, VNode } from "preact";
-import { useLayoutEffect, useRef, useState } from "preact/hooks";
-import emptyImage from "../../assets/empty.png";
-import { TextInputProps } from "./TextInput";
-
-const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
-
-export function ImageInput(props: TextInputProps): VNode {
-  const inputRef = useRef<HTMLInputElement>(null);
-  useLayoutEffect(() => {
-    if (props.grabFocus) {
-      inputRef.current?.focus();
-    }
-  }, [props.grabFocus]);
-
-  const value = props.bind[0];
-  // const [dirty, setDirty] = useState(false)
-  const image = useRef<HTMLInputElement>(null);
-  const [sizeError, setSizeError] = useState(false);
-  function onChange(v: string): void {
-    // setDirty(true);
-    props.bind[1](v);
-  }
-  return (
-    <div class="field">
-      <label class="label">
-        {props.label}
-        {props.tooltip && (
-          <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
-            <i class="mdi mdi-information" />
-          </span>
-        )}
-      </label>
-      <div class="control">
-        <img
-          src={!value ? emptyImage : value}
-          style={{ width: 200, height: 200 }}
-          onClick={() => image.current?.click()}
-        />
-        <input
-          ref={image}
-          style={{ display: "none" }}
-          type="file"
-          name={String(name)}
-          onChange={(e) => {
-            const f: FileList | null = e.currentTarget.files;
-            if (!f || f.length != 1) {
-              return onChange(emptyImage);
-            }
-            if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
-              setSizeError(true);
-              return onChange(emptyImage);
-            }
-            setSizeError(false);
-            return f[0].arrayBuffer().then((b) => {
-              const b64 = btoa(
-                new Uint8Array(b).reduce(
-                  (data, byte) => data + String.fromCharCode(byte),
-                  "",
-                ),
-              );
-              return onChange(`data:${f[0].type};base64,${b64}` as any);
-            });
-          }}
-        />
-        {props.error && <p class="help is-danger">{props.error}</p>}
-        {sizeError && (
-          <p class="help is-danger">Image should be smaller than 1 MB</p>
-        )}
-      </div>
-    </div>
-  );
-}
diff --git a/packages/bank/src/components/fields/NumberInput.tsx 
b/packages/bank/src/components/fields/NumberInput.tsx
deleted file mode 100644
index 4856131..0000000
--- a/packages/bank/src/components/fields/NumberInput.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { h, VNode } from "preact";
-import { useLayoutEffect, useRef, useState } from "preact/hooks";
-
-export interface TextInputProps {
-  label: string;
-  grabFocus?: boolean;
-  error?: string;
-  placeholder?: string;
-  tooltip?: string;
-  onConfirm?: () => void;
-  bind: [string, (x: string) => void];
-}
-
-export function PhoneNumberInput(props: TextInputProps): VNode {
-  const inputRef = useRef<HTMLInputElement>(null);
-  useLayoutEffect(() => {
-    if (props.grabFocus) {
-      inputRef.current?.focus();
-    }
-  }, [props.grabFocus]);
-  const value = props.bind[0];
-  const [dirty, setDirty] = useState(false);
-  const showError = dirty && props.error;
-  return (
-    <div class="field">
-      <label class="label">
-        {props.label}
-        {props.tooltip && (
-          <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
-            <i class="mdi mdi-information" />
-          </span>
-        )}
-      </label>
-      <div class="control has-icons-right">
-        <input
-          value={value}
-          type="tel"
-          placeholder={props.placeholder}
-          class={showError ? "input is-danger" : "input"}
-          onKeyPress={(e) => {
-            if (e.key === 'Enter' && props.onConfirm) {
-              props.onConfirm()
-            }
-          }}
-          onInput={(e) => {
-            setDirty(true);
-            props.bind[1]((e.target as HTMLInputElement).value);
-          }}
-          ref={inputRef}
-          style={{ display: "block" }}
-        />
-      </div>
-      {showError && <p class="help is-danger">{props.error}</p>}
-    </div>
-  );
-}
diff --git a/packages/bank/src/components/fields/TextInput.tsx 
b/packages/bank/src/components/fields/TextInput.tsx
deleted file mode 100644
index 55643b4..0000000
--- a/packages/bank/src/components/fields/TextInput.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import { h, VNode } from "preact";
-import { useLayoutEffect, useRef, useState } from "preact/hooks";
-
-export interface TextInputProps {
-  inputType?: "text" | "number" | "multiline" | "password";
-  label: string;
-  grabFocus?: boolean;
-  disabled?: boolean;
-  error?: string;
-  placeholder?: string;
-  tooltip?: string;
-  onConfirm?: () => void;
-  bind: [string, (x: string) => void];
-}
-
-const TextInputType = function ({ inputType, grabFocus, ...rest }: any): VNode 
{
-  const inputRef = useRef<HTMLInputElement>(null);
-  useLayoutEffect(() => {
-    if (grabFocus) {
-      inputRef.current?.focus();
-    }
-  }, [grabFocus]);
-
-  return inputType === "multiline" ? (
-    <textarea {...rest} rows={5} ref={inputRef} style={{ height: "unset" }} />
-  ) : (
-    <input {...rest} type={inputType} ref={inputRef} />
-  );
-};
-
-export function TextInput(props: TextInputProps): VNode {
-  const value = props.bind[0];
-  const [dirty, setDirty] = useState(false);
-  const showError = dirty && props.error;
-  return (
-    <div class="field">
-      <label class="label">
-        {props.label}
-        {props.tooltip && (
-          <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
-            <i class="mdi mdi-information" />
-          </span>
-        )}
-      </label>
-      <div class="control has-icons-right">
-        <TextInputType
-          inputType={props.inputType}
-          value={value}
-          grabFocus={props.grabFocus}
-          disabled={props.disabled}
-          placeholder={props.placeholder}
-          class={showError ? "input is-danger" : "input"}
-          onKeyPress={(e: any) => {
-            if (e.key === "Enter" && props.onConfirm) {
-              props.onConfirm();
-            }
-          }}
-          onInput={(e: any) => {
-            setDirty(true);
-            props.bind[1]((e.target as HTMLInputElement).value);
-          }}
-          style={{ display: "block" }}
-        />
-      </div>
-      {showError && <p class="help is-danger">{props.error}</p>}
-    </div>
-  );
-}
diff --git a/packages/bank/src/components/menu/LangSelector.tsx 
b/packages/bank/src/components/menu/LangSelector.tsx
deleted file mode 100644
index fa22a29..0000000
--- a/packages/bank/src/components/menu/LangSelector.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import langIcon from "../../assets/icons/languageicon.svg";
-import { useTranslationContext } from "../../context/translation";
-import { strings as messages } from "../../i18n/strings";
-
-type LangsNames = {
-  [P in keyof typeof messages]: string;
-};
-
-const names: LangsNames = {
-  es: "Español [es]",
-  en: "English [en]",
-  fr: "Français [fr]",
-  de: "Deutsch [de]",
-  sv: "Svenska [sv]",
-  it: "Italiano [it]",
-};
-
-function getLangName(s: keyof LangsNames | string): string {
-  if (names[s]) return names[s];
-  return String(s);
-}
-
-export function LangSelector(): VNode {
-  const [updatingLang, setUpdatingLang] = useState(false);
-  const { lang, changeLanguage } = useTranslationContext();
-
-  return (
-    <div class="dropdown is-active ">
-      <div class="dropdown-trigger">
-        <button
-          class="button has-tooltip-left"
-          data-tooltip="change language selection"
-          aria-haspopup="true"
-          aria-controls="dropdown-menu"
-          onClick={() => setUpdatingLang(!updatingLang)}
-        >
-          <div class="icon is-small is-left">
-            <img src={langIcon} />
-          </div>
-          <span>{getLangName(lang)}</span>
-          <div class="icon is-right">
-            <i class="mdi mdi-chevron-down" />
-          </div>
-        </button>
-      </div>
-      {updatingLang && (
-        <div class="dropdown-menu" id="dropdown-menu" role="menu">
-          <div class="dropdown-content">
-            {Object.keys(messages)
-              .filter((l) => l !== lang)
-              .map((l) => (
-                <a
-                  key={l}
-                  class="dropdown-item"
-                  value={l}
-                  onClick={() => {
-                    changeLanguage(l);
-                    setUpdatingLang(false);
-                  }}
-                >
-                  {getLangName(l)}
-                </a>
-              ))}
-          </div>
-        </div>
-      )}
-    </div>
-  );
-}
diff --git a/packages/bank/src/components/menu/NavigationBar.tsx 
b/packages/bank/src/components/menu/NavigationBar.tsx
deleted file mode 100644
index b7876a4..0000000
--- a/packages/bank/src/components/menu/NavigationBar.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, VNode } from "preact";
-import logo from "../../assets/logo.jpeg";
-import { LangSelector } from "./LangSelector";
-
-interface Props {
-  onMobileMenu: () => void;
-  title: string;
-}
-
-export function NavigationBar({ onMobileMenu, title }: Props): VNode {
-  return (
-    <nav
-      class="navbar is-fixed-top"
-      role="navigation"
-      aria-label="main navigation"
-    >
-      <div class="navbar-brand">
-        <span class="navbar-item" style={{ fontSize: 24, fontWeight: 900 }}>
-          {title}
-        </span>
-        {/* <a
-          href="mailto:contact@anastasis.lu";
-          style={{ alignSelf: "center", padding: "0.5em" }}
-        >
-          Contact us
-        </a>
-        <a
-          href="https://bugs.anastasis.li/";
-          style={{ alignSelf: "center", padding: "0.5em" }}
-        >
-          Report a bug
-        </a> */}
-        {/* <a
-          role="button"
-          class="navbar-burger"
-          aria-label="menu"
-          aria-expanded="false"
-          onClick={(e) => {
-            onMobileMenu();
-            e.stopPropagation();
-          }}
-        >
-          <span aria-hidden="true" />
-          <span aria-hidden="true" />
-          <span aria-hidden="true" />
-        </a> */}
-      </div>
-
-      <div class="navbar-menu ">
-        <div class="navbar-end">
-          <div class="navbar-item" style={{ paddingTop: 4, paddingBottom: 4 }}>
-            {/* <LangSelector /> */}
-          </div>
-        </div>
-      </div>
-    </nav>
-  );
-}
diff --git a/packages/bank/src/components/menu/SideBar.tsx 
b/packages/bank/src/components/menu/SideBar.tsx
deleted file mode 100644
index d7833df..0000000
--- a/packages/bank/src/components/menu/SideBar.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, VNode } from "preact";
-import { Translate } from "../../i18n";
-
-interface Props {
-  mobile?: boolean;
-}
-
-export function Sidebar({ mobile }: Props): VNode {
-  // const config = useConfigContext();
-  const config = { version: "none" };
-  // FIXME: add replacement for __VERSION__ with the current version
-  const process = { env: { __VERSION__: "0.0.0" } };
-
-  return (
-    <aside class="aside is-placed-left is-expanded">
-      <div class="aside-tools">
-        <div class="aside-tools-label">
-          <div>
-            <b>euFin bank</b>
-          </div>
-          <div
-            class="is-size-7 has-text-right"
-            style={{ lineHeight: 0, marginTop: -10 }}
-          >
-            Version {process.env.__VERSION__} ({config.version})
-          </div>
-        </div>
-      </div>
-      <div class="menu is-menu-main">
-        <p class="menu-label">
-          <Translate>Bank menu</Translate>
-        </p>
-        <ul class="menu-list">
-          <li>
-            <div class="ml-4">
-              <span class="menu-item-label">
-                <Translate>Select option1</Translate>
-              </span>
-            </div>
-          </li>
-          <li>
-            <div class="ml-4">
-              <span class="menu-item-label">
-                <Translate>Select option2</Translate>
-              </span>
-            </div>
-          </li>
-        </ul>
-      </div>
-    </aside>
-  );
-}
diff --git a/packages/bank/src/components/menu/index.tsx 
b/packages/bank/src/components/menu/index.tsx
deleted file mode 100644
index 99d0f76..0000000
--- a/packages/bank/src/components/menu/index.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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 { ComponentChildren, Fragment, h, VNode } from "preact";
-import Match from "preact-router/match";
-import { useEffect, useState } from "preact/hooks";
-import { NavigationBar } from "./NavigationBar";
-import { Sidebar } from "./SideBar";
-
-interface MenuProps {
-  title: string;
-}
-
-function WithTitle({
-  title,
-  children,
-}: {
-  title: string;
-  children: ComponentChildren;
-}): VNode {
-  useEffect(() => {
-    document.title = `${title}`;
-  }, [title]);
-  return <Fragment>{children}</Fragment>;
-}
-
-export function Menu({ title }: MenuProps): VNode {
-  const [mobileOpen, setMobileOpen] = useState(false);
-
-  return (
-    <Match>
-      {({ path }: { path: string }) => {
-        const titleWithSubtitle = title; // title ? title : (!admin ? 
getInstanceTitle(path, instance) : getAdminTitle(path, instance))
-        return (
-          <WithTitle title={titleWithSubtitle}>
-            <div
-              class={mobileOpen ? "has-aside-mobile-expanded" : ""}
-              onClick={() => setMobileOpen(false)}
-            >
-              <NavigationBar
-                onMobileMenu={() => setMobileOpen(!mobileOpen)}
-                title={titleWithSubtitle}
-              />
-
-              <Sidebar mobile={mobileOpen} />
-            </div>
-          </WithTitle>
-        );
-      }}
-    </Match>
-  );
-}
-
-interface NotYetReadyAppMenuProps {
-  title: string;
-  onLogout?: () => void;
-}
-
-interface NotifProps {
-  notification?: Notification;
-}
-export function NotificationCard({
-  notification: n,
-}: NotifProps): VNode | null {
-  if (!n) return null;
-  return (
-    <div class="notification">
-      <div class="columns is-vcentered">
-        <div class="column is-12">
-          <article
-            class={
-              n.type === "ERROR"
-                ? "message is-danger"
-                : n.type === "WARN"
-                ? "message is-warning"
-                : "message is-info"
-            }
-          >
-            <div class="message-header">
-              <p>{n.message}</p>
-            </div>
-            {n.description && <div class="message-body">{n.description}</div>}
-          </article>
-        </div>
-      </div>
-    </div>
-  );
-}
-
-export function NotYetReadyAppMenu({
-  onLogout,
-  title,
-}: NotYetReadyAppMenuProps): VNode {
-  const [mobileOpen, setMobileOpen] = useState(false);
-
-  useEffect(() => {
-    document.title = `Taler Backoffice: ${title}`;
-  }, [title]);
-
-  return (
-    <div
-      class="has-aside-mobile-expanded"
-      // class={mobileOpen ? "has-aside-mobile-expanded" : ""}
-      onClick={() => setMobileOpen(false)}
-    >
-      <NavigationBar
-        onMobileMenu={() => setMobileOpen(!mobileOpen)}
-        title={title}
-      />
-      {onLogout && <Sidebar mobile={mobileOpen} />}
-    </div>
-  );
-}
-
-export interface Notification {
-  message: string;
-  description?: string | VNode;
-  type: MessageType;
-}
-
-export type ValueOrFunction<T> = T | ((p: T) => T);
-export type MessageType = "INFO" | "WARN" | "ERROR" | "SUCCESS";
diff --git a/packages/bank/src/components/picker/DatePicker.tsx 
b/packages/bank/src/components/picker/DatePicker.tsx
deleted file mode 100644
index d689db3..0000000
--- a/packages/bank/src/components/picker/DatePicker.tsx
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, Component } from "preact";
-
-interface Props {
-  closeFunction?: () => void;
-  dateReceiver?: (d: Date) => void;
-  initialDate?: Date;
-  years?: Array<number>;
-  opened?: boolean;
-}
-interface State {
-  displayedMonth: number;
-  displayedYear: number;
-  selectYearMode: boolean;
-  currentDate: Date;
-}
-const now = new Date();
-
-const monthArrShortFull = [
-  "January",
-  "February",
-  "March",
-  "April",
-  "May",
-  "June",
-  "July",
-  "August",
-  "September",
-  "October",
-  "November",
-  "December",
-];
-
-const monthArrShort = [
-  "Jan",
-  "Feb",
-  "Mar",
-  "Apr",
-  "May",
-  "Jun",
-  "Jul",
-  "Aug",
-  "Sep",
-  "Oct",
-  "Nov",
-  "Dec",
-];
-
-const dayArr = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
-
-const yearArr: number[] = [];
-
-// inspired by https://codepen.io/m4r1vs/pen/MOOxyE
-export class DatePicker extends Component<Props, State> {
-  closeDatePicker() {
-    this.props.closeFunction && this.props.closeFunction(); // Function gets 
passed by parent
-  }
-
-  /**
-   * Gets fired when a day gets clicked.
-   * @param {object} e The event thrown by the <span /> element clicked
-   */
-  dayClicked(e: any) {
-    const element = e.target; // the actual element clicked
-
-    if (element.innerHTML === "") return false; // don't continue if <span /> 
empty
-
-    // get date from clicked element (gets attached when rendered)
-    const date = new Date(element.getAttribute("data-value"));
-
-    // update the state
-    this.setState({ currentDate: date });
-    this.passDateToParent(date);
-  }
-
-  /**
-   * returns days in month as array
-   * @param {number} month the month to display
-   * @param {number} year the year to display
-   */
-  getDaysByMonth(month: number, year: number) {
-    const calendar = [];
-
-    const date = new Date(year, month, 1); // month to display
-
-    const firstDay = new Date(year, month, 1).getDay(); // first weekday of 
month
-    const lastDate = new Date(year, month + 1, 0).getDate(); // last date of 
month
-
-    let day: number | null = 0;
-
-    // the calendar is 7*6 fields big, so 42 loops
-    for (let i = 0; i < 42; i++) {
-      if (i >= firstDay && day !== null) day = day + 1;
-      if (day !== null && day > lastDate) day = null;
-
-      // append the calendar Array
-      calendar.push({
-        day: day === 0 || day === null ? null : day, // null or number
-        date: day === 0 || day === null ? null : new Date(year, month, day), 
// null or Date()
-        today:
-          day === now.getDate() &&
-          month === now.getMonth() &&
-          year === now.getFullYear(), // boolean
-      });
-    }
-
-    return calendar;
-  }
-
-  /**
-   * Display previous month by updating state
-   */
-  displayPrevMonth() {
-    if (this.state.displayedMonth <= 0) {
-      this.setState({
-        displayedMonth: 11,
-        displayedYear: this.state.displayedYear - 1,
-      });
-    } else {
-      this.setState({
-        displayedMonth: this.state.displayedMonth - 1,
-      });
-    }
-  }
-
-  /**
-   * Display next month by updating state
-   */
-  displayNextMonth() {
-    if (this.state.displayedMonth >= 11) {
-      this.setState({
-        displayedMonth: 0,
-        displayedYear: this.state.displayedYear + 1,
-      });
-    } else {
-      this.setState({
-        displayedMonth: this.state.displayedMonth + 1,
-      });
-    }
-  }
-
-  /**
-   * Display the selected month (gets fired when clicking on the date string)
-   */
-  displaySelectedMonth() {
-    if (this.state.selectYearMode) {
-      this.toggleYearSelector();
-    } else {
-      if (!this.state.currentDate) return false;
-      this.setState({
-        displayedMonth: this.state.currentDate.getMonth(),
-        displayedYear: this.state.currentDate.getFullYear(),
-      });
-    }
-  }
-
-  toggleYearSelector() {
-    this.setState({ selectYearMode: !this.state.selectYearMode });
-  }
-
-  changeDisplayedYear(e: any) {
-    const element = e.target;
-    this.toggleYearSelector();
-    this.setState({
-      displayedYear: parseInt(element.innerHTML, 10),
-      displayedMonth: 0,
-    });
-  }
-
-  /**
-   * Pass the selected date to parent when 'OK' is clicked
-   */
-  passSavedDateDateToParent() {
-    this.passDateToParent(this.state.currentDate);
-  }
-  passDateToParent(date: Date) {
-    if (typeof this.props.dateReceiver === "function")
-      this.props.dateReceiver(date);
-    this.closeDatePicker();
-  }
-
-  componentDidUpdate() {
-    // if (this.state.selectYearMode) {
-    //   document.getElementsByClassName('selected')[0].scrollIntoView(); // 
works in every browser incl. IE, replace with scrollIntoViewIfNeeded when 
browsers support it
-    // }
-  }
-
-  constructor(props: any) {
-    super(props);
-
-    this.closeDatePicker = this.closeDatePicker.bind(this);
-    this.dayClicked = this.dayClicked.bind(this);
-    this.displayNextMonth = this.displayNextMonth.bind(this);
-    this.displayPrevMonth = this.displayPrevMonth.bind(this);
-    this.getDaysByMonth = this.getDaysByMonth.bind(this);
-    this.changeDisplayedYear = this.changeDisplayedYear.bind(this);
-    this.passDateToParent = this.passDateToParent.bind(this);
-    this.toggleYearSelector = this.toggleYearSelector.bind(this);
-    this.displaySelectedMonth = this.displaySelectedMonth.bind(this);
-
-    const initial = props.initialDate || now;
-
-    this.state = {
-      currentDate: initial,
-      displayedMonth: initial.getMonth(),
-      displayedYear: initial.getFullYear(),
-      selectYearMode: false,
-    };
-  }
-
-  render() {
-    const {
-      currentDate,
-      displayedMonth,
-      displayedYear,
-      selectYearMode,
-    } = this.state;
-
-    return (
-      <div>
-        <div class={`datePicker ${this.props.opened && "datePicker--opened"}`}>
-          <div class="datePicker--titles">
-            <h3
-              style={{
-                color: selectYearMode
-                  ? "rgba(255,255,255,.87)"
-                  : "rgba(255,255,255,.57)",
-              }}
-              onClick={this.toggleYearSelector}
-            >
-              {currentDate.getFullYear()}
-            </h3>
-            <h2
-              style={{
-                color: !selectYearMode
-                  ? "rgba(255,255,255,.87)"
-                  : "rgba(255,255,255,.57)",
-              }}
-              onClick={this.displaySelectedMonth}
-            >
-              {dayArr[currentDate.getDay()]},{" "}
-              {monthArrShort[currentDate.getMonth()]} {currentDate.getDate()}
-            </h2>
-          </div>
-
-          {!selectYearMode && (
-            <nav>
-              <span onClick={this.displayPrevMonth} class="icon">
-                <i
-                  style={{ transform: "rotate(180deg)" }}
-                  class="mdi mdi-forward"
-                />
-              </span>
-              <h4>
-                {monthArrShortFull[displayedMonth]} {displayedYear}
-              </h4>
-              <span onClick={this.displayNextMonth} class="icon">
-                <i class="mdi mdi-forward" />
-              </span>
-            </nav>
-          )}
-
-          <div class="datePicker--scroll">
-            {!selectYearMode && (
-              <div class="datePicker--calendar">
-                <div class="datePicker--dayNames">
-                  {["S", "M", "T", "W", "T", "F", "S"].map((day, i) => (
-                    <span key={i}>{day}</span>
-                  ))}
-                </div>
-
-                <div onClick={this.dayClicked} class="datePicker--days">
-                  {/*
-                  Loop through the calendar object returned by 
getDaysByMonth().
-                */}
-
-                  {this.getDaysByMonth(
-                    this.state.displayedMonth,
-                    this.state.displayedYear,
-                  ).map((day) => {
-                    let selected = false;
-
-                    if (currentDate && day.date)
-                      selected =
-                        currentDate.toLocaleDateString() ===
-                        day.date.toLocaleDateString();
-
-                    return (
-                      <span
-                        key={day.day}
-                        class={
-                          (day.today ? "datePicker--today " : "") +
-                          (selected ? "datePicker--selected" : "")
-                        }
-                        disabled={!day.date}
-                        data-value={day.date}
-                      >
-                        {day.day}
-                      </span>
-                    );
-                  })}
-                </div>
-              </div>
-            )}
-
-            {selectYearMode && (
-              <div class="datePicker--selectYear">
-                {(this.props.years || yearArr).map((year) => (
-                  <span
-                    key={year}
-                    class={year === displayedYear ? "selected" : ""}
-                    onClick={this.changeDisplayedYear}
-                  >
-                    {year}
-                  </span>
-                ))}
-              </div>
-            )}
-          </div>
-        </div>
-
-        <div
-          class="datePicker--background"
-          onClick={this.closeDatePicker}
-          style={{
-            display: this.props.opened ? "block" : "none",
-          }}
-        />
-      </div>
-    );
-  }
-}
-
-for (let i = 2010; i <= now.getFullYear() + 10; i++) {
-  yearArr.push(i);
-}
diff --git a/packages/bank/src/components/picker/DurationPicker.stories.tsx 
b/packages/bank/src/components/picker/DurationPicker.stories.tsx
deleted file mode 100644
index 7f96cc1..0000000
--- a/packages/bank/src/components/picker/DurationPicker.stories.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, FunctionalComponent } from "preact";
-import { useState } from "preact/hooks";
-import { DurationPicker as TestedComponent } from "./DurationPicker";
-
-export default {
-  title: "Components/Picker/Duration",
-  component: TestedComponent,
-  argTypes: {
-    onCreate: { action: "onCreate" },
-    goBack: { action: "goBack" },
-  },
-};
-
-function createExample<Props>(
-  Component: FunctionalComponent<Props>,
-  props: Partial<Props>,
-) {
-  const r = (args: any) => <Component {...args} />;
-  r.args = props;
-  return r;
-}
-
-export const Example = createExample(TestedComponent, {
-  days: true,
-  minutes: true,
-  hours: true,
-  seconds: true,
-  value: 10000000,
-});
-
-export const WithState = () => {
-  const [v, s] = useState<number>(1000000);
-  return <TestedComponent value={v} onChange={s} days minutes hours seconds />;
-};
diff --git a/packages/bank/src/components/picker/DurationPicker.tsx 
b/packages/bank/src/components/picker/DurationPicker.tsx
deleted file mode 100644
index 8a1faf4..0000000
--- a/packages/bank/src/components/picker/DurationPicker.tsx
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { useTranslator } from "../../i18n";
-import "../../scss/DurationPicker.scss";
-
-export interface Props {
-  hours?: boolean;
-  minutes?: boolean;
-  seconds?: boolean;
-  days?: boolean;
-  onChange: (value: number) => void;
-  value: number;
-}
-
-// inspiration taken from https://github.com/flurmbo/react-duration-picker
-export function DurationPicker({
-  days,
-  hours,
-  minutes,
-  seconds,
-  onChange,
-  value,
-}: Props): VNode {
-  const ss = 1000;
-  const ms = ss * 60;
-  const hs = ms * 60;
-  const ds = hs * 24;
-  const i18n = useTranslator();
-
-  return (
-    <div class="rdp-picker">
-      {days && (
-        <DurationColumn
-          unit={i18n`days`}
-          max={99}
-          value={Math.floor(value / ds)}
-          onDecrease={value >= ds ? () => onChange(value - ds) : undefined}
-          onIncrease={value < 99 * ds ? () => onChange(value + ds) : undefined}
-          onChange={(diff) => onChange(value + diff * ds)}
-        />
-      )}
-      {hours && (
-        <DurationColumn
-          unit={i18n`hours`}
-          max={23}
-          min={1}
-          value={Math.floor(value / hs) % 24}
-          onDecrease={value >= hs ? () => onChange(value - hs) : undefined}
-          onIncrease={value < 99 * ds ? () => onChange(value + hs) : undefined}
-          onChange={(diff) => onChange(value + diff * hs)}
-        />
-      )}
-      {minutes && (
-        <DurationColumn
-          unit={i18n`minutes`}
-          max={59}
-          min={1}
-          value={Math.floor(value / ms) % 60}
-          onDecrease={value >= ms ? () => onChange(value - ms) : undefined}
-          onIncrease={value < 99 * ds ? () => onChange(value + ms) : undefined}
-          onChange={(diff) => onChange(value + diff * ms)}
-        />
-      )}
-      {seconds && (
-        <DurationColumn
-          unit={i18n`seconds`}
-          max={59}
-          value={Math.floor(value / ss) % 60}
-          onDecrease={value >= ss ? () => onChange(value - ss) : undefined}
-          onIncrease={value < 99 * ds ? () => onChange(value + ss) : undefined}
-          onChange={(diff) => onChange(value + diff * ss)}
-        />
-      )}
-    </div>
-  );
-}
-
-interface ColProps {
-  unit: string;
-  min?: number;
-  max: number;
-  value: number;
-  onIncrease?: () => void;
-  onDecrease?: () => void;
-  onChange?: (diff: number) => void;
-}
-
-function InputNumber({
-  initial,
-  onChange,
-}: {
-  initial: number;
-  onChange: (n: number) => void;
-}) {
-  const [value, handler] = useState<{ v: string }>({
-    v: toTwoDigitString(initial),
-  });
-
-  return (
-    <input
-      value={value.v}
-      onBlur={(e) => onChange(parseInt(value.v, 10))}
-      onInput={(e) => {
-        e.preventDefault();
-        const n = Number.parseInt(e.currentTarget.value, 10);
-        if (isNaN(n)) return handler({ v: toTwoDigitString(initial) });
-        return handler({ v: toTwoDigitString(n) });
-      }}
-      style={{
-        width: 50,
-        border: "none",
-        fontSize: "inherit",
-        background: "inherit",
-      }}
-    />
-  );
-}
-
-function DurationColumn({
-  unit,
-  min = 0,
-  max,
-  value,
-  onIncrease,
-  onDecrease,
-  onChange,
-}: ColProps): VNode {
-  const cellHeight = 35;
-  return (
-    <div class="rdp-column-container">
-      <div class="rdp-masked-div">
-        <hr class="rdp-reticule" style={{ top: cellHeight * 2 - 1 }} />
-        <hr class="rdp-reticule" style={{ top: cellHeight * 3 - 1 }} />
-
-        <div class="rdp-column" style={{ top: 0 }}>
-          <div class="rdp-cell" key={value - 2}>
-            {onDecrease && (
-              <button
-                style={{ width: "100%", textAlign: "center", margin: 5 }}
-                onClick={onDecrease}
-              >
-                <span class="icon">
-                  <i class="mdi mdi-chevron-up" />
-                </span>
-              </button>
-            )}
-          </div>
-          <div class="rdp-cell" key={value - 1}>
-            {value > min ? toTwoDigitString(value - 1) : ""}
-          </div>
-          <div class="rdp-cell rdp-center" key={value}>
-            {onChange ? (
-              <InputNumber
-                initial={value}
-                onChange={(n) => onChange(n - value)}
-              />
-            ) : (
-              toTwoDigitString(value)
-            )}
-            <div>{unit}</div>
-          </div>
-
-          <div class="rdp-cell" key={value + 1}>
-            {value < max ? toTwoDigitString(value + 1) : ""}
-          </div>
-
-          <div class="rdp-cell" key={value + 2}>
-            {onIncrease && (
-              <button
-                style={{ width: "100%", textAlign: "center", margin: 5 }}
-                onClick={onIncrease}
-              >
-                <span class="icon">
-                  <i class="mdi mdi-chevron-down" />
-                </span>
-              </button>
-            )}
-          </div>
-        </div>
-      </div>
-    </div>
-  );
-}
-
-function toTwoDigitString(n: number) {
-  if (n < 10) {
-    return `0${n}`;
-  }
-  return `${n}`;
-}
diff --git a/packages/bank/src/context/translation.ts 
b/packages/bank/src/context/translation.ts
index fb12c2e..4953cfa 100644
--- a/packages/bank/src/context/translation.ts
+++ b/packages/bank/src/context/translation.ts
@@ -20,47 +20,12 @@
  */
 
 import { createContext, h, VNode } from "preact";
-import { useContext, useEffect } from "preact/hooks";
+import { useState, useContext, useEffect } from "preact/hooks";
 import { useLang } from "../hooks";
 import * as jedLib from "jed";
 import { strings } from "../i18n/strings";
 
-interface TranslationContextType {
+export interface TranslationStateType {
   lang: string;
   handler: any;
-  changeLanguage: (lang: string) => void;
 }
-
-const initial = {
-  lang: "en",
-  handler: new jedLib.Jed(strings["en"]),
-  changeLanguage: (lang: string) => {},
-};
-
-const TranslationContext = createContext<TranslationContextType>(initial);
-export const useTranslationContext = (): TranslationContextType => initial;
-// export const useTranslationContext = (): TranslationContextType => 
useContext(TranslationContext);
-
-interface Props {
-  initial?: string;
-  children: any;
-  forceLang?: string;
-}
-
-export const TranslationProvider = ({
-  initial,
-  children,
-  forceLang,
-}: Props): VNode => {
-  const [lang, changeLanguage] = useLang(initial);
-  useEffect(() => {
-    if (forceLang) {
-      changeLanguage(forceLang);
-    }
-  });
-  const handler = new jedLib.Jed(strings[lang] || strings["en"]);
-  return h(TranslationContext.Provider, {
-    value: { lang, handler, changeLanguage },
-    children,
-  });
-};
diff --git a/packages/bank/src/i18n/index.tsx b/packages/bank/src/i18n/index.tsx
index 072d89a..c3503fa 100644
--- a/packages/bank/src/i18n/index.tsx
+++ b/packages/bank/src/i18n/index.tsx
@@ -18,18 +18,7 @@
  * Translation helpers for React components and template literals.
  */
 
-/**
- * Imports
- */
-import { ComponentChild, ComponentChildren, h, Fragment, VNode } from "preact";
-
-import { useTranslationContext } from "../context/translation";
-
-export function useTranslator() {
-
-  const ctx = useTranslationContext();
-  const jed = ctx.handler;
-
+export function useTranslator(jed: any) {
   return function str(
     stringSeq: TemplateStringsArray,
     ...values: any[]
@@ -57,157 +46,3 @@ function toI18nString(stringSeq: ReadonlyArray<string>): 
string {
   }
   return s;
 }
-
-interface TranslateSwitchProps {
-  target: number;
-  children: ComponentChildren;
-}
-
-function stringifyChildren(children: ComponentChildren): string {
-  let n = 1;
-  const ss = (children instanceof Array ? children : [children]).map((c) => {
-    if (typeof c === "string") {
-      return c;
-    }
-    return `%${n++}$s`;
-  });
-  const s = ss.join("").replace(/ +/g, " ").trim();
-  return s;
-}
-
-interface TranslateProps {
-  children: ComponentChildren;
-  /**
-   * Component that the translated element should be wrapped in.
-   * Defaults to "div".
-   */
-  wrap?: any;
-
-  /**
-   * Props to give to the wrapped component.
-   */
-  wrapProps?: any;
-}
-
-function getTranslatedChildren(
-  translation: string,
-  children: ComponentChildren,
-): ComponentChild[] {
-  const tr = translation.split(/%(\d+)\$s/);
-  const childArray = children instanceof Array ? children : [children];
-  // Merge consecutive string children.
-  const placeholderChildren = Array<ComponentChild>();
-  for (let i = 0; i < childArray.length; i++) {
-    const x = childArray[i];
-    if (x === undefined) {
-      continue;
-    } else if (typeof x === "string") {
-      continue;
-    } else {
-      placeholderChildren.push(x);
-    }
-  }
-  const result = Array<ComponentChild>();
-  for (let i = 0; i < tr.length; i++) {
-    if (i % 2 == 0) {
-      // Text
-      result.push(tr[i]);
-    } else {
-      const childIdx = Number.parseInt(tr[i], 10) - 1;
-      result.push(placeholderChildren[childIdx]);
-    }
-  }
-  return result;
-}
-
-/**
- * Translate text node children of this component.
- * If a child component might produce a text node, it must be wrapped
- * in a another non-text element.
- *
- * Example:
- * ```
- * <Translate>
- * Hello.  Your score is <span><PlayerScore player={player} /></span>
- * </Translate>
- * ```
- */
-export function Translate({ children }: TranslateProps): VNode {
-  const s = stringifyChildren(children);
-  const ctx = useTranslationContext();
-  const translation: string = ctx.handler.ngettext(s, s, 1);
-  const result = getTranslatedChildren(translation, children);
-  return <Fragment>{result}</Fragment>;
-}
-
-/**
- * Switch translation based on singular or plural based on the target prop.
- * Should only contain TranslateSingular and TransplatePlural as children.
- *
- * Example:
- * ```
- * <TranslateSwitch target={n}>
- *  <TranslateSingular>I have {n} apple.</TranslateSingular>
- *  <TranslatePlural>I have {n} apples.</TranslatePlural>
- * </TranslateSwitch>
- * ```
- */
-export function TranslateSwitch({ children, target }: TranslateSwitchProps) {
-  let singular: VNode<TranslationPluralProps> | undefined;
-  let plural: VNode<TranslationPluralProps> | undefined;
-  // const children = this.props.children;
-  if (children) {
-    (children instanceof Array ? children : [children]).forEach(
-      (child: any) => {
-        if (child.type === TranslatePlural) {
-          plural = child;
-        }
-        if (child.type === TranslateSingular) {
-          singular = child;
-        }
-      },
-    );
-  }
-  if (!singular || !plural) {
-    console.error("translation not found");
-    return h("span", {}, ["translation not found"]);
-  }
-  singular.props.target = target;
-  plural.props.target = target;
-  // We're looking up the translation based on the
-  // singular, even if we must use the plural form.
-  return singular;
-}
-
-interface TranslationPluralProps {
-  children: ComponentChildren;
-  target: number;
-}
-
-/**
- * See [[TranslateSwitch]].
- */
-export function TranslatePlural({
-  children,
-  target,
-}: TranslationPluralProps): VNode {
-  const s = stringifyChildren(children);
-  const ctx = useTranslationContext();
-  const translation = ctx.handler.ngettext(s, s, 1);
-  const result = getTranslatedChildren(translation, children);
-  return <Fragment>{result}</Fragment>;
-}
-
-/**
- * See [[TranslateSwitch]].
- */
-export function TranslateSingular({
-  children,
-  target,
-}: TranslationPluralProps): VNode {
-  const s = stringifyChildren(children);
-  const ctx = useTranslationContext();
-  const translation = ctx.handler.ngettext(s, s, target);
-  const result = getTranslatedChildren(translation, children);
-  return <Fragment>{result}</Fragment>;
-}
diff --git a/packages/bank/src/i18n/strings.ts 
b/packages/bank/src/i18n/strings.ts
index 0722b2b..fb88fe7 100644
--- a/packages/bank/src/i18n/strings.ts
+++ b/packages/bank/src/i18n/strings.ts
@@ -34,7 +34,7 @@ strings['de'] = {
         ""
       ],
       "Page has a problem:": [
-        ""
+        "Es gibt ein Problem:"
       ],
       "": {
         "domain": "messages",
@@ -45,3 +45,31 @@ strings['de'] = {
   }
 };
 
+strings['en'] = {
+  "domain": "messages",
+  "locale_data": {
+    "messages": {
+      "days": [
+        "days"
+      ],
+      "hours": [
+        "hours"
+      ],
+      "minutes": [
+        "minutes"
+      ],
+      "seconds": [
+        "seconds"
+      ],
+      "Page has a problem:": [
+        "Page has a problem:"
+      ],
+      "": {
+        "domain": "messages",
+        "plural_forms": "nplurals=2; plural=(n != 1);",
+        "lang": "en"
+      }
+    }
+  }
+};
+
diff --git a/packages/bank/src/pages/home/index.tsx 
b/packages/bank/src/pages/home/index.tsx
index 9e48b23..5f34db9 100644
--- a/packages/bank/src/pages/home/index.tsx
+++ b/packages/bank/src/pages/home/index.tsx
@@ -4,11 +4,18 @@ import { useState, useEffect, StateUpdater } from 
"preact/hooks";
 import { Buffer } from "buffer";
 import { useTranslator } from "../../i18n";
 import { QR } from "../../components/QR";
+import * as jedLib from "jed";
+import { strings } from "../../i18n/strings";
 
 /*********************************************
  * Type definitions for states and API calls. *
  *********************************************/
 
+interface LangStateType {
+  lang: string;
+  handler: any;
+}
+
 /**
  * Has the information to reach and
  * authenticate at the bank's backend.
@@ -56,7 +63,22 @@ interface AccountStateType {
  * Helpers. *
  ***********/
 
-let i18n = useTranslator();
+
+/**
+ * Trigger language change in the state.  Note: there
+ * is _no_ check on whether the new language exists.
+ */
+function changeLang(
+    lang: string,
+    langStateSetter: StateUpdater<LangStateType>
+) {
+  
+  let newLangState = {
+    lang: lang,
+    handler: new jedLib.Jed(strings[lang])
+  }
+  langStateSetter(newLangState);
+}
 
 /**
  * Craft headers with Authorization and Content-Type.
@@ -544,7 +566,11 @@ export function BankHome(): VNode {
   var [backendState, backendStateSetter] = useBackendState();
   var [pageState, pageStateSetter] = usePageState();
   var [accountState, accountStateSetter] = useAccountState();
-
+  var [langState, langStateSetter] = useState<LangStateType>({
+    lang: "en",
+    handler: new jedLib.Jed(strings["en"]),
+  });
+  let i18n = useTranslator(langState.handler);
   if (pageState.hasError) {
     return <p>{i18n`Page has a problem:`} {pageState.error}</p>;
   }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]