14/07/2026 - 20h

branche_01062025
Cherif 2026-07-14 22:29:48 +02:00
parent 31af9a9777
commit 7f58f2b35e
24 changed files with 9051 additions and 354 deletions

View File

@ -168,6 +168,8 @@ function App() {
const Display_Partner_Catalog_DetailClass_new_v2 = lazy(() => import("./pages/display_partner_catalog_detailclass_new_v2"));
const Display_Partner_Catalog_DetailClass_new_vp = lazy(() => import("./pages/display_partner_catalog_detailclass_new_vp"));
const [screenSizeh, getDimension] = useState({
dynamicWidth: window.innerHeight
@ -287,6 +289,10 @@ function App() {
<Route path="/Display-Partner-Catalog-Detail-formation/:classId/:action" exact component={Display_Partner_Catalog_DetailClass_new_v2} />
<Route path="/Display-Partner-Catalog-Detail-formation_Vp/:classId" exact component={Display_Partner_Catalog_DetailClass_new_vp} />
<Route path="/Display-Partner-Catalog-Detail-formation_Vp/:classId/:action" exact component={Display_Partner_Catalog_DetailClass_new_vp} />
<Route path="/mysy-account-activated/" exact component={AccountUserActivated} />
{/* <Route path="/Produits-Services/" exact component={ProduitsService} />*/}
<Route path="/tarifs_produits_services/" exact component={ProduitsService} />
@ -406,7 +412,7 @@ function App() {
<Route path="/mysy-student-ent/:local_props_apprenant_id/:local_props_menu" exact component={Student_Account_Ent} />
<Route path="/mysy-user-account/:local_props_client_id/:local_props_menu" exact component={Intranet_Client_Account} />

View File

@ -116,6 +116,8 @@ const AddClassManual = (props) => {
const [mytrainingdirectinscription, setmytrainingdirectinscription] = useState("");
const [formation_type, setformation_type] = useState("formation");
const [mycpf, setmycpf] = useState("0");
const [mycpf_label, setmycpf_label] = useState("Non");
@ -2382,6 +2384,15 @@ const AddClassManual = (props) => {
setmytrainingdirectinscription("");
}
if (mylocaltraining.formation_type) {
setformation_type(mylocaltraining.formation_type);
} else {
setformation_type("");
}
if (mylocaltraining.recyclage_alert) {
setp_detail_recyclage_alert(mylocaltraining.recyclage_alert);
} else {
@ -2821,6 +2832,8 @@ const AddClassManual = (props) => {
formData.append('inscription_direct', mytrainingdirectinscription);
formData.append('formation_type', formation_type);
formData.append('note', mynote);
formData.append('published', mypublier);
@ -3768,6 +3781,24 @@ const AddClassManual = (props) => {
];
const New_Option_formation_type = [
{
value: 'formation',
label: 'Formation',
},
{
value: 'atelier',
label: 'Atelier',
},
{
value: '',
label: '',
},
];
const New_Option_is_Ftion_Initiale = [
{ "id": "1", "label": "Oui", "value": "1" },
{ "id": "0", "label": "Non", "value": "0" },
@ -9300,8 +9331,8 @@ const AddClassManual = (props) => {
</div>}
{props.class_is_ftion_initiale && props.class_is_ftion_initiale === "1" &&
New_Getall_Parter_bloc_competence_result && New_Getall_Parter_bloc_competence_result.length > 0 &&
{props.class_is_ftion_initiale && props.class_is_ftion_initiale === "1" &&
New_Getall_Parter_bloc_competence_result && New_Getall_Parter_bloc_competence_result.length > 0 &&
<div className="training_caract">
<Autocomplete
disablePortal
@ -9457,7 +9488,7 @@ const AddClassManual = (props) => {
{props.class_is_ftion_initiale && props.class_is_ftion_initiale === "1" && <>
<div className="diw_row">
&nbsp;
</div>
<div className="training_caract">
@ -9672,7 +9703,7 @@ const AddClassManual = (props) => {
<div className="training_caract">
{is_ftion_initiale !== "1" && <div className="training_caract">
{inscription_direct && inscription_direct.length > 0 && <Autocomplete
disablePortal
name="inscription_direct"
@ -9697,7 +9728,36 @@ const AddClassManual = (props) => {
/>}
</div>
</div>}
{is_ftion_initiale !== "1" && <div className="training_caract">
{New_Option_formation_type && New_Option_formation_type.length > 0 && <Autocomplete
disablePortal
name="formation_type"
id="formation_type"
className="disabled_style"
disabled={!Boolean(props.check_user_acces_right("formation", "write"))}
options={New_Option_formation_type}
// value={mytrainingdirectinscription}
value={New_Option_formation_type.filter((data) => (data).value === String(formation_type))[0].label}
onChange={(event, value) => {
if (value && value.value) {
setformation_type(value.value);
setdatamodification("1");
} else {
setformation_type("");
setdatamodification("1");
}
}}
renderInput={(params) => <TextField {...params} label="Type formation" />
}
/>}
</div>}
</div>
</div>
</div>
@ -11704,9 +11764,9 @@ const AddClassManual = (props) => {
id="competence_nom"
name="competence_nom"
fullWidth
sx={{
backgroundColor: "#FFF",
}}
sx={{
backgroundColor: "#FFF",
}}
options={New_Getall_Employee_Statistic_Question_List_result}
value={New_Getall_Employee_Statistic_Question_List_result.filter((data) => (data)._id === String(selected_statistic_question_id))[0].label}

View File

@ -1935,6 +1935,12 @@ const Apprenant = (props) => {
document.getElementsByName("field_detail_nom")[0].style.backgroundColor = "#f8f9fa";
}
if (document.getElementsByName("detail_nom_jeune_fille") && document.getElementsByName("detail_nom_jeune_fille")[0]) {
document.getElementsByName("detail_nom_jeune_fille")[0].disabled = true;
document.getElementsByName("detail_nom_jeune_fille")[0].style.backgroundColor = "#f8f9fa";
}
if (document.getElementsByName("field_detail_prenom") && document.getElementsByName("field_detail_prenom")[0]) {
document.getElementsByName("field_detail_prenom")[0].disabled = true;
document.getElementsByName("field_detail_prenom")[0].style.backgroundColor = "#f8f9fa";
@ -2031,7 +2037,7 @@ const Apprenant = (props) => {
const list_champs = ["field_detail_lieu_naissance", "field_detail_departement_naissance", "field_detail_pays_naissance", "field_type_pi", "field_num_pi",
"field_type_mobilite", "field_nationalite", "field_droit_image", "field_rgpd", "field_sitation_famille", "field_num_ss", "field_matricule", "field_ine",
"field_handicape_amenagement"]
"field_handicape_amenagement", "detail_nom_jeune_fille"]
for (let i = 0; i < list_champs.length; i++) {
if (document.getElementsByName(String(list_champs[i])) && document.getElementsByName(String(list_champs[i]))[0]) {
@ -2082,6 +2088,12 @@ const Apprenant = (props) => {
document.getElementsByName("field_detail_nom")[0].style.backgroundColor = "#FFFFFF";
}
if (document.getElementsByName("detail_nom_jeune_fille") && document.getElementsByName("field_detail_nom")[0]) {
document.getElementsByName("detail_nom_jeune_fille")[0].disabled = false;
document.getElementsByName("detail_nom_jeune_fille")[0].style.backgroundColor = "#FFFFFF";
}
if (document.getElementsByName("field_detail_prenom") && document.getElementsByName("field_detail_prenom")[0]) {
document.getElementsByName("field_detail_prenom")[0].disabled = false;
document.getElementsByName("field_detail_prenom")[0].style.backgroundColor = "#FFFFFF";
@ -2119,7 +2131,7 @@ const Apprenant = (props) => {
const list_champs = ["field_detail_lieu_naissance", "field_detail_departement_naissance", "field_detail_pays_naissance", "field_type_pi", "field_num_pi",
"field_type_mobilite", "field_nationalite", "field_droit_image", "field_rgpd", "field_sitation_famille", "field_num_ss", "field_matricule", "field_ine",
"field_handicape_amenagement"]
"field_handicape_amenagement", "detail_nom_jeune_fille"]
for (let i = 0; i < list_champs.length; i++) {
if (document.getElementsByName(String(list_champs[i])) && document.getElementsByName(String(list_champs[i]))[0]) {
@ -2349,6 +2361,13 @@ const Apprenant = (props) => {
form.append("telephone", "");
if (p_detail_nom_fille)
form.append("nom_fille", p_detail_nom_fille);
else
form.append("nom_fille", "");
if (p_detail_employeur)
form.append("employeur", p_detail_employeur);
else
@ -9781,15 +9800,15 @@ const Apprenant = (props) => {
La taille de l'image ne doit pas dépasser 1 mega octet
</li>
</div>">
<label for="files_img_class" className="bton_image_class">Charger une photo &nbsp;<FcInfo /></label><br />
<label for="files_img_class" className="bton_image_class btn-upload-photo">Charger une photo &nbsp;<FcInfo /></label><br />
</a>
{String(userimgclassprofilchanged) === "1" &&
<nav className="bton_image_class" onClick={record_apprenant_Image}>Enregistrer la photo<br /> </nav>
<nav className="bton_image_class save-photo-button btn-save-photo" onClick={record_apprenant_Image}>Enregistrer la photo<br /> </nav>
}
{String(isimgclassSelected_recid) && String(isimgclassSelected_recid).length > 3 &&
<nav className="bton_supprime_image_class" onClick={removeRecodedLogoImage}>Supprimer la photo<br /> </nav>
{String(isimgclassSelected_recid) && String(isimgclassSelected_recid).length > 3 && String(userimgclassprofilchanged) !== "1" && String(userimgclassprofil).length > 50 &&
<nav className="bton_supprime_image_class btn-delete-photo" onClick={removeRecodedLogoImage}>Supprimer la photo<br /> </nav>
}
{String(userimgclassprofilchanged) === "1" &&
<div className="koUpdateData" style={{ "color": "orange", "textAlign": "center" }}> /!\ Pensez à enregistrer la photo
@ -10074,7 +10093,7 @@ const Apprenant = (props) => {
</div>
{p_detail_civilite !== "m" && <div className="session_caract"> Nom jeune fille <br />
{p_detail_civilite !== "m" && <div className="session_caract"> Nom jeune fille <br />
<TextField
sx={{ '& legend': { display: 'none' }, '& fieldset': { top: 0 }, }}
required
@ -13360,4 +13379,95 @@ width: 100%;
border: unset;
border-radius: 10px;
}
.save-photo-button {
padding: 10px 22px;
border: none;
border-radius: 8px;
background-color: #0b8b72;
color: #ffffff;
font-family: "DM Sans", Arial, sans-serif;
font-size: 14px;
font-weight: 600;
cursor: pointer;
animation: buttonShake 3s ease-in-out infinite;
}
@keyframes buttonShake {
0%,
80%,
100% {
transform: translateX(0);
}
82% {
transform: translateX(-5px);
}
84% {
transform: translateX(5px);
}
86% {
transform: translateX(-4px);
}
88% {
transform: translateX(4px);
}
90% {
transform: translateX(-2px);
}
92% {
transform: translateX(2px);
}
94% {
transform: translateX(0);
}
}
.save-photo-button:hover {
animation-play-state: paused;
background-color: #08745f;
}
/* Action secondaire */
.btn-upload-photo {
background-color: #e8f1fb;
color: #104277;
border: 1px solid #9fc1e6;
}
/* Action principale */
.btn-save-photo {
background-color: #0b8b72;
color: #ffffff;
border: 1px solid #0b8b72;
}
/* Action destructive */
.btn-delete-photo {
background-color: #fff1f0;
color: #c0392b;
border: 1px solid #f0aaa3;
}
.btn-upload-photo:hover {
background-color: #d9e9f8;
}
.btn-save-photo:hover {
background-color: #08745f;
}
.btn-delete-photo:hover {
background-color: #fde2df;
}
`;

View File

@ -508,7 +508,7 @@ button {
padding: 18px 0 12px;
}
.workshops__header > div {
.workshops__header>div {
display: flex;
align-items: center;
gap: 10px;
@ -551,7 +551,7 @@ button {
padding: 10px 14px;
}
.workshop-row + .workshop-row {
.workshop-row+.workshop-row {
border-top: 1px solid var(--soft-border);
}
@ -632,6 +632,7 @@ button {
}
@media (max-width: 760px) {
.hero-section,
.search-panel,
.results-info,
@ -707,4 +708,97 @@ button {
.details-btn {
width: 100%;
}
}
.atelier-filter-nav {
display: flex;
align-items: center;
gap: 10px;
padding: 8px;
width: fit-content;
max-width: 100%;
overflow-x: auto;
background: #f2f6fb;
border: 1px solid #d8e3ea;
border-radius: 14px;
}
.atelier-filter-button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
min-height: 42px;
padding: 10px 16px;
border: 1px solid transparent;
border-radius: 10px;
background: transparent;
color: #526273;
font-family: "DM Sans", Arial, sans-serif;
font-size: 14px;
font-weight: 600;
white-space: nowrap;
cursor: pointer;
transition:
background-color 0.2s ease,
color 0.2s ease,
border-color 0.2s ease,
box-shadow 0.2s ease,
transform 0.2s ease;
}
.atelier-filter-button:hover {
background: #ffffff;
color: #104277;
border-color: #d8e3ea;
transform: translateY(-1px);
}
.atelier-filter-button.active {
background: #104277;
color: #ffffff;
border-color: #104277;
box-shadow:
0 4px 12px rgba(16, 66, 119, 0.25),
0 1px 3px rgba(16, 66, 119, 0.18);
}
.atelier-filter-button.active:hover {
background: #0c3764;
color: #ffffff;
border-color: #0c3764;
}
.atelier-filter-button:focus-visible {
outline: 3px solid rgba(16, 66, 119, 0.22);
outline-offset: 2px;
}
.atelier-filter-button svg {
flex-shrink: 0;
}
@media screen and (max-width: 700px) {
.atelier-filter-nav {
width: 100%;
padding: 6px;
gap: 6px;
}
.atelier-filter-button {
min-width: max-content;
padding: 9px 12px;
font-size: 13px;
}
}
}

View File

@ -12,7 +12,7 @@ import { DataGrid, GridToolbar, frFR } from '@mui/x-data-grid';
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
import 'react-tooltip/dist/react-tooltip.css'
import { Tooltip } from 'react-tooltip'
import { FcOrgUnit } from "react-icons/fc";
import excel_icone from "../mysy_img/excel_icone.png";
import { format } from 'date-fns';
import fileDownload from 'js-file-download'
@ -79,6 +79,8 @@ import * as XLSX from 'xlsx';
import Modules_Mes_Documents from "./Modules_Mes_Documents";
import Module_Alert_Confirmation from "./Module_Alert_Confirmation";
import Module_Trombinoscope from "./Module_Trombinoscope";
import { makeStyles } from "@material-ui/core/styles";
import Paper from '@material-ui/core/Paper';
import Draggable from 'react-draggable';
@ -1327,6 +1329,11 @@ const DisplayPartnerStagiaires = (props) => {
const [Getall_TrainingParticipant_result, setGetall_TrainingParticipant_result] = useState([]);
function Getall_TrainingParticipant(event) {
var bkp_trombi = display_trombinoscope;
setdisplay_trombinoscope("");
setloading_datagrid(true);
setSelectionModel([]);
@ -1369,10 +1376,12 @@ const DisplayPartnerStagiaires = (props) => {
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
//console.log(" ### Getall_TrainingParticipant form = ", form)
// var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_Statgaire_List_Partner_with_filter/";
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_Statgaire_List_Partner_with_filter_uptimized/";
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_Statgaire_List_Partner_with_filter_uptimized_With_Img/";
setLoading(true);
@ -1387,7 +1396,7 @@ const DisplayPartnerStagiaires = (props) => {
setGetall_TrainingParticipant_result(res.data.message);
setRows(res.data.message);
setdisplay_trombinoscope(bkp_trombi);
}
else {
setloading_datagrid(false);
@ -1468,12 +1477,13 @@ const DisplayPartnerStagiaires = (props) => {
setloading_datagrid(true);
var form = new FormData();
var bkp_trombi = display_trombinoscope;
setdisplay_trombinoscope("");
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_Statgaire_List_Partner_with_filter/";
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_Statgaire_List_Partner_with_filter_uptimized_With_Img/";
setLoading(true);
axios.post(myurl, form).then(res => {
@ -1485,6 +1495,8 @@ const DisplayPartnerStagiaires = (props) => {
setGetall_TrainingParticipant_api("true");
setGetall_TrainingParticipant_result(res.data.message);
setRows(res.data.message);
setdisplay_trombinoscope(bkp_trombi);
}
else {
setloading_datagrid(false);
@ -5922,14 +5934,14 @@ const DisplayPartnerStagiaires = (props) => {
//myRef_head.current.scrollIntoView({ behavior: "smooth" });
if (document.getElementById('myRef_head')) {
// myRef.current.scrollIntoView({ behavior: "smooth" });
var divh = document.getElementById('myRef_head').offsetTop;
window.scrollTo({
top: divh,
behavior: "smooth",
});
}
/* if (document.getElementById('myRef_head')) {
// myRef.current.scrollIntoView({ behavior: "smooth" });
var divh = document.getElementById('myRef_head').offsetTop;
window.scrollTo({
top: divh,
behavior: "smooth",
});
}*/
}
else {
@ -10176,6 +10188,8 @@ const DisplayPartnerStagiaires = (props) => {
}
const [display_trombinoscope, setdisplay_trombinoscope] = useState("");
return (
<div className="displaypartnerstagiaire">
{isLoading && <div className="loader-container">
@ -12663,6 +12677,7 @@ const DisplayPartnerStagiaires = (props) => {
value={New_Option_Filter.filter((data) => (data).value === String(p_filtre1))[0].label}
options={New_Option_Filter}
onChange={(event, value) => {
setp_filtre1_value("");
if (value && value.value) {
setp_filtre1(value.value);
}
@ -13309,13 +13324,57 @@ const DisplayPartnerStagiaires = (props) => {
</div>
</div>
<div style={{ textAlign: "right", "width": '100%', 'float': 'left' }}>
<nav style={{ width: '50%', float: 'left' }}> &nbsp; </nav>
<nav style={{ width: '25%', float: 'left' }}>
&nbsp;
</nav>
{String(display_trombinoscope) !== "1" && <nav style={{ width: '100%', float: 'right', textAlign: "right", marginTop: "10px", paddingRight: '10px' }}>
<nav className="mode_affichage" onClick={(e) => {
setdisplay_trombinoscope("1")
}}> <FcOrgUnit /> Trombinoscope </nav>
<nav className="mode_affichage mode_affichage_selected" onClick={(e) => {
setdisplay_trombinoscope("")
}}> <CiBoxList /> Liste </nav>
Affichage : &nbsp;&nbsp;
</nav>}
{String(display_trombinoscope) === "1" && <nav style={{ width: '100%', float: 'right', textAlign: "right", marginTop: "10px", paddingRight: '10px' }}>
<nav className="mode_affichage mode_affichage_selected" onClick={(e) => {
setdisplay_trombinoscope("1")
}}> <FcOrgUnit /> Trombinoscope </nav>
<nav className="mode_affichage " onClick={(e) => {
setdisplay_trombinoscope("")
}}> <CiBoxList /> Liste </nav>
Affichage : &nbsp;&nbsp;
</nav>}
</div>
<div style={{ "textAlign": "left", "float": "left", "width": "100%", "paddingRight": "10px" }} id="participant_menu_tab">
<div className="session_data">
{String(display_trombinoscope) !== "1" && <div className="session_data">
<div style={{ textAlign: "right", "width": '100%', 'float': 'left' }}>
<nav style={{ width: '50%', float: 'left' }}> &nbsp; </nav>
<nav style={{ width: '50%', float: 'left' }}>
<nav style={{ width: '50%', float: 'left' }}> &nbsp; </nav>
<nav style={{ width: '25%', float: 'left' }}>
&nbsp;
</nav>
<nav style={{ width: '25%', float: 'left' }}>
<FormGroup style={{ float: 'right' }}>
<FormControlLabel control={<Checkbox
checked={display_stagiaire_with_alert}
@ -13325,6 +13384,8 @@ const DisplayPartnerStagiaires = (props) => {
/>} label="Alerte" style={{ color: 'red', fontSize: "10px", fontStyle: 'italic' }} />
</FormGroup>
</nav>
</div>
@ -13457,6 +13518,9 @@ const DisplayPartnerStagiaires = (props) => {
archive: JSON.parse(item).archive,
is_ftion_initiale: JSON.parse(item).is_ftion_initiale,
}
))}
@ -14005,9 +14069,9 @@ const DisplayPartnerStagiaires = (props) => {
</div>
</div>
</div>}
<div className="div_row" style={{ "border": "None" }}>
{String(display_trombinoscope) !== "1" && <div className="div_row" style={{ "border": "None" }}>
{String(props.check_user_acces_right("stagiaire", "write")) === "1" && <div className="div_row_gauche div_row_gauche_etendu" style={{ "textAlign": "left", "paddingLeft": "5px" }}>
@ -14039,8 +14103,16 @@ const DisplayPartnerStagiaires = (props) => {
<a href='/sample/template_import_stagiaires.csv' download>Télécharger un fichier modèle</a>
</div>}
</div>
</div>}
<div className="div_row" ref={myRef_details} id="myRef_details"> &nbsp;</div>
{String(display_trombinoscope) === "1" &&
<Module_Trombinoscope inscrit={rowss} />
}
{selected_id && String(selected_id).length > 0 && <div className="div_row">
<nav style={{ textAlign: 'center', padding: '10px', fontFamily: 'DM Sans' }}> <b>{p_detail_prenom} </b> &nbsp;
<b>{String(p_detail_nom)}</b>- Email <b>{String(p_detail_mail)} </b>- Session <b> {String(p_detail_session_class)} </b>- Ftion <b> {String(selected_class_title)} </b>
@ -15058,18 +15130,18 @@ const DisplayPartnerStagiaires = (props) => {
<img class="img_class_logo" src={userimgclassprofil} style={{ width: '100%' }} /><br />
</div>
<div className="div_row_droite_image">
<div className="div_row_droite_image" style={{ width: '100%' }}>
<input type="file" id="files_img_class" accept="image/*" onChange={imglogoclasschangeHandler} style={{ opacity: "0", zIndex: "-1", maxWidth: "5px", maxHeight: "0px" }} /><br />
<nav style={{ width: '100%' }}>
<label for="files_img_class" className="bton_image_class" style={{ width: '100%' }}>Charger une photo</label><br />
<label for="files_img_class" className="bton_image_class btn-upload-photo" style={{ width: '100%' }}>Charger une photo</label><br />
{String(userimgclassprofilchanged) === "1" &&
<nav className="bton_image_class" onClick={record_Stagiaire_Image} style={{ width: '100%' }}>Enregistrer la photo<br /> </nav>
<nav className="bton_image_class save-photo-button btn-save-photo" onClick={record_Stagiaire_Image} style={{ width: '100%' }}>Enregistrer la photo<br /> </nav>
}
{String(isimgclassSelected_recid) && String(isimgclassSelected_recid).length > 3 &&
<nav className="bton_supprime_image_class" onClick={removeRecodedLogoImage} style={{ width: '100%' }}>Supprimer la photo<br /> </nav>
{String(userimgclassprofil) && String(userimgclassprofil).length > 3 && String(userimgclassprofilchanged) !== "1" && String(userimgclassprofil).length > 50 &&
<nav className="bton_supprime_image_class btn-delete-photo" onClick={removeRecodedLogoImage} style={{ width: '100%' }}>Supprimer la photo<br /> </nav>
}
{String(userimgclassprofilchanged) === "1" &&
<div className="koUpdateData" style={{ "color": "orange", "textAlign": "center" }}> /!\ Pensez à enregistrer la photo
@ -18545,5 +18617,97 @@ width: 12% !important;
font-family: "Dm Sans", system-ui, sans-serif;
font-size: small !important;
}
.save-photo-button {
padding: 10px 22px;
border: none;
border-radius: 8px;
background-color: #0b8b72;
color: #ffffff;
font-family: "DM Sans", Arial, sans-serif;
font-size: 14px;
font-weight: 600;
cursor: pointer;
animation: buttonShake 3s ease-in-out infinite;
}
@keyframes buttonShake {
0%,
80%,
100% {
transform: translateX(0);
}
82% {
transform: translateX(-5px);
}
84% {
transform: translateX(5px);
}
86% {
transform: translateX(-4px);
}
88% {
transform: translateX(4px);
}
90% {
transform: translateX(-2px);
}
92% {
transform: translateX(2px);
}
94% {
transform: translateX(0);
}
}
.save-photo-button:hover {
animation-play-state: paused;
background-color: #08745f;
}
/* Action secondaire */
.btn-upload-photo {
background-color: #e8f1fb;
color: #104277;
border: 1px solid #9fc1e6;
}
/* Action principale */
.btn-save-photo {
background-color: #0b8b72;
color: #ffffff;
border: 1px solid #0b8b72;
}
/* Action destructive */
.btn-delete-photo {
background-color: #fff1f0;
color: #c0392b;
border: 1px solid #f0aaa3;
}
.btn-upload-photo:hover {
background-color: #d9e9f8;
}
.btn-save-photo:hover {
background-color: #08745f;
}
.btn-delete-photo:hover {
background-color: #fde2df;
}
`;

File diff suppressed because it is too large Load Diff

View File

@ -71,6 +71,7 @@ import Paper from '@material-ui/core/Paper';
import Draggable from 'react-draggable';
import { IconButton } from '@material-ui/core';
import Module_RH_Tutorat from "./Module_RH_Tutorat";
import { Stroller } from "@mui/icons-material";
function PaperComponent(props) {
return (
@ -10996,14 +10997,14 @@ const Employes = (props) => {
<nav style={{ width: '100%' }}>
<label for="files_img_class" className="bton_image_class" style={{ width: '100%' }}>Charger une photo</label><br />
<label for="files_img_class" className="bton_image_class btn-upload-photo" style={{ width: '100%' }}>Charger une photo</label><br />
{String(userimgclassprofilchanged) === "1" &&
<nav className="bton_image_class" onClick={record_employee_Image} style={{ width: '100%' }}>Enregistrer la photo<br /> </nav>
<nav className="bton_image_class save-photo-button btn-save-photo" onClick={record_employee_Image} style={{ width: '100%' }}>Enregistrer la photo<br /> </nav>
}
{String(isimgclassSelected_recid) && String(isimgclassSelected_recid).length > 3 &&
<nav className="bton_supprime_image_class" onClick={removeRecodedLogoImage} style={{ width: '100%' }}>Supprimer la photo<br /> </nav>
{String(isimgclassSelected_recid) && String(isimgclassSelected_recid).length > 3 && String(userimgclassprofilchanged) !== "1" && String(userimgclassprofil).length > 50 &&
<nav className="bton_supprime_image_class btn-delete-photo" onClick={removeRecodedLogoImage} style={{ width: '100%' }}>Supprimer la photo<br /> </nav>
}
{String(userimgclassprofilchanged) === "1" &&
<div className="koUpdateData" style={{ "color": "orange", "textAlign": "center" }}> /!\ Pensez à enregistrer la photo
@ -15878,4 +15879,97 @@ width: 100%;
.react-datepicker-wrapper{
width: 100%;
}
.save-photo-button {
padding: 10px 22px;
border: none;
border-radius: 8px;
background-color: #0b8b72;
color: #ffffff;
font-family: "DM Sans", Arial, sans-serif;
font-size: 14px;
font-weight: 600;
cursor: pointer;
animation: buttonShake 3s ease-in-out infinite;
}
@keyframes buttonShake {
0%,
80%,
100% {
transform: translateX(0);
}
82% {
transform: translateX(-5px);
}
84% {
transform: translateX(5px);
}
86% {
transform: translateX(-4px);
}
88% {
transform: translateX(4px);
}
90% {
transform: translateX(-2px);
}
92% {
transform: translateX(2px);
}
94% {
transform: translateX(0);
}
}
.save-photo-button:hover {
animation-play-state: paused;
background-color: #08745f;
}
/* Action secondaire */
.btn-upload-photo {
background-color: #e8f1fb;
color: #104277;
border: 1px solid #9fc1e6;
}
/* Action principale */
.btn-save-photo {
background-color: #0b8b72;
color: #ffffff;
border: 1px solid #0b8b72;
}
/* Action destructive */
.btn-delete-photo {
background-color: #fff1f0;
color: #c0392b;
border: 1px solid #f0aaa3;
}
.btn-upload-photo:hover {
background-color: #d9e9f8;
}
.btn-save-photo:hover {
background-color: #08745f;
}
.btn-delete-photo:hover {
background-color: #fde2df;
}
`;

View File

@ -404,14 +404,17 @@ function Inscription_Information(props) {
var text_label = "";
if (String(local_session_ondemande) === "1") {
text_label = "A la demande (" + String(local_code_session).substring(0, 15) + ")";
if (String(local_session_ondemande) === "1" && String(local_titre).length > 2) {
text_label = "A la demande (" + String(local_titre).substring(0, 50) + ")";
}
else if (String(local_session_ondemande) === "1" && String(local_code_session).length > 2) {
text_label = "A la demande (" + String(local_code_session).substring(0, 50) + ")";
}
else {
if (local_date_debut == local_date_fin) {
text_label = "Le " + local_date_debut
text_label = "Le " + local_date_debut + " "+String(local_titre).substring(0, 50)
} else {
text_label = local_date_debut + " au " + local_date_fin
text_label = local_date_debut + " au " + local_date_fin + " "+String(local_titre).substring(0, 50)
}
}
@ -1211,7 +1214,7 @@ function Inscription_Information(props) {
{props.selected_session_id && String(props.selected_session_id).length > 3 &&
New_GetCurrentClass_result && New_GetCurrentClass_result.length > 0 &&
<div style={{ width: '100%', textAlign: 'center', fontFamily:'DM Sans', color: '#3E6EE3' }}>
<div style={{ width: '100%', textAlign: 'center', fontFamily: 'DM Sans', color: '#3E6EE3' }}>
{New_GetCurrentClass_result.filter((data) => (data)._id === String(props.selected_session_id))[0].label}
</div>}
@ -1378,8 +1381,8 @@ function Inscription_Information(props) {
{mysession &&
<Box alignItems="left" sx={{ '& > :not(style)': { m: 1 }, width: '100%', }}>
&nbsp;
{props.mytrainingdirectinscription !== "1" && <>
<div style={{ "width": "10%" }}> &nbsp; </div>

View File

@ -481,7 +481,7 @@ const Formation_Partner_Catalog_Special_JMJFormation = (props) => {
);
} else {
window.open(
"/Display-Partner-Catalog-Detail-formation/" + props.formation.internal_url,
"/Display-Partner-Catalog-Detail-formation_Vp/" + props.formation.internal_url,
'_blank'
);
}

View File

@ -4255,7 +4255,7 @@ const Jmjformation_Catalogue_Public = (props) => {
</div>
<div style={{ width: '100%', background: '#f3f4fb', paddingTop: "2rem" }}>
<div className="jmj_block_milieu">
<div className="jmj_block_milieu_gauche">
<div className="jmj_block_milieu_gauche">
{showelement === "true" && <div className="rech_leftbox" >
<div className="sous_filter">
@ -4288,7 +4288,7 @@ const Jmjformation_Catalogue_Public = (props) => {
</div>}
</div>
</div>
</div>
<div className="filter_valeur" onChange={TrainingCertifHandle}>

View File

@ -2262,7 +2262,7 @@
.jmj_banniere_mobile {}
.mobile_block_nos_formation{
.mobile_block_nos_formation {
font-weight: 600;
font-size: 35px;
text-align: center;
@ -8429,7 +8429,12 @@
gap: 15px;
width: 100%;
flex-wrap: wrap;
justify-content: left;
justify-content: center;
/* Centrage horizontal */
align-items: center;
/* Centrage vertical */
}
@ -11533,7 +11538,12 @@
gap: 20px;
width: 100%;
flex-wrap: wrap;
justify-content: left;
justify-content: center;
/* Centrage horizontal */
align-items: center;
/* Centrage vertical */
}
@ -14669,7 +14679,11 @@
gap: 24px;
width: 100%;
flex-wrap: wrap;
justify-content: left;
justify-content: center;
/* Centrage horizontal */
align-items: center;
/* Centrage vertical */
}

View File

@ -1,4 +1,4 @@
import React, { useMemo, useState, useEffect } from "react";
import React, { useMemo, useState, useEffect, useRef, } from "react";
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
@ -11,6 +11,7 @@ import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
import axios from "axios";
import { Editor } from '@tinymce/tinymce-react';
import {
Bell,
BookOpen,
@ -30,7 +31,13 @@ import {
Star,
Tag,
UsersRound,
LayoutGrid,
CalendarRange,
ListFilter
} from "lucide-react";
import TextareaAutosize from '@mui/material/TextareaAutosize';
import "./AteliersCatalogue.css";
import CancelPresentationIcon from '@mui/icons-material/CancelPresentation';
@ -39,6 +46,8 @@ import Paper from '@material-ui/core/Paper';
import Draggable from 'react-draggable';
import { IconButton } from '@material-ui/core';
import img_met_autre from "../mysy_img/met_autre.jpg";
function PaperComponent(props) {
return (
<Draggable
@ -239,117 +248,7 @@ function ModeIcon({ mode }) {
return <Building2 size={20} />;
}
function FormationCard_orig({ formation }) {
return (
<article className="module_atelier_catalogue formation-card">
<div className="formation-card__main">
<div className="formation-card__image-wrap">
<img src={formation.image} alt="" className="formation-card__image" />
<button className="favorite-btn" aria-label="Ajouter aux favoris">
<Heart size={18} />
</button>
</div>
<div>
<div className="formation-copy">
<h2>{formation.title}</h2>
<p>{formation.description}</p>
</div>
</div>
<aside className="formation-card__meta">
<div className="meta-list">
<div className="meta-item">
<UsersRound size={18} />
<div>
<span>Public</span>
<strong>{formation.audience}</strong>
</div>
</div>
<div className="meta-item">
<Clock3 size={18} />
<div>
<span>Durée</span>
<strong>{formation.duration}</strong>
</div>
</div>
{formation.price && <div className="meta-item">
<Tag size={18} />
<div>
<span>Prix</span>
<strong className={formation.price === "Gratuit" ? "price-free" : "price"}>
{formation.price}
</strong>
</div>
</div>}
</div>
</aside>
</div>
<div className="module_atelier_catalogue workshops">
<div className="workshops__header">
<div>
<strong>Ateliers disponibles</strong>
<span>{formation.ateliers.length}</span>
</div>
<button className="program-btn">
Voir le programme <ChevronRight size={16} />
</button>
</div>
<div className="module_atelier_catalogue workshops__list">
{formation.ateliers.map((atelier) => (
<div className="workshop-row" key={atelier.code}>
<div className="workshop-cell workshop-code">
<strong>{atelier.code}</strong>
<span>Code session</span>
</div>
<div className="workshop-cell">
<CalendarDays size={20} />
<div>
<strong>{atelier.date}</strong>
<span>{atelier.time}</span>
</div>
</div>
<div className="workshop-cell">
<ModeIcon mode={atelier.mode} />
<div>
<strong>{atelier.mode}</strong>
<span>Mode</span>
</div>
</div>
<div className="workshop-cell">
<MapPin size={20} />
<div>
<strong>{atelier.city}</strong>
<span>{atelier.zip || "Classe virtuelle"}</span>
</div>
</div>
<div className="workshop-cell workshop-places">
<UsersRound size={20} />
<div>
<strong>{atelier.places} places</strong>
<span>disponibles</span>
</div>
</div>
<button className="details-btn">{atelier.cta}</button>
</div>
))}
</div>
</div>
</article>
);
}
export default function Module_Atelier_Catalogue(props) {
@ -358,6 +257,7 @@ export default function Module_Atelier_Catalogue(props) {
const classes = useStyles();
const totalAteliers = useMemo(
() => formations.reduce((acc, formation) => acc + formation.ateliers.length, 0),
[]
@ -369,7 +269,11 @@ export default function Module_Atelier_Catalogue(props) {
<div className="formation-card__main">
<div className="formation-card__image-wrap">
{formation.class_img && String(formation.class_img).length > 50 && <img src={"data:image/png;base64," + `${formation.class_img}`} alt="" className="formation-card__image" />}
{formation.class_img && String(formation.class_img).length > 50 &&
<img src={"data:image/png;base64," + `${formation.class_img}`} alt="" className="formation-card__image" />}
{(!formation.class_img || String(formation.class_img).length <= 50) &&
<img src={img_met_autre} alt="" className="formation-card__image" />}
<button className="favorite-btn" aria-label="Ajouter aux favoris">
<Heart size={18} />
</button>
@ -380,7 +284,11 @@ export default function Module_Atelier_Catalogue(props) {
<div className="formation-copy">
<h2>{formation.title}</h2>
<p>{formation.description}</p>
<p>
{formation.description.length > 150 && String(formation.description).substring(0, 150) + "..."}
{formation.description.length <= 150 && String(formation.description).substring(0, 150)}
</p>
</div>
@ -403,11 +311,11 @@ export default function Module_Atelier_Catalogue(props) {
<strong>{formation.duration} {formation.duration_unit}(s) </strong>
</div>
</div>
{formation.price && <div className="meta-item">
{String(formation.price) !== "0" && <div className="meta-item">
<Tag size={18} />
<div>
<span>Prix</span>
<strong className={formation.price === "Gratuit" ? "price-free" : "price"}>
<strong className="price">
{formation.price}
</strong>
</div>
@ -416,7 +324,7 @@ export default function Module_Atelier_Catalogue(props) {
</aside>
</div>
{formation && formation.external_code && <div style={{ width: '100%' }}> external_code = {formation.external_code} </div>}
{/*formation && formation.external_code && <div style={{ width: '100%' }}> external_code = {formation.external_code} </div>*/}
{formation && formation.tab_session && <div className="module_atelier_catalogue workshops">
@ -425,7 +333,12 @@ export default function Module_Atelier_Catalogue(props) {
<strong>Ateliers disponibles</strong>
<span>{formation.tab_session.length}</span>
</div>
<button className="program-btn">
<button className="program-btn" onClick={(event) => {
setselected_session_programme(formation.programme);
setDialogProgramme_Display_open(true);
}}>
Voir le programme <ChevronRight size={16} />
</button>
</div>
@ -434,15 +347,15 @@ export default function Module_Atelier_Catalogue(props) {
{formation.tab_session.map((atelier) => (
<div className="workshop-row" key={atelier.code_session}>
<div className="workshop-cell workshop-code">
<strong>{atelier.code_session}</strong>
<span>Code </span>
<strong>{atelier.titre}</strong>
</div>
<div className="workshop-cell">
<CalendarDays size={20} />
<div>
<strong>{atelier.date_debut}</strong>
<span>{formation.duration}</span>
<span>{formation.duration} {String(formation.duration_unit).toLowerCase().substring(0, 1)}</span>
</div>
</div>
@ -478,10 +391,21 @@ export default function Module_Atelier_Catalogue(props) {
init_inscrit_info();
setselected_session_id(atelier._id);
setselected_session_code(atelier.code_session);
setselected_session_titre(atelier.titre)
setselected_class_id(formation._id);
setselected_class_internal_url(formation.internal_url);
setselected_class_price(formation.price);
setselected_class_inscription_direct(atelier.class_inscription_direct);
setselected_session_programme(formation.programme);
setselected_session_date_du(atelier.date_debut);
setselected_session_date_au(atelier.date_fin);
setselected_session_mode_animation(atelier.mode_animation);
setselected_session_ville(atelier.ville);
setselected_session_cp(atelier.code_postal);
setselected_session_adresse(atelier.adresse);
}}>Inscription</button>
</div>
@ -523,10 +447,23 @@ export default function Module_Atelier_Catalogue(props) {
const [selected_class_id, setselected_class_id] = useState("");
const [selected_class_internal_url, setselected_class_internal_url] = useState("");
const [selected_class_price, setselected_class_price] = useState("");
const [selected_class_inscription_direct, setselected_class_inscription_direct] = useState("");
const [selected_session_date_du, setselected_session_date_du] = useState("");
const [selected_session_date_au, setselected_session_date_au] = useState("");
const [selected_session_mode_animation, setselected_session_mode_animation] = useState("");
const [selected_session_ville, setselected_session_ville] = useState("");
const [selected_session_cp, setselected_session_cp] = useState("");
const [selected_session_adresse, setselected_session_adresse] = useState("");
const [selected_session_programme, setselected_session_programme] = useState("");
const [selected_session_id, setselected_session_id] = useState("");
const [selected_session_code, setselected_session_code] = useState("");
const [selected_session_titre, setselected_session_titre] = useState("");
const [inscrit_civilite, setinscrit_civilite] = useState("");
const [inscrit_nom, setinscrit_nom] = useState("");
const [inscrit_prenom, setinscrit_prenom] = useState("");
@ -536,10 +473,25 @@ export default function Module_Atelier_Catalogue(props) {
function init_inscrit_info() {
setselected_session_id("");
setselected_session_code("");
setselected_session_titre("");
setinscrit_nom("");
setinscrit_prenom("");
setinscrit_telephone("");
setinscrit_email("");
setselected_session_date_du("");
setselected_session_date_au("");
setselected_session_mode_animation("");
setselected_session_ville("");
setselected_session_cp("");
setselected_session_adresse("");
setselected_session_programme("");
setselected_class_inscription_direct("");
setselected_class_price("");
setselected_class_internal_url("");
setselected_class_id("");
}
@ -743,6 +695,149 @@ export default function Module_Atelier_Catalogue(props) {
}
const [atelier_selected_filter, setatelier_selected_filter] = useState("");
const [active_filtre, setactive_filtre] = useState("");
const [Atelier_Filtre_Selectionne, setAtelier_Filtre_Selectionne] = useState([]);
function afficher_ateliers_par_periode(typeFiltre = "encours") {
const maintenant = new Date();
// Premier jour du mois en cours
const dateDebutPeriode = new Date(
maintenant.getFullYear(),
maintenant.getMonth(),
1
);
let dateFinPeriode;
if (typeFiltre === "3mois") {
// Dernier jour du troisième mois :
// mois en cours + les deux mois suivants
dateFinPeriode = new Date(
maintenant.getFullYear(),
maintenant.getMonth() + 3,
0,
23,
59,
59,
999
);
} else {
// Dernier jour du mois en cours
dateFinPeriode = new Date(
maintenant.getFullYear(),
maintenant.getMonth() + 1,
0,
23,
59,
59,
999
);
}
const resultats = (props.formations || [])
// Conversion des chaînes JSON en objets JavaScript
.map((element) => {
try {
return typeof element === "string"
? JSON.parse(element)
: element;
} catch (error) {
console.error("JSON invalide :", error);
return null;
}
})
// Suppression des éléments invalides
.filter(Boolean)
// Filtrage des sessions de chaque formation
.map((formation) => {
const sessionsFiltrees = Array.isArray(formation.tab_session)
? formation.tab_session.filter((session) => {
if (!session?.date_debut) return false;
/*
* Compatible avec :
* 12/07/2026
* 12/07/2026 09:30
*/
const dateSansHeure = session.date_debut
.trim()
.split(" ")[0];
const [jour, mois, annee] = dateSansHeure
.split("/")
.map(Number);
if (!jour || !mois || !annee) {
return false;
}
const dateDebutSession = new Date(
annee,
mois - 1,
jour
);
// Vérifie également que la date créée correspond bien
// aux valeurs reçues
const dateValide =
!Number.isNaN(dateDebutSession.getTime()) &&
dateDebutSession.getDate() === jour &&
dateDebutSession.getMonth() === mois - 1 &&
dateDebutSession.getFullYear() === annee;
return (
dateValide &&
dateDebutSession >= dateDebutPeriode &&
dateDebutSession <= dateFinPeriode
);
})
: [];
return {
...formation,
tab_session: sessionsFiltrees,
};
})
// Ne garder que les formations qui possèdent une session
// dans la période sélectionnée
.filter((formation) => formation.tab_session.length > 0);
setAtelier_Filtre_Selectionne(resultats);
setatelier_selected_filter("1");
setactive_filtre(typeFiltre);
console.log(" ### resultats = ", resultats)
}
const [DialogProgramme_Display_message, setDialogProgramme_Display_message] = React.useState(false);
const [DialogProgramme_Display_open, setDialogProgramme_Display_open] = React.useState(false);
function DialogProgramme_Display_handle_change_participant_session(message) {
setDialogProgramme_Display_message(message);
setDialogProgramme_Display_open(true);
}
const DialogProgramme_Display_handleClose_buton = () => {
setDialogProgramme_Display_open(false);
};
const editorRef_programme = useRef(null);
const [editorRef_programme_limite, seteditorRef_programme] = useState(5000);
return (
<div className="module_atelier_catalogue" >
{/*** Affichage des messages d'alerte*/}
@ -757,6 +852,93 @@ export default function Module_Atelier_Catalogue(props) {
{/*** FIN Affichage des messages d'alerte*/}
{/*** Dialog pour Afficher le programme */}
<Dialog
open={DialogProgramme_Display_open}
//onClose={DialogProgramme_Display_handleClose}
className="displaypartnersession"
static
onClose={() => null}
PaperProps={{
className: classes.paper, // Apply the paper style
style: {
overflowY: 'unset',
position: 'absolute',
top: '20rem',
margin: "2px",
height: '40rem',
width: '50rem',
maxWidth: 'unset'
},
}}
hideBackdrop={true}
disableScrollLock
classes={{
paper: classes.dialog
}}
PaperComponent={PaperComponent}
aria-labelledby="draggable-dialog-title"
>
<DialogTitle style={{ cursor: 'move', fontFamily: "DM Sans", background: "#f3f4fb", height: '5rem' }} id="draggable-dialog-title" >
Le programme
</DialogTitle>
<DialogContent >
<Editor
onInit={(evt, editor) => editorRef_programme.current = editor}
initialValue={selected_session_programme}
disabled={true}
init={{
resize: false,
height: 500,
menubar: true,
content_style: 'body { font-family:DM Sans,sans-serif; font-size:14px; }'
}}
/>
</DialogContent>
<DialogActions>
<IconButton
autoFocus
onClick={DialogProgramme_Display_handleClose_buton}
color="primary"
className={classes.customizedButton}
>
<CancelPresentationIcon />
</IconButton>
<div className="div_row">
<div className="div_row_gauche">
&nbsp;
</div>
<div className="div_row_droite" style={{ "textAlign": 'center' }}>
<Button onClick={DialogProgramme_Display_handleClose_buton} className="bton_annule_dialog" >Fermer</Button>
</div>
</div>
</DialogActions>
</Dialog>
{/*** Fin Dialog pour Afficher le programme */}
{/*** Dialog pour reinscrire un apprenant à une session */}
@ -774,6 +956,7 @@ export default function Module_Atelier_Catalogue(props) {
position: 'absolute',
top: '20rem',
margin: "2px",
height: '35rem',
},
}}
hideBackdrop={true}
@ -786,10 +969,28 @@ export default function Module_Atelier_Catalogue(props) {
aria-labelledby="draggable-dialog-title"
>
<DialogTitle style={{ cursor: 'move', fontFamily: "DM Sans" }} id="draggable-dialog-title" > Inscription Atelier : {selected_session_code} - {selected_session_id} </DialogTitle>
<DialogTitle style={{ cursor: 'move', fontFamily: "DM Sans", background: "#f3f4fb", height: '5rem' }} id="draggable-dialog-title" >
{selected_session_mode_animation !== "0" && selected_session_mode_animation !== "1" && selected_session_mode_animation !== "2" &&
<font> Atelier : {selected_session_titre} </font>}
{selected_session_mode_animation === "0" &&
<font> Atelier : {selected_session_titre} - Présentiel </font>}
{selected_session_mode_animation === "1" &&
<font> Atelier : {selected_session_titre} - Distanciel </font>}
{selected_session_mode_animation === "2" &&
<font> Atelier : {selected_session_titre} - Hybride </font>}
</DialogTitle>
<DialogContent className="DialogContent_width">
<div className="session_caract"> <b> Civilité </b><br />
<div style={{ textAlign: 'left', minHeight: '6rem' }}> <b> Civilité </b><br />
<Autocomplete
disablePortal
name="event_dialog_civilite"
@ -830,7 +1031,7 @@ export default function Module_Atelier_Catalogue(props) {
</div>
<div style={{ width: "100%", float: 'left' }}>
<div style={{ width: "100%", float: 'left', minHeight: '6rem' }}>
<div className="session_caract_Dialog" style={{ width: "50%", float: 'left' }}> <b> Nom </b> <br />
<TextField
@ -869,7 +1070,7 @@ export default function Module_Atelier_Catalogue(props) {
</div>
<div style={{ width: "100%", float: 'left' }}>
<div style={{ width: "100%", float: 'left', minHeight: '6rem' }}>
<div className="session_caract_Dialog" style={{ width: "50%", float: 'left' }}> <b> Téléphone </b> <br />
<TextField
@ -908,6 +1109,19 @@ export default function Module_Atelier_Catalogue(props) {
</div>
{(selected_session_mode_animation === "0" || selected_session_mode_animation === "2") &&
<div style={{ width: "100%", float: 'left', minHeight: '6rem' }}>
<div className="session_caract_Dialog" style={{ width: "100%", float: 'left' }}> <b> Adresse </b> <br />
</div>
<div style={{ width: "100%", float: 'left', minHeight: '3rem', textAlign: 'left' }}>
{selected_session_adresse} - {selected_session_cp} - {selected_session_ville}
</div>
</div>}
</DialogContent>
@ -925,7 +1139,8 @@ export default function Module_Atelier_Catalogue(props) {
<div className="div_row">
<div className="div_row_gauche">
<Button onClick={RecordData} className="bton_enreg_dialog"> Inscrire</Button>
{String(selected_class_inscription_direct) === "1" && <Button onClick={RecordData} className="bton_enreg_dialog"> S'inscrire</Button>}
{String(selected_class_inscription_direct) !== "1" && <Button onClick={RecordData} className="bton_enreg_dialog"> Se préinscrire</Button>}
</div>
<div className="div_row_droite" style={{ "textAlign": 'center' }}>
<Button onClick={Dialog_add_inscription_handleClose_buton} className="bton_annule_dialog" >Fermer</Button>
@ -945,29 +1160,49 @@ export default function Module_Atelier_Catalogue(props) {
<main className="catalogue-page">
<header className="topbar">
<div className="brand">
<span>my</span>SY
</div>
<nav className="nav-links" aria-label="Navigation principale">
<a href="#" className="nav-link">
<Home size={18} /> Accueil
</a>
<a href="#" className="nav-link nav-link--active">
<BookOpen size={18} /> Catalogue
</a>
<a href="#" className="nav-link">
<Laptop size={18} /> Mes formations
</a>
<a href="#" className="nav-link">
<CalendarDays size={18} /> Mes inscriptions
</a>
<a href="#" className="nav-link">
<Heart size={18} /> Favoris
</a>
<nav className="atelier-filter-nav" aria-label="Filtres des ateliers">
<button
type="button"
className={`atelier-filter-button ${active_filtre === "" ? "active" : ""
}`}
onClick={() => {
setatelier_selected_filter("");
setactive_filtre("");
setAtelier_Filtre_Selectionne(props.formations);
}}
>
<Home size={18} />
<span>Tous</span>
</button>
<button
type="button"
className={`atelier-filter-button ${active_filtre === "encours" ? "active" : ""
}`}
onClick={() => afficher_ateliers_par_periode("encours")}
>
<CalendarDays size={18} />
<span>Mois en cours</span>
</button>
<button
type="button"
className={`atelier-filter-button ${active_filtre === "3mois" ? "active" : ""
}`}
onClick={() => afficher_ateliers_par_periode("3mois")}
>
<BookOpen size={18} />
<span>3 prochains mois</span>
</button>
</nav>
<div className="user-actions">
{/*<div className="user-actions">
<button className="notification-btn" aria-label="Notifications">
<Bell size={19} />
<span>2</span>
@ -975,10 +1210,10 @@ export default function Module_Atelier_Catalogue(props) {
<button className="avatar-btn">
AL <ChevronDown size={14} />
</button>
</div>
</div>*/}
</header>
<section className="hero-section">
{/*<section className="hero-section">
<div>
<h1>Nos ateliers</h1>
<p>Trouvez la formation qui vous correspond et inscrivez-vous à latelier de votre choix.</p>
@ -998,9 +1233,9 @@ export default function Module_Atelier_Catalogue(props) {
Les ateliers
</button>
</div>
</section>
</section>*/}
<section className="search-panel" aria-label="Recherche et filtres">
{/*<section className="search-panel" aria-label="Recherche et filtres">
<div className="search-row">
<label className="search-input">
<Search size={22} />
@ -1014,7 +1249,7 @@ export default function Module_Atelier_Catalogue(props) {
</button>
</div>
<div className="filter-row">
{/*<div className="filter-row">
<div className="filter-chips">
{filters.map((filter) => (
<button className="filter-chip" key={filter.label}>
@ -1025,25 +1260,37 @@ export default function Module_Atelier_Catalogue(props) {
</div>
<button className="reset-btn">Réinitialiser</button>
</div>
</section>
</div>* /}
</section>*/}
<div className="results-info">
{/*<div className="results-info">
<strong>{props.formations.length}</strong> formations · <strong>{totalAteliers}</strong> ateliers ouverts
</div>
</div>*/}
<section className="formation-list">
{atelier_selected_filter !== "1" && <section className="formation-list">
{props.formations.map((formation) => (
<>
{formation.external_code && <nav> TAILLL = {JSON.parse(formation).external_code}</nav>}
<FormationCard formation={JSON.parse(formation)} key={JSON.parse(formation)._id} />
</>
))}
</section>}
{atelier_selected_filter === "1" && <section className="formation-list">
{Atelier_Filtre_Selectionne.map((formation) => (
<>
<FormationCard formation={(formation)} key={(formation)._id} />
</>
))}
</section>
</section>}
</main>
<style>{local_css}</style>
</div>
@ -1061,4 +1308,98 @@ const local_css = `
text-align: justify;
}
.atelier-filter-nav {
display: flex;
align-items: center;
gap: 10px;
padding: 8px;
width: fit-content;
max-width: 100%;
overflow-x: auto;
background: #f2f6fb;
border: 1px solid #d8e3ea;
border-radius: 14px;
}
.atelier-filter-button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
min-height: 42px;
padding: 10px 16px;
border: 1px solid transparent;
border-radius: 10px;
background: transparent;
color: #526273;
font-family: "DM Sans", Arial, sans-serif;
font-size: 14px;
font-weight: 600;
white-space: nowrap;
cursor: pointer;
transition:
background-color 0.2s ease,
color 0.2s ease,
border-color 0.2s ease,
box-shadow 0.2s ease,
transform 0.2s ease;
}
.atelier-filter-button:hover {
background: #ffffff;
color: #104277;
border-color: #d8e3ea;
transform: translateY(-1px);
}
.atelier-filter-button.active {
background: #104277;
color: #ffffff;
border-color: #104277;
box-shadow:
0 4px 12px rgba(16, 66, 119, 0.25),
0 1px 3px rgba(16, 66, 119, 0.18);
}
.atelier-filter-button.active:hover {
background: #0c3764;
color: #ffffff;
border-color: #0c3764;
}
.atelier-filter-button:focus-visible {
outline: 3px solid rgba(16, 66, 119, 0.22);
outline-offset: 2px;
}
.atelier-filter-button svg {
flex-shrink: 0;
}
@media screen and (max-width: 700px) {
.atelier-filter-nav {
width: 100%;
padding: 6px;
gap: 6px;
}
.atelier-filter-button {
min-width: max-content;
padding: 9px 12px;
font-size: 13px;
}
}
.topbar{
justify-content: right !important;
}
`;

View File

@ -0,0 +1,546 @@
import React, { useRef, useState, useEffect, useMemo } from "react";
import TextField from '@mui/material/TextField';
import 'react-confirm-alert/src/react-confirm-alert.css'; // Import css
import Button from '@mui/material/Button';
import axios from "axios";
import { getCookie, setCookie } from 'react-use-cookie';
import { useHistory } from "react-router-dom";
import { DataGrid, GridToolbar, frFR } from '@mui/x-data-grid';
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
import 'react-tooltip/dist/react-tooltip.css'
import Popup from 'reactjs-popup';
import 'reactjs-popup/dist/index.css';
import "react-datepicker/dist/react-datepicker.css";
import 'moment/locale/fr';
import Box from '@mui/material/Box';
import img_loading_spin from "./../mysy_img/mysy_spin_loading.gif";
import { gridClasses } from '@mui/x-data-grid';
import Link from '@mui/material/Link';
import { PiDotsThree } from "react-icons/pi";
import { CiTrash } from "react-icons/ci";
import { IoAddCircleOutline } from "react-icons/io5";
import CancelPresentationIcon from '@mui/icons-material/CancelPresentation';
import { makeStyles } from "@material-ui/core/styles";
import Paper from '@material-ui/core/Paper';
import Draggable from 'react-draggable';
import { IconButton } from '@material-ui/core';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import 'react-tooltip/dist/react-tooltip.css'
import TextareaAutosize from '@mui/material/TextareaAutosize';
import Module_Alert_Confirmation from "./Module_Alert_Confirmation";
import { FaComment } from "react-icons/fa6";
import {
Bell,
BookOpen,
Building2,
Check,
CheckCircle2,
ChevronDown,
ChevronLeft,
ChevronRight,
ClipboardList,
FileText,
GraduationCap,
Grid2X2,
LayoutDashboard,
List,
Mail,
Menu,
MessageSquare,
Plus,
RefreshCw,
Search,
Settings,
SlidersHorizontal,
UserPlus,
Users,
X,
AlertCircle,
Clock3,
} from "lucide-react";
const useStyles = makeStyles((theme) => ({
dialog: {
position: 'absolute',
// left: 10,
top: 400
},
paper: {
overflowY: 'unset',
},
customizedButton: {
position: 'absolute',
left: '98%',
top: '-3%',
backgroundColor: 'lightgray',
color: 'gray',
},
}));
function PaperComponent(props) {
return (
<Draggable
handle="#draggable-dialog-title"
cancel={'[class*="MuiDialogContent-root"]'}
>
<Paper {...props} />
</Draggable>
);
}
const Module_Trombinoscope = (props) => {
const classes = useStyles();
const history = useHistory();
const [submenu, setsubmenu] = useState("");
const [rowss, setRows] = useState([]);
const [isLoading, setLoading] = useState();
const [display_alert_mysy, setdisplay_alert_mysy] = useState("");
const [alert_message, setalert_message] = useState("");
const [alert_type, setalert_type] = useState("");
function clear_alert_message() {
setalert_message("");
}
function clear_alert_type() {
setalert_type("");
}
function clear_display_alert_mysy() {
setdisplay_alert_mysy("");
}
const studentsData = [
{
id: 1,
prenom: "Chérif",
nom: "BALDE",
email: "cherif.balde@email.fr",
formation: "BTS MCO",
pcode_session: "Promo 2026",
group: "Groupe A",
company: "Orange France",
presence: 97,
average: 15.8,
dossier: "complet",
status: "inscrit",
avatar: "CB",
},
{
id: 2,
prenom: "Aïssata",
nom: "DIALLO",
email: "aissata.diallo@email.fr",
formation: "BTS NDRC",
pcode_session: "Promo 2026",
group: "Groupe B",
company: "Société Générale",
presence: 92,
average: 14.6,
dossier: "complet",
status: "inscrit",
avatar: "AD",
},
{
id: 3,
prenom: "Mamadou",
nom: "CAMARA",
email: "mamadou.camara@email.fr",
formation: "Bachelor RH",
pcode_session: "Promo 2026",
group: "Groupe A",
company: "BNP Paribas",
presence: 89,
average: 13.9,
dossier: "incomplet",
status: "preinscrit",
avatar: "MC",
},
{
id: 4,
prenom: "Fatoumata",
nom: "BARRY",
email: "fatou.barry@email.fr",
formation: "Licence CG",
pcode_session: "Promo 2026",
group: "Groupe C",
company: "Carrefour",
presence: 99,
average: 16.2,
dossier: "complet",
status: "inscrit",
avatar: "FB",
},
{
id: 5,
prenom: "Ibrahima",
nom: "SYLLA",
email: "ibrahima.sylla@email.fr",
formation: "Master IA",
pcode_session: "Promo 2026",
group: "Groupe B",
company: "Capgemini",
presence: 71,
average: 11.3,
dossier: "alerte",
status: "suspendu",
avatar: "IS",
},
{
id: 6,
prenom: "Mariama",
nom: "KEITA",
email: "mariama.keita@email.fr",
formation: "BTS SAM",
pcode_session: "Promo 2027",
group: "Groupe A",
company: "L'Oréal",
presence: 95,
average: 15.1,
dossier: "complet",
status: "inscrit",
avatar: "MK",
},
{
id: 7,
prenom: "Abdoulaye",
nom: "NDIAYE",
email: "abdou.ndiaye@email.fr",
formation: "Bachelor Marketing",
pcode_session: "Promo 2026",
group: "Groupe C",
company: "Decathlon",
presence: 90,
average: 14.7,
dossier: "complet",
status: "inscrit",
avatar: "AN",
},
{
id: 8,
prenom: "Ndeye",
nom: "FALL",
email: "ndeye.fall@email.fr",
formation: "BTS CG",
pcode_session: "Promo 2027",
group: "Groupe B",
company: "AXA Assurance",
presence: 78,
average: 12.4,
dossier: "incomplet",
status: "preinscrit",
avatar: "NF",
},
{
id: 9,
prenom: "Ousmane",
nom: "DIAGNE",
email: "ousmane.diagne@email.fr",
formation: "Licence Info",
pcode_session: "Promo 2026",
group: "Groupe A",
company: "Sanofi",
presence: 93,
average: 15.5,
dossier: "complet",
status: "inscrit",
avatar: "OD",
},
{
id: 10,
prenom: "Hawa",
nom: "SOW",
email: "hawa.sow@email.fr",
formation: "Master Supply",
pcode_session: "Promo 2026",
group: "Groupe C",
company: "DHL",
presence: 96,
average: 15.9,
dossier: "complet",
status: "inscrit",
avatar: "HS",
},
];
const sidebarItems = [
{ label: "Tableau de bord", icon: LayoutDashboard },
{ label: "Inscriptions", icon: ClipboardList },
{ label: "Étudiants", icon: Users, active: true },
{ label: "Formations", icon: BookOpen },
{ label: "Entreprises", icon: Building2 },
{ label: "Présences", icon: CheckCircle2 },
{ label: "Évaluations", icon: GraduationCap },
{ label: "Documents", icon: FileText },
{ label: "Messages", icon: MessageSquare },
{ label: "Paramètres", icon: Settings },
];
function getStatusLabel(status) {
return {
inscrit: "Inscrit",
preinscrit: "Préinscrit",
suspendu: "Suspendu",
inactif: "Inactif",
}[status] || status;
}
function StudentCard({ student, selected, onToggle }) {
const dossierConfig = {
complet: {
label: "Complet",
icon: Check,
className: "success",
},
incomplet: {
label: "Incomplet",
icon: Clock3,
className: "warning",
},
alerte: {
label: "Alerte",
icon: AlertCircle,
className: "danger",
},
}[student.dossier];
// const DossierIcon = dossierConfig.icon;
return (
<article className={`student-card ${selected ? "selected" : ""}`}>
<div className="student-card__cover">
<button
type="button"
className={`student-checkbox ${selected ? "checked" : ""}`}
onClick={() => onToggle(student.id)}
aria-label={`Sélectionner ${student.prenom} ${student.nom}`}
>
{selected && <Check size={14} strokeWidth={3} />}
</button>
<div className="student-card__course">
<strong>{student.formation}</strong>
<span>{student.pcode_session}</span>
</div>
<div className="student-card__pattern">
<span />
<span />
<span />
<span />
</div>
</div>
<div className="student-card__avatar-wrap">
<div className={`student-card__avatar avatar-${student.id % 5}`}>
<img src={"data:image/png;base64," + student.logo_img} style={{ width: '100%', borderRadius: '10rem', maxHeight:'164px', maxWidth:'164px' }} /><br />
</div>
</div>
<div className="student-card__body">
<h3>
{student.prenom} <strong>{student.nom}</strong>
</h3>
<a href={`mailto:${student.email}`}>{student.email}</a>
</div>
<div style={{width:'100%', marginBottom:'5px'}}>
<nav style={{fontFamily:'DM Sans', fontSize:'12px', textAlign:'center', fontWeight:'600'}}>
{student.code_session}
</nav>
</div>
</article>
);
}
function Sidebar({ open, onClose }) {
return (
<>
<div
className={`sidebar-backdrop ${open ? "show" : ""}`}
onClick={onClose}
/>
<aside className={`sidebar ${open ? "open" : ""}`}>
<div className="sidebar__brand">
<span>MySy</span>
<small>EYSY</small>
</div>
<nav className="sidebar__nav">
{sidebarItems.map(({ label, icon: Icon, active }) => (
<button
type="button"
key={label}
className={active ? "active" : ""}
>
<Icon size={20} />
<span>{label}</span>
</button>
))}
</nav>
<div className="sidebar__profile">
<div className="profile-avatar">AD</div>
<div>
<strong>Admin MySy</strong>
<span>Administrateur</span>
</div>
<ChevronRight size={18} />
</div>
</aside>
</>
);
}
const [students, setstudents] = useState([]);
//const [students] = useState(studentsData);
const [query, setQuery] = useState("");
const [pcode_session, setpcode_session] = useState("Toutes");
const [group, setGroup] = useState("Tous");
const [status, setStatus] = useState("Tous");
const [selectedIds, setSelectedIds] = useState([]);
const [view, setView] = useState("grid");
const [sidebarOpen, setSidebarOpen] = useState(false);
const filteredStudents = useMemo(() => {
const normalized = query.trim().toLowerCase();
return students.filter((student) => {
const haystack = [
student.prenom,
student.nom,
student.email,
student.formation,
student.group,
student.company,
]
.join(" ")
.toLowerCase();
return (
(!normalized || haystack.includes(normalized)) &&
(pcode_session === "Toutes" || student.pcode_session === pcode_session) &&
(group === "Tous" || student.group === group) &&
(status === "Tous" || student.status === status)
);
});
}, [students, query, pcode_session, group, status]);
const pcode_sessions = [...new Set(students.map((item) => item.pcode_session))];
const groups = [...new Set(students.map((item) => item.group))];
const toggleSelected = (studentId) => {
setSelectedIds((current) =>
current.includes(studentId)
? current.filter((id) => id !== studentId)
: [...current, studentId]
);
};
const resetFilters = () => {
setQuery("");
setpcode_session("Toutes");
setGroup("Tous");
setStatus("Tous");
};
useEffect(() => {
var new_data2 = [];
const new_data = props.inscrit.map((x) => {
//---
var local_student = JSON.parse(x)
new_data2.push(local_student);
});
setstudents(new_data2);
}, [])
return (
<div className="module_trombinoscope">
{isLoading && <div className="loader-container">
<div className="mysy_spinner"> <img src={img_loading_spin} /> </div>
</div>}
{/*** Affichage des messages d'alerte*/}
{display_alert_mysy && String(display_alert_mysy) === "1" &&
<Module_Alert_Confirmation alert_message={alert_message}
alert_type={alert_type}
clear_alert_message={clear_alert_message}
clear_alert_type={clear_alert_type}
clear_display_alert_mysy={clear_display_alert_mysy}
/>
}
{/*** FIN Affichage des messages d'alerte*/}
<div className="app-shell">
<main className="main-content">
{filteredStudents.length ? (
<section className={`students-grid ${view === "list" ? "list-view" : ""}`}>
{filteredStudents.map((student) => (
<StudentCard
key={student.id}
student={student}
selected={selectedIds.includes(student.id)}
onToggle={toggleSelected}
/>
))}
</section>
) : (
<section className="empty-state">
<UserPlus size={38} />
<h2>Aucun étudiant trouvé</h2>
<p>Modifiez les critères de recherche ou réinitialisez les filtres.</p>
<button type="button" className="primary-button" onClick={resetFilters}>
Réinitialiser
</button>
</section>
)}
</main>
</div>
<style>{local_css}</style>
</div >
);
}
export default Module_Trombinoscope;
const local_css = `
`;

View File

@ -2,7 +2,7 @@ import React, { useRef, useState, useMemo, useEffect } from "react";
import { useForm } from "react-hook-form";
import axios from "axios";
import Formation_Partner_Catalog from "./Formation_Partner_Catalog";
import { FaSearch, FaRegArrowAltCircleDown, FaRegArrowAltCircleUp } from 'react-icons/fa';
import { FaSearch, FaRegArrowAltCircleDown, FaRegArrowAltCircleUp } from 'react-icons/fa';
import { IoAppsSharp, IoListSharp } from "react-icons/io5";
import Formation_Grid_2Col from "./Formation_Grid_2Col";
@ -12,8 +12,8 @@ import { useHistory } from "react-router-dom";
import { getCookie, removeCookie } from 'react-use-cookie';
import { Helmet } from "react-helmet";
import AideRecherche from "./AideRecherche"
import { useParams } from 'react-router-dom'
import AideRecherche from "./AideRecherche";
import { useParams } from 'react-router-dom';
import Fotter_Catalog_Pub from "./Fotter_Catalog_Pub";
import img_header_jmg from "../mysy_img2/img_jmj_modif.jpg"
@ -47,7 +47,11 @@ const Mon_Catalogue_Public = (props) => {
const [TrainingPrice, setTrainingPrice] = useState("");
const [SearchText, setSearchText] = useState("");
const [SearchcitiesText, setSearchcitiesText] = useState("");
const [result, setResult] = useState("");
const [result, setResult] = useState([]);
const [result_for_atelier, setresult_for_atelier] = useState([]);
const [myApiResponse, setmyApiResponse] = useState("false");
const [displayAllClasses, setdisplayAllClasses] = useState("0");
const [showelement, setshowelement] = useState("init");
@ -107,6 +111,7 @@ const Mon_Catalogue_Public = (props) => {
const onSubmit = async (data) => {
searchFunction();
searchFunction_for_ateliers();
};
const [Trainingdistance, setTrainingdistance] = useState(0);
@ -139,11 +144,13 @@ const Mon_Catalogue_Public = (props) => {
function clearsearchtext(event) {
setSearchText("");
setResult([]);
setresult_for_atelier([]);
document.getElementById("SearchText").value = "";
setempltysearch("1")
setbesoinaiderecherche("");
settext("");
DisplayXfirstClas();
DisplayXfirstClas_for_atelier();
}
const [suggestion2, setsuggestion2] = useState([]);
@ -947,7 +954,10 @@ const Mon_Catalogue_Public = (props) => {
}
}
DisplayXfirstClas(result.data);
DisplayXfirstClas_for_atelier();
}
@ -995,7 +1005,7 @@ const Mon_Catalogue_Public = (props) => {
});
}
loadDomainMetier();
// loadDomainMetier();
async function loadDomain() {
@ -1021,7 +1031,7 @@ const Mon_Catalogue_Public = (props) => {
}
loadDomain();
// loadDomain();
const listener = event => {
if (event.code === "Enter" || event.code === "NumpadEnter") {
@ -1081,6 +1091,7 @@ const Mon_Catalogue_Public = (props) => {
if (tab_domaine.length <= 0) {
setdomaine_v11(domaine_v11_orig);
DisplayXfirstClas();
DisplayXfirstClas_for_atelier()
return;
}
@ -1133,6 +1144,7 @@ const Mon_Catalogue_Public = (props) => {
if (event.length <= 0) {
setdomaine_v11(domaine_v11_orig);
DisplayXfirstClas();
DisplayXfirstClas_for_atelier()
return;
}
//console.log(domaine_metier);
@ -1195,6 +1207,7 @@ const Mon_Catalogue_Public = (props) => {
// Nettoyage du resultat precedent.
setResult([]);
var crit_TrainingSupport = "";
var crit_TrainingType = "";
var crit_TrainingCertif = "";
@ -1203,13 +1216,9 @@ const Mon_Catalogue_Public = (props) => {
var crit_TrainingPrice = "";
var crit_TrainingDuration = "";
var my_ville = "";
var my_cp = "";
var my_domaine = "";
if (document.getElementById("searchdomain"))
my_domaine = document.getElementById("searchdomain").value;
@ -1330,8 +1339,8 @@ const Mon_Catalogue_Public = (props) => {
// alert("myurl = " + myurl);
axios.post(myurl, form).then(res => {
if (String(res.data.status) != String("false")) {
//console.log(" In test res.data.status = " + res.data.status);
// console.log(" In test res.data.message = " + res.data.message);
//console.log(" In searchFunction res.data.status = " + res.data.status);
console.log(" In searchFunction res.data.message = " + res.data.message);
setmyApiResponse("True");
setResult(res.data.message)
@ -1375,6 +1384,175 @@ const Mon_Catalogue_Public = (props) => {
}
/// Recherche pour les formation de type atelier
function searchFunction_for_ateliers(e) {
// Nettoyage du resultat precedent.
setresult_for_atelier([]);
var crit_TrainingSupport = "";
var crit_TrainingType = "";
var crit_TrainingCertif = "";
var crit_TrainingLang = "";
var crit_TrainingPresentiel = "";
var crit_TrainingPrice = "";
var crit_TrainingDuration = "";
var my_ville = "";
var my_cp = "";
var my_domaine = "";
if (document.getElementById("searchdomain"))
my_domaine = document.getElementById("searchdomain").value;
//Get Criterias
var crit_SearchText = document.getElementById("SearchText").value;
if (document.getElementById("TrainingSupport"))
crit_TrainingSupport = document.getElementById("TrainingSupport").value;
if (document.getElementById("TrainingType"))
crit_TrainingType = document.getElementById("TrainingType").value;
if (document.getElementById("TrainingCertif"))
crit_TrainingCertif = document.getElementById("TrainingCertif").value;
if (crit_TrainingCertif.length == 0)
crit_TrainingCertif = "NA";
if (document.getElementById("TrainingLang"))
crit_TrainingLang = document.getElementById("TrainingLang").value;
if (document.getElementById("TrainingPresentiel"))
crit_TrainingPresentiel = document.getElementById("TrainingPresentiel").value;
if (document.getElementById("TrainingPrice"))
crit_TrainingPrice = document.getElementById("TrainingPrice").value;
if (document.getElementById("duration"))
crit_TrainingDuration = document.getElementById("duration").value;
if (document.getElementById("ville")) {
my_ville = crit_TrainingSupport = document.getElementById("ville").value;
}
if (document.getElementById("zip_code")) {
my_cp = crit_TrainingSupport = document.getElementById("zip_code").value;
}
var crit_Trainingdistance = Trainingdistance;
var form = new FormData();
form.append("search_text", crit_SearchText);
var my_local_user_connect;
var my_local_part_connect;
if (typeof (stored_user) === "undefined" || String(stored_user) === '') {
my_local_user_connect = 0;
} else {
my_local_user_connect = 1;
}
if (typeof (stored_part) === "undefined" || String(stored_part) === '') {
my_local_part_connect = 0;
} else {
my_local_part_connect = 1;
}
if (String(my_local_user_connect) === "1") {
form.append("token", stored_user);
form.append("connection_type", "user");
}
else if (String(my_local_part_connect) === "1") {
form.append("token", stored_part);
form.append("connection_type", "partner");
}
else {
form.append("token", "");
form.append("connection_type", "");
}
form.append("certif", crit_TrainingCertif);
form.append("support", crit_TrainingSupport);
form.append("type", crit_TrainingType);
form.append("lang", crit_TrainingLang);
form.append("price", crit_TrainingPrice);
form.append("distance", crit_Trainingdistance);
form.append("duration", crit_TrainingDuration);
// Ajout des info IP user
form.append("user_ip", IPv4);
form.append("user_country_code", country_code);
form.append("user_country_name", country_name);
form.append("user_city", city);
form.append("user_postal", postal);
form.append("user_latitude", latitude);
form.append("user_longitude", longitude);
form.append("user_state", state);
form.append("subdomain", window.location.host.split(".")[0]);
form.append("formation_type", "atelier");
var myurl = ""
if (displayAllClasses == true) {
myurl = process.env.REACT_APP_API_URL + "myclass/api/get_all_class_Given_partner_owner_recid_No_Login/";
}
else {
myurl = process.env.REACT_APP_API_URL + "myclass/api/recherche_text_simple_for_partner_catalog/";
}
// alert("myurl = " + myurl);
axios.post(myurl, form).then(res => {
if (String(res.data.status) != String("false")) {
//console.log(" In test res.data.status = " + res.data.status);
console.log(" In searchFunction_for_ateliers res.data.message = " + res.data.message);
//setmyApiResponse("True");
setresult_for_atelier(res.data.message)
var myelement;
if (document.getElementById('rech_middlebox')) {
myelement = document.getElementById('rech_middlebox');
}
if (myelement) {
myelement.scrollIntoView({ behavior: 'smooth' });
}
}
else {
//console.log(" In test res.data.status = " + res.data.status);
//console.log(" In test res.data.message = " + res.data.message);
setmyApiResponse("False");
//setmyApimyApiMessage("")
//textInput.current.focus();
}
}).catch((error) => {
// console.warn('Not good man :( mysearchtext = ');
//setmyApiResponse("False");
//setmyApimyApiMessage("")
})
}
// Cette fonction affiche les X premieres formations
@ -1384,6 +1562,132 @@ const Mon_Catalogue_Public = (props) => {
setResult([]);
//Get Criterias
var crit_SearchText = "";
var myurl = "";
var form = new FormData();
form.append("search_text", crit_SearchText);
if (typeof (NewSearchText) === "undefined" || String(NewSearchText) === '') {
crit_SearchText = "";
myurl = process.env.REACT_APP_API_URL + "myclass/api/get_all_class_Given_partner_owner_recid_No_Login_With_Valide_Session/";
form.append("subdomain", window.location.host.split(".")[0]);
// console.log(" ######### laaaaaaaaaaaaa subdomain = ", window.location.host.split(".")[0])
} else {
crit_SearchText = NewSearchText;
myurl = process.env.REACT_APP_API_URL + "myclass/api/recherche_text_simple_for_partner_catalog/";
}
var my_local_user_connect;
var my_local_part_connect;
if (typeof (stored_user) === "undefined" || String(stored_user) === '') {
my_local_user_connect = 0;
} else {
my_local_user_connect = 1;
}
if (typeof (stored_part) === "undefined" || String(stored_part) === '') {
my_local_part_connect = 0;
} else {
my_local_part_connect = 1;
}
if (String(my_local_user_connect) === "1") {
form.append("token", stored_user);
form.append("connection_type", "user");
}
else if (String(my_local_part_connect) === "1") {
form.append("token", stored_part);
form.append("connection_type", "partner");
}
else {
form.append("token", "");
form.append("connection_type", "");
}
form.append("certif", "");
form.append("support", "");
form.append("type", "");
form.append("lang", "");
form.append("price", "");
form.append("distance", "");
form.append("duration", "");
form.append("cpf", "");
// Ajout des info IP user
if (ip) {
//console.log(" ### with IP");
form.append("user_ip", ip.IPv4);
form.append("user_country_code", ip.country_code);
form.append("user_country_name", ip.country_name);
form.append("user_city", ip.city);
form.append("user_postal", ip.postal);
form.append("user_latitude", ip.latitude);
form.append("user_longitude", ip.longitude);
form.append("user_state", ip.state);
}
else {
//console.log(" ### with OUT IP");
form.append("user_ip", IPv4);
form.append("user_country_code", country_code);
form.append("user_country_name", country_name);
form.append("user_city", city);
form.append("user_postal", postal);
form.append("user_latitude", latitude);
form.append("user_longitude", longitude);
form.append("user_state", state);
// alert(" rrtt ");
}
//alert("myurl zzz = " + myurl);
axios.post(myurl, form).then(res => {
if (String(res.data.status) != String("false")) {
//console.log(" In test res.data.status = " + res.data.status);
// console.log(" In DisplayXfirstClas res.data.message = " + res.data.message);
setmyApiResponse("True");
setResult(res.data.message)
// textInput.current.focus();
setbesoinaiderecherche("");
}
else {
//console.log(" In test res.data.status = " + res.data.status);
//console.log(" In test res.data.message = " + res.data.message);
setmyApiResponse("False");
//setmyApimyApiMessage("")
//textInput.current.focus();
}
}).catch((error) => {
// console.warn('Not good man :( mysearchtext = ');
setmyApiResponse("False");
//setmyApimyApiMessage("")
})
}
// Cette fonction affiche les X premieres formations de type atelier
function DisplayXfirstClas_for_atelier(ip) {
// Nettoyage du resultat precedent.
setresult_for_atelier([]);
//Get Criterias
var crit_SearchText = "";
@ -1472,23 +1776,22 @@ const Mon_Catalogue_Public = (props) => {
// alert(" rrtt ");
}
form.append("formation_type", "atelier");
// alert("myurl = " + myurl);
//alert("myurl DisplayXfirstClas_for_atelier = " + myurl);
axios.post(myurl, form).then(res => {
if (String(res.data.status) != String("false")) {
//console.log(" In test res.data.status = " + res.data.status);
//console.log(" In DisplayXfirstClas res.data.message = " + res.data.message);
//console.log(" In DisplayXfirstClas_for_atelier res.data.message = " + res.data.message);
setresult_for_atelier(res.data.message)
setmyApiResponse("True");
setResult(res.data.message)
// textInput.current.focus();
setbesoinaiderecherche("");
}
else {
//console.log(" In test res.data.status = " + res.data.status);
//console.log(" In test res.data.message = " + res.data.message);
setmyApiResponse("False");
//setmyApiResponse("False");
//setmyApimyApiMessage("")
//textInput.current.focus();
}
@ -1496,13 +1799,15 @@ const Mon_Catalogue_Public = (props) => {
}).catch((error) => {
// console.warn('Not good man :( mysearchtext = ');
setmyApiResponse("False");
//setmyApiResponse("False");
//setmyApimyApiMessage("")
})
}
const [trier_par, settrier_par] = useState("1");
function trier(e) {
@ -1757,6 +2062,7 @@ const Mon_Catalogue_Public = (props) => {
setdomaine_v11(domaine_v11_orig);
DisplayXfirstClas();
DisplayXfirstClas_for_atelier();
//setResult([]);
/*const pieces = window.location.href.split("/")
@ -2834,7 +3140,7 @@ const Mon_Catalogue_Public = (props) => {
const [display_formation_session, setdisplay_formation_session] = useState("formation");
const [activeTab, setActiveTab] = useState("formations");
return (
@ -4671,9 +4977,9 @@ const Mon_Catalogue_Public = (props) => {
</div>
</div>
<div style={{ width: '100%', background: '#f3f4fb', paddingTop: "2rem" }}>
<div className="jmj_block_milieu">
<div className="jmj_block_milieu_gauche">
{showelement === "true" && <div className="rech_leftbox" >
<div className="jmj_block_milieu">
{/*<div className="jmj_block_milieu_gauche">
{showelement === "true" && <div className="rech_leftbox" > gggggggggggggggg
<div className="sous_filter">
@ -4819,13 +5125,13 @@ const Mon_Catalogue_Public = (props) => {
</div>
}
</div>
</div>*/}
<div className="jmj_block_milieu_droite">
<div className="jmj_block_milieu_droite" style={{width:'90%', maxWidth:'1400px'}}>
<div className="rech_middlebox" id="rech_middlebox" style={{ width: '100%' }}>
<div style={{ "width": "50%", float: 'left' }}> <h3 style={{ fontFamily: 'DM Sans', color: '#0A043C' }}> Nos Formations </h3></div>
{/* <div style={{ "width": "50%", float: 'left' }}> <h3 style={{ fontFamily: 'DM Sans', color: '#0A043C' }}> Nos Formations </h3></div> */}
<div style={{ "width": "50%", float: 'right' }}>
{/*<div style={{ "width": "50%", float: 'right' }}>
<Button style={{ "width": "40%", float: 'left' }}
onClick={(e) => {
setdisplay_formation_session("formation")
@ -4840,6 +5146,37 @@ const Mon_Catalogue_Public = (props) => {
</div>*/}
<div className="module_atelier_catalogue" style={{ "width": "100%", float: 'left', textAlign: 'center' }}>
<section className="hero-section">
<div className="segment-tabs" role="tablist" aria-label="Type de catalogue">
<button
className={activeTab === "formations" ? "active" : ""}
onClick={(e) => {
setActiveTab("formations")
setdisplay_formation_session("formation")
}}
>
Les formations
</button>
<button
className={activeTab === "ateliers" ? "active" : ""}
onClick={(e) => {
setActiveTab("ateliers")
setdisplay_formation_session("session")
}}
>
Les ateliers
</button>
</div>
</section>
</div>
<div style={{
@ -4861,7 +5198,7 @@ const Mon_Catalogue_Public = (props) => {
onPageChange={page => setCurrentPage2(page)}
/>
</div>
<div style={{ "width": "60%", "float": "right" }}>
{display_formation_session !== "session" && <div style={{ "width": "60%", "float": "right" }}>
<div className="input-group input-group-sm mb-3 ">
<span className="filter_span">Trier par </span>
@ -4885,7 +5222,7 @@ const Mon_Catalogue_Public = (props) => {
/> </span>
</div>
</div>
</div>}
</div>
@ -4897,10 +5234,10 @@ const Mon_Catalogue_Public = (props) => {
{display_formation_session !== "session" && <div style={{ width: '100%', marginBottom: "1rem" }}>
<div className="block_display_flex_formation" style={{ width: '100%' }}>
{result && myApiResponse == "True" && fin == 0 && !newresult &&
result.slice(0, PageSize).map((formation) => (
{result && result.length > 0 &&
result.map((formation) => (
<div className="block_formation" ref={inputEl} id="inputEl_element">
<Formation_Partner_Catalog_Special_JMJFormation formation={JSON.parse(formation)}
key={JSON.parse(formation).title} coeur={JSON.parse(formation).title}
@ -4908,98 +5245,18 @@ const Mon_Catalogue_Public = (props) => {
</div>
))}
{result && myApiResponse == "True" && fin == 0 && newresult &&
newresult.slice(0, PageSize).map((formation) => (
<div className="block_formation" >
<Formation_Partner_Catalog_Special_JMJFormation formation={JSON.parse(formation)}
key={JSON.parse(formation).title} partner_data={New_Get_Subdomain_Partner_Data_result[0]} />
</div>
))}
{result && myApiResponse === "True" && fin === 1 && !newresult
&& currentTableData2
&& currentTableData2.map((formation) => (
<div className="block_formation" >
<Formation_Partner_Catalog_Special_JMJFormation formation={JSON.parse(formation)}
key={JSON.parse(formation).title} partner_data={New_Get_Subdomain_Partner_Data_result[0]} />
</div>
))}
{result && myApiResponse === "True" && fin === 1 && newresult
&& currentTableData2
&& currentTableData2.map((formation) => (
<div className="block_formation" >
<Formation_Partner_Catalog_Special_JMJFormation formation={JSON.parse(formation)} key={JSON.parse(formation).title}
partner_data={New_Get_Subdomain_Partner_Data_result[0]} />
</div>
))}
</div>
</div>}
{display_formation_session === "session22" && <div style={{ width: '100%', marginBottom: "1rem" }}>
<div className="block_display_flex_formation" style={{ width: '100%' }}>
{result && myApiResponse == "True" && fin == 0 && !newresult &&
result.slice(0, PageSize).map((formation) => (
<div style={{ width: '100%', float: 'left' }}>
<div className="block_formation" ref={inputEl} id="inputEl_element">
<Session_Partner_Catalog_Special_Partner formation={JSON.parse(formation)}
key={JSON.parse(formation).title} coeur={JSON.parse(formation).title}
partner_data={New_Get_Subdomain_Partner_Data_result[0]} />
</div>
</div>
))}
{result && myApiResponse == "True" && fin == 0 && newresult &&
newresult.slice(0, PageSize).map((formation) => (
<div className="block_formation" >
<Session_Partner_Catalog_Special_Partner formation={JSON.parse(formation)}
key={JSON.parse(formation).title} partner_data={New_Get_Subdomain_Partner_Data_result[0]} />
</div>
))}
{result && myApiResponse === "True" && fin === 1 && !newresult
&& currentTableData2
&& currentTableData2.map((formation) => (
<div className="block_formation" >
<Session_Partner_Catalog_Special_Partner formation={JSON.parse(formation)}
key={JSON.parse(formation).title} partner_data={New_Get_Subdomain_Partner_Data_result[0]} />
</div>
))}
{result && myApiResponse === "True" && fin === 1 && newresult
&& currentTableData2
&& currentTableData2.map((formation) => (
<div className="block_formation" >
<Session_Partner_Catalog_Special_Partner formation={JSON.parse(formation)} key={JSON.parse(formation).title}
partner_data={New_Get_Subdomain_Partner_Data_result[0]} />
</div>
))}
</div>
</div>}
{display_formation_session === "session" && <div style={{ width: '100%', marginBottom: "1rem" }}>
<Module_Atelier_Catalogue
formations={result} />
formations={result_for_atelier} />
</div>}
</div>

View File

@ -6424,7 +6424,12 @@ function UpdateParnterInfo(props) {
</div>
</div>
</div>
<style>{local_css}</style>
</div>
);
}
export default UpdateParnterInfo;
export default UpdateParnterInfo;
const local_css = `
`;

View File

@ -1823,7 +1823,7 @@ const New_C_Inscription_Detail_Formation_2025 = (props) => {
{parse(String(DetailTraining["programme"]))}sticky_div_hilight
</div>
}
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,14 @@
import Display_Partner_Catalog_DetailClass_new_vp from "../components/Display_Partner_Catalog_DetailClass_new_vp";
export default function display_partner_catalog_detailclass() {
return (
<div>
<div >
</div>
<Display_Partner_Catalog_DetailClass_new_vp />
</div>
);
}

View File

@ -6,7 +6,7 @@
font-family: "DM Sans", "sans-serif";
font-size: "13px";
}
.loader-container {
width: 100%;
@ -678,7 +678,12 @@
text-align: left;
font-size: small;
}
}
.mode_affichage {
width: 25%;
float: right;
cursor: pointer;
text-align: center;
}}
@media only screen and (min-width: 601px) and (max-width: 991px) {
.okUpdateData {
@ -1292,7 +1297,12 @@
font-size: small;
}
}
.mode_affichage {
width: 15%;
float: right;
cursor: pointer;
text-align: center;
}}
@media only screen and (min-width: 992px) and (max-width: 1199px) {
.okUpdateData {
@ -1799,7 +1809,12 @@
font-size: small;
}
}
.mode_affichage {
width: 12%;
float: right;
cursor: pointer;
text-align: center;
}}
@media only screen and (min-width: 1200px) {
.okUpdateData {
@ -2383,7 +2398,13 @@
font-size: small;
}
}
.mode_affichage {
width: 8%;
float: right;
cursor: pointer;
text-align: center;
}
}
.mysy_gris {
background: #ECEFF1 !important;
@ -2392,6 +2413,19 @@
// end media
.mode_affichage_selected {
text-underline-offset: 8px;
text-decoration: green wavy underline;
text-decoration-color: #F8C471;
text-decoration-style: solid;
text-decoration-thickness: 5px;
background: #F4F6F6;
box-shadow: 1px 1px 5px 1px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.separator {
display: flex;
align-items: center;

View File

@ -156,8 +156,9 @@
.hero-section {
display: flex;
justify-content: space-between;
align-items: flex-start;
justify-content: center;
/* centrage horizontal */
align-items: center;
gap: 24px;
padding: 42px 0 22px;
}
@ -322,6 +323,7 @@
border-radius: 18px;
box-shadow: var(--shadow-soft);
overflow: hidden;
margin-bottom: 1rem;
}
.formation-card__main {
@ -576,6 +578,7 @@
.workshop-code {
display: block;
padding-left: 6px;
text-align: left;
}
.workshop-code strong {

File diff suppressed because it is too large Load Diff

View File

@ -9417,7 +9417,7 @@
width: 25%;
float: left;
height: 400px;
display: none;
display: none;
}
.jmj_block_milieu {
@ -12881,8 +12881,9 @@
.jmj_block_milieu_droite {
margin: auto;
width: 70%;
width: 80%;
min-height: 100vh;
max-width: 1200px;
}
@ -16297,7 +16298,7 @@
width: 25%;
float: left;
height: 400px;
display: none;
display: none;
}
.jmj_block_milieu {
@ -16328,8 +16329,9 @@
.jmj_block_milieu_droite {
margin: auto;
width: 70%;
width: 80%;
min-height: 100vh;
max-width: 1200px;
}

View File

@ -132,7 +132,7 @@
width: 100%;
float: left;
border: none;
background: var(--Beige, #FFF5DA);
background: var(--Beige, #ebf1f4);
}
.block_centrer {
@ -150,7 +150,7 @@
height: 3rem;
left: 0px;
background: var(--Beige, #FFF5DA);
background: var(--Beige, #ebf1f4);
}
.display_screen_600_901 {
@ -267,7 +267,7 @@
height: 100px;
left: 0px;
background: var(--Beige, #FFF5DA);
background: var(--Beige, #ebf1f4);
}
}
@ -376,7 +376,7 @@
height: 100px;
left: 0px;
background: var(--Beige, #FFF5DA);
background: var(--Beige, #ebf1f4);
}
}
@ -485,7 +485,7 @@
width: 100%;
height: 150px;
left: 0px;
background: var(--Beige, #FFF5DA);
background: var(--Beige, #ebf1f4);
}
}

View File

@ -638,6 +638,7 @@
font-size: x-small !important;
font-family: "DM Sans", "sans-serif";
margin: 0.4rem !important;
background: #FFF !important;
}
.texte_area_adress {
@ -946,6 +947,7 @@
margin: 0.4rem !important;
margin-top: 0px !important;
margin-bottom: 1.5rem !important;
background: #FFF !important;
}

View File

@ -225,7 +225,7 @@
@import "./components/module_inscrit_suivi_paiement";
@import "./components/module_relance_client_facture";
@import "./components/module_atelier_catalogue";
@import "./components/module_trombinoscope";
// New Design 2025
@import "./components/new_s_sign_in_2025";