merchant-backoffice

ZZZ: Inactive/Deprecated
Log | Files | Refs | Submodules | README

commit f1bb14ac40020e7d413297166dbdcf508fed18eb
parent 4320467db1392e5f48a4acd079f7e2a253cf9984
Author: Sebastian <sebasjm@gmail.com>
Date:   Fri, 23 Apr 2021 11:12:52 -0300

add copyright notice and some minor changes

Diffstat:
Mpackages/frontend/.storybook/preview.js | 16++++++++++++++++
Mpackages/frontend/preact.config.js | 7+++----
Mpackages/frontend/remove-link-stylesheet.sh | 2++
Mpackages/frontend/src/AdminRoutes.tsx | 7++-----
Mpackages/frontend/src/InstanceRoutes.tsx | 62+++++++++++++++++++++++++++-----------------------------------
Mpackages/frontend/src/components/form/DatePicker.tsx | 2+-
Mpackages/frontend/src/components/form/Field.tsx | 6+++---
Mpackages/frontend/src/components/form/InputArray.tsx | 2+-
Mpackages/frontend/src/components/form/InputDate.tsx | 10++++------
Mpackages/frontend/src/components/form/InputDuration.tsx | 6+++---
Mpackages/frontend/src/components/form/InputGroup.tsx | 2+-
Mpackages/frontend/src/components/form/InputImage.tsx | 6+++---
Mpackages/frontend/src/components/form/InputNumber.tsx | 2+-
Mpackages/frontend/src/components/form/InputStock.tsx | 2+-
Mpackages/frontend/src/components/form/InputTaxes.tsx | 3+--
Mpackages/frontend/src/components/menu/LangSelector.tsx | 4++--
Mpackages/frontend/src/components/menu/SideBar.tsx | 1-
Mpackages/frontend/src/components/menu/index.tsx | 23+++++++++++------------
Mpackages/frontend/src/components/modal/index.tsx | 1-
Mpackages/frontend/src/components/notifications/CreatedSuccessfully.tsx | 4++--
Mpackages/frontend/src/components/notifications/Notifications.stories.tsx | 4++--
Mpackages/frontend/src/components/product/ProductForm.tsx | 34++++++++++++++++++++++++----------
Mpackages/frontend/src/components/product/ProductList.tsx | 19+++++++++++++++++--
Mpackages/frontend/src/context/backend.ts | 8++++----
Mpackages/frontend/src/hooks/admin.ts | 15+++++++++++++++
Mpackages/frontend/src/hooks/index.ts | 10+++++++---
Mpackages/frontend/src/hooks/instance.ts | 15+++++++++++++++
Mpackages/frontend/src/hooks/order.ts | 22++++++++++++++++++----
Mpackages/frontend/src/hooks/product.ts | 17++++++++++++++++-
Mpackages/frontend/src/hooks/tips.ts | 21++++++++++++++++++---
Mpackages/frontend/src/hooks/transfer.ts | 15+++++++++++++++
Mpackages/frontend/src/index.tsx | 29+++++++++++++++--------------
Mpackages/frontend/src/messages/en.po | 14++++++++++++++
Mpackages/frontend/src/messages/es.po | 14++++++++++++++
Mpackages/frontend/src/paths/admin/create/Create.stories.tsx | 2+-
Mpackages/frontend/src/paths/admin/create/CreatePage.tsx | 25++++++++++---------------
Mpackages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx | 4++--
Mpackages/frontend/src/paths/admin/create/index.tsx | 4+---
Mpackages/frontend/src/paths/admin/list/Table.tsx | 9++++-----
Mpackages/frontend/src/paths/admin/list/View.stories.tsx | 2+-
Mpackages/frontend/src/paths/admin/list/index.tsx | 11+++++------
Mpackages/frontend/src/paths/instance/details/DetailPage.tsx | 15++++-----------
Mpackages/frontend/src/paths/instance/details/index.tsx | 9++++-----
Mpackages/frontend/src/paths/instance/orders/create/CreatePage.tsx | 40++++++++++++++++++++++------------------
Mpackages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx | 19+++++++++++++++++--
Mpackages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx | 25++++++++++++++++++++-----
Mpackages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx | 8++++----
Mpackages/frontend/src/paths/instance/orders/create/index.tsx | 2+-
Mpackages/frontend/src/paths/instance/orders/details/DetailPage.tsx | 38++++++++++++++------------------------
Mpackages/frontend/src/paths/instance/orders/details/Timeline.tsx | 15+++++++++++++++
Mpackages/frontend/src/paths/instance/orders/details/index.tsx | 3+--
Mpackages/frontend/src/paths/instance/orders/list/Table.tsx | 15+++++----------
Mpackages/frontend/src/paths/instance/orders/list/index.tsx | 15+++++++--------
Mpackages/frontend/src/paths/instance/products/create/CreatePage.tsx | 2+-
Mpackages/frontend/src/paths/instance/products/create/CreatedSuccessfully.tsx | 4++--
Mpackages/frontend/src/paths/instance/products/create/index.tsx | 7+++----
Mpackages/frontend/src/paths/instance/products/list/Table.tsx | 18++++++------------
Mpackages/frontend/src/paths/instance/products/list/index.tsx | 14++++++--------
Mpackages/frontend/src/paths/instance/products/update/UpdatePage.tsx | 2+-
Mpackages/frontend/src/paths/instance/products/update/index.tsx | 9++++-----
Mpackages/frontend/src/paths/instance/tips/create/index.tsx | 2+-
Mpackages/frontend/src/paths/instance/tips/list/index.tsx | 4++--
Mpackages/frontend/src/paths/instance/tips/update/index.tsx | 2+-
Mpackages/frontend/src/paths/instance/transfers/create/index.tsx | 2+-
Mpackages/frontend/src/paths/instance/transfers/list/index.tsx | 6++----
Mpackages/frontend/src/paths/instance/transfers/update/index.tsx | 4++--
Mpackages/frontend/src/paths/instance/update/UpdatePage.tsx | 23+++++++++++------------
Mpackages/frontend/src/paths/instance/update/index.tsx | 5+----
Mpackages/frontend/src/paths/login/index.tsx | 1-
Mpackages/frontend/src/scss/_custom-calendar.scss | 16++++++++++++++++
Mpackages/frontend/src/scss/_loading.scss | 16++++++++++++++++
Mpackages/frontend/src/scss/fonts/nunito.css | 16++++++++++++++++
Mpackages/frontend/src/template.html | 17+++++++++++++++++
Mpackages/frontend/src/utils/amount.ts | 15+++++++++++++++
74 files changed, 540 insertions(+), 311 deletions(-)

