Skip to content
Extraits de code Groupes Projets
Valider 251d6e7c rédigé par nour.amellouk's avatar nour.amellouk
Parcourir les fichiers

term choix done

parent 0feae839
Branches feature/MYD-452
1 requête de fusion!162MYD-452
Pipeline #3690 réussi avec l'étape
in 4 minutes et 7 secondes
Affichage de
avec 737 ajouts et 39 suppressions
import ChoiceEditView from "@/shared/sections/product/add-list-ConfigurationChoixTerme/termeChoix-edit-view";
// ----------------------------------------------------------------------
export const metadata = {
title: "Dashboard: modification d'un choix",
};
type Props = {
params: {
id: string;
choiceId : string
};
};
export default function ChoiceEditPage({ params }: Props) {
const { id, choiceId } = params;
return < ChoiceEditView id={id} choiceId={choiceId} />;
}
import ChoixTerme from "@/shared/sections/product/add-list-ConfigurationChoixTerme/configuration-Cterme-create";
import ChoixTerme from "@/shared/sections/product/add-list-ConfigurationChoixTerme/termeChoix-add-view";
// ----------------------------------------------------------------------
type Props = {
params: {
id: string;
};
};
export const metadata = {
title: "Dashboard: Terme Configuration",
title: "Dashboard: choix de valeur d'un attribut",
};
export default function ProductListPage() {
return <ChoixTerme />;
export default function ChoiceListPage({ params }: Props) {
const { id } = params;
return <ChoixTerme attributid={id} />;
}
......@@ -29,7 +29,13 @@ export const paths = {
attribut: `${ROOTS.DASHBOARD}/product/attribut`,
editAttribut: (id: string) =>
`${ROOTS.DASHBOARD}/product/attribut/${id}/edit`,
termeChoix: `${ROOTS.DASHBOARD}/product/attribut/termeChoix`,
termeChoix: {
root: (attributId: string) =>
`${ROOTS.DASHBOARD}/product/attribut/${attributId}/termeChoix`,
editChoix : (attributId: string, choiceId: string )=>
`${ROOTS.DASHBOARD}/product/attribut/${attributId}/termeChoix/${choiceId}/edit`,
},
termeImage: `${ROOTS.DASHBOARD}/product/attribut/termeImage`,
termeLabel: `${ROOTS.DASHBOARD}/product/attribut/termeLabel`,
termeColor: {
......
......@@ -82,7 +82,7 @@ export default function ProductAttribut() {
const handleConfigureTerms = (type: string, id: string) => {
switch (type) {
case "CHOICE":
router.push(paths.dashboard.admin.product.termeChoix);
router.push(paths.dashboard.admin.product.termeChoix.root(id));
break;
case "IMAGE":
router.push(paths.dashboard.admin.product.termeImage);
......
"use client";
import { useState } from "react";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import DeleteIcon from "@mui/icons-material/Delete";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import Card from "@mui/material/Card";
import { IChoice } from "@/shared/types/term";
import { Alert, Snackbar } from "@mui/material";
import { useAddChoice, useGetChoicesByAttribut } from "@/shared/api/terms";
//------------------------------------------------------
export default function TermChoixAddForm({
attributid,
}: {
attributid: string;
}) {
const { ChoicesMutate } = useGetChoicesByAttribut(attributid);
const [nom, setNom] = useState<string>("");
const [slug, setSlug] = useState<string>("");
const [description, setDescription] = useState<string>("");
// States for Snackbar
const [openSnackbar, setOpenSnackbar] = useState<boolean>(false);
const [snackbarMessage, setSnackbarMessage] = useState<string>("");
const [showSuccessMessage, setShowSuccessMessage] = useState(false);
const handleCloseSnackbar = () => {
setOpenSnackbar(false);
};
const regex = /^[a-zA-Z0-9]+(?:[- ][a-zA-Z0-9]+)*$/; // Regex pour accepter lettres, chiffres et tirets
const slugRegex = /^[a-zA-Z0-9]+(?:[a-zA-Z0-9- ]*[a-zA-Z0-9]+)*$/;
const validateForm = (): boolean => {
if (!nom || !description) {
setSnackbarMessage("Tous les champs requis doivent être remplis.");
setOpenSnackbar(true);
return false;
}
if (!regex.test(nom)) {
setSnackbarMessage(
"Le nom ne doit contenir que des lettres, des chiffres et des tirets."
);
setOpenSnackbar(true);
return false;
}
if (!slugRegex.test(slug) && slug !== "") {
setSnackbarMessage(
"Le slug doit commencer par une lettre ou un chiffre, peut contenir des tirets, et ne doit pas contenir uniquement des caractères spéciaux."
);
setOpenSnackbar(true);
return false;
}
return true;
};
const handleOnSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (!validateForm()) {
return;
}
const choiceRequest: IChoice = {
nom,
slug,
description,
attributeId: attributid,
};
console.log(choiceRequest);
try {
await useAddChoice(choiceRequest);
ChoicesMutate();
setShowSuccessMessage(true);
const timeoutId = setTimeout(() => {
setShowSuccessMessage(false);
clearTimeout(timeoutId);
}, 5000);
} catch (error) {
let errorMessage;
if (
typeof error === "string" &&
error.includes("A Choice with this name already exists")
) {
errorMessage = "Le slug doit également être unique.";
} else if (
error instanceof Error &&
error.message.includes("A Choice tag with this name already exists")
) {
errorMessage = "Le slug doit également être unique.";
}
setSnackbarMessage(errorMessage ?? "Le term choix n'a pas pu être créée.");
setOpenSnackbar(true);
}
};
return (
<Card variant="outlined">
<form onSubmit={handleOnSubmit}>
<Stack spacing={1.5} sx={{ p: 3 }}>
<Typography variant="subtitle2">Ajouter le Terme</Typography>
<TextField
name="nom"
label="Nom"
InputLabelProps={{ shrink: true }}
value={nom}
onChange={(e) => setNom(e.target.value)}
/>
<TextField
label="Slug"
name="slug"
InputLabelProps={{ shrink: true }}
value={slug}
onChange={(e) => setSlug(e.target.value)}
/>
<TextField
name="Description"
label="Description "
multiline
rows={4}
InputLabelProps={{ shrink: true }}
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
<Button type="submit" variant="contained" color="primary">
Ajouter
</Button>
</Stack>
<Snackbar
open={openSnackbar}
autoHideDuration={6000}
onClose={handleCloseSnackbar}
>
<Alert onClose={handleCloseSnackbar} severity="error">
{snackbarMessage}
</Alert>
</Snackbar>
{showSuccessMessage && (
<Alert
severity="success"
onClose={() => setShowSuccessMessage(false)}
>
le choix a été ajoutée avec succès
</Alert>
)}
</form>
</Card>
);
}
"use client";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import Card from "@mui/material/Card";
export default function AttributTermeForm() {
return (
<Card variant="outlined">
<Stack spacing={1.5} sx={{ p: 3 }}>
<Typography variant="subtitle2">Ajouter une Étiquette</Typography>
<TextField name="nom" label="Nom" InputLabelProps={{ shrink: true }} />
<TextField
label="Slug"
name="slug"
InputLabelProps={{ shrink: true }}
/>
<TextField
name="Description"
label="Description "
multiline
rows={4}
InputLabelProps={{ shrink: true }}
/>
<Button type="submit" variant="contained" color="primary">
Enregister
</Button>
</Stack>
</Card>
);
}
......@@ -15,7 +15,6 @@ import Card from "@mui/material/Card";
import { useBoolean } from "@/hooks/use-boolean";
import ConfirmDialog from "@/shared/components/confirm-dialog";
import AttributTermeForm from "./Choixterme-edit-form";
import { useRouter } from "@/hooks";
import { useCallback } from "react";
import {
......@@ -28,25 +27,90 @@ import {
GridRowSelectionModel,
GridToolbarFilterButton,
} from "@mui/x-data-grid";
import { IChoice } from "@/shared/types/term";
import { Alert, CircularProgress, Typography } from "@mui/material";
import { useDeleteChoice, useDeleteChoices, useGetChoicesByAttribut } from "@/shared/api/terms";
import CustomDataGridToolbar from "../add-edit-ConfigurationIColorTerme/GridToolbarContainer";
import TermChoixAddForm from "./Choixterme-add-form";
export default function ChoixTerme() {
export default function ChoixTerme({ attributid }: { attributid: string }) {
const [selectedRowIds, setSelectedRowIds] = useState<GridRowSelectionModel>(
[]
);
const {ChoicesLoading, ChoicesData, ChoicesError, ChoicesMutate }= useGetChoicesByAttribut(attributid);
const router = useRouter();
const handleEditRow = useCallback(
(id: string) => {
router.push(paths.dashboard.admin.product.editTag(id));
router.push(paths.dashboard.admin.product.termeChoix.editChoix(attributid, id));
},
[router]
);
const confirmRows = useBoolean();
const [tableData, setTableData] = useState<IChoice[]>();
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [successMessage, setSuccessMessage] = useState<string | null>(null);
const handleRetry = async () => {
try {
await ChoicesMutate();
} catch (err) {
setErrorMessage("Erreur lors du rechargement des choix.");
setTimeout(() => {
setErrorMessage(null);
}, 5000);
}
};
const handleDeleteRow = async (id: number) => {
try {
const response = await useDeleteChoice(id.toString());
ChoicesMutate();
if (response.status === 200) {
setSelectedRowIds([]);
setSuccessMessage("choix supprimée avec succès.");
}
} catch (error) {
setErrorMessage("Erreur lors de la suppression du choix.");
} finally {
const timeoutId = setTimeout(() => {
setSuccessMessage(null);
setErrorMessage(null);
clearTimeout(timeoutId)
}, 5000);
}
};
const handleDeleteRows = () => {};
const handleDeleteRows = async () => {
try {
if (selectedRowIds.length > 0) {
const idsToDelete = selectedRowIds.map((id) => id.toString());
const response = await useDeleteChoices(idsToDelete);
ChoicesMutate();
if (response.status === 200) {
setSelectedRowIds([]);
setSuccessMessage("choix supprimée(s) avec succès.");
}
}
} catch (error) {
setErrorMessage("Erreur lors de la suppression des choix.");
} finally {
const timeoutId = setTimeout(() => {
setSuccessMessage(null);
setErrorMessage(null);
clearTimeout(timeoutId)
}, 5000);
}
};
const columns: GridColDef[] = [
{
field: "name",
field: "nom",
headerName: "Nom",
flex: 1,
editable: true,
......@@ -62,8 +126,7 @@ export default function ChoixTerme() {
headerName: "Description",
flex: 1,
editable: true,
},
{
},{
field: "total",
headerName: "Total",
flex: 1,
......@@ -92,7 +155,7 @@ export default function ChoixTerme() {
icon={<Iconify icon="solar:trash-bin-trash-bold" />}
label="Supprimer"
onClick={() => {
//handleDeleteRow(params.row.id);
handleDeleteRow(params.row.id);
}}
sx={{ color: "error.main" }}
/>,
......@@ -105,7 +168,15 @@ export default function ChoixTerme() {
},
];
const rows: any [] = [];
const rows = ChoicesData.map((choix)=>({
id : choix.id,
nom : choix.nom,
slug : choix.slug,
description : choix.description,
total : choix.total
}));
return (
<Container
maxWidth="lg"
......@@ -116,14 +187,19 @@ export default function ChoixTerme() {
}}
>
<CustomBreadcrumbs
heading="Attribut"
heading="Attributs"
links={[
{ name: "Dashboard", href: paths.dashboard.root },
{
name: "Product",
href: paths.dashboard.admin.product.root,
},
{ name: "Attribut" },
{ name: "Attribut",
href: paths.dashboard.admin.product.attribut },
{
name : "Choix",
href : paths.dashboard.admin.product.termeChoix.root(attributid)
}
]}
sx={{
mb: {
......@@ -135,83 +211,100 @@ export default function ChoixTerme() {
<Grid container spacing={3}>
<Grid item xs={4}>
<AttributTermeForm />
<TermChoixAddForm attributid={attributid}/>
</Grid>
<Grid item xs={8}>
<Card variant="outlined">
<DataGrid
checkboxSelection
autoHeight
getRowHeight={() => "auto"}
rows={rows}
columns={columns}
disableColumnSelector
disableDensitySelector
onRowSelectionModelChange={(newSelectionModel) => {
setSelectedRowIds(newSelectionModel);
}}
slots={{
toolbar: () => (
<GridToolbarContainer>
<GridToolbarFilterButton />
<GridToolbarExport />
<GridToolbarQuickFilter />
<Stack
spacing={1}
flexGrow={1}
direction="row"
alignItems="center"
justifyContent="flex-end"
>
{!!selectedRowIds.length && (
<Stack>
<Button
size="small"
color="error"
startIcon={
<Iconify icon="solar:trash-bin-trash-bold" />
}
onClick={confirmRows.onTrue}
>
Delete ({selectedRowIds.length})
</Button>
</Stack>
)}
</Stack>
</GridToolbarContainer>
),
}}
slotProps={{
toolbar: {
showQuickFilter: true,
},
}}
/>
</Card>
<ConfirmDialog
open={confirmRows.value}
onClose={confirmRows.onFalse}
title="Supprimer"
content={
<>
Êtes-vous sûr de vouloir supprimer{" "}
<strong> {selectedRowIds.length} </strong> items?
</>
}
action={
<Button
variant="contained"
color="error"
onClick={() => {
handleDeleteRows();
confirmRows.onFalse();
}}
>
Supprimer
{ChoicesLoading ? (
<Stack
direction="row"
spacing={2}
justifyContent="center"
alignItems="center"
sx={{ height: '100%', width: '100%' }}
>
<CircularProgress />
<Typography>Chargement des Labels...</Typography>
</Stack>
) : ChoicesError ? (
<Container>
<Alert severity="error" sx={{ mb: 2 }}>
Impossible de charger la liste des choix
</Alert>
<Button variant="contained" color="primary" onClick={handleRetry}>
Réessayer
</Button>
}
/>
</Container>
) : (
<Card variant="outlined">
<DataGrid
checkboxSelection
autoHeight
getRowHeight={() => "auto"}
rows={ rows }
columns={columns}
disableColumnSelector
disableDensitySelector
pageSizeOptions={[5, 10, 25]}
initialState={{
pagination: {
paginationModel: { pageSize: 10 },
},
}}
onRowSelectionModelChange={(newSelectionModel) => {
setSelectedRowIds(newSelectionModel);
}}
slots={{
toolbar: () => (
<CustomDataGridToolbar
selectedRowIds={selectedRowIds.map(String)}
onDeleteRows={() => confirmRows.onTrue()}
/>
),
}}
slotProps={{
toolbar: {
showQuickFilter: true,
},
}}
/>
{errorMessage && (
<Alert severity="error" onClose={() => setErrorMessage(null)}>
{errorMessage}
</Alert>
)}
{successMessage && (
<Alert severity="success" onClose={() => setSuccessMessage(null)}>
{successMessage}
</Alert>
)}
</Card>
)}
<ConfirmDialog
open={confirmRows.value}
onClose={confirmRows.onFalse}
title="Supprimer"
content={
<>
Êtes-vous sûr de vouloir supprimer{" "}
<strong> {selectedRowIds.length} </strong> item?
</>
}
action={
<Button
variant="contained"
color="error"
onClick={() => {
handleDeleteRows();
confirmRows.onFalse();
}}
>
Supprimer
</Button>
}
/>
</Grid>
</Grid>
</Container>
......
"use client";
import { useEffect, useState } from "react";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import DeleteIcon from "@mui/icons-material/Delete";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import Card from "@mui/material/Card";
import { IChoice } from "@/shared/types/term";
import { Alert, Snackbar } from "@mui/material";
import { useUpdateChoice, useGetChoicesByAttribut, useGetChoice } from "@/shared/api/terms";
//------------------------------------------------------
export default function TermChoixEditForm({ attributid, choiceId }: { attributid: string, choiceId: string }) {
const { ChoicesMutate } = useGetChoicesByAttribut(attributid);
const {choiceData}= useGetChoice(choiceId)
const [nom, setNom] = useState<string>("");
const [slug, setSlug] = useState<string>("");
const [description, setDescription] = useState<string>("");
const formSetter = () => {
setNom(choiceData.nom)
setDescription(choiceData.description)
}
useEffect(()=>{
if(choiceData){
formSetter();
}
},[choiceData])
// States for Snackbar
const [openSnackbar, setOpenSnackbar] = useState<boolean>(false);
const [snackbarMessage, setSnackbarMessage] = useState<string>("");
const [showSuccessMessage, setShowSuccessMessage] = useState(false);
const handleCloseSnackbar = () => {
setOpenSnackbar(false);
};
const regex = /^[a-zA-Z0-9]+(?:[- ][a-zA-Z0-9]+)*$/; // Regex pour accepter lettres, chiffres et tirets
const slugRegex =/^[a-zA-Z0-9]+(?:[a-zA-Z0-9- ]*[a-zA-Z0-9]+)*$/;
const validateForm = (): boolean => {
if (!nom || !description ) {
setSnackbarMessage("Tous les champs requis doivent être remplis.");
setOpenSnackbar(true);
return false;
}
if (!regex.test(nom)) {
setSnackbarMessage("le nom ne doit contenir que des lettres, des chiffres et des tirets.");
setOpenSnackbar(true);
return false;
}
if (!slugRegex.test(slug) && slug!=="") {
setSnackbarMessage("Le slug doit commencer par une lettre ou un chiffre, peut contenir des tirets, et ne doit pas contenir uniquement des caractères spéciaux.");
setOpenSnackbar(true);
return false;
}
return true;
};
const handleOnSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (!validateForm()) {
return;
}
const choiceRequest: IChoice = {
nom,
slug,
description,
attributeId: attributid,
};
try {
await useUpdateChoice(choiceRequest, choiceId);
ChoicesMutate();
setShowSuccessMessage(true);
const timeoutId = setTimeout(() => {
setShowSuccessMessage(false);
clearTimeout(timeoutId);
}, 5000);
} catch (error) {
let errorMessage;
if (
typeof error === "string" &&
error.includes("A Choice with this name already exists")
) {
errorMessage = "Le slug doit également être unique.";
} else if (
error instanceof Error &&
error.message.includes("A Choice with this name already exists")
) {
errorMessage = "Le slug doit également être unique.";
}
setSnackbarMessage(errorMessage ?? "Le term choix n'a pas pu être modifiée.");
setOpenSnackbar(true);
}
};
return (
<Card variant="outlined">
<form onSubmit={handleOnSubmit}>
<Stack spacing={1.5} sx={{ p: 3 }}>
<Typography variant="subtitle2">Ajouter le Terme</Typography>
<TextField
name="nom"
label="Nom"
InputLabelProps={{ shrink: true }}
value={nom}
onChange={(e) => setNom(e.target.value)}
/>
<TextField
label="Slug"
name="slug"
InputLabelProps={{ shrink: true }}
value={slug}
onChange={(e) => setSlug(e.target.value)}
/>
<TextField
name="Description"
label="Description "
multiline
rows={4}
InputLabelProps={{ shrink: true }}
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
<Button type="submit" variant="contained" color="primary">
modifier
</Button>
</Stack>
<Snackbar
open={openSnackbar}
autoHideDuration={6000}
onClose={handleCloseSnackbar}
>
<Alert onClose={handleCloseSnackbar} severity="error">
{snackbarMessage}
</Alert>
</Snackbar>
{showSuccessMessage && (
<Alert severity="success" onClose={() => setShowSuccessMessage(false)}>
le choix a été modifié avec succès
</Alert>
)}
</form>
</Card>
);
}
"use client";
import Container from "@mui/material/Container";
import { paths } from "@/routes/paths";
import { useSettingsContext } from "@/shared/components/settings";
import CustomBreadcrumbs from "@/shared/components/custom-breadcrumbs";
import TermChoixEditForm from "./termeChoix-edit-form";
// import EditTermLabForm from "./termeLabel-edit-form";
"./termeColor-edit-form";
// ----------------------------------------------------------------------
type Props = {
id: string;
choiceId : string;
};
export default function ChoiceEditView({ id , choiceId}: Props) {
const settings = useSettingsContext();
return (
<Container maxWidth={settings.themeStretch ? false : "lg"}>
<CustomBreadcrumbs
heading="Modifier"
links={[
{ name: "Dashboard", href: paths.dashboard.root },
{
name: "Product",
href: paths.dashboard.admin.product.root,
},
{ name: "Attribut",
href: paths.dashboard.admin.product.attribut },
{
name : "choix",
href : paths.dashboard.admin.product.termeChoix.root(id)
},
{
name: "Modifier les choix"
}
]}
sx={{
mb: { xs: 3, md: 5 },
}}
/>
<TermChoixEditForm attributid={id} choiceId={choiceId}/>
</Container>
);
}
0% ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter