Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
7 views14 pages

Create

The document outlines a React component for a menu form using Material-UI and React Hook Form. It includes functionalities to add or edit menu items, fetch existing menus, and handle form submissions with validation. The form features various fields such as menu name, code, parent menu, URL, icon selection, display order, and status, with appropriate error handling and notifications for user feedback.

Uploaded by

fapebix297
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views14 pages

Create

The document outlines a React component for a menu form using Material-UI and React Hook Form. It includes functionalities to add or edit menu items, fetch existing menus, and handle form submissions with validation. The form features various fields such as menu name, code, parent menu, URL, icon selection, display order, and status, with appropriate error handling and notifications for user feedback.

Uploaded by

fapebix297
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 14

// import {

// Box,
// Button,
// Grid,
// Container,
// MenuItem,
// SvgIcon,
// TextField,
// Typography,
// Autocomplete,
// } from "@mui/material";
// import { useForm, Controller } from "react-hook-form";
// import { useRouter } from "next/router";
// import { useEffect, useState } from "react";
// import NextLink from "next/link";

// import { toast } from "react-toastify";


// import { Layout as DashboardLayout } from "src/layouts/dashboard/layout";
// import menuapi from "src/services/api/menu";
// import * as MuiIcons from "@mui/icons-material";
// import availableIcons from "src/static/icons";
// import Link from "next/link";
// import { ArrowLeft } from "src/Icons/ArrowLeft";

// const DynamicMuiIcon = ({ iconName }) => {


// if (!iconName) return null;
// const IconComponent = MuiIcons[iconName];
// return IconComponent ? (
// <IconComponent fontSize="small" />
// ) : (
// <span title="Icon not found">❓</span>
// );
// };

// const defaultValues = {
// menuName: "",
// menuCode: "",
// parentMenuId: "",
// url: "",
// icon: "",
// displayOrder: "",
// status: "Active",
// };

// const MenuForm = () => {


// const {
// register,
// handleSubmit,
// reset,
// watch,
// setValue,
// control,
// formState: { errors },
// } = useForm({ defaultValues });

// const [allMenus, setAllMenus] = useState([]);


// const router = useRouter();
// const { mode = "add", id } = router.query;
// useEffect(() => {
// fetchAllMenus();
// if (mode === "edit" && id) {
// fetchMenuDetails();
// }
// }, [id, mode]);

// const fetchAllMenus = async () => {


// try {
// const res = await menuapi.getAllMenuApi();
// setAllMenus(res.data.data || []);
// } catch (error) {
// toast.error("Failed to load menus");
// }
// };

// const fetchMenuDetails = async () => {


// try {
// const res = await menuapi.getMenuById(id);
// const data = res.data.data;
// reset({
// ...data,
// parentMenuId: data.parentMenuId || "",
// status: data.status || "Active",
// displayOrder: data.displayOrder?.toString() || "",
// });
// } catch (error) {
// console.error(error);
// toast.error("Failed to load menu");
// }
// };

// const isValidObjectId = (id) => /^[0-9a-fA-F]{24}$/.test(id);

// const onSubmit = async (formData) => {


// const cleanedData = {
// menuName: formData.menuName,
// menuCode: formData.menuCode,
// parentMenuId: isValidObjectId(formData.parentMenuId) ?
formData.parentMenuId : null,
// url: formData.url,
// icon: formData.icon,
// displayOrder: Number(formData.displayOrder),
// status: formData.status === "Active" ? "Active" : "Inactive",
// };

// try {
// const res = await menuapi.addMenuApi(cleanedData);
// toast.success("Menu created successfully!");
// router.push("/menumanagement");
// } catch (error) {
// console.error("Submit Error:", error?.response?.data || error);
// toast.error(error?.response?.data?.message || "An error occurred. Please
try again later.");
// }
// };

// // const selectedIconName = watch("icon");


// // const SelectedIcon = selectedIconName && MuiIcons[selectedIconName];
// const [selectedIconName, setSelectedIconName] = useState("");

