[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.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-merchant-backoffice] branch master updated: bank i18n: trying without 'useContext',
gnunet <=