* feat: add user groups * wip: add unit tests * wip: add more tests and normalized name for creation and update * test: add unit tests for group router * fix: type issues, missing mysql schema, rename column creator_id to owner_id * fix: lint and format issues * fix: deepsource issues * fix: forgot to add log message * fix: build not working * chore: address pull request feedback * feat: add mysql migration and fix merge conflicts * fix: format issue and test issue
101 lines
3.0 KiB
TypeScript
101 lines
3.0 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 ?? ((t: TranslationFunction) => t("common.action.cancel"));
|
|
const confirmLabel =
|
|
labels?.confirm ??
|
|
((t: TranslationFunction) => t("common.action.confirm"));
|
|
|
|
const handleCancel = useCallback(
|
|
async (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
typeof cancelProps?.onClick === "function" &&
|
|
cancelProps?.onClick(event);
|
|
typeof onCancel === "function" && (await onCancel());
|
|
closeOnCancel && actions.closeModal();
|
|
},
|
|
[cancelProps?.onClick, onCancel, actions.closeModal],
|
|
);
|
|
|
|
const handleConfirm = useCallback(
|
|
async (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
setLoading(true);
|
|
typeof confirmProps?.onClick === "function" &&
|
|
confirmProps?.onClick(event);
|
|
typeof onConfirm === "function" && (await onConfirm());
|
|
closeOnConfirm && actions.closeModal();
|
|
setLoading(false);
|
|
},
|
|
[confirmProps?.onClick, onConfirm, actions.closeModal],
|
|
);
|
|
|
|
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
|
|
{...confirmProps}
|
|
onClick={handleConfirm}
|
|
color="red.9"
|
|
loading={loading}
|
|
>
|
|
{confirmProps?.children || translateIfNecessary(t, confirmLabel)}
|
|
</Button>
|
|
</Group>
|
|
</>
|
|
);
|
|
},
|
|
).withOptions({});
|