+12








fcd7c979df
Co-authored-by: Artur <145776561+arturict@users.noreply.github.com> Co-authored-by: arturict <arturict@users.noreply.github.com> Co-authored-by: Thomas <thomas@ajnart.fr> Co-authored-by: Afonso Jorge Ramos <afonsojorgeramos@gmail.com> Co-authored-by: Danura30082 <danura30082+github@gmail.com> Co-authored-by: Kushie <122986913+kushiemoon-dev@users.noreply.github.com> Co-authored-by: ajnart <thomas@ajnart.fr> Co-authored-by: ajnart <thomas@ajnart.dev> Co-authored-by: chenjun <chenjun@foxmail.com> Co-authored-by: Wikibear <wikibear@users.noreply.github.com> Co-authored-by: Bergasha <bergasha@gmail.com> Co-authored-by: leafyelin <43306196+leafyelin@users.noreply.github.com> Co-authored-by: Lucas Araujo <lucas.lra@gmail.com> Co-authored-by: GreenMonito <86085570+GreenMonito@users.noreply.github.com> Co-authored-by: Nerdy-Technician <roffo@nerdy-technician.social> Co-authored-by: Jun <34545896+jcstrong@users.noreply.github.com> Co-authored-by: Edmond Abraham <54119952+gitedmond@users.noreply.github.com> Co-authored-by: thrawnx <tight.bulb9384@fastmail.com> Co-authored-by: Chris <58918656+nordada@users.noreply.github.com> Co-authored-by: yi111 <153097222+Yi-111-a@users.noreply.github.com> Co-authored-by: Yanis <naamaneyanis@gmail.com> Co-authored-by: Wikibear <me@sej.de> Co-authored-by: alessiottavo <93441886+alessiottavo@users.noreply.github.com>
105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
import { useCallback, useState } from "react";
|
|
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
import type { ButtonProps, GroupProps } from "@mantine/core";
|
|
import { Box, Button, Group } from "@mantine/core";
|
|
|
|
import type { stringOrTranslation, TranslationFunction } from "@homarr/translation";
|
|
import { translateIfNecessary } from "@homarr/translation";
|
|
import { useI18n } from "@homarr/translation/client";
|
|
|
|
import { createModal } from "./creator";
|
|
|
|
type MaybePromise<T> = T | Promise<T>;
|
|
|
|
export interface ConfirmModalProps {
|
|
title: string;
|
|
children: ReactNode;
|
|
onConfirm?: () => MaybePromise<void>;
|
|
onCancel?: () => MaybePromise<void>;
|
|
closeOnConfirm?: boolean;
|
|
closeOnCancel?: boolean;
|
|
cancelProps?: ButtonProps & ComponentPropsWithoutRef<"button">;
|
|
confirmProps?: ButtonProps & ComponentPropsWithoutRef<"button">;
|
|
groupProps?: GroupProps;
|
|
|
|
labels?: {
|
|
confirm?: stringOrTranslation;
|
|
cancel?: stringOrTranslation;
|
|
};
|
|
}
|
|
|
|
export const ConfirmModal = createModal<Omit<ConfirmModalProps, "title">>(({ actions, innerProps }) => {
|
|
const [loading, setLoading] = useState(false);
|
|
const t = useI18n();
|
|
const { children, onConfirm, onCancel, cancelProps, confirmProps, groupProps, labels } = innerProps;
|
|
|
|
const closeOnConfirm = innerProps.closeOnConfirm ?? true;
|
|
const closeOnCancel = innerProps.closeOnCancel ?? true;
|
|
|
|
const cancelLabel = labels?.cancel ?? ((translate: TranslationFunction) => translate("common.action.cancel"));
|
|
const confirmLabel = labels?.confirm ?? ((translate: TranslationFunction) => translate("common.action.confirm"));
|
|
|
|
const handleCancel = useCallback(
|
|
async (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
if (typeof cancelProps?.onClick === "function") {
|
|
cancelProps.onClick(event);
|
|
}
|
|
|
|
if (typeof onCancel === "function") {
|
|
await onCancel();
|
|
}
|
|
|
|
if (closeOnCancel) {
|
|
actions.closeModal();
|
|
}
|
|
},
|
|
[cancelProps, onCancel, closeOnCancel, actions],
|
|
);
|
|
|
|
const handleConfirm = useCallback(
|
|
async (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
setLoading(true);
|
|
try {
|
|
if (typeof confirmProps?.onClick === "function") {
|
|
await confirmProps.onClick(event);
|
|
}
|
|
|
|
if (typeof onConfirm === "function") {
|
|
await onConfirm();
|
|
}
|
|
|
|
if (closeOnConfirm) {
|
|
actions.closeModal();
|
|
}
|
|
} catch {
|
|
// Keep the modal open. Callers own action-specific error feedback.
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
},
|
|
[confirmProps, onConfirm, closeOnConfirm, actions],
|
|
);
|
|
|
|
return (
|
|
<>
|
|
{children && <Box mb="md">{children}</Box>}
|
|
|
|
<Group justify="flex-end" {...groupProps}>
|
|
<Button variant="default" {...cancelProps} onClick={handleCancel}>
|
|
{cancelProps?.children ?? translateIfNecessary(t, cancelLabel)}
|
|
</Button>
|
|
|
|
<Button
|
|
data-autofocus
|
|
{...confirmProps}
|
|
onClick={handleConfirm}
|
|
color={confirmProps?.color ?? "red.9"}
|
|
loading={loading}
|
|
>
|
|
{confirmProps?.children ?? translateIfNecessary(t, confirmLabel)}
|
|
</Button>
|
|
</Group>
|
|
</>
|
|
);
|
|
}).withOptions({});
|