mirror of
https://github.com/hexastack/hexabot
synced 2025-02-21 11:57:34 +00:00
fix(frontend): apply feedback updates
This commit is contained in:
parent
0b19f45b59
commit
658bfbc924
@ -43,7 +43,9 @@
|
||||
"account_update_success": "Account has been updated successfully",
|
||||
"account_disabled": "Your account has been either disabled or is pending confirmation.",
|
||||
"success_invitation_sent": "Invitation to join has been successfully sent.",
|
||||
"item_delete_confirm": "Are you sure you want to delete this item?",
|
||||
"item_delete_confirm": "Are you sure you want to delete this {{0}} item?",
|
||||
"items_delete_confirm": "Are you sure you want to delete those {{0}} selected items?",
|
||||
"selected": "selected",
|
||||
"item_delete_success": "Item has been deleted successfully",
|
||||
"success_save": "Changes has been saved!",
|
||||
"no_result_found": "No result found",
|
||||
|
@ -43,7 +43,8 @@
|
||||
"account_update_success": "Le compte a été mis à jour avec succès",
|
||||
"account_disabled": "Votre compte a été désactivé ou est en attente de confirmation.",
|
||||
"success_invitation_sent": "L'invitation a été envoyée avec succès.",
|
||||
"item_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer cet élément?",
|
||||
"item_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer cet élément {{0}}?",
|
||||
"items_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer ces {{0}} éléments sélectionnés?",
|
||||
"item_delete_success": "L'élément a été supprimé avec succès",
|
||||
"success_save": "Les modifications ont été enregistrées!",
|
||||
"no_result_found": "Aucun résultat trouvé",
|
||||
|
@ -6,7 +6,6 @@
|
||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||
*/
|
||||
|
||||
|
||||
import CheckIcon from "@mui/icons-material/Check";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { Button, Grid } from "@mui/material";
|
||||
@ -22,7 +21,7 @@ export const DialogFormButtons = <T,>({
|
||||
|
||||
return (
|
||||
<Grid
|
||||
p="5px 15px"
|
||||
p="0.3rem 1rem"
|
||||
width="100%"
|
||||
display="flex"
|
||||
justifyContent="space-between"
|
||||
|
@ -19,17 +19,14 @@ export const FormDialog = <T,>({
|
||||
onSubmit,
|
||||
...rest
|
||||
}: FormDialogProps<T>) => {
|
||||
const handleClose = () => rest.onClose?.({}, "backdropClick");
|
||||
|
||||
return (
|
||||
<Dialog fullWidth {...rest}>
|
||||
<DialogTitle onClose={() => rest.onClose?.({}, "backdropClick")}>
|
||||
{title}
|
||||
</DialogTitle>
|
||||
<DialogTitle onClose={handleClose}>{title}</DialogTitle>
|
||||
<DialogContent>{children}</DialogContent>
|
||||
<DialogActions style={{ padding: "8px" }}>
|
||||
<DialogFormButtons
|
||||
onCancel={() => rest.onClose?.({}, "backdropClick")}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
<DialogActions style={{ padding: "0.5rem" }}>
|
||||
<DialogFormButtons onCancel={handleClose} onSubmit={onSubmit} />
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
|
@ -6,9 +6,16 @@
|
||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||
*/
|
||||
|
||||
import { Button, Dialog, DialogActions, DialogContent } from "@mui/material";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
Grid,
|
||||
} from "@mui/material";
|
||||
import { FC, ReactNode } from "react";
|
||||
|
||||
import { useTranslate } from "@/hooks/useTranslate";
|
||||
import { ConfirmOptions, DialogProps } from "@/types/common/dialogs.types";
|
||||
|
||||
import { DialogTitle } from "../DialogTitle";
|
||||
@ -23,6 +30,7 @@ export interface ConfirmDialogProps
|
||||
extends DialogProps<ConfirmDialogPayload, boolean> {}
|
||||
|
||||
export const ConfirmDialog: FC<ConfirmDialogProps> = ({ payload, ...rest }) => {
|
||||
const { t } = useTranslate();
|
||||
const cancelButtonProps = useDialogLoadingButton(() => rest.onClose(false));
|
||||
const okButtonProps = useDialogLoadingButton(() => rest.onClose(true));
|
||||
|
||||
@ -34,22 +42,24 @@ export const ConfirmDialog: FC<ConfirmDialogProps> = ({ payload, ...rest }) => {
|
||||
onClose={() => rest.onClose(false)}
|
||||
>
|
||||
<DialogTitle onClose={() => rest.onClose(false)}>
|
||||
{payload.title}
|
||||
{payload.title || t("title.warning")}
|
||||
</DialogTitle>
|
||||
<DialogContent>{payload.msg}</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
color={payload.severity || "error"}
|
||||
variant="contained"
|
||||
disabled={!open}
|
||||
autoFocus
|
||||
{...okButtonProps}
|
||||
>
|
||||
{payload.okText}
|
||||
</Button>
|
||||
<Button variant="outlined" disabled={!open} {...cancelButtonProps}>
|
||||
{payload.cancelText}
|
||||
</Button>
|
||||
<Grid p="0.3rem 1rem" gap="0.5rem" display="flex">
|
||||
<Button
|
||||
color={payload.severity || "error"}
|
||||
variant="contained"
|
||||
disabled={!open}
|
||||
autoFocus
|
||||
{...okButtonProps}
|
||||
>
|
||||
{payload.okText || t("label.yes")}
|
||||
</Button>
|
||||
<Button variant="outlined" disabled={!open} {...cancelButtonProps}>
|
||||
{payload.cancelText || t("label.no")}
|
||||
</Button>
|
||||
</Grid>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
|
@ -11,16 +11,30 @@ import { Grid, Typography } from "@mui/material";
|
||||
|
||||
import { useTranslate } from "@/hooks/useTranslate";
|
||||
|
||||
export const ConfirmDialogBody = () => {
|
||||
export const ConfirmDialogBody = ({
|
||||
mode = "click",
|
||||
itemsNumber = 1,
|
||||
}: {
|
||||
mode?: "selection" | "click";
|
||||
itemsNumber?: number;
|
||||
}) => {
|
||||
const { t } = useTranslate();
|
||||
const DialogBodyText =
|
||||
itemsNumber === 1
|
||||
? t("message.item_delete_confirm", {
|
||||
"0": mode === "click" ? "" : t("message.selected"),
|
||||
})
|
||||
: t("message.items_delete_confirm", {
|
||||
"0": itemsNumber.toString(),
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid container gap={1}>
|
||||
<Grid item height="28px">
|
||||
<ErrorIcon sx={{ fontSize: "28px" }} color="error" />
|
||||
<Grid item height="1.75rem">
|
||||
<ErrorIcon sx={{ fontSize: "1.75rem" }} color="error" />
|
||||
</Grid>
|
||||
<Grid item alignSelf="center">
|
||||
<Typography>{t("message.item_delete_confirm")}</Typography>
|
||||
<Typography>{DialogBodyText}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
@ -21,8 +21,8 @@ import { ComponentFormProps } from "@/types/common/dialogs.types";
|
||||
|
||||
export const CategoryForm: FC<ComponentFormProps<ICategory>> = ({
|
||||
data,
|
||||
FormWrapper = React.Fragment,
|
||||
FormWrapperProps,
|
||||
Wrapper = React.Fragment,
|
||||
WrapperProps,
|
||||
...rest
|
||||
}) => {
|
||||
const { t } = useTranslate();
|
||||
@ -84,10 +84,10 @@ export const CategoryForm: FC<ComponentFormProps<ICategory>> = ({
|
||||
}, [data, reset]);
|
||||
|
||||
return (
|
||||
<FormWrapper
|
||||
{...FormWrapperProps}
|
||||
<Wrapper
|
||||
open={!!WrapperProps?.open}
|
||||
onSubmit={submitAsync}
|
||||
open={!!FormWrapperProps?.open}
|
||||
{...WrapperProps}
|
||||
>
|
||||
<form onSubmit={submitAsync}>
|
||||
<ContentContainer>
|
||||
@ -102,7 +102,7 @@ export const CategoryForm: FC<ComponentFormProps<ICategory>> = ({
|
||||
</ContentItem>
|
||||
</ContentContainer>
|
||||
</form>
|
||||
</FormWrapper>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -27,8 +27,8 @@ export const CategoryFormDialog: FC<ComponentFormDialogProps<ICategory>> = ({
|
||||
onSuccess={() => {
|
||||
rest.onClose(true);
|
||||
}}
|
||||
FormWrapper={FormDialog}
|
||||
FormWrapperProps={{
|
||||
Wrapper={FormDialog}
|
||||
WrapperProps={{
|
||||
title: payload ? t("title.edit_category") : t("title.new_category"),
|
||||
...rest,
|
||||
}}
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright © 2024 Hexastack. All rights reserved.
|
||||
* Copyright © 2025 Hexastack. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
||||
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||
*/
|
||||
|
||||
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import FolderIcon from "@mui/icons-material/Folder";
|
||||
@ -24,7 +25,6 @@ import { DataGrid } from "@/app-components/tables/DataGrid";
|
||||
import { useDelete } from "@/hooks/crud/useDelete";
|
||||
import { useDeleteMany } from "@/hooks/crud/useDeleteMany";
|
||||
import { useFind } from "@/hooks/crud/useFind";
|
||||
import { useDialog } from "@/hooks/useDialog";
|
||||
import { useDialogs } from "@/hooks/useDialogs";
|
||||
import { useHasPermission } from "@/hooks/useHasPermission";
|
||||
import { useSearch } from "@/hooks/useSearch";
|
||||
@ -42,7 +42,6 @@ import { CategoryFormDialog } from "./CategoryFormDialog";
|
||||
export const Categories = () => {
|
||||
const { t } = useTranslate();
|
||||
const { toast } = useToast();
|
||||
const deleteDialogCtl = useDialog<string>(false);
|
||||
const hasPermission = useHasPermission();
|
||||
const { onSearch, searchPayload } = useSearch<ICategory>({
|
||||
$iLike: ["label"],
|
||||
@ -53,26 +52,20 @@ export const Categories = () => {
|
||||
params: searchPayload,
|
||||
},
|
||||
);
|
||||
const { mutateAsync: deleteCategory } = useDelete(EntityType.CATEGORY, {
|
||||
onError: (error) => {
|
||||
const options = {
|
||||
onError: (error: Error) => {
|
||||
toast.error(error.message || t("message.internal_server_error"));
|
||||
},
|
||||
onSuccess: () => {
|
||||
deleteDialogCtl.closeDialog();
|
||||
setSelectedCategories([]);
|
||||
toast.success(t("message.item_delete_success"));
|
||||
},
|
||||
});
|
||||
const { mutateAsync: deleteCategories } = useDeleteMany(EntityType.CATEGORY, {
|
||||
onError: (error) => {
|
||||
toast.error(error.message || t("message.internal_server_error"));
|
||||
},
|
||||
onSuccess: () => {
|
||||
deleteDialogCtl.closeDialog();
|
||||
setSelectedCategories([]);
|
||||
toast.success(t("message.item_delete_success"));
|
||||
},
|
||||
});
|
||||
};
|
||||
const { mutate: deleteCategory } = useDelete(EntityType.CATEGORY, options);
|
||||
const { mutate: deleteCategories } = useDeleteMany(
|
||||
EntityType.CATEGORY,
|
||||
options,
|
||||
);
|
||||
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
|
||||
const actionColumns = useActionColumns<ICategory>(
|
||||
EntityType.CATEGORY,
|
||||
@ -87,14 +80,10 @@ export const Categories = () => {
|
||||
{
|
||||
label: ActionColumnLabel.Delete,
|
||||
action: async ({ id }) => {
|
||||
const isConfirmed = await dialogs.confirm(<ConfirmDialogBody />, {
|
||||
title: t("title.warning"),
|
||||
okText: t("label.yes"),
|
||||
cancelText: t("label.no"),
|
||||
});
|
||||
const isConfirmed = await dialogs.confirm(<ConfirmDialogBody />);
|
||||
|
||||
if (isConfirmed) {
|
||||
await deleteCategory(id);
|
||||
deleteCategory(id);
|
||||
}
|
||||
},
|
||||
requires: [PermissionAction.DELETE],
|
||||
@ -176,16 +165,14 @@ export const Categories = () => {
|
||||
color="error"
|
||||
onClick={async () => {
|
||||
const isConfirmed = await dialogs.confirm(
|
||||
<ConfirmDialogBody />,
|
||||
{
|
||||
title: t("title.warning"),
|
||||
okText: t("label.yes"),
|
||||
cancelText: t("label.no"),
|
||||
},
|
||||
<ConfirmDialogBody
|
||||
mode="selection"
|
||||
itemsNumber={selectedCategories.length}
|
||||
/>,
|
||||
);
|
||||
|
||||
if (isConfirmed) {
|
||||
await deleteCategories(selectedCategories);
|
||||
deleteCategories(selectedCategories);
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
@ -148,8 +148,8 @@ export type ComponentFormProps<T> = {
|
||||
data: T | null;
|
||||
onError?: () => void;
|
||||
onSuccess?: () => void;
|
||||
FormWrapper?: React.FC<FormDialogProps<T>>;
|
||||
FormWrapperProps?: Partial<FormDialogProps<T>>;
|
||||
Wrapper?: React.FC<FormDialogProps<T>>;
|
||||
WrapperProps?: Partial<FormDialogProps<T>>;
|
||||
};
|
||||
|
||||
export interface FormButtonsProps<T> {
|
||||
|
Loading…
Reference in New Issue
Block a user