commit 112fccd4bad37f88d60dd8360d9607bfb67933fa parent 2f746b437e74837e63ee10ca6dabbf5ff69b31ec Author: ng <�> Date: Sun, 25 Sep 2022 15:52:42 +0200 style: 🚨 Add consistent quote style for linter + fix multiple errors Diffstat:
29 files changed, 699 insertions(+), 693 deletions(-)
diff --git a/packages/bank/package.json b/packages/bank/package.json @@ -22,7 +22,12 @@ ], "ignorePatterns": [ "build/" - ] + ], + "rules": { + "@typescript-eslint/no-explicit-any": [0], + "@typescript-eslint/ban-ts-comment": [1], + "quotes": [2, "single", {"allowTemplateLiterals": true,"avoidEscape": false}] + } }, "dependencies": { "base64-inline-loader": "1.1.1", diff --git a/packages/bank/src/components/AsyncButton.tsx b/packages/bank/src/components/AsyncButton.tsx @@ -19,10 +19,10 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { ComponentChildren, h, VNode } from "preact"; -import { useLayoutEffect, useRef } from "preact/hooks"; +import { ComponentChildren, h, VNode } from 'preact'; +import { useLayoutEffect, useRef } from 'preact/hooks'; // import { LoadingModal } from "../modal"; -import { useAsync } from "../hooks/async"; +import { useAsync } from '../hooks/async'; // import { Translate } from "../../i18n"; type Props = { @@ -57,7 +57,7 @@ export function AsyncButton({ } return ( - <span data-tooltip={rest["data-tooltip"]} style={{ marginLeft: 5 }}> + <span data-tooltip={rest['data-tooltip']} style={{ marginLeft: 5 }}> <button {...rest} ref={buttonRef} onClick={request} disabled={disabled}> {children} </button> diff --git a/packages/bank/src/components/FileButton.tsx b/packages/bank/src/components/FileButton.tsx @@ -1,5 +1,5 @@ -import { h, VNode } from "preact"; -import { useRef, useState } from "preact/hooks"; +import { h, VNode } from 'preact'; +import { useRef, useState } from 'preact/hooks'; const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024; @@ -23,7 +23,7 @@ export function FileButton(props: Props): VNode { </button> <input ref={fileInputRef} - style={{ display: "none" }} + style={{ display: 'none' }} type="file" onChange={(e) => { const f: FileList | null = e.currentTarget.files; @@ -39,7 +39,7 @@ export function FileButton(props: Props): VNode { return f[0].arrayBuffer().then((b) => { const content = new Uint8Array(b).reduce( (data, byte) => data + String.fromCharCode(byte), - "", + '', ); return props.onChange({ content, diff --git a/packages/bank/src/components/Notifications.tsx b/packages/bank/src/components/Notifications.tsx @@ -19,7 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode } from "preact"; +import { h, VNode } from 'preact'; export interface Notification { message: string; @@ -27,7 +27,7 @@ export interface Notification { type: MessageType; } -export type MessageType = "INFO" | "WARN" | "ERROR" | "SUCCESS"; +export type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS'; interface Props { notifications: Notification[]; @@ -36,16 +36,16 @@ interface Props { function messageStyle(type: MessageType): string { switch (type) { - case "INFO": - return "message is-info"; - case "WARN": - return "message is-warning"; - case "ERROR": - return "message is-danger"; - case "SUCCESS": - return "message is-success"; + case 'INFO': + return 'message is-info'; + case 'WARN': + return 'message is-warning'; + case 'ERROR': + return 'message is-danger'; + case 'SUCCESS': + return 'message is-success'; default: - return "message"; + return 'message'; } } diff --git a/packages/bank/src/components/QR.tsx b/packages/bank/src/components/QR.tsx @@ -14,14 +14,14 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { h, VNode } from "preact"; -import { useEffect, useRef } from "preact/hooks"; -import qrcode from "qrcode-generator"; +import { h, VNode } from 'preact'; +import { useEffect, useRef } from 'preact/hooks'; +import qrcode from 'qrcode-generator'; export function QR({ text }: { text: string }): VNode { const divRef = useRef<HTMLDivElement>(null); useEffect(() => { - const qr = qrcode(0, "L"); + const qr = qrcode(0, 'L'); qr.addData(text); qr.make(); if (divRef.current) @@ -33,14 +33,14 @@ export function QR({ text }: { text: string }): VNode { return ( <div style={{ - width: "100%", - display: "flex", - flexDirection: "column", - alignItems: "left", + width: '100%', + display: 'flex', + flexDirection: 'column', + alignItems: 'left', }} > <div - style={{ width: "50%", minWidth: 200, maxWidth: 300 }} + style={{ width: '50%', minWidth: 200, maxWidth: 300 }} ref={divRef} /> </div> diff --git a/packages/bank/src/components/app.tsx b/packages/bank/src/components/app.tsx @@ -1,7 +1,7 @@ -import { FunctionalComponent, h } from "preact"; -import { TranslationProvider } from "../context/translation"; -import { BankHome } from "../pages/home/index"; -import { Menu } from "./menu"; +import { FunctionalComponent, h } from 'preact'; +import { TranslationProvider } from '../context/translation'; +import { BankHome } from '../pages/home/index'; +import { Menu } from './menu'; const App: FunctionalComponent = () => { return ( diff --git a/packages/bank/src/components/fields/DateInput.tsx b/packages/bank/src/components/fields/DateInput.tsx @@ -1,7 +1,7 @@ -import { format, subYears } from "date-fns"; -import { h, VNode } from "preact"; -import { useLayoutEffect, useRef, useState } from "preact/hooks"; -import { DatePicker } from "../picker/DatePicker"; +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; @@ -22,7 +22,7 @@ export function DateInput(props: DateInputProps): VNode { }, [props.grabFocus]); const [opened, setOpened] = useState(false); - const value = props.bind[0] || ""; + const value = props.bind[0] || ''; const [dirty, setDirty] = useState(false); const showError = dirty && props.error; @@ -43,7 +43,7 @@ export function DateInput(props: DateInputProps): VNode { <p class="control"> <input type="text" - class={showError ? "input is-danger" : "input"} + class={showError ? 'input is-danger' : 'input'} value={value} onKeyPress={(e) => { if (e.key === 'Enter' && props.onConfirm) { @@ -81,7 +81,7 @@ export function DateInput(props: DateInputProps): VNode { closeFunction={() => setOpened(false)} dateReceiver={(d) => { setDirty(true); - const v = format(d, "yyyy-MM-dd"); + const v = format(d, 'yyyy-MM-dd'); props.bind[1](v); }} /> diff --git a/packages/bank/src/components/fields/EmailInput.tsx b/packages/bank/src/components/fields/EmailInput.tsx @@ -1,5 +1,5 @@ -import { h, VNode } from "preact"; -import { useLayoutEffect, useRef, useState } from "preact/hooks"; +import { h, VNode } from 'preact'; +import { useLayoutEffect, useRef, useState } from 'preact/hooks'; export interface TextInputProps { label: string; @@ -37,7 +37,7 @@ export function EmailInput(props: TextInputProps): VNode { required placeholder={props.placeholder} type="email" - class={showError ? "input is-danger" : "input"} + class={showError ? 'input is-danger' : 'input'} onKeyPress={(e) => { if (e.key === 'Enter' && props.onConfirm) { props.onConfirm() @@ -48,7 +48,7 @@ export function EmailInput(props: TextInputProps): VNode { props.bind[1]((e.target as HTMLInputElement).value); }} ref={inputRef} - style={{ display: "block" }} + style={{ display: 'block' }} /> </div> {showError && <p class="help is-danger">{props.error}</p>} diff --git a/packages/bank/src/components/fields/FileInput.tsx b/packages/bank/src/components/fields/FileInput.tsx @@ -18,8 +18,8 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode } from "preact"; -import { useLayoutEffect, useRef, useState } from "preact/hooks"; +import { h, VNode } from 'preact'; +import { useLayoutEffect, useRef, useState } from 'preact/hooks'; const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024; @@ -69,7 +69,7 @@ export function FileInput(props: FileInputProps): VNode { <div class="control"> <input ref={fileInputRef} - style={{ display: "none" }} + style={{ display: 'none' }} type="file" // name={String(name)} onChange={(e) => { @@ -87,7 +87,7 @@ export function FileInput(props: FileInputProps): VNode { 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}); diff --git a/packages/bank/src/components/fields/ImageInput.tsx b/packages/bank/src/components/fields/ImageInput.tsx @@ -18,10 +18,10 @@ * * @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"; +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; @@ -59,7 +59,7 @@ export function ImageInput(props: TextInputProps): VNode { /> <input ref={image} - style={{ display: "none" }} + style={{ display: 'none' }} type="file" name={String(name)} onChange={(e) => { @@ -76,7 +76,7 @@ export function ImageInput(props: TextInputProps): VNode { const b64 = btoa( new Uint8Array(b).reduce( (data, byte) => data + String.fromCharCode(byte), - "", + '', ), ); return onChange(`data:${f[0].type};base64,${b64}` as any); diff --git a/packages/bank/src/components/fields/NumberInput.tsx b/packages/bank/src/components/fields/NumberInput.tsx @@ -1,5 +1,5 @@ -import { h, VNode } from "preact"; -import { useLayoutEffect, useRef, useState } from "preact/hooks"; +import { h, VNode } from 'preact'; +import { useLayoutEffect, useRef, useState } from 'preact/hooks'; export interface TextInputProps { label: string; @@ -36,7 +36,7 @@ export function PhoneNumberInput(props: TextInputProps): VNode { value={value} type="tel" placeholder={props.placeholder} - class={showError ? "input is-danger" : "input"} + class={showError ? 'input is-danger' : 'input'} onKeyPress={(e) => { if (e.key === 'Enter' && props.onConfirm) { props.onConfirm() @@ -47,7 +47,7 @@ export function PhoneNumberInput(props: TextInputProps): VNode { props.bind[1]((e.target as HTMLInputElement).value); }} ref={inputRef} - style={{ display: "block" }} + style={{ display: 'block' }} /> </div> {showError && <p class="help is-danger">{props.error}</p>} diff --git a/packages/bank/src/components/fields/TextInput.tsx b/packages/bank/src/components/fields/TextInput.tsx @@ -1,8 +1,8 @@ -import { h, VNode } from "preact"; -import { useLayoutEffect, useRef, useState } from "preact/hooks"; +import { h, VNode } from 'preact'; +import { useLayoutEffect, useRef, useState } from 'preact/hooks'; export interface TextInputProps { - inputType?: "text" | "number" | "multiline" | "password"; + inputType?: 'text' | 'number' | 'multiline' | 'password'; label: string; grabFocus?: boolean; disabled?: boolean; @@ -21,8 +21,8 @@ const TextInputType = function ({ inputType, grabFocus, ...rest }: any): VNode { } }, [grabFocus]); - return inputType === "multiline" ? ( - <textarea {...rest} rows={5} ref={inputRef} style={{ height: "unset" }} /> + return inputType === 'multiline' ? ( + <textarea {...rest} rows={5} ref={inputRef} style={{ height: 'unset' }} /> ) : ( <input {...rest} type={inputType} ref={inputRef} /> ); @@ -49,9 +49,9 @@ export function TextInput(props: TextInputProps): VNode { grabFocus={props.grabFocus} disabled={props.disabled} placeholder={props.placeholder} - class={showError ? "input is-danger" : "input"} + class={showError ? 'input is-danger' : 'input'} onKeyPress={(e: any) => { - if (e.key === "Enter" && props.onConfirm) { + if (e.key === 'Enter' && props.onConfirm) { props.onConfirm(); } }} @@ -59,7 +59,7 @@ export function TextInput(props: TextInputProps): VNode { setDirty(true); props.bind[1]((e.target as HTMLInputElement).value); }} - style={{ display: "block" }} + style={{ display: 'block' }} /> </div> {showError && <p class="help is-danger">{props.error}</p>} diff --git a/packages/bank/src/components/menu/LangSelector.tsx b/packages/bank/src/components/menu/LangSelector.tsx @@ -19,23 +19,23 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode, Fragment } 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"; +import { h, VNode, Fragment } 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]", + 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 { @@ -55,7 +55,7 @@ export function LangSelectorLikePy(): VNode { <div class="nav" style="position: absolute; background: #0042b2; max-height: 60vh; overflow-y: scroll"> - <br></br> + <br /> {Object.keys(messages) .filter((l) => l !== lang) .map((l) => ( @@ -70,7 +70,7 @@ export function LangSelectorLikePy(): VNode { {getLangName(l)} </a> ))} - <br></br> + <br /> </div> </div> </Fragment> diff --git a/packages/bank/src/components/menu/NavigationBar.tsx b/packages/bank/src/components/menu/NavigationBar.tsx @@ -19,9 +19,9 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode } from "preact"; -import logo from "../../assets/logo.jpeg"; -import { LangSelector } from "./LangSelector"; +import { h, VNode } from 'preact'; +import logo from '../../assets/logo.jpeg'; +import { LangSelector } from './LangSelector'; interface Props { onMobileMenu: () => void; diff --git a/packages/bank/src/components/menu/SideBar.tsx b/packages/bank/src/components/menu/SideBar.tsx @@ -19,8 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode } from "preact"; -import { Translate } from "../../i18n"; +import { h, VNode } from 'preact'; +import { Translate } from '../../i18n'; interface Props { mobile?: boolean; @@ -28,9 +28,9 @@ interface Props { export function Sidebar({ mobile }: Props): VNode { // const config = useConfigContext(); - const config = { version: "none" }; + const config = { version: 'none' }; // FIXME: add replacement for __VERSION__ with the current version - const process = { env: { __VERSION__: "0.0.0" } }; + const process = { env: { __VERSION__: '0.0.0' } }; return ( <aside class="aside is-placed-left is-expanded"> diff --git a/packages/bank/src/components/menu/index.tsx b/packages/bank/src/components/menu/index.tsx @@ -14,11 +14,11 @@ 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"; +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; @@ -47,7 +47,7 @@ export function Menu({ title }: MenuProps): VNode { return ( <WithTitle title={titleWithSubtitle}> <div - class={mobileOpen ? "has-aside-mobile-expanded" : ""} + class={mobileOpen ? 'has-aside-mobile-expanded' : ''} onClick={() => setMobileOpen(false)} > <NavigationBar @@ -82,11 +82,11 @@ export function NotificationCard({ <div class="column is-12"> <article class={ - n.type === "ERROR" - ? "message is-danger" - : n.type === "WARN" - ? "message is-warning" - : "message is-info" + n.type === 'ERROR' + ? 'message is-danger' + : n.type === 'WARN' + ? 'message is-warning' + : 'message is-info' } > <div class="message-header"> @@ -132,4 +132,4 @@ export interface Notification { } export type ValueOrFunction<T> = T | ((p: T) => T); -export type MessageType = "INFO" | "WARN" | "ERROR" | "SUCCESS"; +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 @@ -19,7 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, Component } from "preact"; +import { h, Component } from 'preact'; interface Props { closeFunction?: () => void; @@ -37,36 +37,36 @@ interface State { const now = new Date(); const monthArrShortFull = [ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", + '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", + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', ]; -const dayArr = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; +const dayArr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; const yearArr: number[] = []; @@ -83,10 +83,10 @@ export class DatePicker extends Component<Props, State> { dayClicked(e: any) { const element = e.target; // the actual element clicked - if (element.innerHTML === "") return false; // don't continue if <span /> empty + 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")); + const date = new Date(element.getAttribute('data-value')); // update the state this.setState({ currentDate: date }); @@ -194,7 +194,7 @@ export class DatePicker extends Component<Props, State> { this.passDateToParent(this.state.currentDate); } passDateToParent(date: Date) { - if (typeof this.props.dateReceiver === "function") + if (typeof this.props.dateReceiver === 'function') this.props.dateReceiver(date); this.closeDatePicker(); } @@ -238,13 +238,13 @@ export class DatePicker extends Component<Props, State> { return ( <div> - <div class={`datePicker ${this.props.opened && "datePicker--opened"}`}> + <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)", + ? 'rgba(255,255,255,.87)' + : 'rgba(255,255,255,.57)', }} onClick={this.toggleYearSelector} > @@ -253,12 +253,12 @@ export class DatePicker extends Component<Props, State> { <h2 style={{ color: !selectYearMode - ? "rgba(255,255,255,.87)" - : "rgba(255,255,255,.57)", + ? 'rgba(255,255,255,.87)' + : 'rgba(255,255,255,.57)', }} onClick={this.displaySelectedMonth} > - {dayArr[currentDate.getDay()]},{" "} + {dayArr[currentDate.getDay()]},{' '} {monthArrShort[currentDate.getMonth()]} {currentDate.getDate()} </h2> </div> @@ -267,7 +267,7 @@ export class DatePicker extends Component<Props, State> { <nav> <span onClick={this.displayPrevMonth} class="icon"> <i - style={{ transform: "rotate(180deg)" }} + style={{ transform: 'rotate(180deg)' }} class="mdi mdi-forward" /> </span> @@ -284,7 +284,7 @@ export class DatePicker extends Component<Props, State> { {!selectYearMode && ( <div class="datePicker--calendar"> <div class="datePicker--dayNames"> - {["S", "M", "T", "W", "T", "F", "S"].map((day, i) => ( + {['S', 'M', 'T', 'W', 'T', 'F', 'S'].map((day, i) => ( <span key={i}>{day}</span> ))} </div> @@ -309,8 +309,8 @@ export class DatePicker extends Component<Props, State> { <span key={day.day} class={ - (day.today ? "datePicker--today " : "") + - (selected ? "datePicker--selected" : "") + (day.today ? 'datePicker--today ' : '') + + (selected ? 'datePicker--selected' : '') } disabled={!day.date} data-value={day.date} @@ -328,7 +328,7 @@ export class DatePicker extends Component<Props, State> { {(this.props.years || yearArr).map((year) => ( <span key={year} - class={year === displayedYear ? "selected" : ""} + class={year === displayedYear ? 'selected' : ''} onClick={this.changeDisplayedYear} > {year} @@ -343,7 +343,7 @@ export class DatePicker extends Component<Props, State> { class="datePicker--background" onClick={this.closeDatePicker} style={{ - display: this.props.opened ? "block" : "none", + display: this.props.opened ? 'block' : 'none', }} /> </div> diff --git a/packages/bank/src/components/picker/DurationPicker.stories.tsx b/packages/bank/src/components/picker/DurationPicker.stories.tsx @@ -19,16 +19,16 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, FunctionalComponent } from "preact"; -import { useState } from "preact/hooks"; -import { DurationPicker as TestedComponent } from "./DurationPicker"; +import { h, FunctionalComponent } from 'preact'; +import { useState } from 'preact/hooks'; +import { DurationPicker as TestedComponent } from './DurationPicker'; export default { - title: "Components/Picker/Duration", + title: 'Components/Picker/Duration', component: TestedComponent, argTypes: { - onCreate: { action: "onCreate" }, - goBack: { action: "goBack" }, + onCreate: { action: 'onCreate' }, + goBack: { action: 'goBack' }, }, }; diff --git a/packages/bank/src/components/picker/DurationPicker.tsx b/packages/bank/src/components/picker/DurationPicker.tsx @@ -19,10 +19,10 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode } from "preact"; -import { useState } from "preact/hooks"; -import { useTranslator } from "../../i18n"; -import "../../scss/DurationPicker.scss"; +import { h, VNode } from 'preact'; +import { useState } from 'preact/hooks'; +import { useTranslator } from '../../i18n'; +import '../../scss/DurationPicker.scss'; export interface Props { hours?: boolean; @@ -129,9 +129,9 @@ function InputNumber({ }} style={{ width: 50, - border: "none", - fontSize: "inherit", - background: "inherit", + border: 'none', + fontSize: 'inherit', + background: 'inherit', }} /> ); @@ -157,7 +157,7 @@ function DurationColumn({ <div class="rdp-cell" key={value - 2}> {onDecrease && ( <button - style={{ width: "100%", textAlign: "center", margin: 5 }} + style={{ width: '100%', textAlign: 'center', margin: 5 }} onClick={onDecrease} > <span class="icon"> @@ -167,7 +167,7 @@ function DurationColumn({ )} </div> <div class="rdp-cell" key={value - 1}> - {value > min ? toTwoDigitString(value - 1) : ""} + {value > min ? toTwoDigitString(value - 1) : ''} </div> <div class="rdp-cell rdp-center" key={value}> {onChange ? ( @@ -182,13 +182,13 @@ function DurationColumn({ </div> <div class="rdp-cell" key={value + 1}> - {value < max ? toTwoDigitString(value + 1) : ""} + {value < max ? toTwoDigitString(value + 1) : ''} </div> <div class="rdp-cell" key={value + 2}> {onIncrease && ( <button - style={{ width: "100%", textAlign: "center", margin: 5 }} + style={{ width: '100%', textAlign: 'center', margin: 5 }} onClick={onIncrease} > <span class="icon"> diff --git a/packages/bank/src/context/translation.ts b/packages/bank/src/context/translation.ts @@ -19,11 +19,11 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { createContext, h, VNode } from "preact"; -import { useContext, useEffect } from "preact/hooks"; -import { useLang } from "../hooks"; -import * as jedLib from "jed"; -import { strings } from "../i18n/strings"; +import { createContext, h, VNode } from 'preact'; +import { useContext, useEffect } from 'preact/hooks'; +import { useLang } from '../hooks'; +import * as jedLib from 'jed'; +import { strings } from '../i18n/strings'; interface Type { lang: string; @@ -31,7 +31,7 @@ interface Type { changeLanguage: (l: string) => void; } const initial = { - lang: "en", + lang: 'en', handler: null, changeLanguage: () => { /** @@ -62,8 +62,8 @@ export const TranslationProvider = ({ changeLanguage(forceLang); } }); - console.log("lang store", strings); - const handler = new jedLib.Jed(strings[lang] || strings["en"]); + console.log('lang store', strings); + const handler = new jedLib.Jed(strings[lang] || strings['en']); return h(Context.Provider, { value: { lang, handler, changeLanguage }, children, diff --git a/packages/bank/src/declaration.d.ts b/packages/bank/src/declaration.d.ts @@ -1,20 +1,20 @@ -declare module "*.css" { +declare module '*.css' { const mapping: Record<string, string>; export default mapping; } -declare module "*.svg" { +declare module '*.svg' { const content: any; export default content; } -declare module "*.jpeg" { +declare module '*.jpeg' { const content: any; export default content; } -declare module "*.png" { +declare module '*.png' { const content: any; export default content; } -declare module "jed" { +declare module 'jed' { const x: any; export = x; } diff --git a/packages/bank/src/hooks/async.ts b/packages/bank/src/hooks/async.ts @@ -18,7 +18,7 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { useState } from "preact/hooks"; +import { useState } from 'preact/hooks'; // import { cancelPendingRequest } from "./backend"; export interface Options { @@ -51,9 +51,9 @@ export function useAsync<T>( }, tooLong); try { - console.log("calling async", args); + console.log('calling async', args); const result = await fn(...args); - console.log("async back", result); + console.log('async back', result); setData(result); } catch (error) { setError(error); diff --git a/packages/bank/src/hooks/index.ts b/packages/bank/src/hooks/index.ts @@ -19,14 +19,14 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { StateUpdater, useState } from "preact/hooks"; +import { StateUpdater, useState } from 'preact/hooks'; export type ValueOrFunction<T> = T | ((p: T) => T); const calculateRootPath = () => { const rootPath = typeof window !== undefined ? window.location.origin + window.location.pathname - : "/"; + : '/'; return rootPath; }; @@ -34,14 +34,14 @@ export function useBackendURL( url?: string, ): [string, boolean, StateUpdater<string>, () => void] { const [value, setter] = useNotNullLocalStorage( - "backend-url", + 'backend-url', url || calculateRootPath(), ); - const [triedToLog, setTriedToLog] = useLocalStorage("tried-login"); + const [triedToLog, setTriedToLog] = useLocalStorage('tried-login'); const checkedSetter = (v: ValueOrFunction<string>) => { - setTriedToLog("yes"); - return setter((p) => (v instanceof Function ? v(p) : v).replace(/\/$/, "")); + setTriedToLog('yes'); + return setter((p) => (v instanceof Function ? v(p) : v).replace(/\/$/, '')); }; const resetBackend = () => { @@ -54,7 +54,7 @@ export function useBackendDefaultToken(): [ string | undefined, StateUpdater<string | undefined>, ] { - return useLocalStorage("backend-token"); + return useLocalStorage('backend-token'); } export function useBackendInstanceToken( @@ -64,7 +64,7 @@ export function useBackendInstanceToken( const [defaultToken, defaultSetToken] = useBackendDefaultToken(); // instance named 'default' use the default token - if (id === "default") { + if (id === 'default') { return [defaultToken, defaultSetToken]; } return [token, setToken]; @@ -72,11 +72,11 @@ export function useBackendInstanceToken( export function useLang(initial?: string): [string, StateUpdater<string>] { const browserLang = - typeof window !== "undefined" + typeof window !== 'undefined' ? navigator.language || (navigator as any).userLanguage : undefined; - const defaultLang = (browserLang || initial || "en").substring(0, 2); - return useNotNullLocalStorage("lang-preference", defaultLang); + const defaultLang = (browserLang || initial || 'en').substring(0, 2); + return useNotNullLocalStorage('lang-preference', defaultLang); } export function useLocalStorage( @@ -86,7 +86,7 @@ export function useLocalStorage( const [storedValue, setStoredValue] = useState<string | undefined>((): | string | undefined => { - return typeof window !== "undefined" + return typeof window !== 'undefined' ? window.localStorage.getItem(key) || initialValue : initialValue; }); @@ -96,7 +96,7 @@ export function useLocalStorage( ) => { setStoredValue((p) => { const toStore = value instanceof Function ? value(p) : value; - if (typeof window !== "undefined") { + if (typeof window !== 'undefined') { if (!toStore) { window.localStorage.removeItem(key); } else { @@ -115,7 +115,7 @@ export function useNotNullLocalStorage( initialValue: string, ): [string, StateUpdater<string>] { const [storedValue, setStoredValue] = useState<string>((): string => { - return typeof window !== "undefined" + return typeof window !== 'undefined' ? window.localStorage.getItem(key) || initialValue : initialValue; }); @@ -123,7 +123,7 @@ export function useNotNullLocalStorage( const setValue = (value: string | ((val: string) => string)) => { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); - if (typeof window !== "undefined") { + if (typeof window !== 'undefined') { if (!valueToStore) { window.localStorage.removeItem(key); } else { diff --git a/packages/bank/src/i18n/index.tsx b/packages/bank/src/i18n/index.tsx @@ -21,9 +21,9 @@ /** * Imports */ -import { ComponentChild, ComponentChildren, h, Fragment, VNode } from "preact"; +import { ComponentChild, ComponentChildren, h, Fragment, VNode } from 'preact'; -import { useTranslationContext } from "../context/translation"; +import { useTranslationContext } from '../context/translation'; export function useTranslator() { const ctx = useTranslationContext(); @@ -46,7 +46,7 @@ export function useTranslator() { * Convert template strings to a msgid */ function toI18nString(stringSeq: ReadonlyArray<string>): string { - let s = ""; + let s = ''; for (let i = 0; i < stringSeq.length; i++) { s += stringSeq[i]; if (i < stringSeq.length - 1) { @@ -64,12 +64,12 @@ interface TranslateSwitchProps { function stringifyChildren(children: ComponentChildren): string { let n = 1; const ss = (children instanceof Array ? children : [children]).map((c) => { - if (typeof c === "string") { + if (typeof c === 'string') { return c; } return `%${n++}$s`; }); - const s = ss.join("").replace(/ +/g, " ").trim(); + const s = ss.join('').replace(/ +/g, ' ').trim(); return s; } @@ -99,7 +99,7 @@ function getTranslatedChildren( const x = childArray[i]; if (x === undefined) { continue; - } else if (typeof x === "string") { + } else if (typeof x === 'string') { continue; } else { placeholderChildren.push(x); @@ -167,8 +167,8 @@ export function TranslateSwitch({ children, target }: TranslateSwitchProps) { ); } if (!singular || !plural) { - console.error("translation not found"); - return h("span", {}, ["translation not found"]); + console.error('translation not found'); + return h('span', {}, ['translation not found']); } singular.props.target = target; plural.props.target = target; diff --git a/packages/bank/src/i18n/strings.ts b/packages/bank/src/i18n/strings.ts @@ -18,453 +18,453 @@ export const strings: {[s: string]: any} = {}; strings['de'] = { - "domain": "messages", - "locale_data": { - "messages": { - "days": [ - "" + 'domain': 'messages', + 'locale_data': { + 'messages': { + 'days': [ + '' ], - "hours": [ - "" + 'hours': [ + '' ], - "minutes": [ - "" + 'minutes': [ + '' ], - "seconds": [ - "" + 'seconds': [ + '' ], - "Clear": [ - "" + 'Clear': [ + '' ], - "Logout": [ - "" + 'Logout': [ + '' ], - "Demo Bank": [ - "" + 'Demo Bank': [ + '' ], - "Go back": [ - "" + 'Go back': [ + '' ], - "Wire transfer": [ - "" + 'Wire transfer': [ + '' ], - "Transfer money to another account of this bank:": [ - "" + 'Transfer money to another account of this bank:': [ + '' ], - "Want to try the raw payto://-format?": [ - "" + 'Want to try the raw payto://-format?': [ + '' ], - "Transfer money via the Payto system:": [ - "" + 'Transfer money via the Payto system:': [ + '' ], - "payto address": [ - "" + 'payto address': [ + '' ], - "Confirm": [ - "" + 'Confirm': [ + '' ], - "Confirm Withdrawal": [ - "" + 'Confirm Withdrawal': [ + '' ], - "Waiting the bank to create the operaion...": [ - "" + 'Waiting the bank to create the operaion...': [ + '' ], - "This withdrawal was aborted!": [ - "" + 'This withdrawal was aborted!': [ + '' ], - "Withdraw to a Taler Wallet": [ - "" + 'Withdraw to a Taler Wallet': [ + '' ], - "You can use this QR code to withdraw to your mobile wallet:": [ - "" + 'You can use this QR code to withdraw to your mobile wallet:': [ + '' ], - "this link": [ - "" + 'this link': [ + '' ], - "Abort": [ - "" + 'Abort': [ + '' ], - "Start withdrawal": [ - "" + 'Start withdrawal': [ + '' ], - "Withdraw Money into a Taler wallet": [ - "" + 'Withdraw Money into a Taler wallet': [ + '' ], - "Amount to withdraw": [ - "" + 'Amount to withdraw': [ + '' ], - "Please login!": [ - "" + 'Please login!': [ + '' ], - "Login": [ - "" + 'Login': [ + '' ], - "Register to the euFin bank!": [ - "" + 'Register to the euFin bank!': [ + '' ], - "Registration form": [ - "" + 'Registration form': [ + '' ], - "Register": [ - "" + 'Register': [ + '' ], - "Date": [ - "" + 'Date': [ + '' ], - "Amount": [ - "" + 'Amount': [ + '' ], - "Counterpart": [ - "" + 'Counterpart': [ + '' ], - "Subject": [ - "" + 'Subject': [ + '' ], - "Username or account label '%1$s' not found. Won't login.": [ - "" + 'Username or account label \'%1$s\' not found. Won\'t login.': [ + '' ], - "Wrong credentials given.": [ - "" + 'Wrong credentials given.': [ + '' ], - "Account information could not be retrieved.": [ - "" + 'Account information could not be retrieved.': [ + '' ], - "Close wire transfer": [ - "" + 'Close wire transfer': [ + '' ], - "Close Taler withdrawal": [ - "" + 'Close Taler withdrawal': [ + '' ], - "Bank account balance:": [ - "" + 'Bank account balance:': [ + '' ], - "Latest transactions:": [ - "" + 'Latest transactions:': [ + '' ], - "Transfer money manually": [ - "" + 'Transfer money manually': [ + '' ], - "List of public accounts was not found.": [ - "" + 'List of public accounts was not found.': [ + '' ], - "List of public accounts could not be retrieved.": [ - "" + 'List of public accounts could not be retrieved.': [ + '' ], - "History of public accounts": [ - "" + 'History of public accounts': [ + '' ], - "Page has a problem: logged in but backend state is lost.": [ - "" + 'Page has a problem: logged in but backend state is lost.': [ + '' ], - "Welcome to the euFin bank!": [ - "" + 'Welcome to the euFin bank!': [ + '' ], - "": { - "domain": "messages", - "plural_forms": "nplurals=2; plural=(n != 1);", - "lang": "de" + '': { + 'domain': 'messages', + 'plural_forms': 'nplurals=2; plural=(n != 1);', + 'lang': 'de' } } } }; strings['en'] = { - "domain": "messages", - "locale_data": { - "messages": { - "days": [ - "days" + 'domain': 'messages', + 'locale_data': { + 'messages': { + 'days': [ + 'days' ], - "hours": [ - "hours" + 'hours': [ + 'hours' ], - "minutes": [ - "minutes" + 'minutes': [ + 'minutes' ], - "seconds": [ - "seconds" + 'seconds': [ + 'seconds' ], - "Clear": [ - "" + 'Clear': [ + '' ], - "Logout": [ - "" + 'Logout': [ + '' ], - "Demo Bank": [ - "" + 'Demo Bank': [ + '' ], - "Go back": [ - "Go back" + 'Go back': [ + 'Go back' ], - "Wire transfer": [ - "" + 'Wire transfer': [ + '' ], - "Transfer money to another account of this bank:": [ - "" + 'Transfer money to another account of this bank:': [ + '' ], - "Want to try the raw payto://-format?": [ - "" + 'Want to try the raw payto://-format?': [ + '' ], - "Transfer money via the Payto system:": [ - "" + 'Transfer money via the Payto system:': [ + '' ], - "payto address": [ - "" + 'payto address': [ + '' ], - "Confirm": [ - "" + 'Confirm': [ + '' ], - "Confirm Withdrawal": [ - "Confirm withdrawal" + 'Confirm Withdrawal': [ + 'Confirm withdrawal' ], - "Waiting the bank to create the operaion...": [ - "" + 'Waiting the bank to create the operaion...': [ + '' ], - "This withdrawal was aborted!": [ - "" + 'This withdrawal was aborted!': [ + '' ], - "Withdraw to a Taler Wallet": [ - "Charge Taler wallet" + 'Withdraw to a Taler Wallet': [ + 'Charge Taler wallet' ], - "You can use this QR code to withdraw to your mobile wallet:": [ - "" + 'You can use this QR code to withdraw to your mobile wallet:': [ + '' ], - "this link": [ - "" + 'this link': [ + '' ], - "Abort": [ - "" + 'Abort': [ + '' ], - "Start withdrawal": [ - "Start withdrawal" + 'Start withdrawal': [ + 'Start withdrawal' ], - "Withdraw Money into a Taler wallet": [ - "Charge Taler wallet" + 'Withdraw Money into a Taler wallet': [ + 'Charge Taler wallet' ], - "Amount to withdraw": [ - "Amount to withdraw" + 'Amount to withdraw': [ + 'Amount to withdraw' ], - "Please login!": [ - "" + 'Please login!': [ + '' ], - "Login": [ - "" + 'Login': [ + '' ], - "Register to the euFin bank!": [ - "" + 'Register to the euFin bank!': [ + '' ], - "Registration form": [ - "" + 'Registration form': [ + '' ], - "Register": [ - "" + 'Register': [ + '' ], - "Date": [ - "" + 'Date': [ + '' ], - "Amount": [ - "" + 'Amount': [ + '' ], - "Counterpart": [ - "" + 'Counterpart': [ + '' ], - "Subject": [ - "" + 'Subject': [ + '' ], - "Username or account label '%1$s' not found. Won't login.": [ - "" + 'Username or account label \'%1$s\' not found. Won\'t login.': [ + '' ], - "Wrong credentials given.": [ - "" + 'Wrong credentials given.': [ + '' ], - "Account information could not be retrieved.": [ - "" + 'Account information could not be retrieved.': [ + '' ], - "Close wire transfer": [ - "" + 'Close wire transfer': [ + '' ], - "Close Taler withdrawal": [ - "Close Taler withdrawal" + 'Close Taler withdrawal': [ + 'Close Taler withdrawal' ], - "Bank account balance:": [ - "" + 'Bank account balance:': [ + '' ], - "Latest transactions:": [ - "" + 'Latest transactions:': [ + '' ], - "Transfer money manually": [ - "" + 'Transfer money manually': [ + '' ], - "List of public accounts was not found.": [ - "" + 'List of public accounts was not found.': [ + '' ], - "List of public accounts could not be retrieved.": [ - "" + 'List of public accounts could not be retrieved.': [ + '' ], - "History of public accounts": [ - "" + 'History of public accounts': [ + '' ], - "Page has a problem: logged in but backend state is lost.": [ - "Page has a problem: logged in but backend state is lost." + 'Page has a problem: logged in but backend state is lost.': [ + 'Page has a problem: logged in but backend state is lost.' ], - "Welcome to the euFin bank!": [ - "Welcome to euFin bank: Taler+IBAN now possible!" + 'Welcome to the euFin bank!': [ + 'Welcome to euFin bank: Taler+IBAN now possible!' ], - "": { - "domain": "messages", - "plural_forms": "nplurals=2; plural=(n != 1);", - "lang": "en" + '': { + 'domain': 'messages', + 'plural_forms': 'nplurals=2; plural=(n != 1);', + 'lang': 'en' } } } }; strings['it'] = { - "domain": "messages", - "locale_data": { - "messages": { - "days": [ - "" + 'domain': 'messages', + 'locale_data': { + 'messages': { + 'days': [ + '' ], - "hours": [ - "" + 'hours': [ + '' ], - "minutes": [ - "" + 'minutes': [ + '' ], - "seconds": [ - "" + 'seconds': [ + '' ], - "Clear": [ - "Cancella" + 'Clear': [ + 'Cancella' ], - "Logout": [ - "" + 'Logout': [ + '' ], - "Demo Bank": [ - "Banca 'demo'" + 'Demo Bank': [ + 'Banca \'demo\'' ], - "Go back": [ - "Indietro" + 'Go back': [ + 'Indietro' ], - "Wire transfer": [ - "Bonifico" + 'Wire transfer': [ + 'Bonifico' ], - "Transfer money to another account of this bank:": [ - "Trasferisci fondi a un altro conto di questa banca:" + 'Transfer money to another account of this bank:': [ + 'Trasferisci fondi a un altro conto di questa banca:' ], - "Want to try the raw payto://-format?": [ - "Prova il trasferimento tramite il formato Payto!" + 'Want to try the raw payto://-format?': [ + 'Prova il trasferimento tramite il formato Payto!' ], - "Transfer money via the Payto system:": [ - "Effettua un bonifico tramite il sistema Payto:" + 'Transfer money via the Payto system:': [ + 'Effettua un bonifico tramite il sistema Payto:' ], - "payto address": [ - "indirizzo Payto" + 'payto address': [ + 'indirizzo Payto' ], - "Confirm": [ - "Conferma" + 'Confirm': [ + 'Conferma' ], - "Confirm Withdrawal": [ - "Conferma il ritiro" + 'Confirm Withdrawal': [ + 'Conferma il ritiro' ], - "Waiting the bank to create the operaion...": [ - "La banca sta creando l'operazione..." + 'Waiting the bank to create the operaion...': [ + 'La banca sta creando l\'operazione...' ], - "This withdrawal was aborted!": [ - "Questo ritiro è stato annullato!" + 'This withdrawal was aborted!': [ + 'Questo ritiro è stato annullato!' ], - "Withdraw to a Taler Wallet": [ - "Ritira contante nel portafoglio Taler" + 'Withdraw to a Taler Wallet': [ + 'Ritira contante nel portafoglio Taler' ], - "You can use this QR code to withdraw to your mobile wallet:": [ - "Usa questo codice QR per ritirare contante nel tuo wallet:" + 'You can use this QR code to withdraw to your mobile wallet:': [ + 'Usa questo codice QR per ritirare contante nel tuo wallet:' ], - "this link": [ - "questo link" + 'this link': [ + 'questo link' ], - "Abort": [ - "Annulla" + 'Abort': [ + 'Annulla' ], - "Start withdrawal": [ - "Ritira contante" + 'Start withdrawal': [ + 'Ritira contante' ], - "Withdraw Money into a Taler wallet": [ - "Ritira contante nel portafoglio Taler" + 'Withdraw Money into a Taler wallet': [ + 'Ritira contante nel portafoglio Taler' ], - "Amount to withdraw": [ - "Somma da ritirare" + 'Amount to withdraw': [ + 'Somma da ritirare' ], - "Please login!": [ - "Accedi!" + 'Please login!': [ + 'Accedi!' ], - "Login": [ - "Accedi" + 'Login': [ + 'Accedi' ], - "Register to the euFin bank!": [ - "Apri un conto in banca euFin!" + 'Register to the euFin bank!': [ + 'Apri un conto in banca euFin!' ], - "Registration form": [ - "Registrazione" + 'Registration form': [ + 'Registrazione' ], - "Register": [ - "Registrati" + 'Register': [ + 'Registrati' ], - "Date": [ - "" + 'Date': [ + '' ], - "Amount": [ - "Somma" + 'Amount': [ + 'Somma' ], - "Counterpart": [ - "Controparte" + 'Counterpart': [ + 'Controparte' ], - "Subject": [ - "Causale" + 'Subject': [ + 'Causale' ], - "Username or account label '%1$s' not found. Won't login.": [ - "L'utente '%1$s' non esiste. Login impossibile" + 'Username or account label \'%1$s\' not found. Won\'t login.': [ + 'L\'utente \'%1$s\' non esiste. Login impossibile' ], - "Wrong credentials given.": [ - "Credenziali invalide." + 'Wrong credentials given.': [ + 'Credenziali invalide.' ], - "Account information could not be retrieved.": [ - "Impossibile ricevere le informazioni relative al conto." + 'Account information could not be retrieved.': [ + 'Impossibile ricevere le informazioni relative al conto.' ], - "Close wire transfer": [ - "Chiudi il bonifico" + 'Close wire transfer': [ + 'Chiudi il bonifico' ], - "Close Taler withdrawal": [ - "Chiudi il ritiro Taler" + 'Close Taler withdrawal': [ + 'Chiudi il ritiro Taler' ], - "Bank account balance:": [ - "Bilancio:" + 'Bank account balance:': [ + 'Bilancio:' ], - "Latest transactions:": [ - "Ultime transazioni:" + 'Latest transactions:': [ + 'Ultime transazioni:' ], - "Transfer money manually": [ - "Effettua un bonifico" + 'Transfer money manually': [ + 'Effettua un bonifico' ], - "List of public accounts was not found.": [ - "Lista conti pubblici non trovata." + 'List of public accounts was not found.': [ + 'Lista conti pubblici non trovata.' ], - "List of public accounts could not be retrieved.": [ - "Lista conti pubblici non pervenuta." + 'List of public accounts could not be retrieved.': [ + 'Lista conti pubblici non pervenuta.' ], - "History of public accounts": [ - "Storico dei conti pubblici" + 'History of public accounts': [ + 'Storico dei conti pubblici' ], - "Page has a problem: logged in but backend state is lost.": [ - "Stato inconsistente: accesso utente effettuato ma stato con server perso." + 'Page has a problem: logged in but backend state is lost.': [ + 'Stato inconsistente: accesso utente effettuato ma stato con server perso.' ], - "Welcome to the euFin bank!": [ - "Benvenuti in banca euFin!" + 'Welcome to the euFin bank!': [ + 'Benvenuti in banca euFin!' ], - "": { - "domain": "messages", - "plural_forms": "nplurals=2; plural=(n != 1);", - "lang": "it" + '': { + 'domain': 'messages', + 'plural_forms': 'nplurals=2; plural=(n != 1);', + 'lang': 'it' } } } diff --git a/packages/bank/src/index.tsx b/packages/bank/src/index.tsx @@ -1,3 +1,3 @@ -import App from "./components/app"; +import App from './components/app'; export default App; diff --git a/packages/bank/src/pages/home/index.tsx b/packages/bank/src/pages/home/index.tsx @@ -1,14 +1,15 @@ -import useSWR, { SWRConfig, useSWRConfig } from "swr"; -import useSWRImmutable from "swr/immutable"; -import { h, Fragment, ComponentChildren, VNode, createContext } from "preact"; -import { useCallback, useRef, useState, useEffect, StateUpdater, useContext } from "preact/hooks"; -import { Buffer } from "buffer"; -import { useTranslator, Translate } from "../../i18n"; -import { QR } from "../../components/QR"; -import { useNotNullLocalStorage, useLocalStorage } from "../../hooks"; -import "../../scss/main.scss"; -import talerLogo from "../../assets/logo-white.svg"; -import { LangSelectorLikePy as LangSelector} from "../../components/menu/LangSelector"; +/* eslint-disable @typescript-eslint/no-explicit-any */ +import useSWR, { SWRConfig, useSWRConfig } from 'swr'; +import useSWRImmutable from 'swr/immutable'; +import { h, Fragment, ComponentChildren, VNode, createContext } from 'preact'; +import { useCallback, useRef, useState, useEffect, StateUpdater, useContext } from 'preact/hooks'; +import { Buffer } from 'buffer'; +import { useTranslator, Translate } from '../../i18n'; +import { QR } from '../../components/QR'; +import { useNotNullLocalStorage, useLocalStorage } from '../../hooks'; +import '../../scss/main.scss'; +import talerLogo from '../../assets/logo-white.svg'; +import { LangSelectorLikePy as LangSelector} from '../../components/menu/LangSelector'; // Uncomment to allow test runs: // const __LIBEUFIN_UI_ALLOW_REGISTRATIONS__ = 1; @@ -39,8 +40,8 @@ import { LangSelectorLikePy as LangSelector} from "../../components/menu/LangSel /************ * Contexts * ***********/ -var CurrencyContext = createContext<any>(null); -var PageContext = createContext<any>(null); +const CurrencyContext = createContext<any>(null); +const PageContext = createContext<any>(null); /********************************************** * Type definitions for states and API calls. * @@ -154,13 +155,13 @@ function goPublicAccounts(pageStateSetter: StateUpdater<PageStateType>) { * the input is invalid, the valid amount otherwise. */ function validateAmount(maybeAmount: string): any { - const amountRegex = "^[0-9]+(\.[0-9]+)?$"; + const amountRegex = '^[0-9]+(\.[0-9]+)?$'; if (!maybeAmount) { console.log(`Entered amount (${maybeAmount}) mismatched <input> pattern.`); return; } - if (typeof maybeAmount !== "undefined" || maybeAmount !== "") { - console.log("Maybe valid amount: " + maybeAmount); + if (typeof maybeAmount !== 'undefined' || maybeAmount !== '') { + console.log(`Maybe valid amount: ${ maybeAmount}`); // tolerating comma instead of point. const re = RegExp(amountRegex) if (!re.test(maybeAmount)) { @@ -175,10 +176,10 @@ function validateAmount(maybeAmount: string): any { * Extract IBAN from a Payto URI. */ function getIbanFromPayto(url: string): string { - const pathSplit = new URL(url).pathname.split("/"); - var lastIndex = pathSplit.length - 1; + const pathSplit = new URL(url).pathname.split('/'); + let lastIndex = pathSplit.length - 1; // Happens if the path ends with "/". - if (pathSplit[lastIndex] === "") lastIndex--; + if (pathSplit[lastIndex] === '') lastIndex--; const iban = pathSplit[lastIndex]; return iban; } @@ -190,7 +191,7 @@ function parseAmount(val: string): Amount { const format = /^[A-Z]+:[0-9]+(\.[0-9]+)?$/; if (!format.test(val)) throw Error(`Backend gave invalid amount: ${val}.`) - const amountSplit = val.split(":"); + const amountSplit = val.split(':'); return {value: amountSplit[1], currency: amountSplit[0]} } @@ -199,8 +200,8 @@ function parseAmount(val: string): Amount { * exception if not found. */ function getUsername(backendState: BackendStateTypeOpt): string { - if (typeof backendState === "undefined") { - throw Error("Username can't be found in a undefined backend state.") + if (typeof backendState === 'undefined') { + throw Error('Username can\'t be found in a undefined backend state.') } return backendState.username; } @@ -215,23 +216,23 @@ async function postToBackend( backendState: BackendStateTypeOpt, body: string ): Promise<any> { - if (typeof backendState === "undefined") { - throw Error("Credentials can't be found in a undefined backend state.") + if (typeof backendState === 'undefined') { + throw Error('Credentials can\'t be found in a undefined backend state.') } const { username, password } = backendState; - let headers = prepareHeaders(username, password); + const headers = prepareHeaders(username, password); // Backend URL must have been stored _with_ a final slash. const url = new URL(uri, backendState.url) return await fetch(url.href, { method: 'POST', - headers: headers, - body: body, + headers, + body, } ); } function useTransactionPageNumber(): [number, StateUpdater<number>] { - const ret = useNotNullLocalStorage("transaction-page", "0"); + const ret = useNotNullLocalStorage('transaction-page', '0'); const retObj = JSON.parse(ret[0]); const retSetter: StateUpdater<number> = function(val) { const newVal = val instanceof Function ? JSON.stringify(val(retObj)) : JSON.stringify(val) @@ -244,14 +245,14 @@ function useTransactionPageNumber(): [number, StateUpdater<number>] { * Craft headers with Authorization and Content-Type. */ function prepareHeaders(username: string, password: string) { - let headers = new Headers(); + const headers = new Headers(); headers.append( - "Authorization", - `Basic ${Buffer.from(username + ":" + password).toString("base64")}` + 'Authorization', + `Basic ${Buffer.from(`${username }:${ password}`).toString('base64')}` ); headers.append( - "Content-Type", - "application/json" + 'Content-Type', + 'application/json' ) return headers; } @@ -263,8 +264,8 @@ function prepareHeaders(username: string, password: string) { const getRootPath = () => { const maybeRootPath = typeof window !== undefined ? window.location.origin + window.location.pathname - : "/"; - if (!maybeRootPath.endsWith("/")) return maybeRootPath + "/"; + : '/'; + if (!maybeRootPath.endsWith('/')) return `${maybeRootPath }/`; return maybeRootPath; }; @@ -281,7 +282,7 @@ function useShowPublicAccount( state?: string ): [string | undefined, StateUpdater<string | undefined>] { - const ret = useLocalStorage("show-public-account", JSON.stringify(state)); + const ret = useLocalStorage('show-public-account', JSON.stringify(state)); const retObj: string | undefined = ret[0] ? JSON.parse(ret[0]) : ret[0]; const retSetter: StateUpdater<string | undefined> = function(val) { const newVal = val instanceof Function ? JSON.stringify(val(retObj)) : JSON.stringify(val) @@ -299,7 +300,7 @@ function useRawPaytoInputType( state?: RawPaytoInputType ): [RawPaytoInputTypeOpt, StateUpdater<RawPaytoInputTypeOpt>] { - const ret = useLocalStorage("raw-payto-input-state", state); + const ret = useLocalStorage('raw-payto-input-state', state); const retObj: RawPaytoInputTypeOpt = ret[0]; const retSetter: StateUpdater<RawPaytoInputTypeOpt> = function(val) { const newVal = val instanceof Function ? val(retObj) : val @@ -320,7 +321,7 @@ function useWireTransferRequestType( state?: WireTransferRequestType ): [WireTransferRequestTypeOpt, StateUpdater<WireTransferRequestTypeOpt>] { - const ret = useLocalStorage("wire-transfer-request-state", JSON.stringify(state)); + const ret = useLocalStorage('wire-transfer-request-state', JSON.stringify(state)); const retObj: WireTransferRequestTypeOpt = ret[0] ? JSON.parse(ret[0]) : ret[0]; const retSetter: StateUpdater<WireTransferRequestTypeOpt> = function(val) { const newVal = val instanceof Function ? JSON.stringify(val(retObj)) : JSON.stringify(val) @@ -339,7 +340,7 @@ function useCredentialsRequestType( state?: CredentialsRequestType ): [CredentialsRequestTypeOpt, StateUpdater<CredentialsRequestTypeOpt>] { - const ret = useLocalStorage("credentials-request-state", JSON.stringify(state)); + const ret = useLocalStorage('credentials-request-state', JSON.stringify(state)); const retObj: CredentialsRequestTypeOpt = ret[0] ? JSON.parse(ret[0]) : ret[0]; const retSetter: StateUpdater<CredentialsRequestTypeOpt> = function(val) { const newVal = val instanceof Function ? JSON.stringify(val(retObj)) : JSON.stringify(val) @@ -358,7 +359,7 @@ function useBackendState( state?: BackendStateType ): [BackendStateTypeOpt, StateUpdater<BackendStateTypeOpt>] { - const ret = useLocalStorage("backend-state", JSON.stringify(state)); + const ret = useLocalStorage('backend-state', JSON.stringify(state)); const retObj: BackendStateTypeOpt = ret[0] ? JSON.parse(ret[0]) : ret[0]; const retSetter: StateUpdater<BackendStateTypeOpt> = function(val) { const newVal = val instanceof Function ? JSON.stringify(val(retObj)) : JSON.stringify(val) @@ -376,7 +377,7 @@ function useAccountState( state?: AccountStateType ): [AccountStateTypeOpt, StateUpdater<AccountStateTypeOpt>] { - const ret = useLocalStorage("account-state", JSON.stringify(state)); + const ret = useLocalStorage('account-state', JSON.stringify(state)); const retObj: AccountStateTypeOpt = ret[0] ? JSON.parse(ret[0]) : ret[0]; const retSetter: StateUpdater<AccountStateTypeOpt> = function(val) { const newVal = val instanceof Function ? JSON.stringify(val(retObj)) : JSON.stringify(val) @@ -399,12 +400,12 @@ function usePageState( withdrawalInProgress: false, } ): [PageStateType, StateUpdater<PageStateType>] { - const ret = useNotNullLocalStorage("page-state", JSON.stringify(state)); + const ret = useNotNullLocalStorage('page-state', JSON.stringify(state)); const retObj: PageStateType = JSON.parse(ret[0]); - console.log("Current page state", retObj); + console.log('Current page state', retObj); const retSetter: StateUpdater<PageStateType> = function(val) { const newVal = val instanceof Function ? JSON.stringify(val(retObj)) : JSON.stringify(val) - console.log("Setting new page state", newVal) + console.log('Setting new page state', newVal) ret[1](newVal) } return [retObj, retSetter]; @@ -434,20 +435,20 @@ async function abortWithdrawalCall( withdrawalId: string | undefined, pageStateSetter: StateUpdater<PageStateType> ) { - if (typeof backendState === "undefined") { - console.log("No credentials found."); - pageStateSetter((prevState) => ({...prevState, hasError: true, error: "No credentials found."})) + if (typeof backendState === 'undefined') { + console.log('No credentials found.'); + pageStateSetter((prevState) => ({...prevState, hasError: true, error: 'No credentials found.'})) return; } - if (typeof withdrawalId === "undefined") { - console.log("No withdrawal ID found."); - pageStateSetter((prevState) => ({...prevState, hasError: true, error: "No withdrawal ID found."})) + if (typeof withdrawalId === 'undefined') { + console.log('No withdrawal ID found.'); + pageStateSetter((prevState) => ({...prevState, hasError: true, error: 'No withdrawal ID found.'})) return; } try { const { username, password } = backendState; - let headers = prepareHeaders(username, password); + const headers = prepareHeaders(username, password); /** * NOTE: tests show that when a same object is being * POSTed, caching might prevent same requests from being @@ -464,9 +465,9 @@ async function abortWithdrawalCall( `access-api/accounts/${backendState.username}/withdrawals/${withdrawalId}/abort`, backendState.url ) - var res = await fetch(url.href, {method: 'POST', headers: headers}) + var res = await fetch(url.href, {method: 'POST', headers}) } catch (error) { - console.log("Could not abort the withdrawal", error); + console.log('Could not abort the withdrawal', error); pageStateSetter((prevState) => ({ ...prevState, hasError: true, @@ -480,15 +481,15 @@ async function abortWithdrawalCall( hasError: true, error: `Withdrawal abortion gave response error (${res.status})`})) return; - } else { - console.log("Withdrawal operation aborted!"); + } + console.log('Withdrawal operation aborted!'); pageStateSetter((prevState) => { const { talerWithdrawUri, withdrawalId, ...rest } = prevState; return { ...rest, - withdrawalOutcome: "Withdrawal aborted!" + withdrawalOutcome: 'Withdrawal aborted!' }}) - } + } /** @@ -507,20 +508,20 @@ async function confirmWithdrawalCall( pageStateSetter: StateUpdater<PageStateType> ) { - if (typeof backendState === "undefined") { - console.log("No credentials found."); - pageStateSetter((prevState) => ({...prevState, hasError: true, error: "No credentials found."})) + if (typeof backendState === 'undefined') { + console.log('No credentials found.'); + pageStateSetter((prevState) => ({...prevState, hasError: true, error: 'No credentials found.'})) return; } - if (typeof withdrawalId === "undefined") { - console.log("No withdrawal ID found."); - pageStateSetter((prevState) => ({...prevState, hasError: true, error: "No withdrawal ID found."})) + if (typeof withdrawalId === 'undefined') { + console.log('No withdrawal ID found.'); + pageStateSetter((prevState) => ({...prevState, hasError: true, error: 'No withdrawal ID found.'})) return; } try { const { username, password } = backendState; - let headers = prepareHeaders(username, password); + const headers = prepareHeaders(username, password); /** * NOTE: tests show that when a same object is being * POSTed, caching might prevent same requests from being @@ -539,10 +540,10 @@ async function confirmWithdrawalCall( ) var res = await fetch(url.href, { method: 'POST', - headers: headers + headers }) } catch (error) { - console.log("Could not POST withdrawal confirmation to the bank", error); + console.log('Could not POST withdrawal confirmation to the bank', error); pageStateSetter((prevState) => ({ ...prevState, hasError: true, @@ -556,15 +557,15 @@ async function confirmWithdrawalCall( hasError: true, error: `Withdrawal confirmation gave response error (${res.status})`})) return; - } else { - console.log("Withdrawal operation confirmed!"); + } + console.log('Withdrawal operation confirmed!'); pageStateSetter((prevState) => { const { talerWithdrawUri, ...rest } = prevState; return { ...rest, - withdrawalOutcome: "Withdrawal confirmed!" + withdrawalOutcome: 'Withdrawal confirmed!' }}) - } + } /** @@ -591,7 +592,7 @@ async function createTransactionCall( ) } catch (error) { - console.log("Could not POST transaction request to the bank", error); + console.log('Could not POST transaction request to the bank', error); pageStateSetter((prevState) => ({ ...prevState, hasError: true, @@ -609,10 +610,10 @@ async function createTransactionCall( return; } // status is 200 OK here, tell the user. - console.log("Wire transfer created!"); + console.log('Wire transfer created!'); pageStateSetter((prevState) => ({ ...prevState, - transferOutcome: "Wire transfer created!" + transferOutcome: 'Wire transfer created!' })) // Only at this point the input data can // be discarded. @@ -633,14 +634,14 @@ async function createWithdrawalCall( backendState: BackendStateTypeOpt, pageStateSetter: StateUpdater<PageStateType> ) { - if (typeof backendState === "undefined") { - console.log("Page has a problem: no credentials found in the state."); - pageStateSetter((prevState) => ({...prevState, hasError: true, error: "No credentials given."})) + if (typeof backendState === 'undefined') { + console.log('Page has a problem: no credentials found in the state.'); + pageStateSetter((prevState) => ({...prevState, hasError: true, error: 'No credentials given.'})) return; } try { const { username, password } = backendState; - let headers = prepareHeaders(username, password); + const headers = prepareHeaders(username, password); // Let bank generate withdraw URI: const url = new URL( @@ -649,12 +650,12 @@ async function createWithdrawalCall( ) var res = await fetch(url.href, { method: 'POST', - headers: headers, - body: JSON.stringify({amount: amount}), + headers, + body: JSON.stringify({amount}), } ); } catch (error) { - console.log("Could not POST withdrawal request to the bank", error); + console.log('Could not POST withdrawal request to the bank', error); pageStateSetter((prevState) => ({ ...prevState, hasError: true, @@ -671,8 +672,8 @@ async function createWithdrawalCall( return; } - console.log("Withdrawal operation created!"); - let resp = await res.json(); + console.log('Withdrawal operation created!'); + const resp = await res.json(); pageStateSetter((prevState: PageStateType) => ({ ...prevState, withdrawalInProgress: true, @@ -735,22 +736,22 @@ async function registrationCall( if (!baseUrl.endsWith('/')) { baseUrl += '/' } - let headers = new Headers(); + const headers = new Headers(); headers.append( - "Content-Type", - "application/json" + 'Content-Type', + 'application/json' ) - const url = new URL("access-api/testing/register", baseUrl) + const url = new URL('access-api/testing/register', baseUrl) try { var res = await fetch(url.href, { method: 'POST', body: JSON.stringify(req), - headers: headers + headers }); } catch (error) { console.log(`Could not POST new registration to the bank (${url.href})`, error); pageStateSetter((prevState) => ({ - ...prevState, hasError: true, error: "Registration failed, please report." + ...prevState, hasError: true, error: 'Registration failed, please report.' })); return; } @@ -783,11 +784,11 @@ async function registrationCall( function Currency(): VNode { const { data, error } = useSWR(`${getRootPath()}integration-api/config`, fetcher); - if (typeof error !== "undefined") { + if (typeof error !== 'undefined') { return <b>error: currency could not be retrieved</b>; } - if (typeof data === "undefined") return <Fragment>"..."</Fragment>; - console.log("found bank config", data); + if (typeof data === 'undefined') return <Fragment>"..."</Fragment>; + console.log('found bank config', data); return data.currency; } @@ -798,7 +799,7 @@ function ErrorBanner(Props: any): VNode | null { return ( <p class="informational informational-fail">{pageState.error} <a href="#" onClick={() => { - pageStateSetter(function (prevState: PageStateType) { + pageStateSetter((prevState: PageStateType) => { delete prevState.error; // delete error message return {...prevState, hasError: false} // delete error state })}}> @@ -810,7 +811,7 @@ function ErrorBanner(Props: any): VNode | null { function BankFrame(Props: any): VNode { const i18n = useTranslator(); const [pageState, pageStateSetter] = useContext(PageContext); - console.log("BankFrame state", pageState); + console.log('BankFrame state', pageState); const logOut = ( <a href="#" @@ -833,14 +834,14 @@ function BankFrame(Props: any): VNode { }}>{i18n`Logout`}</a>); // Prepare demo sites links. - let DEMO_SITES = [ - ["Landing", "__DEMO_SITE_LANDING_URL__"], - ["Bank", "__DEMO_SITE_BANK_URL__"], - ["Blog", "__DEMO_SITE_BLOG_URL__"], - ["Donations", "__DEMO_SITE_DONATIONS_URL__"], - ["Survey", "__DEMO_SITE_SURVEY_URL__"], + const DEMO_SITES = [ + ['Landing', '__DEMO_SITE_LANDING_URL__'], + ['Bank', '__DEMO_SITE_BANK_URL__'], + ['Blog', '__DEMO_SITE_BLOG_URL__'], + ['Donations', '__DEMO_SITE_DONATIONS_URL__'], + ['Survey', '__DEMO_SITE_SURVEY_URL__'], ]; - let demo_sites = []; + const demo_sites = []; for (const i in DEMO_SITES) { demo_sites.push(<a href={DEMO_SITES[i][1]}>{DEMO_SITES[i][0]}</a>) } @@ -867,8 +868,7 @@ function BankFrame(Props: any): VNode { src={talerLogo} height="100" width="224" - style="margin: 2em 2em"> - </img> + style="margin: 2em 2em" /> </a> </header> <div style="display:flex; flex-direction: column;" class="navcontainer"> @@ -880,14 +880,14 @@ function BankFrame(Props: any): VNode { </nav> </div> <section id="main" class="content"> - <ErrorBanner pageState={[pageState, pageStateSetter]}/> + <ErrorBanner pageState={[pageState, pageStateSetter]} /> {pageState.isLoggedIn ? logOut : null} {Props.children} - <hr></hr> + <hr /> <div> <p>You can learn more about GNU Taler on our <a href="https://taler.net">main website</a>.</p> </div> - <div style="flex-grow:1"></div> + <div style="flex-grow:1" /> <p>Copyright © 2014—2022 Taler Systems SA</p> </section> </Fragment>); @@ -899,21 +899,21 @@ function PaytoWireTransfer(Props: any): VNode { const [submitData, submitDataSetter] = useWireTransferRequestType(); const [rawPaytoInput, rawPaytoInputSetter] = useRawPaytoInputType(); const i18n = useTranslator(); - const amountRegex = "^[0-9]+(\.[0-9]+)?$"; - const ibanRegex = "^[A-Z][A-Z][0-9]+$"; - var amountInput = ""; - var receiverInput = ""; - var subjectInput = ""; - var transactionData: TransactionRequestType; + const amountRegex = '^[0-9]+(\.[0-9]+)?$'; + const ibanRegex = '^[A-Z][A-Z][0-9]+$'; + const amountInput = ''; + const receiverInput = ''; + const subjectInput = ''; + let transactionData: TransactionRequestType; const focusInput = useRef(null); useEffect(() => { - console.log("Now focus", focusInput); + console.log('Now focus', focusInput); if (focusInput.current) { // @ts-ignore focusInput.current.focus(); } }, []); - console.log("wire form page state", pageState); + console.log('wire form page state', pageState); const goBackForm = <a href="#" onClick={ () => { pageStateSetter((prevState: PageStateType) => ({...prevState, tryManualTransfer: false})) @@ -928,7 +928,7 @@ function PaytoWireTransfer(Props: any): VNode { }>{i18n`Go back`}</a>; if (!pageState.isRawPayto) { - console.log("wire transfer form"); + console.log('wire transfer form'); return (<article> <div> <h2>{i18n`Wire transfer`}</h2> @@ -959,31 +959,31 @@ function PaytoWireTransfer(Props: any): VNode { placeholder="amount" required value={ - typeof submitData !== "undefined" - && typeof submitData.amount !== "undefined" ? submitData.amount : "" + typeof submitData !== 'undefined' + && typeof submitData.amount !== 'undefined' ? submitData.amount : '' } pattern={amountRegex} onInput={(e): void => { submitDataSetter((submitData: any) => ({ ...submitData, - amount: e.currentTarget.value.replace(",", "."), + amount: e.currentTarget.value.replace(',', '.'), }))}} /> <label>{currency}</label><br /><br /> <input type="submit" value="Send" onClick={() => { if ( - typeof submitData === "undefined" - || (typeof submitData.iban === "undefined" - || submitData.iban === "") - || (typeof submitData.subject === "undefined" - || submitData.subject === "") - || (typeof submitData.amount === "undefined" - || submitData.amount === "") + typeof submitData === 'undefined' + || (typeof submitData.iban === 'undefined' + || submitData.iban === '') + || (typeof submitData.subject === 'undefined' + || submitData.subject === '') + || (typeof submitData.amount === 'undefined' + || submitData.amount === '') ) { - console.log("Not all the fields were given."); + console.log('Not all the fields were given.'); pageStateSetter((prevState: PageStateType) => - ({...prevState, hasError: true, error: "Field(s) missing."})) + ({...prevState, hasError: true, error: 'Field(s) missing.'})) return; } transactionData = { @@ -1001,7 +1001,7 @@ function PaytoWireTransfer(Props: any): VNode { <p><a href="#" onClick={() => { - console.log("switch to raw payto form"); + console.log('switch to raw payto form'); pageStateSetter((prevState: any) => ({...prevState, isRawPayto: true})); }}>{i18n`Want to try the raw payto://-format?`} </a></p> @@ -1009,7 +1009,7 @@ function PaytoWireTransfer(Props: any): VNode { {goBackForm} </article>); } - console.log("rendering raw payto form"); + console.log('rendering raw payto form'); return (<article> <div> <h2>{i18n`Wire transfer`}</h2> @@ -1034,11 +1034,11 @@ function PaytoWireTransfer(Props: any): VNode { onClick={() => { // empty string evaluates to false. if (!rawPaytoInput) { - console.log("Didn't get any raw Payto string!"); + console.log('Didn\'t get any raw Payto string!'); return; } transactionData = {paytoUri: rawPaytoInput}; - if (typeof transactionData.paytoUri === "undefined" || + if (typeof transactionData.paytoUri === 'undefined' || transactionData.paytoUri.length === 0) return; createTransactionCall( transactionData, @@ -1064,7 +1064,7 @@ function TalerWithdrawalConfirmationQuestion(Props: any): VNode { a: Math.floor(Math.random() * 10), b: Math.floor(Math.random() * 10) } - var captchaAnswer = ""; + let captchaAnswer = ''; return (<Fragment> <h1 class="nav">{i18n`Confirm Withdrawal`}</h1> @@ -1091,7 +1091,7 @@ function TalerWithdrawalConfirmationQuestion(Props: any): VNode { return; } pageStateSetter((prevState: PageStateType) => - ({...prevState, hasError: true, error: "Answer is wrong."})) + ({...prevState, hasError: true, error: 'Answer is wrong.'})) }} /> <input type="submit" @@ -1117,7 +1117,7 @@ function QrCodeSection({talerWithdrawUri, abortButton}:{talerWithdrawUri:string, //Taler Wallet WebExtension is listening to headers response and tab updates. //In the SPA there is no header response with the Taler URI so //this hack manually triggers the tab update after the QR is in the DOM. - window.location.href = window.location.href.split("#")[0] + "#" + window.location.href = `${window.location.href.split('#')[0] }#` },[]) return <section id="main" class="content"> @@ -1155,7 +1155,7 @@ function TalerWithdrawalQRCode(Props: any): VNode { const { data, error, mutate } = useSWR(`integration-api/withdrawal-operation/${withdrawalId}`); - if (typeof error !== "undefined") { + if (typeof error !== 'undefined') { console.log(`withdrawal (${withdrawalId}) was never (correctly) created at the bank...`, error); pageStateSetter((prevState: PageStateType) => ({ ...prevState, @@ -1166,14 +1166,14 @@ function TalerWithdrawalQRCode(Props: any): VNode { } // data didn't arrive yet and wallet didn't communicate: - if (typeof data === "undefined") { + if (typeof data === 'undefined') { return <p>{i18n`Waiting the bank to create the operaion...`}</p> } /** * Wallet didn't communicate withdrawal details yet: */ - console.log("withdrawal status", data); + console.log('withdrawal status', data); if (data.aborted) { pageStateSetter((prevState: PageStateType) => { const { @@ -1208,10 +1208,10 @@ function TalerWithdrawal(Props: any): VNode { const {backendState, pageStateSetter} = Props; const currency = useContext(CurrencyContext); const i18n = useTranslator(); - var submitAmount = "5.00"; // must match the first <select> child. - const amountRegex = "^[0-9]+(\.[0-9]+)?$"; + let submitAmount = '5.00'; // must match the first <select> child. + // const amountRegex = "^[0-9]+(\.[0-9]+)?$"; // currently unused - var submitButton = <input + const submitButton = <input id="select-exchange" class="pure-button pure-button-primary" type="submit" @@ -1295,12 +1295,12 @@ function LoginForm(Props: any): VNode { type="submit" class="pure-button pure-button-primary" onClick={() => { - if (typeof submitData === "undefined") { - console.log("login data is undefined", submitData); + if (typeof submitData === 'undefined') { + console.log('login data is undefined', submitData); return; } if (submitData.password.length == 0 || submitData.username.length == 0) { - console.log("username or password is the empty string", submitData); + console.log('username or password is the empty string', submitData); return; } loginCall( @@ -1320,6 +1320,7 @@ function LoginForm(Props: any): VNode { * Collect and submit registration data. */ function RegistrationForm(Props: any): VNode { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [pageState, pageStateSetter] = useContext(PageContext); const [submitData, submitDataSetter] = useCredentialsRequestType(); const i18n = useTranslator(); @@ -1327,7 +1328,7 @@ function RegistrationForm(Props: any): VNode { return ( <Fragment> <h1 class="nav">{i18n`Registration form`}</h1> - <aside class="sidebar" id="left"></aside> + <aside class="sidebar" id="left" /> <article> <div class="register-form"> <form action="javascript:void(0);" class="pure-form"> @@ -1377,29 +1378,29 @@ function RegistrationForm(Props: any): VNode { autofocus class="pure-button pure-button-primary" onClick={() => { - console.log("maybe submitting the registration.."); + console.log('maybe submitting the registration..'); console.log(submitData); - if (typeof submitData === "undefined") { + if (typeof submitData === 'undefined') { console.log(`submit data ${submitData} is undefined`); return; } - if ((typeof submitData.password === "undefined") || - (typeof submitData.username === "undefined")) { - console.log("username or password is undefined"); + if ((typeof submitData.password === 'undefined') || + (typeof submitData.username === 'undefined')) { + console.log('username or password is undefined'); return; } if (submitData.password.length === 0 || submitData.username.length === 0) { - console.log("username or password are the empty string"); + console.log('username or password are the empty string'); return; } - console.log("submitting the registration.."); + console.log('submitting the registration..'); registrationCall( {...submitData}, Props.backendStateSetter, // will store BE URL, if OK. pageStateSetter ); - console.log("Clearing the input data"); + console.log('Clearing the input data'); /** * FIXME: clearing the data should be done by setting * it to undefined, instead of the empty strings, just @@ -1407,7 +1408,7 @@ function RegistrationForm(Props: any): VNode { * strings due to a non lively update of the <input> fields * after setting to undefined. */ - submitDataSetter({username: "", password: ""})}}>{i18n`Register`}</button> + submitDataSetter({username: '', password: ''})}}>{i18n`Register`}</button> // FIXME: should use a different color <button autofocus @@ -1432,8 +1433,8 @@ function Transactions(Props: any): VNode { const { data, error } = useSWR( `access-api/accounts/${accountLabel}/transactions?page=${pageNumber}` ); - if (typeof error !== "undefined") { - console.log("transactions not found error", error); + if (typeof error !== 'undefined') { + console.log('transactions not found error', error); switch(error.status) { case 404: { return <p>Transactions page {pageNumber} was not found.</p> @@ -1462,16 +1463,16 @@ function Transactions(Props: any): VNode { </tr> </thead> <tbody> - {data.transactions.map(function(item: any) { - const sign = item.direction == "DBIT" ? "-" : ""; - const counterpart = item.direction == "DBIT" ? item.creditorIban : item.debtorIban; + {data.transactions.map((item: any) => { + const sign = item.direction == 'DBIT' ? '-' : ''; + const counterpart = item.direction == 'DBIT' ? item.creditorIban : item.debtorIban; // Pattern: // // DD/MM YYYY subject -5 EUR // DD/MM YYYY subject 5 EUR const dateRegex = /^([0-9]{4})-([0-9]{2})-([0-9]{1,2})/ const dateParse = dateRegex.exec(item.date) - const date = dateParse !== null ? `${dateParse[3]}/${dateParse[2]} ${dateParse[1]}` : "date not found" + const date = dateParse !== null ? `${dateParse[3]}/${dateParse[2]} ${dateParse[1]}` : 'date not found' return (<tr> <td>{date}</td> <td>{sign}{item.amount} {item.currency}</td> @@ -1509,13 +1510,13 @@ function Account(Props: any): VNode { * This part shows a list of transactions: with 5 elements by * default and offers a "load more" button. */ - var [txPageNumber, setTxPageNumber] = useTransactionPageNumber() - var txsPages = [] + const [txPageNumber, setTxPageNumber] = useTransactionPageNumber() + const txsPages = [] for (let i = 0; i <= txPageNumber; i++) { txsPages.push(<Transactions accountLabel={accountLabel} pageNumber={i} />) } - if (typeof error !== "undefined") { - console.log("account error", error); + if (typeof error !== 'undefined') { + console.log('account error', error); /** * FIXME: to minimize the code, try only one invocation * of pageStateSetter, after having decided the error @@ -1620,7 +1621,7 @@ function Account(Props: any): VNode { */ console.log(`maybe new withdrawal ${talerWithdrawUri}`); if (talerWithdrawUri) { - console.log("Bank created a new Taler withdrawal"); + console.log('Bank created a new Taler withdrawal'); return ( <BankFrame> <TalerWithdrawalQRCode @@ -1647,7 +1648,7 @@ function Account(Props: any): VNode { </div> <section id="menu"> <p>{i18n`Bank account balance:`} <br /> - { data.balance.credit_debit_indicator == "debit" ? (<b>-</b>) : null } + { data.balance.credit_debit_indicator == 'debit' ? (<b>-</b>) : null } <b>{`${balance.value} ${balance.currency}`}</b></p> </section> <CurrencyContext.Provider value={balance.currency}> @@ -1676,15 +1677,15 @@ function SWRWithCredentials(props: any): VNode { const { username, password, backendUrl } = props; const headers = new Headers(); headers.append( - "Authorization", - `Basic ${Buffer.from(username + ":" + password).toString("base64")}` + 'Authorization', + `Basic ${Buffer.from(`${username }:${ password}`).toString('base64')}` ); - console.log("Likely backend base URL", backendUrl); + console.log('Likely backend base URL', backendUrl); return ( <SWRConfig value={{ fetcher: (url) => - fetch(backendUrl + url || "", { headers: headers }).then( + fetch(backendUrl + url || '', { headers }).then( (r) => { if (!r.ok) { throw {status: r.status, json: r.json()}; @@ -1698,12 +1699,12 @@ function SWRWithCredentials(props: any): VNode { function SWRWithoutCredentials(Props: any): VNode { const { baseUrl } = Props; - console.log("Base URL", baseUrl); + console.log('Base URL', baseUrl); return ( <SWRConfig value={{ fetcher: (url) => - fetch(baseUrl + url || "").then( + fetch(baseUrl + url || '').then( (r) => { if (!r.ok) { throw {status: r.status, json: r.json()}; @@ -1720,50 +1721,50 @@ function SWRWithoutCredentials(Props: any): VNode { */ function PublicHistories(Props: any): VNode { const [showAccount, setShowAccount] = useShowPublicAccount(); - const { data, error } = useSWR("access-api/public-accounts"); + const { data, error } = useSWR('access-api/public-accounts'); const i18n = useTranslator(); - if (typeof error !== "undefined") { - console.log("account error", error); + if (typeof error !== 'undefined') { + console.log('account error', error); switch(error.status) { - case 404: { - console.log("public accounts: 404", error); + case 404: + console.log('public accounts: 404', error); Props.pageStateSetter((prevState: PageStateType) => ({ ...prevState, hasError: true, showPublicHistories: false, error: i18n`List of public accounts was not found.` })); - } - default: { - console.log("public accounts: non-404 error", error); + break; + default: + console.log('public accounts: non-404 error', error); Props.pageStateSetter((prevState: PageStateType) => ({ ...prevState, hasError: true, showPublicHistories: false, error: i18n`List of public accounts could not be retrieved.` })); - } + break; } } if (!data) return <p>Waiting public accounts list...</p> - var txs: any = {}; - var accountsBar = []; + const txs: any = {}; + const accountsBar = []; /** * Show the account specified in the props, or just one * from the list if that's not given. */ - if (typeof showAccount === "undefined" && data.publicAccounts.length > 0) + if (typeof showAccount === 'undefined' && data.publicAccounts.length > 0) setShowAccount(data.publicAccounts[1].accountLabel); console.log(`Public history tab: ${showAccount}`); // Ask story of all the public accounts. for (const account of data.publicAccounts) { - console.log("Asking transactions for", account.accountLabel) + console.log('Asking transactions for', account.accountLabel) const isSelected = account.accountLabel == showAccount; accountsBar.push( - <li class={isSelected ? "pure-menu-selected pure-menu-item" : "pure-menu-item pure-menu"}> + <li class={isSelected ? 'pure-menu-selected pure-menu-item' : 'pure-menu-item pure-menu'}> <a href="#" class="pure-menu-link" onClick={() => setShowAccount(account.accountLabel)}>{account.accountLabel}</a> @@ -1778,7 +1779,7 @@ function PublicHistories(Props: any): VNode { <article> <div class="pure-menu pure-menu-horizontal" name="accountMenu"> <ul class="pure-menu-list">{accountsBar}</ul> - {typeof showAccount !== "undefined" ? txs[showAccount] : <p>No public transactions found.</p>} + {typeof showAccount !== 'undefined' ? txs[showAccount] : <p>No public transactions found.</p>} {Props.children} </div> </article> @@ -1791,11 +1792,11 @@ function PublicHistories(Props: any): VNode { * the balance, otherwise it offers to login. */ export function BankHome(): VNode { - var [backendState, backendStateSetter] = useBackendState(); - var [pageState, pageStateSetter] = usePageState(); - var [accountState, accountStateSetter] = useAccountState(); + const [backendState, backendStateSetter] = useBackendState(); + const [pageState, pageStateSetter] = usePageState(); + const [accountState, accountStateSetter] = useAccountState(); const setTxPageNumber = useTransactionPageNumber()[1]; - var i18n = useTranslator(); + const i18n = useTranslator(); if (pageState.showPublicHistories) { return (<SWRWithoutCredentials baseUrl={getRootPath()}> @@ -1812,9 +1813,9 @@ export function BankHome(): VNode { </SWRWithoutCredentials>); } if (pageState.tryRegister) { - // @ts-ignore - console.log("allow registrations?", __LIBEUFIN_UI_ALLOW_REGISTRATIONS__) - // @ts-ignore + // @ts-expect-error Global variable unknown to ts + console.log('allow registrations?', __LIBEUFIN_UI_ALLOW_REGISTRATIONS__) + // @ts-expect-error Global variable unknown to ts if (__LIBEUFIN_UI_ALLOW_REGISTRATIONS__) { return ( <PageContext.Provider value={[pageState, pageStateSetter]}> @@ -1833,7 +1834,7 @@ export function BankHome(): VNode { ); } if (pageState.isLoggedIn) { - if (typeof backendState === "undefined") { + if (typeof backendState === 'undefined') { pageStateSetter((prevState) => ({ ...prevState, hasError: true, @@ -1842,7 +1843,7 @@ export function BankHome(): VNode { })); return <p>Error: waiting for details...</p>; } - console.log("Showing the profile page.."); + console.log('Showing the profile page..'); return ( <SWRWithCredentials username={backendState.username} @@ -1858,8 +1859,8 @@ export function BankHome(): VNode { * Currency only known _after_ a user logs in / registers. Thus not * mentioning the currency right at the home page (as instead the Python * bank did.) FIXME: currency needed at startup too. */ - var regMsg = function () { - // @ts-ignore + const regMsg = function () { + // @ts-expect-error Global variable unknown to ts if (__LIBEUFIN_UI_ALLOW_REGISTRATIONS__) { return (<Fragment> <p><Translate>If you are a new customer please diff --git a/packages/bank/src/pages/notfound/index.tsx b/packages/bank/src/pages/notfound/index.tsx @@ -1,5 +1,5 @@ -import { FunctionalComponent, h } from "preact"; -import { Link } from "preact-router/match"; +import { FunctionalComponent, h } from 'preact'; +import { Link } from 'preact-router/match'; const Notfound: FunctionalComponent = () => { return ( diff --git a/packages/bank/src/pages/profile/index.tsx b/packages/bank/src/pages/profile/index.tsx @@ -1,5 +1,5 @@ -import { FunctionalComponent, h } from "preact"; -import { useEffect, useState } from "preact/hooks"; +import { FunctionalComponent, h } from 'preact'; +import { useEffect, useState } from 'preact/hooks'; interface Props { user: string;