2022-05-18 10:15:54 +02:00
|
|
|
import { useEffect, useRef, useState } from "react";
|
|
|
|
import styles from "../../styles/exos/ModalCard.module.scss";
|
2022-06-24 13:42:16 +02:00
|
|
|
import { isBrowser, isEmpty, parseClassName } from "../../utils/utils.js";
|
2022-05-18 10:15:54 +02:00
|
|
|
import ExoPrinterForm from "./ExoPrinterForm.jsx";
|
|
|
|
import Tag from "../Tag.jsx";
|
|
|
|
import { HiOutlineTrash } from "react-icons/hi";
|
|
|
|
import { TiEdit } from "react-icons/ti";
|
|
|
|
import { AiOutlineClose } from "react-icons/ai";
|
|
|
|
import { notificationService } from "../../services/notification.service.js";
|
|
|
|
import { AlertType, useAlert } from "../../context/alert.context.js";
|
|
|
|
import { ExoEditForm } from "./ExoEditForm.jsx";
|
|
|
|
import {
|
|
|
|
delExo,
|
|
|
|
delTag,
|
2022-06-24 13:42:16 +02:00
|
|
|
favExo,
|
2022-05-18 10:15:54 +02:00
|
|
|
getExos,
|
|
|
|
getModelFile,
|
|
|
|
setTags,
|
|
|
|
} from "../../requests/requests.exos.js";
|
|
|
|
import { useMutation, useQuery, useQueryClient } from "react-query";
|
|
|
|
import { TagCreatable } from "./TagCreate.jsx";
|
2022-06-11 23:39:03 +02:00
|
|
|
import Link from "next/link";
|
2022-06-24 13:42:16 +02:00
|
|
|
import { HiOutlineDuplicate } from "react-icons/hi";
|
|
|
|
import { useSessionContext } from "../../context/session.context.js";
|
2022-06-11 23:39:03 +02:00
|
|
|
export default function ModalCard({ step, onClose, onDelete, tags, queryKey }) {
|
|
|
|
|
2022-05-18 10:15:54 +02:00
|
|
|
const [tagMode, setTagMode] = useState(false);
|
|
|
|
|
|
|
|
const alert = useAlert();
|
|
|
|
const [edit, setEdit] = useState(false);
|
|
|
|
const queryClient = useQueryClient();
|
2022-06-24 19:51:47 +02:00
|
|
|
|
2022-05-18 10:15:54 +02:00
|
|
|
const {
|
|
|
|
isLoading: isUpdating,
|
|
|
|
isFetching,
|
|
|
|
data: step_data,
|
|
|
|
} = useQuery(
|
|
|
|
["exo-data", step.id_code],
|
2022-06-24 19:51:47 +02:00
|
|
|
async () => await getExos(step.id_code).catch(() => {
|
|
|
|
notificationService.error('Erreur', "Exercice introuvable")
|
|
|
|
}),
|
2022-05-18 10:15:54 +02:00
|
|
|
{ initialData: step, refetchOnWindowFocus: !edit }
|
|
|
|
);
|
|
|
|
const [selected, setSelected] = useState([]);
|
|
|
|
const [tagOptions, setTagOptions] = useState(
|
|
|
|
tags.map((tag) => {
|
|
|
|
return {
|
|
|
|
...tag,
|
|
|
|
isDisabled: step_data.tags.map((t) => t.id_code).includes(tag.id_code),
|
|
|
|
};
|
|
|
|
})
|
|
|
|
);
|
2022-06-24 13:42:16 +02:00
|
|
|
const {authData} = useSessionContext()
|
2022-05-18 10:15:54 +02:00
|
|
|
useEffect(() => {
|
|
|
|
setTagOptions(
|
|
|
|
tags.map((tag) => {
|
|
|
|
return {
|
|
|
|
...tag,
|
|
|
|
isDisabled: step_data.tags
|
|
|
|
.map((t) => t.id_code)
|
|
|
|
.includes(tag.id_code),
|
|
|
|
};
|
|
|
|
})
|
|
|
|
);
|
|
|
|
return () => {
|
|
|
|
setTagOptions([]);
|
|
|
|
};
|
|
|
|
}, [step_data.tags, tags]);
|
|
|
|
|
|
|
|
const { mutate: setTagMutate } = useMutation(
|
|
|
|
async () => await setTags({ step: step.id_code, tags: [...selected] }),
|
|
|
|
{
|
2022-06-11 23:39:03 +02:00
|
|
|
onSuccess: (data) => {
|
|
|
|
//queryClient.invalidateQueries(step.id_code);
|
|
|
|
queryClient.setQueryData(['exo-data', step.id_code],(old) => {
|
|
|
|
return {...old, tags: data.data.tags}
|
|
|
|
})
|
|
|
|
queryClient.setQueryData(queryKey, (old) => {
|
|
|
|
console.log('TEST OLD', old)
|
|
|
|
return {
|
|
|
|
...old,
|
|
|
|
results: [
|
|
|
|
...old.results.map((r) => {
|
|
|
|
if (r.id_code === data.data.id_code) {
|
|
|
|
return { ...r, tags: data.data.tags };
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
};
|
|
|
|
});
|
2022-05-18 10:15:54 +02:00
|
|
|
queryClient.invalidateQueries("tags");
|
2022-06-11 23:39:03 +02:00
|
|
|
queryClient.invalidateQueries(queryKey[0], { inactive: true });
|
|
|
|
|
2022-05-18 10:15:54 +02:00
|
|
|
setSelected([]);
|
|
|
|
notificationService.success("Tags", `Tags de ${step.name} modifiés !`, {
|
|
|
|
autoClose: true,
|
|
|
|
});
|
|
|
|
setTagMode(false);
|
|
|
|
},
|
2022-06-11 23:39:03 +02:00
|
|
|
onError: (e) => {
|
|
|
|
console.log('error', e)
|
2022-05-18 10:15:54 +02:00
|
|
|
notificationService.error(
|
|
|
|
"Erreur",
|
|
|
|
`Les tags de ${step.name} n'ont pu être modifiés !`
|
|
|
|
);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
const { mutate: delTagMutate } = useMutation(
|
|
|
|
async (tag) => {
|
|
|
|
return await delTag({ tag: tag, step: step.id_code });
|
|
|
|
},
|
|
|
|
{
|
|
|
|
onSuccess: (data) => {
|
2022-06-11 23:39:03 +02:00
|
|
|
var tagsSelected = queryKey[2].tags || null;
|
|
|
|
if (tagsSelected && tagsSelected.includes(data.data.tagId)) {
|
|
|
|
queryClient.invalidateQueries(queryKey);
|
|
|
|
}
|
|
|
|
queryClient.setQueryData(["exo-data", step.id_code], (old) => {
|
|
|
|
return { ...old, tags: data.data.tags };
|
|
|
|
});
|
|
|
|
queryClient.setQueryData(queryKey, (old) => {
|
2022-06-24 17:27:17 +02:00
|
|
|
|
2022-06-11 23:39:03 +02:00
|
|
|
return {
|
|
|
|
...old,
|
|
|
|
results: [
|
|
|
|
...old.results.map((r) => {
|
|
|
|
if (r.id_code === data.data.id_code) {
|
|
|
|
return { ...r, tags: data.data.tags };
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
};
|
|
|
|
});
|
|
|
|
queryClient.invalidateQueries(queryKey[0], { inactive: true });
|
|
|
|
|
2022-05-18 10:15:54 +02:00
|
|
|
queryClient.invalidateQueries("tags");
|
|
|
|
notificationService.success(
|
|
|
|
"Tags",
|
2022-06-11 23:39:03 +02:00
|
|
|
`Tag ${data.data.name} retiré à ${step.name} !`,
|
2022-05-18 10:15:54 +02:00
|
|
|
{
|
|
|
|
autoClose: true,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
setTagMode(false);
|
|
|
|
},
|
|
|
|
onError: () => {
|
|
|
|
notificationService.error(
|
|
|
|
"Erreur",
|
|
|
|
`Le tag n'a pu être retiré de ${step.name} !`
|
|
|
|
);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2022-06-11 23:39:03 +02:00
|
|
|
|
2022-05-18 10:15:54 +02:00
|
|
|
const [full, setFull] = useState({ state: false, fade: false });
|
|
|
|
const fadeFull = (state) => {
|
|
|
|
setFull({ state: !state, fade: state });
|
|
|
|
setTimeout(() => {
|
|
|
|
setFull({ state: state, fade: false });
|
|
|
|
}, 300);
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className={styles["ex_card--full"]}
|
|
|
|
onKeyDown={(e) => {
|
|
|
|
if (e.code == "Escape") {
|
|
|
|
onClose();
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
//id={"card-" + step_data.id_code}
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
className={parseClassName([
|
|
|
|
styles["ex_card--body"],
|
|
|
|
edit ? "marginb-p0" : undefined,
|
|
|
|
full.fade ? styles["ex_card-fade"] : undefined,
|
|
|
|
full.fade || full.state ? styles["ex_card--big"] : undefined,
|
|
|
|
full.state ? "vh-100" : undefined,
|
|
|
|
edit ? styles["edit-card"] : undefined,
|
|
|
|
])}
|
|
|
|
>
|
|
|
|
{isFetching && (
|
|
|
|
<div className={styles["updating"]}>
|
|
|
|
<span className="loader"></span>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
2022-06-24 13:42:16 +02:00
|
|
|
{!(isFetching || isUpdating) && (
|
2022-05-18 10:15:54 +02:00
|
|
|
<>
|
|
|
|
{!edit && full.state == false && (
|
2022-06-11 23:39:03 +02:00
|
|
|
<div className={styles["ex_card--title"]}>
|
|
|
|
{step_data.name}
|
2022-06-24 13:42:16 +02:00
|
|
|
{step_data.original != null && (
|
|
|
|
<Link href={`/exercices/${step_data.original}`}>
|
|
|
|
<a title="Voir l'exercice original">Exercice original</a>
|
|
|
|
</Link>
|
|
|
|
)}
|
|
|
|
{!step_data.isUser && (
|
|
|
|
<p className={styles.author}>{step_data.author.username}</p>
|
|
|
|
)}
|
2022-06-11 23:39:03 +02:00
|
|
|
</div>
|
2022-05-18 10:15:54 +02:00
|
|
|
)}
|
|
|
|
|
2022-06-24 13:42:16 +02:00
|
|
|
{!edit && full.state == false && (
|
|
|
|
<ExoPrinterForm step={step_data} />
|
|
|
|
)}
|
2022-05-18 10:15:54 +02:00
|
|
|
|
|
|
|
{edit && (
|
|
|
|
<ExoEditForm
|
2022-06-24 13:42:16 +02:00
|
|
|
step={step_data}
|
2022-05-18 10:15:54 +02:00
|
|
|
cancel={() => {
|
|
|
|
setEdit(false);
|
|
|
|
}}
|
|
|
|
setFull={fadeFull}
|
|
|
|
full={full.state}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</div>
|
2022-06-24 13:42:16 +02:00
|
|
|
{!(isFetching || isUpdating) && full.state == false && !isEmpty(authData)&& (
|
2022-05-18 10:15:54 +02:00
|
|
|
<div
|
|
|
|
className={parseClassName([
|
|
|
|
styles["ex_card--footer"],
|
|
|
|
tagMode == true
|
|
|
|
? styles["tag_card"]
|
|
|
|
: styles["ex_card--footer-not-tag"],
|
|
|
|
])}
|
|
|
|
>
|
|
|
|
{tagMode == false && !edit && full.state == false && (
|
|
|
|
<>
|
|
|
|
<div className={styles["tag--container"]}>
|
|
|
|
{step_data.tags.map((t, i) => {
|
|
|
|
return <Tag key={i} tag={t} onDelete={delTagMutate} />;
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
onClick={() => {
|
|
|
|
setTagMode(true);
|
|
|
|
}}
|
|
|
|
className={styles["ex_card--add-tag"]}
|
|
|
|
>
|
|
|
|
{" "}
|
|
|
|
<hr /> <p> +</p>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
{tagMode && !edit && full.state == false && (
|
|
|
|
<>
|
|
|
|
<TagCreatable
|
|
|
|
options={tagOptions}
|
|
|
|
selectOption={setSelected}
|
|
|
|
select={selected}
|
|
|
|
onCreate={setTagOptions}
|
|
|
|
/>
|
|
|
|
<div className="margint-p3 flex-column">
|
|
|
|
<button onClick={setTagMutate} className="exo-btn">
|
|
|
|
Valider
|
|
|
|
</button>
|
|
|
|
<button
|
|
|
|
onClick={() => {
|
|
|
|
setTagMode(false);
|
|
|
|
setSelected([]);
|
|
|
|
}}
|
|
|
|
className="cancel-btn"
|
|
|
|
>
|
|
|
|
Annuler
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{!edit && !(isFetching || isUpdating) && full.state == false && (
|
|
|
|
<div className={styles["icon-container"]}>
|
|
|
|
{/* <Delete className={styles['icon']}/> */}
|
|
|
|
|
|
|
|
<AiOutlineClose
|
|
|
|
className={parseClassName([styles["icon"]])}
|
|
|
|
onClick={onClose}
|
|
|
|
/>
|
2022-06-24 13:42:16 +02:00
|
|
|
{isBrowser &&
|
|
|
|
localStorage.getItem("token") != null &&
|
|
|
|
!step_data.isUser && (
|
|
|
|
<HiOutlineDuplicate
|
|
|
|
onClick={() => {
|
|
|
|
favExo(step.id_code).then((res) => {
|
|
|
|
setRegistered(res.isRegistered);
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{step_data.isUser == true && (
|
|
|
|
<div>
|
|
|
|
<HiOutlineTrash
|
|
|
|
className={parseClassName([styles["icon"], styles["delete"]])}
|
|
|
|
onClick={() => {
|
|
|
|
alert.alert({
|
|
|
|
title: "Êtes-vous sûr ?",
|
|
|
|
active: true,
|
|
|
|
message: `Vous allez supprimer l'exercice ${step_data.name} ! Cette action est irréversible !`,
|
|
|
|
type: AlertType.Warning,
|
|
|
|
validate: () => {
|
|
|
|
delExo(step.id_code).then(() => {
|
|
|
|
notificationService.success(
|
|
|
|
"Suppression",
|
|
|
|
`Exercice ${step_data.name} supprimé !`,
|
|
|
|
{ autoClose: true, keepAfterRouteChange: true }
|
|
|
|
);
|
|
|
|
onDelete(step.id_code);
|
|
|
|
onClose();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
<TiEdit
|
|
|
|
className={parseClassName([styles["icon"], styles["edit"]])}
|
|
|
|
onClick={() => {
|
|
|
|
setEdit(true);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
2022-05-18 10:15:54 +02:00
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|