// useEffect(() => {
// const iconFromForm = watch("icon");
// if (iconFromForm) {
// setSelectedIconName(iconFromForm);
// }
// }, [watch("icon")]);

// const SelectedIcon = selectedIconName && MuiIcons[selectedIconName];

// return (
// <Box component="main" sx={{ flexGrow: 1, py: 3 }}>
// <Container maxWidth={false}>
// <Box sx={{ mb: 4, display: "inline-block", width: "100%" }}>
// <Box sx={{ mb: 4 }}>
// <Link href="/menumanagement" passHref legacyBehavior>
// <Box
// component="a"
// sx={{
// display: "flex",
// alignItems: "center",
// textDecoration: "none",
// color: "text.primary",
// width: "fit-content",
// "&:hover": {
// textDecoration: "underline",
// color: "#60176F", // optional hover color
// },
// }}
// >
// <ArrowLeft fontSize="small" sx={{ mr: 1 }} />
// <Typography variant="subtitle2" sx={{ textDecoration:
"underline" }}>
// Back
// </Typography>
// </Box>
// </Link>
// </Box>

// <Grid container justifyContent="space-between" spacing={3}>


// <Grid item sx={{ alignItems: "center", display: "flex", overflow:
"hidden" }}>
// <Typography
// variant="h5"
// sx={{ color: "#60176F", fontWeight: 600, marginBottom: "3px" }}
// >
// {mode === "edit" ? "Edit Menu" : "Add New Menu"}
// </Typography>
// </Grid>
// </Grid>

// <Box
// component="form"
// onSubmit={handleSubmit(onSubmit)}
// sx={{
// mt: 3,
// P: 3,
// width: "100%",
// maxWidth: { xs: "100%", md: "100%" },
// mx: "auto",
// }}
// >
// <Grid container spacing={3}>
// <Grid item xs={12} sm={6}>
// <TextField
// label="MENU NAME"
// fullWidth
// {...register("menuName", { required: true })}
// error={!!errors.menuName}
// helperText={errors.menuName && "Menu name is required"}
// />
// </Grid>

// <Grid item xs={12} sm={6}>


// <TextField
// label="MENU CODE"
// fullWidth
// {...register("menuCode", { required: true })}
// error={!!errors.menuCode}
// helperText={errors.menuCode && "Menu code is required"}
// />
// </Grid>

// <Grid item xs={12} sm={6}>


// <Controller
// name="parentMenuId"
// control={control}
// render={({ field }) => (
// <TextField
// {...field}
// label="PARENT MENU"
// fullWidth
// select
// value={field.value || ""}
// onChange={(e) => {
// field.onChange(e.target.value);
// }}
// error={!!errors.parentMenuId}
// helperText={errors.parentMenuId?.message}
// >
// <MenuItem value="">
// <em>No Parent Menu</em>
// </MenuItem>
// {allMenus.map((menu) => (
// <MenuItem key={menu.id} value={menu.id}>
// {menu.menuName}
// </MenuItem>
// ))}
// </TextField>
// )}
// />
// </Grid>

// <Grid item xs={12} sm={6}>


// <TextField
// label="URL"
// fullWidth
// {...register("url", { required: "URL is required" })}
// error={!!errors.url}
// helperText={errors.url && "URL is required"}
// />
// </Grid>

// {/* <Grid item xs={12} sm={6}>

// <Autocomplete
// options={availableIcons}
// fullWidth
// renderInput={(params) => (
// <TextField
// {...params}
// label="ICON"
// error={!!errors.icon}
// helperText={errors.icon && "Icon is required"}
// />
// )}
// renderOption={(props, option) => (
// <li {...props} style={{ display: 'flex', alignItems:
'center', gap: '8px' }}>
// <DynamicMuiIcon iconName={option} />
// <span>{option}</span>
// </li>
// )}
// value={selectedIconName || ""}
// onChange={(_, newValue) => setValue("icon", newValue || "")}
// {...register("icon", { required: "Icon is required" })}
// />
// {SelectedIcon && (
// <Box mt={1}>
// <SelectedIcon fontSize="large" />
// </Box>
// )}
// </Grid> */}
// {/* <Grid item xs={12} sm={6}>
// <Autocomplete
// options={availableIcons}
// fullWidth
// value={selectedIconName || ""}
// onChange={(_, newValue) => {
// setSelectedIconName(newValue || "");
// setValue("icon", newValue || "",
{ shouldValidate: true }); // Update form state
// }}
// renderInput={(params) => (
// <TextField
// {...params}
// label="ICON"
// error={!!errors.icon}
// helperText={errors.icon && "Icon is
required"}
// {...register("icon", { required:
"Icon is required" })}

