From a314b5350e269676e8c39eda4cc7842751b1a7fc Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 1 Sep 2020 02:32:06 +0800 Subject: ... --- .../ClientApp/src/app/common/OperationDialog.tsx | 381 --------------------- 1 file changed, 381 deletions(-) delete mode 100644 Timeline/ClientApp/src/app/common/OperationDialog.tsx (limited to 'Timeline/ClientApp/src/app/common/OperationDialog.tsx') diff --git a/Timeline/ClientApp/src/app/common/OperationDialog.tsx b/Timeline/ClientApp/src/app/common/OperationDialog.tsx deleted file mode 100644 index bca4580c..00000000 --- a/Timeline/ClientApp/src/app/common/OperationDialog.tsx +++ /dev/null @@ -1,381 +0,0 @@ -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { - Spinner, - Container, - ModalBody, - Label, - Input, - FormGroup, - FormFeedback, - ModalFooter, - Button, - Modal, - ModalHeader, - FormText, -} from "reactstrap"; - -import { UiLogicError } from "../common"; - -const DefaultProcessPrompt: React.FC = (_) => { - return ( - - - - ); -}; - -interface DefaultErrorPromptProps { - error?: string; -} - -const DefaultErrorPrompt: React.FC = (props) => { - const { t } = useTranslation(); - - let result =

{t("operationDialog.error")}

; - - if (props.error != null) { - result = ( - <> - {result} -

{props.error}

- - ); - } - - return result; -}; - -export type OperationInputOptionalError = undefined | null | string; - -export interface OperationInputErrorInfo { - [index: number]: OperationInputOptionalError; -} - -export type OperationInputValidator = ( - value: TValue, - values: (string | boolean)[] -) => OperationInputOptionalError | OperationInputErrorInfo; - -export interface OperationTextInputInfo { - type: "text"; - password?: boolean; - label?: string; - initValue?: string; - textFieldProps?: Omit< - React.InputHTMLAttributes, - "type" | "value" | "onChange" - >; - helperText?: string; - validator?: OperationInputValidator; -} - -export interface OperationBoolInputInfo { - type: "bool"; - label: string; - initValue?: boolean; -} - -export interface OperationSelectInputInfoOption { - value: string; - label: string; - icon?: React.ReactElement; -} - -export interface OperationSelectInputInfo { - type: "select"; - label: string; - options: OperationSelectInputInfoOption[]; - initValue?: string; -} - -export type OperationInputInfo = - | OperationTextInputInfo - | OperationBoolInputInfo - | OperationSelectInputInfo; - -interface OperationResult { - type: "success" | "failure"; - data: unknown; -} - -interface OperationDialogProps { - open: boolean; - close: () => void; - title: React.ReactNode; - titleColor?: "default" | "dangerous" | "create" | string; - onProcess: (inputs: (string | boolean)[]) => Promise; - inputScheme?: OperationInputInfo[]; - inputPrompt?: string | (() => React.ReactNode); - processPrompt?: () => React.ReactNode; - successPrompt?: (data: unknown) => React.ReactNode; - failurePrompt?: (error: unknown) => React.ReactNode; - onSuccessAndClose?: () => void; -} - -const OperationDialog: React.FC = (props) => { - const inputScheme = props.inputScheme ?? []; - - const { t } = useTranslation(); - - type Step = "input" | "process" | OperationResult; - const [step, setStep] = useState("input"); - const [values, setValues] = useState<(boolean | string)[]>( - inputScheme.map((i) => { - if (i.type === "bool") { - return i.initValue ?? false; - } else if (i.type === "text" || i.type === "select") { - return i.initValue ?? ""; - } else { - throw new UiLogicError("Unknown input scheme."); - } - }) - ); - const [inputError, setInputError] = useState({}); - - const close = (): void => { - if (step !== "process") { - props.close(); - if ( - typeof step === "object" && - step.type === "success" && - props.onSuccessAndClose - ) { - props.onSuccessAndClose(); - } - } else { - console.log("Attempt to close modal when processing."); - } - }; - - const onConfirm = (): void => { - setStep("process"); - props.onProcess(values).then( - (d: unknown) => { - setStep({ - type: "success", - data: d, - }); - }, - (e: unknown) => { - setStep({ - type: "failure", - data: e, - }); - } - ); - }; - - let body: React.ReactNode; - if (step === "input") { - let inputPrompt = - typeof props.inputPrompt === "function" - ? props.inputPrompt() - : props.inputPrompt; - inputPrompt =
{inputPrompt}
; - - const updateValue = ( - index: number, - newValue: string | boolean - ): (string | boolean)[] => { - const oldValues = values; - const newValues = oldValues.slice(); - newValues[index] = newValue; - setValues(newValues); - return newValues; - }; - - const testErrorInfo = (errorInfo: OperationInputErrorInfo): boolean => { - for (let i = 0; i < inputScheme.length; i++) { - if (inputScheme[i].type === "text" && errorInfo[i] != null) { - return true; - } - } - return false; - }; - - const calculateError = ( - oldError: OperationInputErrorInfo, - index: number, - newError: OperationInputOptionalError | OperationInputErrorInfo - ): OperationInputErrorInfo => { - if (newError === undefined) { - return oldError; - } else if (newError === null || typeof newError === "string") { - return { ...oldError, [index]: newError }; - } else { - const newInputError: OperationInputErrorInfo = { ...oldError }; - for (const [index, error] of Object.entries(newError)) { - if (error !== undefined) { - newInputError[+index] = error as OperationInputOptionalError; - } - } - return newInputError; - } - }; - - const validateAll = (): boolean => { - let newInputError = inputError; - for (let i = 0; i < inputScheme.length; i++) { - const item = inputScheme[i]; - if (item.type === "text") { - newInputError = calculateError( - newInputError, - i, - item.validator?.(values[i] as string, values) - ); - } - } - const result = !testErrorInfo(newInputError); - setInputError(newInputError); - return result; - }; - - body = ( - <> - - {inputPrompt} - {inputScheme.map((item, index) => { - const value = values[index]; - const error: string | undefined = ((e) => - typeof e === "string" ? t(e) : undefined)(inputError?.[index]); - - if (item.type === "text") { - return ( - - {item.label && } - { - const v = e.target.value; - const newValues = updateValue(index, v); - setInputError( - calculateError( - inputError, - index, - item.validator?.(v, newValues) - ) - ); - }} - invalid={error != null} - {...item.textFieldProps} - /> - {error != null && {error}} - {item.helperText && {t(item.helperText)}} - - ); - } else if (item.type === "bool") { - return ( - - { - updateValue( - index, - (e.target as HTMLInputElement).checked - ); - }} - /> - - - ); - } else if (item.type === "select") { - return ( - - - { - updateValue(index, event.target.value); - }} - > - {item.options.map((option, i) => { - return ( - - ); - })} - - - ); - } - })} - - - - - - - ); - } else if (step === "process") { - body = ( - - {props.processPrompt?.() ?? } - - ); - } else { - let content: React.ReactNode; - const result = step; - if (result.type === "success") { - content = - props.successPrompt?.(result.data) ?? t("operationDialog.success"); - if (typeof content === "string") - content =

{content}

; - } else { - content = props.failurePrompt?.(result.data) ?? ; - if (typeof content === "string") - content = ; - } - body = ( - <> - {content} - - - - - ); - } - - const title = typeof props.title === "string" ? t(props.title) : props.title; - - return ( - - - {title} - - {body} - - ); -}; - -export default OperationDialog; -- cgit v1.2.3