diff --git a/packages/frontend/.storybook/preview.js b/packages/frontend/.storybook/preview.js @@ -1,3 +1,19 @@ +/* + 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 "../src/scss/main.scss" import { MessageProvider } from "preact-messages"; import { ConfigContextProvider } from '../src/context/backend' diff --git a/packages/frontend/preact.config.js b/packages/frontend/preact.config.js @@ -22,13 +22,12 @@ import { DefinePlugin } from 'webpack'; import pack from './package.json'; +import * as cp from 'child_process'; -const commitHash = require('child_process') - .execSync('git rev-parse --short HEAD') - .toString(); +const commitHash = cp.execSync('git rev-parse --short HEAD').toString(); export default { - webpack(config, env, helpers, options) { + webpack(config, env) { // ensure that process.env will not be undefined on runtime config.node.process = 'mock' diff --git a/packages/frontend/remove-link-stylesheet.sh b/packages/frontend/remove-link-stylesheet.sh @@ -1,3 +1,5 @@ +# This script has been placed in the public domain. + FILE=$(ls single/bundle.*.css) BUNDLE=${FILE#single} grep -q '<link href="'$BUNDLE'" rel="stylesheet">' single/index.html || { echo bundle $BUNDLE not found in index.html; exit 1; } diff --git a/packages/frontend/src/AdminRoutes.tsx b/packages/frontend/src/AdminRoutes.tsx @@ -15,11 +15,9 @@ */ import { h, VNode } from "preact"; import Router, { route, Route } from "preact-router"; -import { useMessageTemplate } from "preact-messages"; -import { Notification } from "./utils/types"; - -import InstanceListPage from './paths/admin/list'; import InstanceCreatePage from "./paths/admin/create"; +import InstanceListPage from './paths/admin/list'; + export enum AdminPaths { list_instances = '/instances', @@ -27,7 +25,6 @@ export enum AdminPaths { } export function AdminRoutes(): VNode { - const i18n = useMessageTemplate(); return <Router> diff --git a/packages/frontend/src/InstanceRoutes.tsx b/packages/frontend/src/InstanceRoutes.tsx @@ -19,40 +19,29 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { AnyComponent, Fragment, FunctionalComponent, FunctionComponent, h, RenderableProps, VNode } from 'preact'; -import { useCallback, useEffect, useMemo } from "preact/hooks"; -import { Route, Router, route } from 'preact-router'; -import { useMessageTemplate } from 'preact-messages'; import { createHashHistory } from 'history'; -import { useBackendDefaultToken, useBackendInstanceToken } from './hooks'; +import { Fragment, FunctionComponent, h, VNode } from 'preact'; +import { useMessageTemplate } from 'preact-messages'; +import { Route, route, Router } from 'preact-router'; +import { useCallback, useEffect, useMemo } from "preact/hooks"; +import { Loading } from './components/exception/loading'; +import { NotificationCard } from './components/menu'; import { InstanceContextProvider, useBackendContext } from './context/backend'; -import { HttpError, HttpResponseServerError, RequestInfo, SwrError } from "./hooks/backend"; -// import { Notification } from './utils/types'; - -import LoginPage from './paths/login'; +import { useBackendDefaultToken, useBackendInstanceToken } from './hooks'; +import { HttpError } from "./hooks/backend"; +import InstanceCreatePage from "./paths/admin/create"; +import InstanceListPage from './paths/admin/list'; +import OrderCreatePage from './paths/instance/orders/create'; +import OrderDetailsPage from './paths/instance/orders/details'; +import OrderListPage from './paths/instance/orders/list'; +import ProductCreatePage from './paths/instance/products/create'; +import ProductListPage from './paths/instance/products/list'; +import ProductUpdatePage from './paths/instance/products/update'; +import TransferListPage from './paths/instance/transfers/list'; import InstanceUpdatePage, { Props as InstanceUpdatePageProps } from "./paths/instance/update"; -import DetailPage from './paths/instance/details'; +import LoginPage from './paths/login'; import NotFoundPage from './paths/notfound'; -import ProductListPage from './paths/instance/products/list' -import ProductCreatePage from './paths/instance/products/create' -import ProductUpdatePage from './paths/instance/products/update' - -import OrderListPage from './paths/instance/orders/list' -import OrderCreatePage from './paths/instance/orders/create' -import OrderDetailsPage from './paths/instance/orders/details' - -import TipListPage from './paths/instance/tips/list' -import TipCreatePage from './paths/instance/tips/create' -import TipUpdatePage from './paths/instance/tips/update' - -import TransferListPage from './paths/instance/transfers/list' -import TransferCreatePage from './paths/instance/transfers/create' - -import InstanceListPage from './paths/admin/list'; -import InstanceCreatePage from "./paths/admin/create"; -import { NotificationCard } from './components/menu'; -import { Loading } from './components/exception/loading'; export enum InstancePaths { // details = '/', @@ -74,6 +63,9 @@ export enum InstancePaths { // transfers_new = '/transfer/new', } +// eslint-disable-next-line @typescript-eslint/no-empty-function +const noop = () => {} + export enum AdminPaths { list_instances = '/instances', new_instance = '/instance/new', @@ -106,7 +98,7 @@ export function InstanceRoutes({ id, admin }: Props): VNode { } }; - const value = useMemo(() => ({ id, token, admin }), [id, token]) + const value = useMemo(() => ({ id, token, admin }), [id, token, admin]) const LoginPageServerError = (error: HttpError) => <Fragment> <NotificationCard notification={{ message: `Server reported a problem: HTTP status #${error.status}`, description: `Got message: ${error.message} from: ${error.info?.url}`, type: 'ERROR' }} /> @@ -119,7 +111,7 @@ export function InstanceRoutes({ id, admin }: Props): VNode { </Fragment> function IfAdminCreateDefaultOr<T>(Next: FunctionComponent<any>) { - return (props?: T) => { + return function IfAdminCreateDefaultOrImpl(props?: T) { if (admin && id === 'default') { return <Fragment> <NotificationCard notification={{ @@ -134,9 +126,9 @@ export function InstanceRoutes({ id, admin }: Props): VNode { } if (props) { return <Next {...props} /> - } else { + } return <Next /> - } + } } @@ -167,7 +159,7 @@ export function InstanceRoutes({ id, admin }: Props): VNode { <Route path={AdminPaths.update_instance} component={AdminInstanceUpdatePage} onBack={() => route(AdminPaths.list_instances)} onConfirm={() => { route(AdminPaths.list_instances); }} - onUpdateError={(e: Error) => { }} + onUpdateError={noop} onNotFound={NotFoundPage} /> } @@ -178,7 +170,7 @@ export function InstanceRoutes({ id, admin }: Props): VNode { <Route path={InstancePaths.update} component={InstanceUpdatePage} onBack={() => { route(`/`); }} onConfirm={() => { route(`/`); }} - onUpdateError={(e: Error) => { }} + onUpdateError={noop} onNotFound={IfAdminCreateDefaultOr(NotFoundPage)} onUnauthorized={LoginPageAccessDenied} onLoadError={LoginPageServerError} diff --git a/packages/frontend/src/components/form/DatePicker.tsx b/packages/frontend/src/components/form/DatePicker.tsx @@ -196,7 +196,7 @@ 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={{ diff --git a/packages/frontend/src/components/form/Field.tsx b/packages/frontend/src/components/form/Field.tsx @@ -19,8 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode, createContext, ComponentChildren } from "preact"; -import { StateUpdater, useContext, useMemo, useState } from "preact/hooks"; +import { ComponentChildren, createContext, h, VNode } from "preact"; +import { StateUpdater, useContext, useMemo } from "preact/hooks"; export interface FormType<T> { object: Partial<T>; @@ -63,7 +63,7 @@ interface ProviderProps<T> { children: ComponentChildren } -export function FormProvider<T>({ object = {}, errors = {}, name = '', valueHandler, children }: ProviderProps<T>) { +export function FormProvider<T>({ object = {}, errors = {}, name = '', valueHandler, children }: ProviderProps<T>): VNode { const initial = useMemo(() => object,[]) const value = useMemo<FormType<T>>(() => ({errors, object, initial, valueHandler, name, toStr: {}, fromStr: {}}), [errors, object, valueHandler]) diff --git a/packages/frontend/src/components/form/InputArray.tsx b/packages/frontend/src/components/form/InputArray.tsx @@ -21,7 +21,7 @@ import { h, VNode } from "preact"; import { Message, useMessage, useMessageTemplate } from "preact-messages"; import { useState } from "preact/hooks"; -import { FormErrors, useField, ValidationError } from "./Field"; +import { useField, ValidationError } from "./Field"; export interface Props<T> { name: T; diff --git a/packages/frontend/src/components/form/InputDate.tsx b/packages/frontend/src/components/form/InputDate.tsx @@ -19,13 +19,11 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { format } from "date-fns"; -import { ComponentChildren, Fragment, h } from "preact"; +import { h, VNode } from "preact"; import { Message, useMessage } from "preact-messages"; import { useState } from "preact/hooks"; -import { Amount } from "../../declaration"; import { DatePicker } from "./DatePicker"; import { useField } from "./Field"; -import { InputWithAddon } from "./InputWithAddon"; export interface Props<T> { name: keyof T; @@ -35,13 +33,13 @@ export interface Props<T> { withTimestampSupport?: boolean; } -export function InputDate<T>({ name, readonly, expand, withTimestampSupport }: Props<T>) { +export function InputDate<T>({ name, readonly, expand, withTimestampSupport }: Props<T>): VNode { const [opened, setOpened] = useState(false) - const [editing, setEditing] = useState(false) + // const [editing, setEditing] = useState(false) const { error, value, onChange, formName } = useField<T>(name); - const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`); + // const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`); const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`); let strValue = '' diff --git a/packages/frontend/src/components/form/InputDuration.tsx b/packages/frontend/src/components/form/InputDuration.tsx @@ -18,11 +18,11 @@ * * @author Sebastian Javier Marchano (sebasjm) */ +import { formatDuration, intervalToDuration } from "date-fns"; import { h, VNode } from "preact"; import { RelativeTime } from "../../declaration"; -import { InputWithAddon } from "./InputWithAddon"; -import { formatDuration, intervalToDuration } from "date-fns"; import { useField } from "./Field"; +import { InputWithAddon } from "./InputWithAddon"; export interface Props<T> { name: keyof T; @@ -30,7 +30,7 @@ export interface Props<T> { readonly?: boolean; } -export function InputDuration<T>({ name, expand, readonly }: Props<T>) { +export function InputDuration<T>({ name, expand, readonly }: Props<T>): VNode { const { value } = useField<T>(name); return <InputWithAddon<T> name={name} readonly={readonly} addonAfter={readableDuration(value as any)} expand={expand} diff --git a/packages/frontend/src/components/form/InputGroup.tsx b/packages/frontend/src/components/form/InputGroup.tsx @@ -21,7 +21,7 @@ import { ComponentChildren, h, VNode } from "preact"; import { Message } from "preact-messages"; import { useState } from "preact/hooks"; -import { useField, useGroupField } from "./Field"; +import { useGroupField } from "./Field"; export interface Props<T> { name: keyof T; diff --git a/packages/frontend/src/components/form/InputImage.tsx b/packages/frontend/src/components/form/InputImage.tsx @@ -18,11 +18,11 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { ComponentChildren, Fragment, h } from "preact"; -import { useField } from "./Field"; -import emptyImage from "../../assets/empty.png"; +import { ComponentChildren, h } from "preact"; import { Message, useMessage } from "preact-messages"; import { useRef, useState } from "preact/hooks"; +import emptyImage from "../../assets/empty.png"; +import { useField } from "./Field"; export interface Props<T> { name: keyof T; diff --git a/packages/frontend/src/components/form/InputNumber.tsx b/packages/frontend/src/components/form/InputNumber.tsx @@ -34,7 +34,7 @@ export interface Props<T> { export function InputNumber<T>({ name, readonly, expand, children, side }: Props<T>) { return <InputWithAddon<T> name={name} readonly={readonly} - fromStr={(v) => parseInt(v, 10)} toStr={(v) => ""+v} + fromStr={(v) => parseInt(v, 10)} toStr={(v) => `${v}`} inputType='number' expand={expand} inputExtra={{ min: 0 }} children={children} diff --git a/packages/frontend/src/components/form/InputStock.tsx b/packages/frontend/src/components/form/InputStock.tsx @@ -126,7 +126,7 @@ export function InputStock<T>({ name, readonly, alreadyExist }: Props<T>) { </FormProvider> <div class="field is-horizontal"> - <div class="field-label is-normal"></div> + <div class="field-label is-normal" /> <div class="field-body is-flex-grow-3"> <div class="field"> {stockUpdateDescription} diff --git a/packages/frontend/src/components/form/InputTaxes.tsx b/packages/frontend/src/components/form/InputTaxes.tsx @@ -60,8 +60,7 @@ export function InputTaxes<T>({ name, readonly }: Props<T>) { <FormProvider<Entity> name="tax" errors={errors} object={value} valueHandler={valueHandler} > <div class="field is-horizontal"> - <div class="field-label is-normal"> - </div> + <div class="field-label is-normal" /> <div class="field-body" style={{ display: 'block' }}> {taxes.map((v: any) => <div class="tags has-addons mt-3 mb-0 mr-3" style={{ flexWrap: 'nowrap' }}> <span class="tag is-medium is-info mb-0" style={{ maxWidth: '90%' }}><b>{v.tax}</b>: {v.name}</span> diff --git a/packages/frontend/src/components/menu/LangSelector.tsx b/packages/frontend/src/components/menu/LangSelector.tsx @@ -16,9 +16,9 @@ import { h, VNode } from "preact"; import { useState } from "preact/hooks"; +import langIcon from '../../assets/icons/languageicon.svg'; import { useBackendContext } from "../../context/backend"; -import langIcon from '../../assets/icons/languageicon.svg' -import * as messages from '../../messages' +import * as messages from '../../messages'; type LangsNames = { [P in keyof typeof messages]: string diff --git a/packages/frontend/src/components/menu/SideBar.tsx b/packages/frontend/src/components/menu/SideBar.tsx @@ -21,7 +21,6 @@ import { Fragment, h, VNode } from 'preact'; -import { useContext } from 'preact/hooks'; import { useBackendContext, useConfigContext } from '../../context/backend'; import { LangSelector } from './LangSelector'; diff --git a/packages/frontend/src/components/menu/index.tsx b/packages/frontend/src/components/menu/index.tsx @@ -15,14 +15,14 @@ */ import { ComponentChildren, Fragment, h, VNode } from "preact"; +import Match from 'preact-router/match'; import { useEffect, useState } from "preact/hooks"; import { AdminPaths } from "../../AdminRoutes"; +import { calculateRootPath } from "../../hooks"; import { InstancePaths } from "../../InstanceRoutes"; +import { Notification } from "../../utils/types"; import { NavigationBar } from "./NavigationBar"; import { Sidebar } from "./SideBar"; -import Match from 'preact-router/match'; -import { Notification } from "../../utils/types"; -import { calculateRootPath } from "../../hooks"; function getInstanceTitle(path: string, id: string): string { @@ -45,7 +45,6 @@ function getInstanceTitle(path: string, id: string): string { } } -const INSTANCE_ID_LOOKUP = /^\/instance\/([^/]*)\// function getAdminTitle(path: string, instance: string) { if (path === AdminPaths.new_instance) return `New instance` if (path === AdminPaths.list_instances) return `Instances` @@ -75,14 +74,14 @@ export function Menu({ onLogout, title, instance, admin }: MenuProps): VNode { return (<WithTitle title={titleWithSubtitle}> <div class={mobileOpen ? "has-aside-mobile-expanded" : ""} onClick={() => setMobileOpen(false)}> <NavigationBar onMobileMenu={() => setMobileOpen(!mobileOpen)} title={titleWithSubtitle} /> - + {onLogout && <Sidebar onLogout={onLogout} admin={admin && adminInstance} instance={instance} mobile={mobileOpen} />} - { admin && !adminInstance && <nav class="level"> + {admin && !adminInstance && <nav class="level"> <div class="level-item has-text-centered has-background-warning"> <p class="is-size-5">You are viewing the instance <b>"{instance}"</b>. <a href={calculateRootPath()} >go back</a></p> </div> - </nav> } + </nav>} </div> </WithTitle> ) @@ -98,7 +97,7 @@ interface NotYetReadyAppMenuProps { interface NotifProps { notification?: Notification; } -export function NotificationCard({ notification: n }: NotifProps) { +export function NotificationCard({ notification: n }: NotifProps): VNode | null { if (!n) return null return <div class="notification"> <div class="columns is-vcentered"> @@ -107,10 +106,10 @@ export function NotificationCard({ notification: n }: NotifProps) { <div class="message-header"> <p>{n.message}</p> </div> - { n.description && - <div class="message-body"> - {n.description} - </div> } + {n.description && + <div class="message-body"> + {n.description} + </div>} </article> </div> </div> diff --git a/packages/frontend/src/components/modal/index.tsx b/packages/frontend/src/components/modal/index.tsx @@ -23,7 +23,6 @@ import { ComponentChildren, h, VNode } from "preact"; import { Message } from "preact-messages"; import { useState } from "preact/hooks"; -import { MerchantBackend } from "../../declaration"; import { FormProvider } from "../form/Field"; import { Input } from "../form/Input"; diff --git a/packages/frontend/src/components/notifications/CreatedSuccessfully.tsx b/packages/frontend/src/components/notifications/CreatedSuccessfully.tsx @@ -17,7 +17,7 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { ComponentChildren, h } from "preact"; +import { ComponentChildren, h, VNode } from "preact"; interface Props { onCreateAnother?: () => void; @@ -25,7 +25,7 @@ interface Props { children: ComponentChildren; } -export function CreatedSuccessfully({ children, onConfirm, onCreateAnother }: Props) { +export function CreatedSuccessfully({ children, onConfirm, onCreateAnother }: Props): VNode { return <div class="columns is-fullwidth is-vcentered content-full-size"> <div class="column" /> <div class="column is-three-quarters"> diff --git a/packages/frontend/src/components/notifications/Notifications.stories.tsx b/packages/frontend/src/components/notifications/Notifications.stories.tsx @@ -19,8 +19,8 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode } from 'preact'; -import { Notifications } from './index' +import { h } from 'preact'; +import { Notifications } from './index'; export default { diff --git a/packages/frontend/src/components/product/ProductForm.tsx b/packages/frontend/src/components/product/ProductForm.tsx @@ -1,19 +1,33 @@ +/* + 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 { h } from "preact"; import { useCallback, useEffect, useState } from "preact/hooks"; +import * as yup from 'yup'; +import { useBackendContext } from "../../context/backend"; +import { MerchantBackend } from "../../declaration"; +import { + ProductCreateSchema as createSchema, ProductUpdateSchema as updateSchema +} from '../../schemas'; import { FormErrors, FormProvider } from "../form/Field"; import { Input } from "../form/Input"; import { InputCurrency } from "../form/InputCurrency"; -import { useBackendContext, useConfigContext } from "../../context/backend"; -import { MerchantBackend } from "../../declaration"; -import { - ProductUpdateSchema as updateSchema, - ProductCreateSchema as createSchema, -} from '../../schemas' -import * as yup from 'yup'; -import { InputWithAddon } from "../form/InputWithAddon"; import { InputImage } from "../form/InputImage"; -import { InputTaxes } from "../form/InputTaxes"; import { InputStock, Stock } from "../form/InputStock"; +import { InputTaxes } from "../form/InputTaxes"; +import { InputWithAddon } from "../form/InputWithAddon"; type Entity = MerchantBackend.Products.ProductDetail & { product_id: string } @@ -79,7 +93,7 @@ export function ProductForm({ onSubscribe, initial, alreadyExist, }: Props) { <Input<Entity> name="unit" /> <InputCurrency<Entity> name="price" /> - <InputStock name="stock" alreadyExist={alreadyExist}/> + <InputStock name="stock" alreadyExist={alreadyExist} /> <InputTaxes<Entity> name="taxes" /> diff --git a/packages/frontend/src/components/product/ProductList.tsx b/packages/frontend/src/components/product/ProductList.tsx @@ -1,4 +1,19 @@ -import { h } from "preact" +/* + 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 { h, VNode } from "preact" import { MerchantBackend } from "../../declaration" import { multiplyPrice } from "../../utils/amount" @@ -9,7 +24,7 @@ interface Props { handler: (d: MerchantBackend.Product, index: number) => void; }[] } -export function ProductList({ list, actions = [] }: Props) { +export function ProductList({ list, actions = [] }: Props): VNode { return <div class="table-container"> <table class="table is-fullwidth is-striped is-hoverable is-fullwidth"> <thead> diff --git a/packages/frontend/src/context/backend.ts b/packages/frontend/src/context/backend.ts @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ import { createContext } from 'preact' -import { StateUpdater, useContext } from 'preact/hooks' +import { useContext } from 'preact/hooks' export interface BackendContextType { url: string; @@ -58,9 +58,9 @@ const ConfigContext = createContext<ConfigContextType>(null!) const InstanceContext = createContext<InstanceContextType>({} as any) export const ConfigContextProvider = ConfigContext.Provider -export const useConfigContext = () => useContext(ConfigContext); +export const useConfigContext = (): ConfigContextType => useContext(ConfigContext); export const BackendContextProvider = BackendContext.Provider -export const useBackendContext = () => useContext(BackendContext); +export const useBackendContext = (): BackendContextType => useContext(BackendContext); export const InstanceContextProvider = InstanceContext.Provider -export const useInstanceContext = () => useContext(InstanceContext); +export const useInstanceContext = (): InstanceContextType => useContext(InstanceContext); diff --git a/packages/frontend/src/hooks/admin.ts b/packages/frontend/src/hooks/admin.ts @@ -1,3 +1,18 @@ +/* + 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 { MerchantBackend } from '../declaration'; import { useBackendContext } from '../context/backend'; import { request, mutateAll } from './backend'; diff --git a/packages/frontend/src/hooks/index.ts b/packages/frontend/src/hooks/index.ts @@ -19,11 +19,12 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { StateUpdater, useCallback, useEffect, useState } from "preact/hooks"; +import { StateUpdater, useCallback, useState } from "preact/hooks"; +import { BackendContextType } from "../context/backend"; import { ValueOrFunction } from '../utils/types'; -export function useBackendContextState() { +export function useBackendContextState(): BackendContextType { const [lang, setLang] = useLang() const [url, triedToLog, changeBackend, resetBackend] = useBackendURL(); const [token, updateToken] = useBackendDefaultToken(); @@ -129,8 +130,11 @@ export function useNotNullLocalStorage(key: string, initialValue: string): [stri return [storedValue, setValue]; } +// eslint-disable-next-line @typescript-eslint/no-empty-function +const noop = () => {} + export function useListener<T>(onCall: (r: T) => void): [() => void, (listener: () => T) => void] { - const [state, setState] = useState({ run: () => { } }) + const [state, setState] = useState({ run: noop }) const subscriber = (listener: () => T) => { setState({ diff --git a/packages/frontend/src/hooks/instance.ts b/packages/frontend/src/hooks/instance.ts @@ -1,3 +1,18 @@ +/* + 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 { MerchantBackend } from '../declaration'; import { useBackendContext, useInstanceContext } from '../context/backend'; import { fetcher, HttpError, HttpResponse, HttpResponseOk, request, SwrError } from './backend'; diff --git a/packages/frontend/src/hooks/order.ts b/packages/frontend/src/hooks/order.ts @@ -1,10 +1,24 @@ -import { addHours, addSeconds, format } from 'date-fns'; +/* + 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 { useEffect, useState } from 'preact/hooks'; import useSWR from 'swr'; import { useBackendContext, useInstanceContext } from '../context/backend'; import { MerchantBackend } from '../declaration'; import { MAX_RESULT_SIZE, PAGE_SIZE } from '../utils/constants'; -import { fetcher, HttpError, HttpResponse, HttpResponseOk, HttpResponsePaginated, mutateAll, request, SwrError, WithPagination } from './backend'; +import { fetcher, HttpError, HttpResponse, HttpResponseOk, HttpResponsePaginated, mutateAll, request } from './backend'; export interface OrderAPI { //FIXME: add OutOfStockResponse on 410 @@ -182,9 +196,9 @@ export function useInstanceOrders(args: InstanceOrderFilter, updateFilter: (d: D } const orders = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.orders.slice().reverse().concat((afterData || lastAfter).data.orders) - if (loadingAfter || loadingBefore) return { loading: true, data: { orders: orders } } + if (loadingAfter || loadingBefore) return { loading: true, data: { orders } } if (beforeData && afterData) { - return { ok: true, data: { orders: orders }, ...pagination } + return { ok: true, data: { orders }, ...pagination } } return { loading: true } diff --git a/packages/frontend/src/hooks/product.ts b/packages/frontend/src/hooks/product.ts @@ -1,8 +1,23 @@ +/* + 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 { useEffect } from 'preact/hooks'; import useSWR, { useSWRInfinite } from 'swr'; import { useBackendContext, useInstanceContext } from '../context/backend'; import { MerchantBackend, WithId } from '../declaration'; -import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request, SwrError } from './backend'; +import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request } from './backend'; export interface ProductAPI { diff --git a/packages/frontend/src/hooks/tips.ts b/packages/frontend/src/hooks/tips.ts @@ -1,7 +1,22 @@ -import { MerchantBackend } from '../declaration'; -import { useBackendContext, useInstanceContext } from '../context/backend'; -import { request, mutateAll, HttpResponse, SwrError, fetcher, HttpError, HttpResponseOk } from './backend'; +/* + 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 useSWR from 'swr'; +import { useBackendContext, useInstanceContext } from '../context/backend'; +import { MerchantBackend } from '../declaration'; +import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request } from './backend'; export function useTipsMutateAPI(): TipsMutateAPI { diff --git a/packages/frontend/src/hooks/transfer.ts b/packages/frontend/src/hooks/transfer.ts @@ -1,3 +1,18 @@ +/* + 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 { MerchantBackend } from '../declaration'; import { useBackendContext, useInstanceContext } from '../context/backend'; import { request, mutateAll, HttpResponse, HttpError, HttpResponseOk } from './backend'; diff --git a/packages/frontend/src/index.tsx b/packages/frontend/src/index.tsx @@ -19,23 +19,23 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import "./scss/main.scss" - import { h, VNode } from 'preact'; -import { useMemo } from "preact/hooks"; -import { route } from 'preact-router'; import { MessageProvider, useMessageTemplate } from 'preact-messages'; - -import * as messages from './messages' -import { useBackendContextState } from './hooks'; +import { route } from 'preact-router'; +import { useMemo } from "preact/hooks"; +import { ApplicationReadyRoutes } from "./ApplicationReadyRoutes"; +import { Loading } from "./components/exception/loading"; +import { NotificationCard, NotYetReadyAppMenu } from "./components/menu"; import { BackendContextProvider, ConfigContextProvider, useBackendContext } from './context/backend'; +import { useBackendContextState } from './hooks'; import { useBackendConfig } from "./hooks/backend"; +import * as messages from './messages'; +import LoginPage from './paths/login'; +import "./scss/main.scss"; import { hasKey, onTranslationError } from "./utils/functions"; -import LoginPage from './paths/login'; -import { ApplicationReadyRoutes } from "./ApplicationReadyRoutes"; -import { NotificationCard, NotYetReadyAppMenu } from "./components/menu"; -import { Loading } from "./components/exception/loading"; + + export default function Application(): VNode { const state = useBackendContextState() @@ -50,7 +50,7 @@ export default function Application(): VNode { } function ApplicationStatusRoutes(): VNode { - const { changeBackend, triedToLog, updateToken, resetBackend } = useBackendContext() + const { changeBackend, triedToLog, updateToken } = useBackendContext() const result = useBackendConfig(); const i18n = useMessageTemplate() @@ -60,6 +60,9 @@ function ApplicationStatusRoutes(): VNode { route('/') } + const { currency, version } = result.ok ? result.data : { currency: 'unknown', version: 'unknown' } + const ctx = useMemo(() => ({ currency, version }), [currency, version]) + if (!triedToLog) { return <div id="app"> <NotYetReadyAppMenu title="Welcome!" /> @@ -104,8 +107,6 @@ function ApplicationStatusRoutes(): VNode { <LoginPage onConfirm={updateLoginInfoAndGoToRoot} /> </div> - const ctx = useMemo(() => ({ currency: result.data.currency, version: result.data.version }), [result.data.currency, result.data.version]) - return <div id="app" class="has-navbar-fixed-top"> <ConfigContextProvider value={ctx}> <ApplicationReadyRoutes /> diff --git a/packages/frontend/src/messages/en.po b/packages/frontend/src/messages/en.po @@ -1,3 +1,17 @@ +# 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/> + # Examples from http://pology.nedohodnik.net/doc/user/en_US/ch-poformat.html msgid "" msgstr "" diff --git a/packages/frontend/src/messages/es.po b/packages/frontend/src/messages/es.po @@ -1,3 +1,17 @@ +# 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/> + # Examples from http://pology.nedohodnik.net/doc/user/en_US/ch-poformat.html msgid "" msgstr "" diff --git a/packages/frontend/src/paths/admin/create/Create.stories.tsx b/packages/frontend/src/paths/admin/create/Create.stories.tsx @@ -20,7 +20,7 @@ */ import { h, VNode } from 'preact'; -import { CreatePage } from './CreatePage' +import { CreatePage } from './CreatePage'; export default { diff --git a/packages/frontend/src/paths/admin/create/CreatePage.tsx b/packages/frontend/src/paths/admin/create/CreatePage.tsx @@ -20,34 +20,29 @@ */ import { h, VNode } from "preact"; +import { Message } from "preact-messages"; import { useState } from "preact/hooks"; -import { MerchantBackend } from "../../../declaration"; import * as yup from 'yup'; -import { FormErrors, FormProvider } from "../../../components/form/Field" -import { InstanceCreateSchema as schema } from '../../../schemas' -import { Message } from "preact-messages"; +import { FormErrors, FormProvider } from "../../../components/form/Field"; import { Input } from "../../../components/form/Input"; -import { InputSecured } from "../../../components/form/InputSecured"; -import { InputWithAddon } from "../../../components/form/InputWithAddon"; -import { InputGroup } from "../../../components/form/InputGroup"; -import { useConfigContext, useBackendContext } from "../../../context/backend"; -import { InputDuration } from "../../../components/form/InputDuration"; import { InputCurrency } from "../../../components/form/InputCurrency"; +import { InputDuration } from "../../../components/form/InputDuration"; +import { InputGroup } from "../../../components/form/InputGroup"; import { InputPayto } from "../../../components/form/InputPayto"; +import { InputSecured } from "../../../components/form/InputSecured"; +import { InputWithAddon } from "../../../components/form/InputWithAddon"; +import { useBackendContext } from "../../../context/backend"; +import { MerchantBackend } from "../../../declaration"; +import { InstanceCreateSchema as schema } from '../../../schemas'; type Entity = MerchantBackend.Instances.InstanceConfigurationMessage & { auth_token?: string } interface Props { onCreate: (d: Entity) => void; - isLoading: boolean; onBack?: () => void; forceId?: string; } -interface KeyValue { - [key: string]: string; -} - function with_defaults(id?: string): Partial<Entity> { return { id, @@ -57,7 +52,7 @@ function with_defaults(id?: string): Partial<Entity> { }; } -export function CreatePage({ onCreate, isLoading, onBack, forceId }: Props): VNode { +export function CreatePage({ onCreate, onBack, forceId }: Props): VNode { const [value, valueHandler] = useState(with_defaults(forceId)) const [errors, setErrors] = useState<FormErrors<Entity>>({}) diff --git a/packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx b/packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx @@ -17,11 +17,11 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { h } from "preact"; +import { h, VNode } from "preact"; import { CreatedSuccessfully } from "../../../components/notifications/CreatedSuccessfully"; import { Entity } from "./index"; -export function InstanceCreatedSuccessfully({ entity, onConfirm }: { entity: Entity; onConfirm: () => void; }) { +export function InstanceCreatedSuccessfully({ entity, onConfirm }: { entity: Entity; onConfirm: () => void; }): VNode { return <CreatedSuccessfully onConfirm={onConfirm}> <div class="field is-horizontal"> <div class="field-label is-normal"> diff --git a/packages/frontend/src/paths/admin/create/index.tsx b/packages/frontend/src/paths/admin/create/index.tsx @@ -22,7 +22,6 @@ import { useState } from "preact/hooks"; import { NotificationCard } from "../../../components/menu"; import { MerchantBackend } from "../../../declaration"; import { useAdminAPI } from "../../../hooks/admin"; -import { RequestInfo } from "../../../hooks/backend"; import { Notification } from "../../../utils/types"; import { CreatePage } from "./CreatePage"; import { InstanceCreatedSuccessfully } from "./InstanceCreatedSuccessfully"; @@ -49,9 +48,8 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode { <CreatePage onBack={onBack} forceId={forceId} - isLoading={false} onCreate={(d: MerchantBackend.Instances.InstanceConfigurationMessage) => { - createInstance(d).then((r) => { + createInstance(d).then(() => { setCreatedOk(d) }).catch((error) => { setNotif({ diff --git a/packages/frontend/src/paths/admin/list/Table.tsx b/packages/frontend/src/paths/admin/list/Table.tsx @@ -19,11 +19,10 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode } from "preact" -import { Message } from "preact-messages" -import { StateUpdater, useEffect, useState } from "preact/hooks" -import { useBackendContext } from "../../../context/backend"; -import { MerchantBackend } from "../../../declaration" +import { h, VNode } from "preact"; +import { Message } from "preact-messages"; +import { StateUpdater, useEffect, useState } from "preact/hooks"; +import { MerchantBackend } from "../../../declaration"; import { calculateRootPath } from "../../../hooks"; interface Props { diff --git a/packages/frontend/src/paths/admin/list/View.stories.tsx b/packages/frontend/src/paths/admin/list/View.stories.tsx @@ -20,7 +20,7 @@ */ import { h } from 'preact'; -import { View } from './View' +import { View } from './View'; export default { diff --git a/packages/frontend/src/paths/admin/list/index.tsx b/packages/frontend/src/paths/admin/list/index.tsx @@ -20,15 +20,14 @@ */ import { Fragment, h, VNode } from 'preact'; -import { View } from './View'; -import { HttpError, HttpResponseServerError, RequestInfo, SwrError } from '../../../hooks/backend'; -import { useAdminAPI } from "../../../hooks/admin"; import { useState } from 'preact/hooks'; -import { MerchantBackend } from '../../../declaration'; -import { Notification } from '../../../utils/types'; -import { DeleteModal } from '../../../components/modal'; import { Loading } from '../../../components/exception/loading'; +import { DeleteModal } from '../../../components/modal'; +import { MerchantBackend } from '../../../declaration'; +import { useAdminAPI } from "../../../hooks/admin"; +import { HttpError } from '../../../hooks/backend'; import { useBackendInstances } from '../../../hooks/instance'; +import { View } from './View'; interface Props { onCreate: () => void; diff --git a/packages/frontend/src/paths/instance/details/DetailPage.tsx b/packages/frontend/src/paths/instance/details/DetailPage.tsx @@ -21,11 +21,9 @@ import { h, VNode } from "preact"; import { useState } from "preact/hooks"; -import { MerchantBackend } from "../../../declaration"; -import { InstanceSchema as schema } from '../../../schemas' -import { Message } from "preact-messages"; -import { Input } from "../../../components/form/Input"; import { FormProvider } from "../../../components/form/Field"; +import { Input } from "../../../components/form/Input"; +import { MerchantBackend } from "../../../declaration"; type Entity = MerchantBackend.Instances.InstanceReconfigurationMessage; interface Props { @@ -34,10 +32,6 @@ interface Props { selected: MerchantBackend.Instances.QueryInstancesResponse; } -interface KeyValue { - [key: string]: string; -} - function convert(from: MerchantBackend.Instances.QueryInstancesResponse): Entity { const { accounts, ...rest } = from const payto_uris = accounts.filter(a => a.active).map(a => a.payto_uri) @@ -49,9 +43,8 @@ function convert(from: MerchantBackend.Instances.QueryInstancesResponse): Entity return { ...defaults, ...rest, payto_uris }; } -export function DetailPage({ onUpdate, selected, onDelete }: Props): VNode { +export function DetailPage({ selected }: Props): VNode { const [value, valueHandler] = useState<Partial<Entity>>(convert(selected)) - const [errors, setErrors] = useState<KeyValue>({}) return <div> <section class="hero is-hero-bar"> @@ -75,7 +68,7 @@ export function DetailPage({ onUpdate, selected, onDelete }: Props): VNode { <div class="columns"> <div class="column" /> <div class="column is-6"> - <FormProvider<Entity> errors={errors} object={value} valueHandler={valueHandler} > + <FormProvider<Entity> object={value} valueHandler={valueHandler} > <Input<Entity> name="name" readonly /> <Input<Entity> name="payto_uris" readonly /> diff --git a/packages/frontend/src/paths/instance/details/index.tsx b/packages/frontend/src/paths/instance/details/index.tsx @@ -15,13 +15,12 @@ */ import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; -import { useInstanceContext } from "../../../context/backend"; -import { HttpError, HttpResponseServerError, RequestInfo, SwrError } from "../../../hooks/backend"; -import { DetailPage } from "./DetailPage"; -import { DeleteModal } from "../../../components/modal"; import { Loading } from "../../../components/exception/loading"; +import { DeleteModal } from "../../../components/modal"; +import { useInstanceContext } from "../../../context/backend"; +import { HttpError } from "../../../hooks/backend"; import { useInstanceAPI, useInstanceDetails } from "../../../hooks/instance"; -import { MerchantBackend } from "../../../declaration"; +import { DetailPage } from "./DetailPage"; interface Props { onUnauthorized: () => VNode; diff --git a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx @@ -19,24 +19,24 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { add } from "date-fns"; import { Fragment, h, VNode } from "preact"; -import { useEffect, useState } from "preact/hooks"; -import { MerchantBackend, WithId } from "../../../../declaration"; -import { FormErrors, FormProvider } from "../../../../components/form/Field" import { Message } from "preact-messages"; -import { useConfigContext } from "../../../../context/backend"; -import { InputGroup } from "../../../../components/form/InputGroup"; -import { InventoryProductForm } from "./InventoryProductForm"; -import { NonInventoryProductFrom } from "./NonInventoryProductForm"; -import { InputCurrency } from "../../../../components/form/InputCurrency"; -import { Input } from "../../../../components/form/Input"; -import { OrderCreateSchema as schema } from '../../../../schemas/index'; +import { useEffect, useState } from "preact/hooks"; import * as yup from 'yup'; +import { FormErrors, FormProvider } from "../../../../components/form/Field"; +import { Input } from "../../../../components/form/Input"; +import { InputCurrency } from "../../../../components/form/InputCurrency"; import { InputDate } from "../../../../components/form/InputDate"; +import { InputGroup } from "../../../../components/form/InputGroup"; +import { ProductList } from "../../../../components/product/ProductList"; +import { useConfigContext } from "../../../../context/backend"; +import { MerchantBackend, WithId } from "../../../../declaration"; import { useInstanceDetails } from "../../../../hooks/instance"; -import { add } from "date-fns"; +import { OrderCreateSchema as schema } from '../../../../schemas/index'; import { multiplyPrice, rate, subtractPrices, sumPrices } from "../../../../utils/amount"; -import { ProductList } from "../../../../components/product/ProductList"; +import { InventoryProductForm } from "./InventoryProductForm"; +import { NonInventoryProductFrom } from "./NonInventoryProductForm"; interface Props { onCreate: (d: MerchantBackend.Orders.PostOrderRequest) => void; @@ -198,27 +198,31 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { } }) }) - }, [value.pricing.order_price]) + }, [value.pricing.order_price, totalTax]) const details_response = useInstanceDetails() + const dmwf = !details_response.ok ? undefined : details_response.data.default_max_wire_fee; + const dmdf = !details_response.ok ? undefined : details_response.data.default_max_deposit_fee; + const dwfa = !details_response.ok ? undefined : details_response.data.default_wire_fee_amortization; + const dpd = !details_response.ok ? undefined : details_response.data.default_pay_delay; useEffect(() => { if (details_response.ok) { valueHandler(v => { - const defaultPayDeadline = !details_response.data.default_pay_delay || details_response.data.default_pay_delay.d_ms === "forever" ? undefined : add(new Date(), { seconds: details_response.data.default_pay_delay.d_ms / 1000 }) + const defaultPayDeadline = !dpd || dpd.d_ms === "forever" ? undefined : add(new Date(), { seconds: dpd.d_ms / 1000 }) return ({ ...v, payments: { ...v.payments, - max_wire_fee: details_response.data.default_max_wire_fee, - max_fee: details_response.data.default_max_deposit_fee, - wire_fee_amortization: details_response.data.default_wire_fee_amortization, + max_wire_fee: dmwf, + max_fee: dmdf, + wire_fee_amortization: dwfa, pay_deadline: defaultPayDeadline, refund_deadline: defaultPayDeadline, } }) }) } - }, [details_response.ok]) + }, [details_response.ok, dmwf, dmdf, dwfa, dpd]) return <div> diff --git a/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx b/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx @@ -1,4 +1,19 @@ -import { h } from "preact"; +/* + 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 { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { FormErrors, FormProvider } from "../../../../components/form/Field"; import { InputNumber } from "../../../../components/form/InputNumber"; @@ -16,7 +31,7 @@ interface Props { onAddProduct: (product: MerchantBackend.Products.ProductDetail & WithId, quantity: number) => void } -export function InventoryProductForm({ currentProducts, onAddProduct }: Props) { +export function InventoryProductForm({ currentProducts, onAddProduct }: Props): VNode { const [state, setState] = useState<Partial<Form>>({}) const [errors, setErrors] = useState<FormErrors<Form>>({}) diff --git a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx @@ -1,9 +1,24 @@ -import { Fragment, h } from "preact"; +/* + 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 { Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { ConfirmModal } from "../../../../components/modal"; +import { ProductForm } from "../../../../components/product/ProductForm"; import { MerchantBackend } from "../../../../declaration"; import { useListener } from "../../../../hooks"; -import { ProductForm } from "../../../../components/product/ProductForm"; type Entity = MerchantBackend.Product @@ -11,7 +26,7 @@ interface Props { onAddProduct: (p: Entity) => void; value?: Entity; } -export function NonInventoryProductFrom({ value, onAddProduct }: Props) { +export function NonInventoryProductFrom({ value, onAddProduct }: Props): VNode { const [showCreateProduct, setShowCreateProduct] = useState(false) const editing = !!value @@ -20,7 +35,7 @@ export function NonInventoryProductFrom({ value, onAddProduct }: Props) { setShowCreateProduct(editing) }, [editing]) - const [ submitForm, addFormSubmitter ] = useListener<Partial<MerchantBackend.Products.ProductAddDetail> | undefined>((result) => { + const [submitForm, addFormSubmitter] = useListener<Partial<MerchantBackend.Products.ProductAddDetail> | undefined>((result) => { if (result) { setShowCreateProduct(false) onAddProduct({ @@ -39,7 +54,7 @@ export function NonInventoryProductFrom({ value, onAddProduct }: Props) { total_stock: value?.quantity || 0, taxes: [] } - + return <Fragment> <div class="buttons"> <button class="button is-success" onClick={() => setShowCreateProduct(true)} >add new product</button> diff --git a/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx b/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx @@ -13,7 +13,7 @@ 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 { h } from "preact"; +import { h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { CreatedSuccessfully } from "../../../../components/notifications/CreatedSuccessfully"; import { useOrderAPI } from "../../../../hooks/order"; @@ -25,15 +25,15 @@ interface Props { onCreateAnother?: () => void; } -export function OrderCreatedSuccessfully({ entity, onConfirm, onCreateAnother }: Props) { +export function OrderCreatedSuccessfully({ entity, onConfirm, onCreateAnother }: Props): VNode { const { getPaymentURL } = useOrderAPI() const [url, setURL] = useState<string | undefined>(undefined) - + useEffect(() => { getPaymentURL(entity.response.order_id).then(response => { setURL(response.data) }) - },[entity.response.order_id]) + }, [getPaymentURL, entity.response.order_id]) return <CreatedSuccessfully onConfirm={onConfirm} onCreateAnother={onCreateAnother}> <div class="field is-horizontal"> diff --git a/packages/frontend/src/paths/instance/orders/create/index.tsx b/packages/frontend/src/paths/instance/orders/create/index.tsx @@ -36,7 +36,7 @@ interface Props { onBack?: () => void; onConfirm: () => void; } -export default function ({ onConfirm, onBack }: Props): VNode { +export default function OrderCreate({ onConfirm, onBack }: Props): VNode { const { createOrder } = useOrderAPI() const [notif, setNotif] = useState<Notification | undefined>(undefined) const [createdOk, setCreatedOk] = useState<Entity | undefined>(undefined); diff --git a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx @@ -19,20 +19,19 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { format } from "date-fns"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; -import { MerchantBackend } from "../../../../declaration"; -import { Input } from "../../../../components/form/Input"; import { FormProvider } from "../../../../components/form/Field"; -import { NotificationCard } from "../../../../components/menu"; -import { useConfigContext } from "../../../../context/backend"; +import { Input } from "../../../../components/form/Input"; import { InputCurrency } from "../../../../components/form/InputCurrency"; +import { NotificationCard } from "../../../../components/menu"; +import { ProductList } from "../../../../components/product/ProductList"; +import { MerchantBackend } from "../../../../declaration"; +import { mergeRefunds } from "../../../../utils/amount"; import { copyToClipboard } from "../../../../utils/functions"; -import { format } from "date-fns"; -import { Event, Timeline } from "./Timeline"; import { RefundModal } from "../list/Table"; -import { mergeRefunds } from "../../../../utils/amount"; -import { ProductList } from "../../../../components/product/ProductList"; +import { Event, Timeline } from "./Timeline"; type Entity = MerchantBackend.Orders.MerchantOrderStatusResponse; interface Props { @@ -42,10 +41,6 @@ interface Props { onRefund: (id: string, value: MerchantBackend.Orders.RefundRequest) => void; } -interface KeyValue { - [key: string]: string; -} - type Paid = MerchantBackend.Orders.CheckPaymentPaidResponse type Unpaid = MerchantBackend.Orders.CheckPaymentUnpaidResponse type Claimed = MerchantBackend.Orders.CheckPaymentClaimedResponse @@ -86,8 +81,6 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. events.sort((a, b) => a.when.getTime() - b.when.getTime()) const [value, valueHandler] = useState<Partial<Claimed>>(order) - const [errors, setErrors] = useState<KeyValue>({}) - const config = useConfigContext() return <div> <section class="section"> @@ -152,7 +145,7 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. </div> <div class="column is-8" > <div class="title">Payment details</div> - <FormProvider<Claimed> errors={errors} object={value} valueHandler={valueHandler} > + <FormProvider<Claimed> object={value} valueHandler={valueHandler} > <Input name="contract_terms.summary" readonly inputType="multiline" /> <InputCurrency name="contract_terms.amount" readonly /> <Input<Claimed> name="order_status" readonly /> @@ -209,7 +202,7 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. description: 'delivery', type: 'delivery' }) - order.refund_details.reduce(mergeRefunds,[]).forEach(e => { + order.refund_details.reduce(mergeRefunds, []).forEach(e => { events.push({ when: new Date(e.timestamp.t_ms), description: `refund: ${e.amount}: ${e.reason}`, @@ -231,8 +224,7 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. }) events.sort((a, b) => a.when.getTime() - b.when.getTime()) - const [value, valueHandler] = useState<Partial<Paid>>({ ...order, fee: 'COL:0.1' } as any) - const [errors, setErrors] = useState<KeyValue>({}) + const [value, valueHandler] = useState<Partial<Paid>>(order) const refundable = new Date().getTime() < order.contract_terms.refund_deadline.t_ms @@ -307,10 +299,9 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. </div> <div class="column is-8" > <div class="title">Payment details</div> - <FormProvider<Paid> errors={errors} object={value} valueHandler={valueHandler} > + <FormProvider<Paid> object={value} valueHandler={valueHandler} > <Input name="contract_terms.summary" readonly inputType="multiline" /> <InputCurrency name="contract_terms.amount" readonly /> - <InputCurrency name="fee" readonly /> {order.refunded && <InputCurrency<Paid> name="refund_amount" readonly />} <InputCurrency<Paid> name="deposit_total" readonly /> <Input<Paid> name="order_status" readonly /> @@ -327,7 +318,7 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. </div> <div class="column" /> </div> - </section> :undefined } + </section> : undefined} </div> <div class="column" /> @@ -338,7 +329,6 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.CheckPaymentUnpaidResponse }) { const [value, valueHandler] = useState<Partial<Unpaid>>(order) - const [errors, setErrors] = useState<KeyValue>({}) return <div> <section class="hero is-hero-bar"> @@ -376,7 +366,7 @@ function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.C <div class="columns"> <div class="column" /> <div class="column is-6"> - <FormProvider<Unpaid> errors={errors} object={value} valueHandler={valueHandler} > + <FormProvider<Unpaid> object={value} valueHandler={valueHandler} > <Input<Unpaid> name="order_status" readonly /> <Input<Unpaid> name="order_status_url" readonly /> <Input<Unpaid> name="taler_pay_uri" readonly /> @@ -395,7 +385,7 @@ export function DetailPage({ id, selected, onRefund }: Props): VNode { const DetailByStatus = function () { switch (selected.order_status) { case 'claimed': return <ClaimedPage id={id} order={selected} /> - case 'paid': return <PaidPage id={id} order={selected} onRefund={(order) => setShowRefund(id)} /> + case 'paid': return <PaidPage id={id} order={selected} onRefund={setShowRefund} /> case 'unpaid': return <UnpaidPage id={id} order={selected} /> default: return <div>unknown order status</div> } diff --git a/packages/frontend/src/paths/instance/orders/details/Timeline.tsx b/packages/frontend/src/paths/instance/orders/details/Timeline.tsx @@ -1,3 +1,18 @@ +/* + 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 { format } from "date-fns"; import { h } from "preact"; diff --git a/packages/frontend/src/paths/instance/orders/details/index.tsx b/packages/frontend/src/paths/instance/orders/details/index.tsx @@ -17,8 +17,7 @@ import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading"; import { NotificationCard } from "../../../../components/menu"; -import { MerchantBackend } from "../../../../declaration"; -import { HttpError, HttpResponseServerError, RequestInfo } from "../../../../hooks/backend"; +import { HttpError } from "../../../../hooks/backend"; import { useOrderDetails, useOrderAPI } from "../../../../hooks/order"; import { Notification } from "../../../../utils/types"; import { DetailPage } from "./DetailPage"; diff --git a/packages/frontend/src/paths/instance/orders/list/Table.tsx b/packages/frontend/src/paths/instance/orders/list/Table.tsx @@ -20,22 +20,20 @@ */ import { format } from "date-fns"; -import { Fragment, h, VNode } from "preact" -import { Message } from "preact-messages" -import { StateUpdater, useCallback, useEffect, useRef, useState } from "preact/hooks" +import { h, VNode } from "preact"; +import { Message } from "preact-messages"; +import { StateUpdater, useState } from "preact/hooks"; import { FormErrors, FormProvider } from "../../../../components/form/Field"; import { Input } from "../../../../components/form/Input"; import { InputCurrency } from "../../../../components/form/InputCurrency"; import { InputGroup } from "../../../../components/form/InputGroup"; import { InputSelector } from "../../../../components/form/InputSelector"; import { ConfirmModal } from "../../../../components/modal"; -import { useConfigContext } from "../../../../context/backend"; -import { MerchantBackend, WithId } from "../../../../declaration" +import { MerchantBackend, WithId } from "../../../../declaration"; import { useOrderDetails } from "../../../../hooks/order"; import { RefoundSchema } from "../../../../schemas"; import { mergeRefunds, subtractPrices, sumPrices } from "../../../../utils/amount"; import { AMOUNT_ZERO_REGEX } from "../../../../utils/constants"; -import { Actions, buildActions } from "../../../../utils/table"; type Entity = MerchantBackend.Orders.OrderHistoryEntry & WithId interface Props { @@ -49,12 +47,9 @@ interface Props { hasMoreAfter?: boolean; onLoadMoreAfter?: () => void; } -// onLoadMoreBefore={result.loadMorePrev} hasMoreBefore={!result.isReachingStart} -// onLoadMoreAfter={result.loadMore} hasMoreAfter={!result.isReachingEnd} export function CardTable({ instances, onCreate, onRefund, onCopyURL, onSelect, onLoadMoreAfter, onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: Props): VNode { - const [actionQueue, actionQueueHandler] = useState<Actions<Entity>[]>([]); const [rowSelection, rowSelectionHandler] = useState<string[]>([]) const [showRefund, setShowRefund] = useState<string | undefined>(undefined) @@ -124,7 +119,7 @@ function Table({ instances, onSelect, onRefund, onCopyURL, onLoadMoreAfter, onLo </tr> </thead> <tbody> - {instances.map((i, pos) => { + {instances.map((i) => { return <tr> <td onClick={(): void => onSelect(i)} style={{ cursor: 'pointer' }} >{format(new Date(i.timestamp.t_ms), 'yyyy/MM/dd HH:mm:ss')}</td> <td onClick={(): void => onSelect(i)} style={{ cursor: 'pointer' }} >{i.amount}</td> diff --git a/packages/frontend/src/paths/instance/orders/list/index.tsx b/packages/frontend/src/paths/instance/orders/list/index.tsx @@ -19,18 +19,17 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { format } from 'date-fns'; import { h, VNode } from 'preact'; import { useState } from 'preact/hooks'; -import { MerchantBackend } from '../../../../declaration'; -import { HttpError, HttpResponseServerError, RequestInfo, SwrError } from '../../../../hooks/backend'; -import { CardTable } from './Table'; -import { format } from 'date-fns'; +import { Loading } from '../../../../components/exception/loading'; import { DatePicker } from '../../../../components/form/DatePicker'; import { NotificationCard } from '../../../../components/menu'; -import { Notification } from '../../../../utils/types'; -import { copyToClipboard } from '../../../../utils/functions'; +import { HttpError } from '../../../../hooks/backend'; import { InstanceOrderFilter, useInstanceOrders, useOrderAPI } from '../../../../hooks/order'; -import { Loading } from '../../../../components/exception/loading'; +import { copyToClipboard } from '../../../../utils/functions'; +import { Notification } from '../../../../utils/types'; +import { CardTable } from './Table'; interface Props { onUnauthorized: () => VNode; @@ -71,7 +70,7 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo return; } try { - const r = await getPaymentURL(orderId) + await getPaymentURL(orderId) onSelect(orderId) setErrorOrderId(undefined) } catch { diff --git a/packages/frontend/src/paths/instance/products/create/CreatePage.tsx b/packages/frontend/src/paths/instance/products/create/CreatePage.tsx @@ -20,9 +20,9 @@ */ import { h, VNode } from "preact"; -import { MerchantBackend } from "../../../../declaration"; import { Message } from "preact-messages"; import { ProductForm } from "../../../../components/product/ProductForm"; +import { MerchantBackend } from "../../../../declaration"; import { useListener } from "../../../../hooks"; type Entity = MerchantBackend.Products.ProductDetail & { product_id: string} diff --git a/packages/frontend/src/paths/instance/products/create/CreatedSuccessfully.tsx b/packages/frontend/src/paths/instance/products/create/CreatedSuccessfully.tsx @@ -13,7 +13,7 @@ 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 { h } from "preact"; +import { h, VNode } from "preact"; import { CreatedSuccessfully as Template } from "../../../../components/notifications/CreatedSuccessfully"; import { Entity } from "./index"; @@ -23,7 +23,7 @@ interface Props { onCreateAnother?: () => void; } -export function CreatedSuccessfully({ entity, onConfirm, onCreateAnother }: Props) { +export function CreatedSuccessfully({ entity, onConfirm, onCreateAnother }: Props): VNode { return <Template onConfirm={onConfirm} onCreateAnother={onCreateAnother}> <div class="field is-horizontal"> diff --git a/packages/frontend/src/paths/instance/products/create/index.tsx b/packages/frontend/src/paths/instance/products/create/index.tsx @@ -23,18 +23,17 @@ import { Fragment, h, VNode } from 'preact'; import { useState } from 'preact/hooks'; import { NotificationCard } from '../../../../components/menu'; import { MerchantBackend } from '../../../../declaration'; -import { useOrderAPI } from '../../../../hooks/order'; +import { useProductAPI } from '../../../../hooks/product'; import { Notification } from '../../../../utils/types'; -import { CreatePage } from './CreatePage'; import { CreatedSuccessfully } from './CreatedSuccessfully'; -import { useProductAPI } from '../../../../hooks/product'; +import { CreatePage } from './CreatePage'; export type Entity = MerchantBackend.Products.ProductAddDetail interface Props { onBack?: () => void; onConfirm: () => void; } -export default function ({ onConfirm, onBack }: Props): VNode { +export default function CreateProduct({ onConfirm, onBack }: Props): VNode { const { createProduct } = useProductAPI() const [notif, setNotif] = useState<Notification | undefined>(undefined) const [createdOk, setCreatedOk] = useState<Entity | undefined>(undefined); diff --git a/packages/frontend/src/paths/instance/products/list/Table.tsx b/packages/frontend/src/paths/instance/products/list/Table.tsx @@ -22,15 +22,11 @@ import { format } from "date-fns" import { ComponentChildren, Fragment, h, VNode } from "preact" import { Message } from "preact-messages" -import { StateUpdater, useEffect, useState } from "preact/hooks" +import { StateUpdater, useState } from "preact/hooks" import { FormErrors, FormProvider } from "../../../../components/form/Field" -import { Input } from "../../../../components/form/Input" import { InputCurrency } from "../../../../components/form/InputCurrency" import { InputNumber } from "../../../../components/form/InputNumber" -import { useConfigContext } from "../../../../context/backend" import { MerchantBackend, WithId } from "../../../../declaration" -import { useProductAPI } from "../../../../hooks/product" -import { Actions, buildActions } from "../../../../utils/table" type Entity = MerchantBackend.Products.ProductDetail & WithId @@ -50,9 +46,7 @@ export function CardTable({ instances, onCreate, onSelect, onUpdate, onDelete }: <header class="card-header"> <p class="card-header-title"><span class="icon"><i class="mdi mdi-shopping" /></span><Message id="Products" /></p> - <div class="card-header-icon" aria-label="more options"> - - </div> + <div class="card-header-icon" aria-label="more options" /> <div class="card-header-icon" aria-label="more options"> <button class="button is-info" type="button" onClick={onCreate}> <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" /></span> @@ -100,7 +94,7 @@ function Table({ rowSelection, rowSelectionHandler, instances, onSelect, onUpdat <tbody> {instances.map(i => { - let restStockInfo = !i.next_restock ? '' : ( + const restStockInfo = !i.next_restock ? '' : ( i.next_restock.t_ms === 'never' ? 'never' : `restock at ${format(new Date(i.next_restock.t_ms), 'yyyy/MM/dd')}` @@ -183,7 +177,7 @@ function FastProductUpdateForm({ product, onUpdate, onCancel }: FastProductUpdat <InputNumber<FastProductUpdate> name="incoming" /> <InputNumber<FastProductUpdate> name="lost" /> <div class="field is-horizontal"> - <div class="field-label is-normal"></div> + <div class="field-label is-normal" /> <div class="field-body is-flex-grow-3"> <div class="field"> {stockUpdateDescription} @@ -224,10 +218,10 @@ function EmptyTable(): VNode { function difference(price: string, tax: number) { if (!tax) return price; const ps = price.split(':') - const p = parseInt(ps[1]) + const p = parseInt(ps[1], 10) ps[1] = `${p - tax}` return ps.join(':') } function sum(taxes: MerchantBackend.Tax[]) { - return taxes.reduce((p, c) => p + parseInt(c.tax.split(':')[1]), 0) + return taxes.reduce((p, c) => p + parseInt(c.tax.split(':')[1], 10), 0) } \ No newline at end of file diff --git a/packages/frontend/src/paths/instance/products/list/index.tsx b/packages/frontend/src/paths/instance/products/list/index.tsx @@ -20,16 +20,14 @@ */ import { h, VNode } from 'preact'; -import { HttpError } from '../../../../hooks/backend'; -import { useProductAPI } from "../../../../hooks/product"; -import { CardTable } from './Table'; -import { useConfigContext } from '../../../../context/backend'; -import { MerchantBackend, WithId } from '../../../../declaration'; +import { useState } from 'preact/hooks'; import { Loading } from '../../../../components/exception/loading'; -import { useInstanceProducts } from '../../../../hooks/product'; import { NotificationCard } from '../../../../components/menu'; -import { useState } from 'preact/hooks'; +import { MerchantBackend, WithId } from '../../../../declaration'; +import { HttpError } from '../../../../hooks/backend'; +import { useInstanceProducts, useProductAPI } from "../../../../hooks/product"; import { Notification } from '../../../../utils/types'; +import { CardTable } from './Table'; interface Props { onUnauthorized: () => VNode; @@ -38,7 +36,7 @@ interface Props { onSelect: (id: string) => void; onLoadError: (e: HttpError) => VNode; } -export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNotFound }: Props): VNode { +export default function ProductList({ onUnauthorized, onLoadError, onCreate, onSelect, onNotFound }: Props): VNode { const result = useInstanceProducts() const { deleteProduct, updateProduct } = useProductAPI() const [notif, setNotif] = useState<Notification | undefined>(undefined) diff --git a/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx b/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx @@ -20,9 +20,9 @@ */ import { h, VNode } from "preact"; -import { MerchantBackend, WithId } from "../../../../declaration"; import { Message } from "preact-messages"; import { ProductForm } from "../../../../components/product/ProductForm"; +import { MerchantBackend, WithId } from "../../../../declaration"; import { useListener } from "../../../../hooks"; type Entity = MerchantBackend.Products.ProductDetail & WithId diff --git a/packages/frontend/src/paths/instance/products/update/index.tsx b/packages/frontend/src/paths/instance/products/update/index.tsx @@ -21,14 +21,13 @@ import { Fragment, h, VNode } from 'preact'; import { useState } from 'preact/hooks'; +import { Loading } from '../../../../components/exception/loading'; import { NotificationCard } from '../../../../components/menu'; import { MerchantBackend } from '../../../../declaration'; -import { useOrderAPI } from '../../../../hooks/order'; +import { HttpError } from '../../../../hooks/backend'; +import { useProductAPI, useProductDetails } from '../../../../hooks/product'; import { Notification } from '../../../../utils/types'; import { UpdatePage } from './UpdatePage'; -import { useProductAPI, useProductDetails } from '../../../../hooks/product'; -import { HttpError } from '../../../../hooks/backend'; -import { Loading } from '../../../../components/exception/loading'; export type Entity = MerchantBackend.Products.ProductAddDetail interface Props { @@ -39,7 +38,7 @@ interface Props { onLoadError: (e: HttpError) => VNode; pid: string; } -export default function ({ pid, onConfirm, onBack, onUnauthorized, onNotFound, onLoadError }: Props): VNode { +export default function UpdateProduct({ pid, onConfirm, onBack, onUnauthorized, onNotFound, onLoadError }: Props): VNode { const { updateProduct } = useProductAPI() const result = useProductDetails(pid) const [notif, setNotif] = useState<Notification | undefined>(undefined) diff --git a/packages/frontend/src/paths/instance/tips/create/index.tsx b/packages/frontend/src/paths/instance/tips/create/index.tsx @@ -21,6 +21,6 @@ import { h, VNode } from 'preact'; -export default function ():VNode { +export default function CreateTips():VNode { return <div>tip create page</div> } \ No newline at end of file diff --git a/packages/frontend/src/paths/instance/tips/list/index.tsx b/packages/frontend/src/paths/instance/tips/list/index.tsx @@ -23,7 +23,7 @@ import { h, VNode } from 'preact'; import { Loading } from '../../../../components/exception/loading'; import { useConfigContext } from '../../../../context/backend'; import { MerchantBackend } from '../../../../declaration'; -import { HttpError, HttpResponseServerError, RequestInfo } from '../../../../hooks/backend'; +import { HttpError } from '../../../../hooks/backend'; import { useInstanceTips, useTipsMutateAPI } from "../../../../hooks/tips"; import { CardTable } from './Table'; @@ -32,7 +32,7 @@ interface Props { onLoadError: (e: HttpError) => VNode; onNotFound: () => VNode; } -export default function ({ onUnauthorized, onLoadError, onNotFound }: Props): VNode { +export default function ListTips({ onUnauthorized, onLoadError, onNotFound }: Props): VNode { const result = useInstanceTips() const { createReserve, deleteReserve } = useTipsMutateAPI() const { currency } = useConfigContext() diff --git a/packages/frontend/src/paths/instance/tips/update/index.tsx b/packages/frontend/src/paths/instance/tips/update/index.tsx @@ -21,6 +21,6 @@ import { h, VNode } from 'preact'; -export default function ():VNode { +export default function UpdateTips():VNode { return <div>tip update page</div> } \ No newline at end of file diff --git a/packages/frontend/src/paths/instance/transfers/create/index.tsx b/packages/frontend/src/paths/instance/transfers/create/index.tsx @@ -21,6 +21,6 @@ import { h, VNode } from 'preact'; -export default function ():VNode { +export default function CreateTransfer():VNode { return <div>transfer create page</div> } \ No newline at end of file diff --git a/packages/frontend/src/paths/instance/transfers/list/index.tsx b/packages/frontend/src/paths/instance/transfers/list/index.tsx @@ -21,9 +21,7 @@ import { h, VNode } from 'preact'; import { Loading } from '../../../../components/exception/loading'; -import { useConfigContext } from '../../../../context/backend'; -import { MerchantBackend } from '../../../../declaration'; -import { HttpError, HttpResponseServerError, RequestInfo, SwrError } from '../../../../hooks/backend'; +import { HttpError } from '../../../../hooks/backend'; import { useInstanceTransfers, useTransferMutateAPI } from "../../../../hooks/transfer"; import { CardTable } from './Table'; @@ -32,7 +30,7 @@ interface Props { onLoadError: (error: HttpError) => VNode; onNotFound: () => VNode; } -export default function ({ onUnauthorized, onLoadError, onNotFound }: Props): VNode { +export default function ListTransfer({ onUnauthorized, onLoadError, onNotFound }: Props): VNode { const result = useInstanceTransfers() const { informTransfer } = useTransferMutateAPI() diff --git a/packages/frontend/src/paths/instance/transfers/update/index.tsx b/packages/frontend/src/paths/instance/transfers/update/index.tsx @@ -21,6 +21,6 @@ import { h, VNode } from 'preact'; -export default function ():VNode { - return <div>order update page</div> +export default function UpdateTransfer():VNode { + return <div>order transfer page</div> } \ No newline at end of file diff --git a/packages/frontend/src/paths/instance/update/UpdatePage.tsx b/packages/frontend/src/paths/instance/update/UpdatePage.tsx @@ -20,21 +20,20 @@ */ import { h, VNode } from "preact"; -import { useContext, useState } from "preact/hooks"; -import { MerchantBackend } from "../../../declaration"; -import * as yup from 'yup'; -import { FormProvider, FormErrors } from "../../../components/form/Field" -import { InputGroup } from "../../../components/form/InputGroup" - -import { InstanceUpdateSchema as schema } from '../../../schemas' import { Message } from "preact-messages"; +import { useState } from "preact/hooks"; +import * as yup from 'yup'; +import { FormErrors, FormProvider } from "../../../components/form/Field"; import { Input } from "../../../components/form/Input"; -import { InputSecured } from "../../../components/form/InputSecured"; -import { useConfigContext, useInstanceContext } from "../../../context/backend"; -import { InputDuration } from "../../../components/form/InputDuration"; import { InputCurrency } from "../../../components/form/InputCurrency"; +import { InputDuration } from "../../../components/form/InputDuration"; +import { InputGroup } from "../../../components/form/InputGroup"; import { InputPayto } from "../../../components/form/InputPayto"; -import { InputArray } from "../../../components/form/InputArray"; +import { InputSecured } from "../../../components/form/InputSecured"; +import { useInstanceContext } from "../../../context/backend"; +import { MerchantBackend } from "../../../declaration"; +import { InstanceUpdateSchema as schema } from '../../../schemas'; + type Entity = MerchantBackend.Instances.InstanceReconfigurationMessage & { auth_token?: string } @@ -63,7 +62,7 @@ function getTokenValuePart(t?: string): string | undefined { return match[1] } -export function UpdatePage({ onUpdate, isLoading, selected, onBack }: Props): VNode { +export function UpdatePage({ onUpdate, selected, onBack }: Props): VNode { const { token } = useInstanceContext() const currentTokenValue = getTokenValuePart(token) const [value, valueHandler] = useState<Partial<Entity>>(convert(selected, currentTokenValue)) diff --git a/packages/frontend/src/paths/instance/update/index.tsx b/packages/frontend/src/paths/instance/update/index.tsx @@ -14,12 +14,9 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ import { Fragment, h, VNode } from "preact"; -import { useState } from "preact/hooks"; import { Loading } from "../../../components/exception/loading"; -import { UpdateTokenModal } from "../../../components/modal"; -import { useInstanceContext } from "../../../context/backend"; import { MerchantBackend } from "../../../declaration"; -import { HttpError, HttpResponseServerError, RequestInfo, SwrError } from "../../../hooks/backend"; +import { HttpError } from "../../../hooks/backend"; import { useInstanceAPI, useInstanceDetails } from "../../../hooks/instance"; import { UpdatePage } from "./UpdatePage"; diff --git a/packages/frontend/src/paths/login/index.tsx b/packages/frontend/src/paths/login/index.tsx @@ -20,7 +20,6 @@ */ import { h, VNode } from "preact"; import { LoginModal } from '../../components/exception/login'; -import { Notification } from "../../utils/types"; interface Props { onConfirm: (url: string, token?: string) => void; diff --git a/packages/frontend/src/scss/_custom-calendar.scss b/packages/frontend/src/scss/_custom-calendar.scss @@ -1,3 +1,19 @@ +/* + 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/> + */ + :root { --primary-color: #3298dc; diff --git a/packages/frontend/src/scss/_loading.scss b/packages/frontend/src/scss/_loading.scss @@ -1,3 +1,19 @@ +/* + 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/> + */ + .lds-ring { display: inline-block; position: relative; diff --git a/packages/frontend/src/scss/fonts/nunito.css b/packages/frontend/src/scss/fonts/nunito.css @@ -1,3 +1,19 @@ +/* + 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/> + */ + @font-face { font-family: 'Nunito'; font-style: normal; diff --git a/packages/frontend/src/template.html b/packages/frontend/src/template.html @@ -1,3 +1,20 @@ +<!-- + 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 +--> <!DOCTYPE html> <html lang="en" class="has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded"> <head> diff --git a/packages/frontend/src/utils/amount.ts b/packages/frontend/src/utils/amount.ts @@ -1,3 +1,18 @@ +/* + 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 { MerchantBackend } from "../declaration"; /**