import { useState, ReactNode } from "react";
import classNames from "classnames";
import { useC, Text, ThemeColor } from "../common";
import Button from "../button/Button";
import {
useInputs,
InputGroup,
InitializeInfo as InputInitializer,
InputValueDict,
InputScheme,
} from "../input/InputGroup";
import LoadingButton from "../button/LoadingButton";
import Dialog from "./Dialog";
import "./OperationDialog.css";
interface OperationDialogPromptProps {
message?: Text;
customMessage?: ReactNode;
className?: string;
}
function OperationDialogPrompt(props: OperationDialogPromptProps) {
const { message, customMessage, className } = props;
const c = useC();
return (
{message &&
{c(message)}
}
{customMessage}
);
}
export interface OperationDialogProps {
open: boolean;
close: () => void;
color?: ThemeColor;
title: Text;
inputPrompt?: Text;
successPrompt?: (data: TData) => ReactNode;
failurePrompt?: (error: unknown) => ReactNode;
inputInit?: InputInitializer;
inputScheme?: InputScheme;
onProcess: (inputs: InputValueDict) => Promise;
onSuccessAndClose?: (data: TData) => void;
}
function OperationDialog(props: OperationDialogProps) {
const {
open,
close,
color,
title,
inputPrompt,
successPrompt,
failurePrompt,
inputInit,
inputScheme,
onProcess,
onSuccessAndClose,
} = props;
if (process.env.NODE_ENV === "development") {
if (inputScheme == null && inputInit == null) {
throw Error("Scheme or Init? Choose one and create one.");
}
if (inputScheme != null && inputInit != null) {
throw Error("Scheme or Init? Choose one and drop one");
}
}
const c = useC();
type Step =
| { type: "input" }
| { type: "process" }
| {
type: "success";
data: TData;
}
| {
type: "failure";
data: unknown;
};
const [step, setStep] = useState({ type: "input" });
const { inputGroupProps, hasError, setAllDisabled, confirm } = useInputs({
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
init: inputInit ?? { scheme: inputScheme! },
});
function onClose() {
if (step.type !== "process") {
close();
if (step.type === "success" && props.onSuccessAndClose) {
onSuccessAndClose?.(step.data);
}
} else {
console.log("Attempt to close modal dialog when processing.");
}
}
function onConfirm() {
const result = confirm();
if (result.type === "ok") {
setStep({ type: "process" });
setAllDisabled(true);
onProcess(result.values).then(
(d) => {
setStep({
type: "success",
data: d,
});
},
(e: unknown) => {
setStep({
type: "failure",
data: e,
});
},
);
}
}
let body: ReactNode;
if (step.type === "input" || step.type === "process") {
const isProcessing = step.type === "process";
body = (
{c("operationDialog.confirm")}
);
} else {
const result = step;
const promptProps: OperationDialogPromptProps =
result.type === "success"
? {
message: "operationDialog.success",
customMessage: successPrompt?.(result.data),
}
: {
message: "operationDialog.error",
customMessage: failurePrompt?.(result.data),
};
body = (
);
}
return (
);
}
export default OperationDialog;