From 3d76c030c55ef0861600b9f0c2e80ef0402bfe98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8D=80=E6=B6=A7=E6=9E=97?= Date: Thu, 1 Feb 2024 20:12:35 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A8=E5=8D=95=E7=9A=84=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E7=8A=B6=E6=80=81=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/form.ts | 81 +++++++++++++++++++++++++++++++++++++--------- src/module/form.ts | 40 +++++++++++++++-------- 2 files changed, 92 insertions(+), 29 deletions(-) diff --git a/src/data/form.ts b/src/data/form.ts index 36b398c..dc07e1d 100644 --- a/src/data/form.ts +++ b/src/data/form.ts @@ -1,50 +1,101 @@ +import * as m from "mithril"; import { Either, Just, Maybe, Nothing } from "purify-ts"; import { ValidatorResult, ValidatorError } from "../data/internal/error"; -import { Mutable, mutable } from "./internal/lens"; +import { Mutable, mutable, Prism } from "./internal/lens"; +import { _just } from "./lens"; + +export interface FormInit { + _tag: "FormInit"; +} + +const formInitValue: FormInit = { + _tag: "FormInit" +}; + +export interface FormLoading { + _tag: "FormLoading"; +}; + +const formLoadingValue: FormLoading = { + _tag: "FormLoading" +}; + +export interface FormResult { + _tag: "FormResult"; + _value: Maybe; +} + +const mkFormResult = (value: Maybe): FormResult => ({ + _tag: "FormResult", + _value: value +}); + +export type FormState = FormInit | FormLoading | FormResult; + +const _isloading = (): Prism => ({ + get: s => Just(s._tag === "FormLoading"), + set: (s, _) => Just(s) +}); + +const _result = (): Prism> => ({ + get: s => { + if (s._tag === "FormResult") { + return Just(s._value); + } + else { + return Nothing; + } + }, + set: (s, _) => Just(s) +}); export interface FormMutable extends Mutable { validate: (f: (data: T) => ValidatorResult) => Promise>; - resetErr: () => void; + resetTip: () => void; reset: () => void; - getErr: () => Maybe; + getResult: () => Maybe>; isValidating: () => boolean; } export const formMut = (state: T): FormMutable => { - const err = mutable>(Nothing); + const formState = mutable(formInitValue); const mut = mutable(state); - const isProcessing = mutable(false); const validate: FormMutable["validate"] = async f => { - isProcessing.set(true); + formState.set(formLoadingValue); + m.redraw(); + const s = mut.get(); const r = await f(s); - r.ifLeft(e => err.set(Just(e))); - isProcessing.set(false); + const es = r.swap().toMaybe(); + formState.set(mkFormResult(es)); + m.redraw(); return r; }; - const resetErr: FormMutable["resetErr"] = () => { - err.set(Nothing); + const resetTip: FormMutable["resetTip"] = () => { + formState.set(formInitValue); }; const reset: FormMutable["reset"] = () => { - resetErr(); + resetTip(); mut.set(state); }; - const getErr: FormMutable["getErr"] = err.get; + const getResult: FormMutable["getResult"] = () => + formState.prism(_result()).get(); - const isValidating: FormMutable["isValidating"] = isProcessing.get; + const isValidating: FormMutable["isValidating"] = () => + formState.prism(_isloading()).get().orDefault(false); return { ...mut, validate, - resetErr, + resetTip, reset, - getErr, + getResult, isValidating }; }; diff --git a/src/module/form.ts b/src/module/form.ts index aa1c21c..4936ab0 100644 --- a/src/module/form.ts +++ b/src/module/form.ts @@ -4,6 +4,7 @@ import { Maybe } from "purify-ts"; import { LoadingShape, Size, StateLevel } from "../data/var"; import { FormMutable } from "../data/form"; import { Message } from "../element/message"; +import { ValidatorError } from "../data"; export interface FormAttr { loading?: LoadingShape; @@ -12,6 +13,19 @@ export interface FormAttr { formdata?: FormMutable; } +const renderSuccuss = (callback: () => void): m.Vnode => + m(Message, { state: StateLevel.Positive }, [ + m("i.close.icon", { onclick: callback }), + m("div.header", "操作成功!") + ]); + +const renderFailure = (callback: () => void, xs: ValidatorError): m.Vnode => + m(Message, { state: StateLevel.Negative }, [ + m("i.close.icon", { onclick: callback }), + m("div.header", "提交操作不成功!"), + m("ul.list", xs.map(a => m("li", a))) + ]); + export const Form = (): m.Component> => { return { view: ({ attrs, children }) => { @@ -24,22 +38,20 @@ export const Form = (): m.Component> => { loadShape, selectKlass("inverted", attrs.isInvert), Maybe.fromNullable(attrs.size), - fd.chain(fd => fd.getErr()).map(_ => "error") + fd.chain(fd => fd.getResult()).map(_ => "error") ]); - const errMsg = fd.chain(data => { - const onclick = () => data.resetErr(); - - return data.getErr().map(msg => m( - Message, - { state: StateLevel.Error }, - [ - m("i.close.icon", { onclick }), - m("div.header", "提交数据验证出错"), - m("ul.list", msg.map(a => m("li", a))) - ] - )); - }); + const errMsg = fd + .filter(d => !d.isValidating()) + .map(data => { + const onclick = () => data.resetTip(); + return data.getResult() + .map(v => v.caseOf({ + Just: xs => renderFailure(onclick, xs), + Nothing: () => renderSuccuss(onclick) + })) + .extract(); + }); return m("div.ui.form", { class: klass }, [ (children as m.Children),