merchant-backoffice

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

commit 6c363c92e2e371e8a961965c7f3534be9e32e994
parent 8877b1438bca30f1b9f4d4ccf2e376b0edab1c1b
Author: Sebastian <sebasjm@gmail.com>
Date:   Fri, 26 Feb 2021 15:12:39 -0300

managed token update

Diffstat:
Mbuild-system/Makefile | 9+++++++++
Mpackages/frontend/.storybook/preview.js | 4++--
Mpackages/frontend/package.json | 1+
Mpackages/frontend/src/components/form/Field.tsx | 24+++++++-----------------
Apackages/frontend/src/components/form/InputSecured.stories.tsx | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpackages/frontend/src/components/form/InputSecured.tsx | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mpackages/frontend/src/routes/instances/update/UpdatePage.tsx | 1-
7 files changed, 136 insertions(+), 40 deletions(-)

diff --git a/build-system/Makefile b/build-system/Makefile @@ -69,3 +69,12 @@ install: build for file in `find packages/frontend/build/ -type f`; do \ install -m 644 -D $$file ${prefix}/$${file#packages/frontend/build/}; \ done + +.PHONY: install +install-view: + pnpm run --filter merchant-backoffice build-storybook + echo install -d ${prefix} + for file in `find packages/frontend/storybook-static/ -type f`; do \ + install -m 644 -D $$file ${prefix}/$${file#packages/frontend/storybook-static/}; \ + done + diff --git a/packages/frontend/.storybook/preview.js b/packages/frontend/.storybook/preview.js @@ -23,7 +23,7 @@ export const globalTypes = { icon: 'globe', items: [ { value: 'en', right: '🇺🇸', title: 'English' }, - { value: 'es', right: '🇪🇸', title: 'Español' }, + { value: 'es', right: '🇪🇸', title: 'Spanish' }, ], }, }, @@ -31,7 +31,7 @@ export const globalTypes = { export const decorators = [ (Story, { globals }) => { - return <MessageProvider locale={globals.locale} onError="warn" messages={messages[globals.locale]} > + return <MessageProvider locale={globals.locale} onError="warn" messages={messages[globals.locale]} pathSep={null} onError={() => null}> <Story /> </MessageProvider> }, diff --git a/packages/frontend/package.json b/packages/frontend/package.json @@ -13,6 +13,7 @@ "test": "jest ./tests", "typedoc": "typedoc src", "clean": "rimraf build storybook-static docs", + "build-storybook": "build-storybook", "storybook": "start-storybook -p 6006" }, "engines": { diff --git a/packages/frontend/src/components/form/Field.tsx b/packages/frontend/src/components/form/Field.tsx @@ -19,22 +19,12 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode, createContext } from "preact"; +import { h, VNode, createContext, ComponentChildren } from "preact"; import { StateUpdater, useContext, useMemo, useState } from "preact/hooks"; -import { BackendContext, ConfigContext } from '../../context/backend'; -import { Input } from "./Input"; -import { InputArray } from "./InputArray"; -import { InputWithAddon } from "./InputWithAddon"; -import { InputSecured } from "./InputSecured"; - -interface Props<T> { - name: keyof T; - info: any; - readonly?: boolean; -} export interface FormType<T> { object: Partial<T>; + initial: Partial<T>; errors: FormErrors<T>; toStr: FormtoStr<T>; fromStr: FormfromStr<T>; @@ -67,14 +57,13 @@ export type FormUpdater<T> = { interface ProviderProps<T> { object?: Partial<T>; errors?: FormErrors<T>; - // toStr?: FormtoStr<T>; - // fromStr?: FormfromStr<T>; valueHandler: StateUpdater<Partial<T>>; - children: VNode[] | VNode + children: ComponentChildren } export function FormProvider<T>({ object = {}, errors = {}, valueHandler, children }: ProviderProps<T>) { - const value = useMemo<FormType<T>>(() => ({errors, object, valueHandler, toStr: {}, fromStr: {}}), [errors, object, valueHandler]) + const initial = useMemo(() => object,[]) + const value = useMemo<FormType<T>>(() => ({errors, object, initial, valueHandler, toStr: {}, fromStr: {}}), [errors, object, valueHandler]) return <FormContext.Provider value={value}> <form onSubmit={(e) => { e.preventDefault() @@ -86,7 +75,7 @@ export function FormProvider<T>({ object = {}, errors = {}, valueHandler, childr } export function useField<T>(name: keyof T) { - const { errors, object, toStr, fromStr, valueHandler } = useContext<FormType<T>>(FormContext) + const { errors, object, initial, toStr, fromStr, valueHandler } = useContext<FormType<T>>(FormContext) type P = typeof name type V = T[P] @@ -102,6 +91,7 @@ export function useField<T>(name: keyof T) { return { error: errors[name], value: object[name], + initial: initial[name], onChange: updateField(name), toStr: toStr[name] ? toStr[name]! : defaultToString, fromStr: fromStr[name] ? fromStr[name]! : defaultFromString, diff --git a/packages/frontend/src/components/form/InputSecured.stories.tsx b/packages/frontend/src/components/form/InputSecured.stories.tsx @@ -0,0 +1,57 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { h, VNode } from 'preact'; +import { useState } from 'preact/hooks'; +import { FormProvider } from './Field'; +import { InputSecured } from './InputSecured' + +export default { + title: 'Fields/InputSecured', + component: InputSecured, +}; +{/* <FormProvider<Entity> errors={errors} object={value} valueHandler={valueHandler} > */ } +{/* <InputSecured<Entity> name="auth_token" /> */ } + +type T = {auth_token: string | null} + +export const InitialValueEmpty = () => { + const [state, setState] = useState<Partial<T>>({auth_token: ''}) + return <FormProvider<T> object={state} errors={{}} valueHandler={setState}> + Initial value: '' + <InputSecured<T> name="auth_token" /> + </FormProvider> +} + +export const InitialValueToken = () => { + const [state, setState] = useState<Partial<T>>({auth_token: 'token'}) + return <FormProvider<T> object={state} errors={{}} valueHandler={setState}> + <InputSecured<T> name="auth_token" /> + </FormProvider> +} + +export const InitialValueNull = () => { + const [state, setState] = useState<Partial<T>>({auth_token: null}) + return <FormProvider<T> object={state} errors={{}} valueHandler={setState}> + Initial value: '' + <InputSecured<T> name="auth_token" /> + </FormProvider> +} diff --git a/packages/frontend/src/components/form/InputSecured.tsx b/packages/frontend/src/components/form/InputSecured.tsx @@ -18,7 +18,7 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { h, VNode } from "preact"; +import { Fragment, h, VNode } from "preact"; import { Message, useMessage } from "preact-messages"; import { useState } from "preact/hooks"; import { DeleteModal } from "../modal"; @@ -29,13 +29,24 @@ export interface Props<T> { readonly?: boolean; } +const TokenStatus = ({ prev, post }: any) => { + if ((prev === undefined || prev === null) && (post === undefined || post === null)) + return null + return (prev === post) ? null : ( + post === null ? + <span class="tag is-danger is-align-self-center ml-2">Deleting</span> : + <span class="tag is-warning is-align-self-center ml-2">Changing</span> + ) +} + export function InputSecured<T>({ name, readonly }: Props<T>): VNode { - const {error, value, onChange, toStr, fromStr } = useField<T>(name); - + const { error, value, initial, onChange, toStr, fromStr } = useField<T>(name); + const placeholder = useMessage(`fields.instance.${name}.placeholder`, {}); const tooltip = useMessage(`fields.instance.${name}.tooltip`, {}); const [active, setActive] = useState(false); + const [newValue, setNuewValue] = useState(toStr(value)) return <div class="field is-horizontal"> <div class="field-label is-normal"> @@ -47,23 +58,52 @@ export function InputSecured<T>({ name, readonly }: Props<T>): VNode { </label> </div> <div class="field-body"> - <div class="field"> - <div class="field has-addons"> - <label class="b-checkbox checkbox"> - <input type="checkbox" checked={active} onClick={(): void => { onChange(fromStr('')); setActive(!active); }} /> - <span class="check" /> - </label> - <p class="control"> - <input class="input" type="text" - placeholder={placeholder} readonly={readonly || !active} - disabled={readonly || !active} - name={String(name)} value={toStr(value)} - onChange={(e): void => onChange(fromStr(e.currentTarget.value))} /> - <Message id={`fields.instance.${name}.help`}> </Message> - </p> - </div> - {error ? <p class="help is-danger"><Message id={`validation.${error.type}`} fields={error.params}>{error.message}</Message></p> : null} - </div> + {!active ? + <Fragment> + <div class="field has-addons"> + <button class="button" onClick={(): void => { setActive(!active); }} > + <div class="icon is-left"><i class="mdi mdi-lock-reset" /></div> + <span>Manage token</span> + </button> + <TokenStatus prev={initial} post={value} /> + </div> + </Fragment> : + <Fragment> + <div class="field has-addons"> + <div class="control"> + <input class="input" type="password" + placeholder={placeholder} readonly={readonly || !active} + disabled={readonly || !active} + name={String(name)} value={newValue} + onInput={(e): void => { + setNuewValue(e.currentTarget.value) + }} /> + <Message id={`fields.instance.${name}.help`}> </Message> + </div> + <div class="control"> + <button class="button is-info" disabled={fromStr(newValue) === value} onClick={(): void => { onChange(fromStr(newValue)); setActive(!active); }} > + <div class="icon is-left"><i class="mdi mdi-lock-outline" /></div> + <span>Update</span> + </button> + </div> + </div> + <div class="control"> + <button class="button is-danger" disabled={null === value} onClick={(): void => { onChange(null!); setActive(!active); }} > + <div class="icon is-left"><i class="mdi mdi-lock-open-variant" /></div> + <span>Remove</span> + </button> + </div> + <div class="field ml-4"> + <div class="control"> + <button class="button " onClick={(): void => { onChange(initial!); setActive(!active); }} > + <div class="icon is-left"><i class="mdi mdi-lock-open-variant" /></div> + <span>Cancel update</span> + </button> + </div> + </div> + </Fragment> + } + {error ? <p class="help is-danger"><Message id={`validation.${error.type}`} fields={error.params}>{error.message}</Message></p> : null} </div> </div>; } diff --git a/packages/frontend/src/routes/instances/update/UpdatePage.tsx b/packages/frontend/src/routes/instances/update/UpdatePage.tsx @@ -31,7 +31,6 @@ import { Message } from "preact-messages"; import { Input } from "../../../components/form/Input"; import { InputSecured } from "../../../components/form/InputSecured"; import { ConfigContext } from "../../../context/backend"; -import { InputArray } from "../../../components/form/InputArray"; import { InputDuration } from "../../../components/form/InputDuration"; import { InputCurrency } from "../../../components/form/InputCurrency"; import { InputPayto } from "../../../components/form/InputPayto";