// />
// )}
// renderOption={(props, option) => (
// <li {...props} style={{ display: "flex",
alignItems: "center", gap: "8px" }}>
// <DynamicMuiIcon iconName={option} />
// <span>{option}</span>
// </li>
// )}
// />
// {selectedIconName && (
// <Box mt={1} display="flex"
alignItems="center" gap="8px">
// <DynamicMuiIcon
iconName={selectedIconName} fontSize="large" />
// <span>{selectedIconName}</span>
// </Box>
// )}
// </Grid> */}
// <Grid item xs={12} sm={6}>
// <Controller
// name="icon"
// control={control}
// rules={{ required: "Icon is required" }}
// render={({ field }) => (
// <Autocomplete
// options={availableIcons}
// fullWidth
// value={field.value || ""}
// onChange={(_, value) => field.onChange(value)}
// renderOption={(props, option) => (
// <li
// {...props}
// style={{ display: "flex", alignItems: "center", gap:
"8px" }}
// >
// <DynamicMuiIcon iconName={option} />
// {option}
// </li>
// )}
// renderInput={(params) => (
// <TextField
// {...params}
// label="ICON"
// error={!!errors.icon}
// helperText={errors.icon?.message}
// InputProps={{
// ...params.InputProps,
// startAdornment: selectedIconName ? (
// <Box sx={{ mr: 1, display: "flex", alignItems:
"center" }}>
// <DynamicMuiIcon iconName={selectedIconName} />
// </Box>
// ) : null,
// }}
// />
// )}
// />
// )}
// />
// </Grid>
// <Grid item xs={12} sm={6}>
// <TextField
// label="DISPLAY ORDER"
// fullWidth
// {...register("displayOrder", { required: true })}
// error={!!errors.displayOrder}
// helperText={errors.displayOrder && "Display order is
required"}
// />
// </Grid>

// <Grid item xs={12} sm={6}>


// <TextField
// select
// label="STATUS"
// fullWidth
// defaultValue="Y"
// {...register("status", { required: "Status is required" })}
// error={!!errors.status}
// helperText={errors.status && "Status is required"}
// >
// <MenuItem value="Y">Active</MenuItem>
// <MenuItem value="N">Inactive</MenuItem>
// </TextField>
// </Grid>
// </Grid>

// <Box sx={{ display: "flex", mt: 3 }}>


// <Button type="submit" variant="contained" sx={{ marginRight:
"10px" }}>
// {mode === "edit" ? "Save Changes" : "Add Menu"}
// </Button>
// <Button
// variant="outlined"
// onClick={() => router.push("/menumanagement")}
// sx={{ color: "#60176F", borderColor: "#60176F" }}
// >
// Cancel
// </Button>
// </Box>
// </Box>
// </Box>
// </Container>
// </Box>
// );
// };

// MenuForm.getLayout = (page) => <DashboardLayout>{page}</DashboardLayout>;


// export default MenuForm;
import {
Box,
Button,
Grid,
Container,
MenuItem,
SvgIcon,
TextField,
Typography,
Autocomplete,
} from "@mui/material";
import { useForm, Controller } from "react-hook-form";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import NextLink from "next/link";
import { toast } from "react-toastify";
import menuapi from "src/services/api/menu";
import * as MuiIcons from "@mui/icons-material";
import availableIcons from "src/static/icons";
import Link from "next/link";
import { Layout as DashboardLayout } from "src/layouts/dashboard/layout";
import { ArrowLeft } from "src/Icons/ArrowLeft";

const DynamicMuiIcon = ({ iconName }) => {


if (!iconName) return null;
const IconComponent = MuiIcons[iconName];
return IconComponent ? (
<IconComponent fontSize="small" />
) : (
<span title="Icon not found">❓</span>
);
};

const defaultValues = {
menuName: "",
menuCode: "",
parentMenuId: "",
url: "",
icon: "",
displayOrder: "",
status: "Active",
};

const MenuForm = () => {


const {
register,
handleSubmit,
reset,
watch,
setValue,
control,
formState: { errors },
} = useForm({ defaultValues });

const [allMenus, setAllMenus] = useState([]);


const router = useRouter();
const { mode = "add", id } = router.query;

useEffect(() => {
fetchAllMenus();
if (mode === "edit" && id) {
fetchMenuDetails();
}
}, [id, mode]);

const fetchAllMenus = async () => {


try {
const res = await menuapi.getAllMenuApi();
setAllMenus(res.data.data || []);
} catch (error) {
toast.error("Failed to load menus");
}
};

const fetchMenuDetails = async () => {


try {
const res = await menuapi.getMenuById(id);
const data = res.data.data;
reset({
...data,
parentMenuId: data.parentMenuId?.toString() || "",
status: data.status || "Active",
displayOrder: data.displayOrder?.toString() || "",
});
} catch (error) {
console.error(error);
toast.error("Failed to load menu");
}
};

const isValidObjectId = (id) => /^[0-9a-fA-F]{24}$/.test(id);

const onSubmit = async (formData) => {


const cleanedData = {
menuName: formData.menuName,
menuCode: formData.menuCode,
parentMenuId: isValidObjectId(formData.parentMenuId) ?
formData.parentMenuId : null,
url: formData.url,
icon: formData.icon,
displayOrder: Number(formData.displayOrder),
status: formData.status === "Active" ? "Active" : "Inactive",
};

try {
if (mode === "edit" && id) {
await menuapi.updateMenuApi(id, cleanedData);
toast.success("Menu updated successfully!");
} else {
await menuapi.addMenuApi(cleanedData);
toast.success("Menu created successfully!");
}
router.push("/menumanagement");
} catch (error) {
console.error("Submit Error:", error?.response?.data || error);
toast.error(error?.response?.data?.message || "An error occurred. Please try
again later.");
}
};

const [selectedIconName, setSelectedIconName] = useState("");

useEffect(() => {
const subscription = watch((value, { name }) => {
if (name === "icon") {
setSelectedIconName(value.icon || "");
}
});
return () => subscription.unsubscribe();
}, [watch]);

return (
<Box component="main" sx={{ flexGrow: 1, py: 3 }}>
<Container maxWidth={false}>
<Box sx={{ mb: 4, display: "inline-block", width: "100%" }}>
<Box sx={{ mb: 4 }}>
<Link href="/menumanagement" passHref legacyBehavior>
<Box
component="a"
sx={{
display: "flex",
alignItems: "center",
textDecoration: "none",
color: "text.primary",
width: "fit-content",
"&:hover": {
textDecoration: "underline",
color: "#60176F",
},
}}
>
<ArrowLeft fontSize="small" sx={{ mr: 1 }} />
<Typography variant="subtitle2" sx={{ textDecoration:
"underline" }}>
Back
</Typography>
</Box>
</Link>
</Box>

<Grid container justifyContent="space-between" spacing={3}>


<Grid item sx={{ alignItems: "center", display: "flex", overflow:
"hidden" }}>
<Typography
variant="h5"
sx={{ color: "#60176F", fontWeight: 600, marginBottom: "3px" }}
>
{mode === "edit" ? "Edit Menu" : "Add New Menu"}
</Typography>
</Grid>
</Grid>

<Box
component="form"
onSubmit={handleSubmit(onSubmit)}
sx={{
mt: 3,
p: 3,
width: "100%",
maxWidth: { xs: "100%", md: "100%" },
mx: "auto",
}}
>
<Grid container spacing={3}>
<Grid item xs={12} sm={6}>
<TextField
label="MENU NAME"
fullWidth
{...register("menuName", { required: "Menu name is required" })}
error={!!errors.menuName}
helperText={errors.menuName?.message}
/>
</Grid>

<Grid item xs={12} sm={6}>


<TextField
label="MENU CODE"
fullWidth
{...register("menuCode", { required: "Menu code is required" })}
error={!!errors.menuCode}
helperText={errors.menuCode?.message}
/>
</Grid>

{/* <Grid item xs={12} sm={6}>


<Controller
name="parentMenuId"
control={control}
render={({ field }) => (
<TextField
label="PARENT MENU Name"
fullWidth
select
{...field}
value={field.value || ""} // Ensure this is always a string
onChange={(event) => field.onChange(event.target.value)}
error={!!errors.parentMenuId}
helperText={errors.parentMenuId?.message || ""}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{allMenus.map((menu) => (
<MenuItem key={menu.id} value={menu.id ? menu.id.toString() : ""}>
{menu.menuName || "Unnamed Menu"}
</MenuItem>
))}

</TextField>
)}
/>
</Grid> */}
<Grid item xs={12} sm={6}>
<Controller
name="parentMenuId"
control={control}
render={({ field }) => (
<TextField
label="PARENT MENU NAME"
fullWidth
select
{...field}
value={field.value || ""}
onChange={(event) => field.onChange(event.target.value)}
error={!!errors.parentMenuId}
helperText={errors.parentMenuId?.message || ""}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
{allMenus.map((menu) => (
<MenuItem key={menu._id} value={menu._id}>
{menu.menuName}
</MenuItem>
))}
</TextField>
)}
/>
</Grid>

<Grid item xs={12} sm={6}>


<TextField
label="URL"
fullWidth
{...register("url")}
error={!!errors.url}
helperText={errors.url?.message}
/>
</Grid>

<Grid item xs={12} sm={6}>


<Controller
name="icon"
control={control}
rules={{ required: "Icon is required" }}
render={({ field }) => (
<Autocomplete
options={availableIcons}
fullWidth
value={field.value || ""}
onChange={(_, value) => {
field.onChange(value);
setSelectedIconName(value || "");
}}
renderOption={(props, option) => (
<li
{...props}
style={{ display: "flex", alignItems: "center", gap:
"8px" }}
>
<DynamicMuiIcon iconName={option} />
{option}
</li>
)}
renderInput={(params) => (
<TextField
{...params}
label="ICON"
error={!!errors.icon}
helperText={errors.icon?.message}
InputProps={{
...params.InputProps,
startAdornment: selectedIconName ? (
<Box sx={{ mr: 1, display: "flex", alignItems:
"center" }}>
<DynamicMuiIcon iconName={selectedIconName} />
</Box>
) : null,
}}
/>
)}
/>
)}
/>
</Grid>

<Grid item xs={12} sm={6}>


<TextField
label="DISPLAY ORDER"
fullWidth
type="number"
{...register("displayOrder", {
required: "Display order is required",
valueAsNumber: true,
})}
error={!!errors.displayOrder}
helperText={errors.displayOrder?.message}
/>
</Grid>

<Grid item xs={12} sm={6}>


<TextField
select
label="STATUS"
fullWidth
{...register("status", { required: "Status is required" })}
error={!!errors.status}
helperText={errors.status?.message}
>
<MenuItem value="Active">Active</MenuItem>
<MenuItem value="Inactive">Inactive</MenuItem>
</TextField>
</Grid>
</Grid>

<Box sx={{ display: "flex", mt: 3 }}>


<Button type="submit" variant="contained" sx={{ marginRight:
"10px" }}>
{mode === "edit" ? "Save Changes" : "Add Menu"}
</Button>
<Button
variant="outlined"
onClick={() => router.push("/menumanagement")}
sx={{ color: "#60176F", borderColor: "#60176F" }}
>
Cancel
</Button>
</Box>
</Box>
</Box>
</Container>
</Box>
);
};

MenuForm.getLayout = (page) => <DashboardLayout>{page}</DashboardLayout>;


export default MenuForm;

You might also like