05/07/26 - 20h

branche_01062025
Cherif 2026-07-05 20:26:51 +02:00
parent 75a9c77bbb
commit 15db34ae19
16 changed files with 8566 additions and 73 deletions

View File

@ -0,0 +1,710 @@
:root {
--mysy-blue: #104277;
--mysy-blue-2: #0f56bd;
--mysy-blue-3: #eaf2ff;
--text: #071943;
--muted: #63708c;
--border: #dbe4f2;
--soft-border: #edf2fa;
--bg: #f3f6fc;
--card: #ffffff;
--green: #11985a;
--green-bg: #e9fbf2;
--red: #c8203a;
--red-bg: #ffedf1;
--shadow: 0 14px 40px rgba(16, 66, 119, 0.1);
--shadow-soft: 0 8px 22px rgba(16, 66, 119, 0.08);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: "DM Sans", Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: var(--bg);
color: var(--text);
}
button,
input {
font: inherit;
}
button {
cursor: pointer;
}
.catalogue-page {
min-height: 100vh;
padding-bottom: 56px;
}
.topbar {
height: 72px;
display: flex;
align-items: center;
gap: 32px;
padding: 0 56px;
background: rgba(255, 255, 255, 0.92);
border-bottom: 1px solid var(--soft-border);
position: sticky;
top: 0;
z-index: 20;
backdrop-filter: blur(14px);
}
.brand {
font-size: 28px;
font-weight: 900;
letter-spacing: -1px;
color: var(--mysy-blue);
white-space: nowrap;
}
.brand span {
font-weight: 700;
}
.nav-links {
display: flex;
align-items: stretch;
gap: 8px;
height: 100%;
flex: 1;
justify-content: center;
}
.nav-link {
display: flex;
align-items: center;
gap: 8px;
padding: 0 14px;
color: #697590;
text-decoration: none;
border-bottom: 3px solid transparent;
font-size: 14px;
font-weight: 700;
}
.nav-link--active {
color: var(--mysy-blue-2);
border-color: var(--mysy-blue-2);
}
.user-actions {
display: flex;
align-items: center;
gap: 14px;
}
.notification-btn,
.avatar-btn {
border: 0;
background: transparent;
}
.notification-btn {
position: relative;
width: 42px;
height: 42px;
display: grid;
place-items: center;
color: #31405f;
}
.notification-btn span {
position: absolute;
top: 7px;
right: 5px;
background: #e43145;
color: #fff;
min-width: 17px;
height: 17px;
border-radius: 999px;
display: grid;
place-items: center;
font-size: 10px;
font-weight: 800;
}
.avatar-btn {
display: inline-flex;
align-items: center;
gap: 7px;
background: var(--mysy-blue);
color: #fff;
padding: 10px 12px;
border-radius: 999px;
font-weight: 800;
}
.hero-section,
.search-panel,
.results-info,
.formation-list {
width: min(1320px, calc(100% - 64px));
margin-left: auto;
margin-right: auto;
}
.hero-section {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 24px;
padding: 42px 0 22px;
}
.hero-section h1 {
margin: 0;
font-size: clamp(34px, 4vw, 46px);
letter-spacing: -1.4px;
line-height: 1.05;
}
.hero-section p {
margin: 10px 0 0;
color: var(--muted);
font-size: 16px;
}
.segment-tabs {
display: flex;
padding: 5px;
border: 1px solid var(--border);
border-radius: 999px;
background: #fff;
min-width: 360px;
box-shadow: var(--shadow-soft);
}
.segment-tabs button {
flex: 1;
border: 0;
background: transparent;
color: var(--mysy-blue);
padding: 14px 26px;
border-radius: 999px;
font-weight: 800;
}
.segment-tabs button.active {
background: linear-gradient(135deg, var(--mysy-blue), #0d56c4);
color: #fff;
box-shadow: 0 10px 22px rgba(15, 86, 196, 0.22);
}
.search-panel {
background: #fff;
border: 1px solid var(--border);
border-radius: 18px;
padding: 20px;
box-shadow: var(--shadow);
}
.search-row {
display: grid;
grid-template-columns: 1fr 180px;
gap: 18px;
}
.search-input {
display: flex;
align-items: center;
gap: 12px;
height: 62px;
border: 1px solid #c8d7eb;
border-radius: 12px;
padding: 0 18px;
color: #71809b;
background: #fff;
}
.search-input input {
border: 0;
outline: 0;
flex: 1;
color: var(--text);
font-size: 15px;
}
.sort-btn {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
text-align: left;
gap: 2px 12px;
height: 62px;
border: 1px solid #c8d7eb;
background: #fff;
border-radius: 12px;
padding: 0 16px;
color: var(--text);
}
.sort-btn span {
font-size: 12px;
color: var(--muted);
}
.sort-btn svg {
grid-row: 1 / span 2;
grid-column: 2;
}
.filter-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
margin-top: 20px;
}
.filter-chips {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.filter-chip {
display: inline-flex;
align-items: center;
gap: 8px;
height: 44px;
padding: 0 16px;
border: 1px solid var(--border);
border-radius: 10px;
color: var(--mysy-blue-2);
background: linear-gradient(180deg, #fff, #f8fbff);
font-weight: 800;
font-size: 14px;
}
.filter-chip:hover {
border-color: #aac3e8;
box-shadow: 0 7px 16px rgba(16, 66, 119, 0.08);
}
.reset-btn,
.program-btn {
border: 0;
background: transparent;
color: var(--mysy-blue-2);
font-weight: 800;
}
.results-info {
margin-top: 22px;
color: var(--muted);
font-size: 15px;
}
.results-info strong {
color: var(--text);
}
.formation-list {
display: grid;
gap: 22px;
margin-top: 16px;
}
.formation-card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 18px;
box-shadow: var(--shadow-soft);
overflow: hidden;
}
.formation-card__main {
display: grid;
grid-template-columns: 320px 1fr 250px;
gap: 28px;
padding: 22px;
}
.formation-card__image-wrap {
position: relative;
min-height: 190px;
}
.formation-card__image {
display: block;
width: 100%;
height: 190px;
object-fit: cover;
border-radius: 14px;
}
.favorite-btn {
position: absolute;
top: 12px;
right: 12px;
width: 38px;
height: 38px;
border: 1px solid rgba(255, 255, 255, 0.8);
border-radius: 12px;
display: grid;
place-items: center;
background: rgba(255, 255, 255, 0.86);
color: #78859d;
backdrop-filter: blur(8px);
}
.favorite-btn:hover {
color: #e43145;
}
.formation-card__content {
display: grid;
grid-template-columns: 54px 1fr;
gap: 18px;
align-items: flex-start;
padding-top: 8px;
}
.formation-icon {
width: 54px;
height: 54px;
display: grid;
place-items: center;
border-radius: 18px;
color: var(--mysy-blue-2);
background: var(--mysy-blue-3);
}
.formation-icon--green {
color: #0f8b53;
background: #e9fbf2;
}
.formation-icon--purple {
color: #7457e7;
background: #f1edff;
}
.formation-copy h2 {
margin: 0 0 12px;
color: var(--mysy-blue);
font-size: 28px;
line-height: 1.15;
letter-spacing: -0.7px;
}
.formation-copy p {
max-width: 700px;
margin: 0;
color: #475572;
line-height: 1.55;
}
.rating-line {
display: flex;
align-items: center;
gap: 10px;
margin-top: 16px;
font-weight: 800;
color: #3e4b65;
font-size: 14px;
}
.rating-stars {
display: inline-flex;
gap: 2px;
color: #f6ad19;
}
.formation-card__meta {
padding-top: 6px;
}
.badges {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 22px;
}
.badge {
display: inline-flex;
align-items: center;
border-radius: 999px;
padding: 8px 12px;
font-size: 12px;
font-weight: 900;
}
.badge--danger {
color: var(--red);
background: var(--red-bg);
}
.badge--success {
color: var(--green);
background: var(--green-bg);
}
.badge--soft {
color: var(--mysy-blue-2);
background: var(--mysy-blue-3);
}
.meta-list {
display: grid;
gap: 16px;
}
.meta-item {
display: grid;
grid-template-columns: 24px 1fr;
gap: 12px;
align-items: flex-start;
color: #53617d;
}
.meta-item span,
.workshop-cell span {
display: block;
color: var(--muted);
font-size: 12px;
font-weight: 600;
}
.meta-item strong,
.workshop-cell strong {
display: block;
margin-top: 2px;
color: var(--text);
font-size: 14px;
line-height: 1.25;
}
.meta-item .price {
color: var(--mysy-blue-2);
font-size: 19px;
font-weight: 900;
}
.meta-item .price-free {
color: var(--green);
font-size: 19px;
font-weight: 900;
}
.workshops {
border-top: 1px solid var(--soft-border);
padding: 0 18px 18px;
}
.workshops__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
padding: 18px 0 12px;
}
.workshops__header > div {
display: flex;
align-items: center;
gap: 10px;
color: var(--mysy-blue);
font-size: 18px;
}
.workshops__header span {
min-width: 28px;
height: 26px;
padding: 0 9px;
border-radius: 999px;
display: inline-grid;
place-items: center;
background: var(--mysy-blue-3);
color: var(--mysy-blue-2);
font-weight: 900;
font-size: 13px;
}
.program-btn {
display: inline-flex;
align-items: center;
gap: 4px;
}
.workshops__list {
border: 1px solid var(--border);
border-radius: 14px;
overflow: hidden;
background: #fff;
}
.workshop-row {
display: grid;
grid-template-columns: 1.5fr 1.5fr 1.2fr 1.15fr 1.15fr 144px;
align-items: center;
gap: 16px;
min-height: 72px;
padding: 10px 14px;
}
.workshop-row + .workshop-row {
border-top: 1px solid var(--soft-border);
}
.workshop-row:hover {
background: #f8fbff;
}
.workshop-cell {
min-width: 0;
display: grid;
grid-template-columns: 24px 1fr;
align-items: center;
gap: 10px;
color: var(--mysy-blue-2);
}
.workshop-code {
display: block;
padding-left: 6px;
}
.workshop-code strong {
color: var(--mysy-blue);
}
.workshop-places span {
color: var(--green);
}
.details-btn {
border: 0;
background: linear-gradient(135deg, var(--mysy-blue), #0d56c4);
color: #fff;
height: 42px;
border-radius: 9px;
font-weight: 900;
box-shadow: 0 9px 18px rgba(16, 66, 119, 0.18);
}
.details-btn:hover {
filter: brightness(1.04);
transform: translateY(-1px);
}
@media (max-width: 1120px) {
.topbar {
padding: 0 24px;
}
.nav-links {
display: none;
}
.formation-card__main {
grid-template-columns: 240px 1fr;
}
.formation-card__meta {
grid-column: 1 / -1;
display: flex;
justify-content: space-between;
gap: 22px;
}
.meta-list {
grid-template-columns: repeat(3, 1fr);
flex: 1;
}
.workshop-row {
grid-template-columns: 1.2fr 1.4fr 1fr 1fr;
}
.workshop-row .workshop-cell:nth-of-type(5),
.details-btn {
grid-column: span 2;
}
}
@media (max-width: 760px) {
.hero-section,
.search-panel,
.results-info,
.formation-list {
width: min(100% - 28px, 1320px);
}
.topbar {
height: auto;
min-height: 68px;
}
.hero-section {
flex-direction: column;
padding-top: 26px;
}
.segment-tabs {
width: 100%;
min-width: 0;
}
.search-row {
grid-template-columns: 1fr;
}
.filter-row {
align-items: flex-start;
flex-direction: column;
}
.formation-card__main {
grid-template-columns: 1fr;
gap: 20px;
}
.formation-card__image {
height: 220px;
}
.formation-card__content {
grid-template-columns: 1fr;
}
.formation-card__meta {
display: block;
}
.meta-list {
grid-template-columns: 1fr;
}
.formation-copy h2 {
font-size: 24px;
}
.workshops__header {
align-items: flex-start;
flex-direction: column;
}
.workshop-row {
grid-template-columns: 1fr;
gap: 12px;
padding: 16px;
}
.workshop-row .workshop-cell:nth-of-type(5),
.details-btn {
grid-column: auto;
}
.details-btn {
width: 100%;
}
}

View File

@ -32,6 +32,7 @@ import moment from "moment";
import 'moment/locale/fr';
import { useCookies } from "react-cookie";
import InputAdornment from '@mui/material/InputAdornment';
import { FcOrgUnit } from "react-icons/fc";
import { AiFillCloseCircle } from "react-icons/ai";
import Box from '@mui/material/Box';
import { Typography, LinearProgress } from '@mui/material';
@ -3730,6 +3731,75 @@ const DisplayPartnerSession = (props) => {
const [New_Get_Conflit_On_Inscription_result, setNew_Get_Conflit_On_Inscription_result] = useState([]);
const [Get_Conflit_On_Inscription_api, setGet_Conflit_On_Inscription_api] = useState();
const [Get_Conflit_On_Inscription_message, setGet_Conflit_On_Inscription_message] = useState();
const [Get_Conflit_On_Inscription_result, setGet_Conflit_On_Inscription_result] = useState([]);
function Get_Conflit_On_Inscription() {
var form = new FormData();
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
//console.log("### form = ", form);
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_Inscription_Conflit/";
setLoading(true);
axios.post(myurl, form).then(res => {
//console.log(" In Get_Conflit_On_Inscription res.data.status = " + res.data.status);
// console.log(" In Get_Conflit_On_Inscription res.data.message r_class = " + res.data.message);
setLoading(false);
if (String(res.data.status) === String("true")) {
setGet_Conflit_On_Inscription_api("true");
setGet_Conflit_On_Inscription_message(res.data.message);
var new_data2 = [];
const new_data = res.data.message.map((x) => {
new_data2.push(x)
});
if (new_data2.length > 0)
setNew_Get_Conflit_On_Inscription_result(new_data2);
else
setNew_Get_Conflit_On_Inscription_result([])
setDialog_List_Conflit_Inscription(true);
}
else {
setGet_Conflit_On_Inscription_api("false");
setGet_Conflit_On_Inscription_message(res.data.message);
// alert(res.data.message);
setdisplay_alert_mysy("1");
setalert_message(res.data.message);
setalert_type("error");
}
}).catch((error) => {
setLoading(false);
console.warn('Get_Conflit_On_Inscription : Not good man :( Get_Conflit_On_Inscription = ' + error);
setGet_Conflit_On_Inscription_api("false");
setdisplay_alert_mysy("1");
setalert_message(" Impossible de récuperer la liste des conflits ");
setalert_type("error");
})
}
useEffect(() => {
Get_List_Mode_Financement();
@ -16540,6 +16610,15 @@ const DisplayPartnerSession = (props) => {
};
const [Dialog_List_Conflit_Inscription, setDialog_List_Conflit_Inscription] = useState(false);
const Close_Dialog_List_Conflit_Inscription = () => {
// clean_order_detail_fields();
setDialog_List_Conflit_Inscription(false);
};
return (
<div className="displaypartnersession">
@ -16559,6 +16638,302 @@ const DisplayPartnerSession = (props) => {
{/*** FIN Affichage des messages d'alerte*/}
{/********** Dialog pour Conflit_Inscription */}
<Dialog
open={Dialog_List_Conflit_Inscription}
className="displaypartnersession"
static
onClose={() => null}
PaperProps={{
className: classes.paper,
style: {
overflowY: "unset",
position: "absolute",
top: "15rem",
margin: "2px",
},
}}
hideBackdrop={true}
disableScrollLock
classes={{
paper: classes.dialog,
}}
PaperComponent={PaperComponent}
aria-labelledby="draggable-dialog-title"
>
<DialogTitle
id="draggable-dialog-title"
style={{
cursor: "move",
background: "#fff",
fontFamily: "DM Sans",
fontWeight: 700,
color: "#104277",
borderBottom: "1px solid #eef2f6",
maxWidth:'unset',
width:'60rem'
}}
>
Conflits dinscription
</DialogTitle>
<DialogContent
style={{
fontFamily: "DM Sans",
paddingTop: "16px",
background: "#f8fafc",
}}
>
{New_Get_Conflit_On_Inscription_result &&
New_Get_Conflit_On_Inscription_result.length > 0 && (
<div className="div_row">
<div className="Grid_1_col">
<div
className="Grid_2_col_sub_colone"
style={{
minHeight: "10rem",
padding: "0px",
background: "transparent",
}}
>
<div style={{ width: "100%", float: "left" }}>
<div
style={{
display: "flex",
flexDirection: "column",
gap: "12px",
width: "100%",
}}
>
{New_Get_Conflit_On_Inscription_result.map((conflit) => (
<div
style={{
width: "100%",
textAlign: "left",
background: "#fff",
borderRadius: "16px",
padding: "16px",
border: "1px solid #e6eaf0",
boxShadow:
"0 18px 45px rgba(16, 66, 119, 0.10), 0 4px 14px rgba(15, 37, 82, 0.05)",
}}
>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "flex-start",
gap: "12px",
marginBottom: "14px",
}}
>
<div>
<div
style={{
fontSize: "15px",
fontWeight: 800,
color: "#FF4500",
}}
>
{String(JSON.parse(conflit).apprenant_nom)}{" "} {String(JSON.parse(conflit).apprenant_prenom)}
</div>
</div>
</div>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
gap: "12px",
}}
>
{JSON.parse(conflit).sessions_en_conflit &&
JSON.parse(conflit).sessions_en_conflit.map((session, sessionIndex) => (
<div
key={`${session.session_id || "session"}-${sessionIndex}`}
style={{
background: "#f8fafc",
border: "1px solid #e2e8f0",
borderRadius: "14px",
padding: "14px",
}}
>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
gap: "8px",
marginBottom: "10px",
}}
>
<div
style={{
fontSize: "13px",
fontWeight: 800,
color: "#101828",
}}
>
{String(session.code_session || "Session")}
</div>
<div
style={{
fontSize: "11px",
fontWeight: 700,
color: "#104277",
background: "#eaf2ff",
padding: "4px 8px",
borderRadius: "999px",
}}
>
Session {sessionIndex + 1}
</div>
</div>
<div
style={{
fontSize: "12px",
color: "#475467",
lineHeight: "1.8",
}}
>
<div>
Du{" "}
<strong style={{ color: "#101828" }}>
{String(session.date_debut || "-")}
</strong>{" "}
au{" "}
<strong style={{ color: "#101828" }}>
{String(session.date_fin || "-")}
</strong>
</div>
{session.code_session && (
<div>
Code :
<strong style={{ color: "#101828" }}>
{String(session.code_session)}
</strong>
</div>
)}
</div>
</div>
))}
</div>
</div>
))}
</div>
</div>
</div>
</div>
</div>
)}
{New_Get_Conflit_On_Inscription_result &&
New_Get_Conflit_On_Inscription_result.length <= 0 && (
<div className="div_row">
<div className="Grid_1_col">
<div
className="Grid_2_col_sub_colone"
style={{
minHeight: "10rem",
padding: "0px",
background: "transparent",
}}
>
<div
style={{
width: "100%",
background: "#fff",
borderRadius: "16px",
padding: "24px",
border: "1px solid #e6eaf0",
textAlign: "center",
boxShadow:
"0 18px 45px rgba(16, 66, 119, 0.08), 0 4px 14px rgba(15, 37, 82, 0.04)",
}}
>
<div
style={{
width: "48px",
height: "48px",
borderRadius: "50%",
background: "#ecfdf3",
color: "#027a48",
display: "flex",
alignItems: "center",
justifyContent: "center",
margin: "0 auto 12px auto",
fontSize: "22px",
fontWeight: 800,
}}
>
</div>
<div
className="Grid_2_col_sub_colone_header"
style={{
background: "transparent",
color: "#104277",
fontWeight: 800,
fontSize: "15px",
}}
>
Aucun conflit détecté
</div>
<div
style={{
fontSize: "13px",
color: "#667085",
marginTop: "6px",
}}
>
Les inscriptions contrôlées ne présentent aucun chevauchement de sessions.
</div>
</div>
</div>
</div>
</div>
)}
</DialogContent>
<DialogActions
style={{
background: "#fff",
borderTop: "1px solid #eef2f6",
padding: "10px 16px",
}}
>
<IconButton
onClick={Close_Dialog_List_Conflit_Inscription}
color="primary"
className={classes.customizedButton}
disableRipple
disableFocusRipple
>
<CancelPresentationIcon />
</IconButton>
</DialogActions>
</Dialog>
{/********** FIN Dialog pour Conflit_Inscription */}
{/* Dialog pour gerer les Distanciel_Orga */}
<Dialog
open={Dialog_Distanciel_Orga_open}
@ -21987,6 +22362,8 @@ const DisplayPartnerSession = (props) => {
</nav>
<nav style={{ width: '80%', float: 'right', textAlign: "right", marginTop: "10px" }}>
<nav className="mode_affichage" onClick={Get_Conflit_On_Inscription}> <FcOrgUnit /> Conflit </nav>
{session_display_view && String(session_display_view) === "timeline" && <nav className="mode_affichage mode_affichage_selected" onClick={func_session_display_timeline_view}> <FcTimeline /> Line </nav>}
{(!session_display_view || String(session_display_view) !== "timeline") && <nav className="mode_affichage" onClick={func_session_display_timeline_view}> <FcTimeline /> Line </nav>}

View File

@ -267,7 +267,7 @@ const ENT_Student_Header = () => {
removeCookie(acces_right_token_name,);
removeCookie("tokenmysychapprenant");
removeCookie("tokenmysych");
// removeCookie("tokenmysych");
removeCookie("tokenmysychconnecteduserid");
removeCookie("tokenmysytypeconnexion");
@ -299,7 +299,7 @@ const ENT_Student_Header = () => {
removeCookie("tokenmysychapprenant");
removeCookie("tokenmysych");
removeCookie("tokenmysypart");
// removeCookie("tokenmysypart");
removeCookie("tokenmysytuteurrhid",);
removeCookie("tokenmysychconnecteduserid");
removeCookie("tokenmysytypeconnexion");

View File

@ -11415,7 +11415,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_nom}
onChange={(e) => {
@ -11437,7 +11437,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_nom_fille}
onChange={(e) => {
@ -11459,7 +11459,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_prenom}
onChange={(e) => {
@ -11485,7 +11485,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_mail}
onChange={(e) => {
@ -11511,7 +11511,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_profession}
onChange={(e) => {
@ -11531,7 +11531,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_siret}
onChange={(e) => {
@ -11615,7 +11615,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_piece_identite_num}
onChange={(e) => {
@ -11645,7 +11645,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style enable_style"
value={p_detail_nationalite}
onChange={(e) => {
@ -11722,7 +11722,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style enable_style"
value={p_detail_naissance_departement}
onChange={(e) => {
@ -11787,7 +11787,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_tel_mobile}
onChange={(e) => {
@ -11808,7 +11808,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_tel}
onChange={(e) => {
@ -11829,7 +11829,7 @@ const Employes = (props) => {
InputLabelProps={{
shrink: true,
}}
disabled={false}
disabled={Boolean(employee_data_edit_mode)}
className="disabled_style"
value={p_detail_adresse}
onChange={(e) => {
@ -14046,7 +14046,7 @@ const Employes = (props) => {
{String(acces_right_data_changed) === "1" && String(acces_right_data_edit_mode) === "1" && <div className="div_row_gauche" style={{ "textAlign": 'left', 'marginLeft': '15px' }}>
<Button variant="contained" className="bton_enreg" onClick={Update_user_access_right_Data}>Enregistrer
<Button variant="contained" className="bton_enreg" onClick={Update_user_access_right_Data}>MAJ Droits Accès
</Button>
</div>}
@ -14224,7 +14224,9 @@ const Employes = (props) => {
</div>}
</div>
<div className="div_row" style={{ "border": "None", "color": "orange", "textAlign": "center" }}>
{/*** On masque le pavé ci-dessous pour eviter confusions d'affichage */}
{String(acces_right_data_edit_mode) !== "1" && <div className="div_row" style={{ "border": "None", "color": "orange", "textAlign": "center" }}>
<div className="div_row_gauche" style={{ "textAlign": 'left', 'marginLeft': '15px' }}>
@ -14242,7 +14244,7 @@ const Employes = (props) => {
>Annuler
</Button>
</div>
</div>
</div>}
<div className="div_row" style={{ "border": "None" }}>
&nbsp;

View File

@ -1705,6 +1705,15 @@ const Groupe_Apprenant = (props) => {
setp_detail_type_groupe_code("");
}
if (mylocal_groupe.groupe_inscription_type_id) {
setp_detail_type_groupe_id(mylocal_groupe.groupe_inscription_type_id);
} else {
setp_detail_type_groupe_id("");
}
if (mylocal_groupe.session_id) {
setp_detail_session_id(mylocal_groupe.session_id);
} else {

View File

@ -0,0 +1,503 @@
import React, { useState, useEffect } from "react";
import { useHistory } from "react-router-dom";
import { useCookies } from "react-cookie";
import { confirmAlert } from 'react-confirm-alert';
import Fotter_Catalog_Pub from "../Fotter_Catalog_Pub";
import img_met_program from "../../mysy_img/met_programmation.jpg";
import img_met_graphisme from "../../mysy_img/metier_graphisme.jpg";
import img_met_autre from "../../mysy_img/met_autre.jpg";
import img_met_digital from "../../mysy_img/met_digital.jpg";
import img_met_management from "../../mysy_img/met_management.jpg";
import img_met_dev_perso from "../../mysy_img/metier_dev_perso.jpg";
import img_met_rh from "../../mysy_img/met_rh.jpg";
import img_met_bureautic from "../../mysy_img/met_burautic.jpg";
import img_met_vente from "../../mysy_img/met_vente.jpg";
import axios from "axios";
//import { Rating } from 'react-simple-star-rating'
import Rating from '@mui/material/Rating';
import parse from 'html-react-parser'
import { CiLocationOn } from "react-icons/ci";
const Session_Partner_Catalog_Special_Partner = (props) => {
const [userconnected, setuserconnected] = useState("0");
const [partnerconnected, setpartnerconnected] = useState("0");
const [cookie, setCookie, removeCookie] = useCookies(['tokenmysych']);
const [cookie_part, setCookie_part, removeCookie_part] = useCookies(['tokenmysypart']);
const history = useHistory();
const [myfilter, setmyfilter] = useState(props.formation.price);
const [profileimg, setprofileimg] = useState(props.formation.price);
// Gestion des Cookies
const stored_partner = cookie_part.tokenmysypart;
const stored_user = cookie.tokenmysych;
function test(val) {
if (userconnected === "0" && partnerconnected === "0") {
confirmAlert({
title: 'Activer votre session ?',
message: 'Merci de vous connecter pour acceder au detail de cette formation',
buttons: [
{
label: 'Oui',
onClick: () => { history.push("/mysy-training-login/training/" + props.formation.internal_url) }
},
{
label: 'Non',
onClick: () => { return }
}
],
closeOnEscape: false,
closeOnClickOutside: false,
keyCodeForClose: [8, 32],
willUnmount: () => { },
afterClose: () => { },
onClickOutside: () => { },
onKeypress: () => { },
onKeypressEscape: () => { },
});
} else {
window.open(
"/Display-Detail-formation/" + props.formation.internal_url,
'_blank'
);
}
}
const [myclassimage, setmyclassimage] = useState();
const [isclassimage, setisclassimage] = useState("False");
const [userimgclassprofil, setuserimgclassprofil] = useState("");
const [class_img_stored_in_bdd, setclass_img_stored_in_bdd] = useState("");
function getClassImage_no_token() {
var myurl = process.env.REACT_APP_API_URL + "myclass/api/getRecodedClassImage_no_token/";
var form = new FormData();
form.append("type", "partner");
form.append("related_collection", "myclass");
form.append("related_collection_recid", props.formation._id);
form.append("class_external_code", props.formation.external_code);
axios.post(myurl, form).then(res => {
// console.log(" getClassImage_no_token : In test res.data.status = ", res.data.status);
if (String(res.data.status) === "true") {
//console.log(" getClassImage_no_token: res.data.message.img = ", res.data.message);
if (res.data.message.img.length > 0) {
setisclassimage("True");
}
else {
setisclassimage("False");
}
setisclassimage(res.data.message.img);
var ch_img = "data:image/png;base64," + res.data.message.img;
setclass_img_stored_in_bdd(ch_img);
// console.log(" getClassImage_no_token: setclass_img_stored_in_bdd = ", setclass_img_stored_in_bdd);
}
else {
// console.log(" In Erreur res.data.status = " + res.data.status);
//console.log(" In Erreur res.data.message = " + res.data.message);
setisclassimage("False");
setuserimgclassprofil();
setclass_img_stored_in_bdd();
}
}).catch((error) => {
console.warn('getClassImage ee: Not good man :( getClassImage = ');
setisclassimage("False");
setuserimgclassprofil("");
setclass_img_stored_in_bdd("");
})
}
/* Cette variable accompagne la gestion des images par defaut.
idée : si la valeur de "DetailTraining.metier" != "management, digital, office, rh, vente, dev_perso"
alors l'utilisateur à créer une formation avec un metier qui n'est pas geré, donc on met une image par defaut
*/
const [ismetiermanaged, setismetiermanaged] = useState();
const liste_metier = ["management", "digital", "office", "rh", "vente", "dev_perso"];
useEffect(() => {
setmyfilter(props.myfil);
// console.log(" #### useEffect props.formation = ", props.formation);
if (typeof (stored_user) === "undefined" || String(stored_user) === '') {
setuserconnected("0");
} else {
setuserconnected("1");
}
if (typeof (stored_partner) === "undefined" || String(stored_partner) === '') {
setpartnerconnected("0");
} else {
setpartnerconnected("1");
}
getClassImage_no_token();
GetCurrentClass_trainingsession();
GetCurrentClass_trainingsession_cities();
// Verifier si le metier est geré
if (props.formation.metier) {
if (!liste_metier.includes(props.formation.metier)) {
setismetiermanaged("0"); // j'ai une valeur dans metier, mais qui n'est pas geré
}
}
else {
setismetiermanaged("0");
}
if (props.formation.img_url && String(props.formation.img_url).length > 0) {
setismetiermanaged("1");
}
}, []);
const [GetCurrentClass_api, setGetCurrentClass_api] = useState();
const [GetCurrentClass_message, setGetCurrentClass_message] = useState();
const [GetCurrentClass_result, setGetCurrentClass_result] = useState();
function GetCurrentClass_trainingsession(event) {
var form = new FormData();
form.append("class_internal_url", props.formation.internal_url);
form.append("token", stored_partner);
var myurl = process.env.REACT_APP_API_URL + "myclass/api/GetActiveSessionFormation_List/";
axios.post(myurl, form).then(res => {
if (res.data.status != "false") {
//console.log(" In GetCurrentClass_trainingsession res.data.status = " + res.data.status);
//console.log(" In GetCurrentClass_trainingsession res.data.message r_class = " + res.data.message);
setGetCurrentClass_api("true");
setGetCurrentClass_result(res.data.message);
}
else {
setGetCurrentClass_api("false");
setGetCurrentClass_message(res.data.message);
}
}).catch((error) => {
console.warn('Not good man :( GetCurrentClass_trainingsession = ', error);
setGetCurrentClass_api("false");
//setmyApimyApiMessage("")
})
}
const [GetCurrentClass_trainingsession_cities_api, setGetCurrentClass_trainingsession_cities_api] = useState();
const [GetCurrentClass_trainingsession_cities_message, setGetCurrentClass_trainingsession_cities_message] = useState();
const [GetCurrentClass_trainingsession_cities_result, setGetCurrentClass_trainingsession_cities_result] = useState([]);
function GetCurrentClass_trainingsession_cities(event) {
var form = new FormData();
form.append("class_internal_url", props.formation.internal_url);
form.append("token", stored_partner);
var myurl = process.env.REACT_APP_API_URL + "myclass/api/GetActiveSession_Cities_And_Distance_Formation_List/";
axios.post(myurl, form).then(res => {
if (res.data.status != "false") {
//console.log(" In GetCurrentClass_trainingsession_cities res.data.status = " + res.data.status);
//console.log(" In GetCurrentClass_trainingsession_cities res.data.message r_class = " + res.data.message);
setGetCurrentClass_trainingsession_cities_api("true");
setGetCurrentClass_trainingsession_cities_result(res.data.message);
}
else {
setGetCurrentClass_trainingsession_cities_api("false");
setGetCurrentClass_trainingsession_cities_message(res.data.message);
}
}).catch((error) => {
console.warn('Not good man :( GetCurrentClass_trainingsession_cities = ', error);
setGetCurrentClass_trainingsession_cities_api("false");
//setmyApimyApiMessage("")
})
}
const styles = {
list: {
display: 'flex',
flexDirection: 'column',
gap: '32px',
width: '100%',
},
row: {
display: 'flex',
flexDirection: 'row',
gap: '24px',
width: '100%',
},
card: {
flexGrow: 1,
backgroundColor: '#fff',
borderRadius: '8px',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
},
image: {
maxWidth: '100%',
height: '200px',
overflow: 'hidden',
margin: "auto",
},
content: {
padding: '16px',
},
header: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
},
eligibility: {
backgroundColor: '#e2e9fb',
padding: '4px 8px',
borderRadius: '4px',
fontSize: '12px',
fontWeight: 'bold',
},
title: {
fontSize: '14px',
fontWeight: 'bold',
margin: '8px 0',
},
price: {
fontSize: '14px',
fontWeight: 'bold',
color: '#000',
},
description: {
fontSize: '12px',
color: '#666',
margin: '8px 0',
height: "40px",
overflow: "hidden",
},
details: {
display: 'flex',
justifyContent: 'space-between',
marginTop: '16px',
},
button: {
backgroundColor: '#007bff',
color: '#fff',
padding: '8px 16px',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
},
buttonOutline: {
backgroundColor: '#fff',
color: '#007bff',
padding: '8px 16px',
border: '1px solid #007bff',
borderRadius: '4px',
cursor: 'pointer',
},
};
return (
<div className="new_formation_2025">
NB SESSION = {props.formation.tab_session.length}
{props.formation.tab_session && props.formation.tab_session.map((val) => (
<div style={styles.card}>
CODE SESSION = {val.code_session}
<div style={{ width: '100%', textAlign: 'right', zIndex: '9999' }}>
<div style={{ width: '50%', float: 'left' }}> &nbsp; </div>
{props.formation.cpf && String(props.formation.cpf) === String("1") && <div className="case_cpf" >
<span className="tag_cpf_txt_ok_cpf" >{"OUI CPF"}</span>
</div>
}
{props.formation.cpf && String(props.formation.cpf) !== String("1") && <div className="case_cpf">
<span className="tag_cpf_txt_no_ok_cpf">{"NON CPF"}</span>
</div>
}
{!props.formation.cpf && String(props.formation.cpf) !== String("1") && <div className="case_cpf">
<span className="tag_cpf_txt_no_ok_cpf">{"NON CPF"}</span>
</div>}
</div>
{class_img_stored_in_bdd && String(class_img_stored_in_bdd).length > 50 &&
<img src={class_img_stored_in_bdd} alt="Formation" style={styles.image} />
}
{(!class_img_stored_in_bdd || String(class_img_stored_in_bdd).length < 50) &&
(!props.formation.img_url || String(props.formation.img_url).length <= 10) &&
String(ismetiermanaged) !== "0" && String(ismetiermanaged) !== "1" &&
<div >
{(!props.formation.img_url || String(props.formation.img_url).length <= 0) &&
props.formation.metier && String(props.formation.metier).toLocaleLowerCase() === String("it") &&
String(isclassimage) === "False" && <img src={img_met_program} alt="informatique" style={styles.image} />}
{(!props.formation.img_url || String(props.formation.img_url).length <= 0) &&
props.formation.metier && String(props.formation.metier).toLocaleLowerCase() === String("graphisme") &&
String(isclassimage) === "False" && <img src={img_met_graphisme} alt="graphisme" style={styles.image} />}
{(!props.formation.img_url || String(props.formation.img_url).length <= 0) &&
props.formation.metier && String(props.formation.metier).toLocaleLowerCase() === String("management") &&
String(isclassimage) === "False" && <img src={img_met_management} alt="management" style={styles.image} />}
{(!props.formation.img_url || String(props.formation.img_url).length <= 0) &&
props.formation.metier && String(props.formation.metier).toLocaleLowerCase() === String("digital") &&
String(isclassimage) === "False" && <img src={img_met_digital} alt="digital" style={styles.image} />}
{(!props.formation.img_url || String(props.formation.img_url).length <= 0) &&
props.formation.metier && String(props.formation.metier).toLocaleLowerCase() === String("office") &&
String(isclassimage) === "False" && <img src={img_met_bureautic} alt="office" style={styles.image} />}
{!props.formation.img_url || String(props.formation.img_url).length <= 0 &&
props.formation.metier && String(props.formation.metier).toLocaleLowerCase() === String("rh") &&
String(isclassimage) === "False" && <img src={img_met_rh} alt="ressources humaines" style={styles.image} />}
{!props.formation.img_url || String(props.formation.img_url).length <= 0 &&
props.formation.metier && String(props.formation.metier).toLocaleLowerCase() === String("vente") &&
String(isclassimage) === "False" && <img src={img_met_vente} alt="vente" style={styles.image} />}
{!props.formation.img_url || String(props.formation.img_url).length <= 0 &&
props.formation.metier && String(props.formation.metier).toLocaleLowerCase() === String("dev_perso") &&
String(isclassimage) === "False" && <img src={img_met_dev_perso} alt="developpement personnel" style={styles.image} />}
{String(isclassimage) === "True" && <img src={userimgclassprofil} alt="developpement personnel" style={styles.image} />}
</div>
}
{(!class_img_stored_in_bdd || String(class_img_stored_in_bdd).length < 50) && String(ismetiermanaged) === "0" && String(userimgclassprofil).length > 100 &&
<div>
<img src={userimgclassprofil} alt="autre" style={styles.image} />
{/*props.formation.institut_formation && <div style={{ width: '100%', "textAlign": "center" }}> Dispensé par :<br />
{String(props.formation.institut_formation)} </div>*/}
</div>}
{(!class_img_stored_in_bdd || String(class_img_stored_in_bdd).length < 50) && String(ismetiermanaged) === "0" && String(userimgclassprofil).length <= 100 &&
<div>
<img src={img_met_autre} alt="autre" style={styles.image} />
{/*props.formation.institut_formation && <div style={{ width: '100%', "textAlign": "center" }}> Dispensé par :<br />
{String(props.formation.institut_formation)} </div>*/}
</div>}
{(!class_img_stored_in_bdd || String(class_img_stored_in_bdd).length < 50) && String(ismetiermanaged) === "1" &&
<div>
<img src={props.formation.img_url} alt="autre" style={styles.image} />
{/*props.formation.institut_formation && <div style={{ width: '100%', "textAlign": "center" }}> Dispensé par : <br />
{String(props.formation.institut_formation)} </div>*/}
</div>}
<div className="block_main_contente">
<div className="block_top_content">
<div className="div_row_gauche" >
{props.formation.note && String(props.formation.note).length === 1 &&
parseInt(String(props.formation.note)) <= 5 &&
<Rating name="half-rating-read" defaultValue={props.formation.note} precision={0.5} readOnly style={{ fontSize: '15px' }} />
}
</div>
<h3 className="formation_titre">{String(parse(String(props.formation.title).replace(/(<([^>]+)>)/ig, ''))).substring(0, 50)}</h3>
{props.formation.discounted_price && props.formation.business_prices && <p className="formation_prix">{props.formation.discounted_price}
{parseFloat(String(props.formation.partnaire_tva)) > 0 && <> HT&nbsp; </>}
{parseFloat(String(props.formation.partnaire_tva)) <= 0 && <> TTC&nbsp; </>}
</p>}
{props.formation.business_prices && props.formation.business_prices.length <= 0 && props.formation.inscription_direct !== "1"
&& <p className="formation_prix">
{parseFloat(String(props.formation.price)) <= 0 && <> Gratuit </>}
{parseFloat(String(props.formation.price)) > 0 && <> {props.formation.price} </>}
{parseFloat(String(props.formation.partnaire_tva)) > 0 && parseFloat(String(props.formation.price)) > 0 && <> HT&nbsp; </>}
{parseFloat(String(props.formation.partnaire_tva)) <= 0 && parseFloat(String(props.formation.price)) > 0 && <> TTC&nbsp; </>}
</p>}
{props.formation.business_prices && props.formation.business_prices.length > 0 && props.formation.inscription_direct !== "1" &&
<p style={{ width: '100%', float: 'left' }}>
<p className="formation_prix" style={{ width: '100%', float: 'left' }}>{props.formation.business_prices[0].discounted_price}
{parseFloat(String(props.formation.partnaire_tva)) > 0 && <> HT&nbsp; </>}
{parseFloat(String(props.formation.partnaire_tva)) <= 0 && <> TTC&nbsp; </>}
<font className='training_price_barre' style={{ fontSize: '14px' }}> {props.formation.price}
{parseFloat(String(props.formation.partnaire_tva)) > 0 && <> HT&nbsp; </>}
{parseFloat(String(props.formation.partnaire_tva)) <= 0 && <> TTC&nbsp; </>}
</font>
<font className='discount_block' style={{ fontSize: '14px' }}> ({props.formation.business_prices[0].discount} %) </font></p>
</p>}
<p className="formation_description"> {String(parse(String(props.formation.description).replace(/(<([^>]+)>)/ig, ''))).substring(0, 80)}...</p>
</div>
</div>
<div className="block_cats">
<button className="block_cats_bton_detail">
<nav className="block_cats_bton_detail_text"
onClick={(e) => {
e.preventDefault();
if (props.formation.url && props.formation.url.length > 5) {
window.open(
props.formation.url,
'_blank'
);
} else {
window.open(
"/Display-Partner-Catalog-Detail-formation/" + props.formation.internal_url,
'_blank'
);
}
}}> Voir les détails </nav></button>
</div>
</div>
))}
</div>
)
}
export default Session_Partner_Catalog_Special_Partner;

View File

@ -0,0 +1,720 @@
import React, { useMemo, useState, useEffect } from "react";
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 img_loading_spin from "./../mysy_img/mysy_spin_loading.gif";
import { Fab } from "@material-ui/core";
import Module_Alert_Confirmation from "./Module_Alert_Confirmation";
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
import axios from "axios";
import {
Bell,
BookOpen,
Building2,
CalendarDays,
ChevronDown,
ChevronRight,
Clock3,
Heart,
Home,
Laptop,
MapPin,
Monitor,
Search,
SlidersHorizontal,
Sparkles,
Star,
Tag,
UsersRound,
} from "lucide-react";
import "./AteliersCatalogue.css";
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';
function PaperComponent(props) {
return (
<Draggable
handle="#draggable-dialog-title"
cancel={'[class*="MuiDialogContent-root"]'}
>
<Paper {...props} />
</Draggable>
);
}
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',
},
}));
const formations = [
{
_id: "f1",
title: "Poser des règles et des limites aux enfants accueillis",
description:
"Le fonctionnement émotionnel du petit et ses besoins en sécurité pour se développer. Apprenez à poser un cadre bienveillant et sécurisant adapté à chaque enfant.",
image:
"https://images.unsplash.com/photo-1516321497487-e288fb19713f?auto=format&fit=crop&w=900&q=80",
rating: "4,6",
reviews: 128,
price: "270 € HT",
duration: "7 heures",
audience: "Professionnels de la petite enfance",
badge: "Non CPF",
badgeType: "danger",
highlight: "Populaire",
icon: <UsersRound size={22} />,
iconTone: "blue",
ateliers: [
{
code: "ADF_20260421_A",
date: "21 avril 2026",
time: "9h00 17h00",
mode: "Présentiel",
city: "Lyon",
zip: "69003",
places: 6,
cta: "Voir les détails",
},
{
code: "ADF_20260512_D",
date: "12 mai 2026",
time: "9h00 17h00",
mode: "Distanciel",
city: "En ligne",
zip: "",
places: 10,
cta: "Voir les détails",
},
{
code: "ADF_20260616_H",
date: "16 juin 2026",
time: "9h00 17h00",
mode: "Hybride",
city: "Paris",
zip: "75011",
places: 7,
cta: "Sinscrire",
},
],
},
{
_id: "f2",
title: "Accueillir un enfant en situation de handicap",
description:
"Comprendre les différents types de handicap et leurs impacts au quotidien. Adapter laccueil et les pratiques pour favoriser linclusion et le bien-être.",
image:
"https://images.unsplash.com/photo-1544776193-352d25ca82cd?auto=format&fit=crop&w=900&q=80",
rating: "4,8",
reviews: 92,
price: "Gratuit",
duration: "7 heures",
audience: "Professionnels de la petite enfance",
badge: "CPF",
badgeType: "success",
highlight: "Nouveau",
icon: <Sparkles size={22} />,
iconTone: "green",
ateliers: [
{
code: "ADF_20260505_P",
date: "5 mai 2026",
time: "9h00 17h00",
mode: "Présentiel",
city: "Marseille",
zip: "13002",
places: 8,
cta: "Voir les détails",
},
{
code: "ADF_20260602_D",
date: "2 juin 2026",
time: "9h00 17h00",
mode: "Distanciel",
city: "En ligne",
zip: "",
places: 12,
cta: "Sinscrire",
},
],
},
{
_id: "f3",
title: "Développer le langage chez le jeune enfant",
description:
"Stimuler le langage oral et accompagner les premières acquisitions à travers des jeux, des histoires et des interactions adaptées.",
image:
"https://images.unsplash.com/photo-1503676260728-1c00da094a0b?auto=format&fit=crop&w=900&q=80",
rating: "4,5",
reviews: 76,
price: "210 € HT",
duration: "7 heures",
audience: "Professionnels de la petite enfance",
badge: "CPF",
badgeType: "success",
highlight: "Populaire",
icon: <BookOpen size={22} />,
iconTone: "purple",
ateliers: [
{
code: "ADF_20260428_L",
date: "28 avril 2026",
time: "9h00 17h00",
mode: "Présentiel",
city: "Lille",
zip: "59000",
places: 9,
cta: "Voir les détails",
},
{
code: "ADF_20260519_D",
date: "19 mai 2026",
time: "9h00 17h00",
mode: "Distanciel",
city: "En ligne",
zip: "",
places: 15,
cta: "Voir les détails",
},
{
code: "ADF_20260609_H",
date: "9 juin 2026",
time: "9h00 17h00",
mode: "Hybride",
city: "Toulouse",
zip: "31000",
places: 6,
cta: "Sinscrire",
},
],
},
];
const filters = [
{ label: "Tous les filtres", icon: <SlidersHorizontal size={16} /> },
{ label: "Présentiel", icon: <Building2 size={16} /> },
{ label: "Distanciel", icon: <Monitor size={16} /> },
{ label: "Hybride", icon: <Laptop size={16} /> },
{ label: "CPF", icon: <Sparkles size={16} /> },
{ label: "Gratuit", icon: <Tag size={16} /> },
{ label: "Payant", icon: <Tag size={16} /> },
];
function Stars() {
return (
<div className="module_atelier_catalogue rating-stars" aria-label="Note formation">
{[1, 2, 3, 4, 5].map((item) => (
<Star key={item} size={15} fill="currentColor" />
))}
</div>
);
}
function ModeIcon({ mode }) {
if (mode === "Distanciel") return <Monitor size={20} />;
if (mode === "Hybride") return <Laptop size={20} />;
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) {
const [activeTab, setActiveTab] = useState("formations");
const classes = useStyles();
const totalAteliers = useMemo(
() => formations.reduce((acc, formation) => acc + formation.ateliers.length, 0),
[]
);
function FormationCard({ 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} {formation.duration_unit}(s) </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>
{formation && formation.external_code && <div style={{ width: '100%' }}> external_code = {formation.external_code} </div>}
{formation && formation.tab_session && <div className="module_atelier_catalogue workshops">
<div className="workshops__header">
<div>
<strong>Ateliers disponibles</strong>
<span>{formation.tab_session.length}</span>
</div>
<button className="program-btn">
Voir le programme <ChevronRight size={16} />
</button>
</div>
<div className="module_atelier_catalogue workshops__list">
{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>
</div>
<div className="workshop-cell">
<CalendarDays size={20} />
<div>
<strong>{atelier.date_debut}</strong>
<span>{formation.duration}</span>
</div>
</div>
<div className="workshop-cell">
<ModeIcon mode={atelier.mode} />
<div>
{atelier.mode_animation === "0" && <strong>Présentiel</strong>}
{atelier.mode_animation === "1" && <strong>Distanciel</strong>}
{atelier.mode_animation === "2" && <strong>Hybride</strong>}
<span>Mode</span>
</div>
</div>
<div className="workshop-cell">
<MapPin size={20} />
<div>
<strong>{atelier.ville}</strong>
{atelier.mode_animation === "1" && <span>En ligne</span>}
{atelier.mode_animation !== "1" && atelier.ville && <span>{atelier.ville}</span>}
</div>
</div>
<div className="workshop-cell workshop-places">
<UsersRound size={20} />
<div>
<strong>{atelier.nb_participant} places</strong>
<span>disponibles</span>
</div>
</div>
<button className="details-btn" onClick={(event) => {
setDialog_add_inscription_open(true);
init_inscrit_info();
setselected_session_id(atelier._id);
setselected_session_code(atelier.code_session)
}}>Inscription</button>
</div>
))}
</div>
</div>}
</article>
);
}
useEffect(() => {
// console.log(" ### props.formations = ", props.formations)
}, [])
const [Dialog_add_inscription_message, setDialog_add_inscription_message] = React.useState(false);
const [Dialog_add_inscription_open, setDialog_add_inscription_open] = React.useState(false);
function Dialog_add_inscription_handle_change_participant_session(message) {
setDialog_add_inscription_message(message);
setDialog_add_inscription_open(true);
}
const Dialog_add_inscription_handleClose_buton = () => {
setDialog_add_inscription_open(false);
init_inscrit_info();
};
const [selected_session_id, setselected_session_id] = useState("");
const [selected_session_code, setselected_session_code] = useState("");
const [inscrit_nom, setinscrit_nom] = useState("");
const [inscrit_prenom, setinscrit_prenom] = useState("");
const [inscrit_telephone, setinscrit_telephone] = useState("");
const [inscrit_email, setinscrit_email] = useState("");
function init_inscrit_info() {
setselected_session_id("");
setselected_session_code("");
setinscrit_nom("");
setinscrit_prenom("");
setinscrit_telephone("");
setinscrit_email("");
}
return (
<div className="module_atelier_catalogue" >
{/*** Dialog pour reinscrire un apprenant à une session */}
<Dialog
open={Dialog_add_inscription_open}
//onClose={Dialog_add_inscription_handleClose}
className="displaypartnersession"
static
onClose={() => null}
PaperProps={{
className: classes.paper, // Apply the paper style
style: {
overflowY: 'unset',
position: 'absolute',
top: '10rem',
margin: "2px",
},
}}
hideBackdrop={true}
disableScrollLock
classes={{
paper: classes.dialog
}}
PaperComponent={PaperComponent}
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>
<DialogContent className="DialogContent_width">
<div className="div_row" > &nbsp;
</div>
</DialogContent>
<DialogActions>
<IconButton
autoFocus
onClick={Dialog_add_inscription_handleClose_buton}
color="primary"
className={classes.customizedButton}
>
<CancelPresentationIcon />
</IconButton>
<div className="div_row">
<div className="div_row_gauche">
<Button onClick={"Add_Inscription_List_Apprenant"} className="bton_enreg_dialog"> Inscrire</Button>
</div>
<div className="div_row_droite" style={{ "textAlign": 'center' }}>
<Button onClick={Dialog_add_inscription_handleClose_buton} className="bton_annule_dialog" >Fermer</Button>
</div>
</div>
</DialogActions>
</Dialog>
{/*** Fin Dialog pour reinscrire un apprenant à une session */}
<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>
<div className="user-actions">
<button className="notification-btn" aria-label="Notifications">
<Bell size={19} />
<span>2</span>
</button>
<button className="avatar-btn">
AL <ChevronDown size={14} />
</button>
</div>
</header>
<section className="hero-section">
<div>
<h1>Nos ateliers</h1>
<p>Trouvez la formation qui vous correspond et inscrivez-vous à latelier de votre choix.</p>
</div>
<div className="segment-tabs" role="tablist" aria-label="Type de catalogue">
<button
className={activeTab === "formations" ? "active" : ""}
onClick={() => setActiveTab("formations")}
>
Les formations
</button>
<button
className={activeTab === "ateliers" ? "active" : ""}
onClick={() => setActiveTab("ateliers")}
>
Les ateliers
</button>
</div>
</section>
<section className="search-panel" aria-label="Recherche et filtres">
<div className="search-row">
<label className="search-input">
<Search size={22} />
<input placeholder="Rechercher une formation, un thème, un mot-clé…" />
</label>
<button className="sort-btn">
<span>Trier par</span>
<strong>Pertinence</strong>
<ChevronDown size={18} />
</button>
</div>
<div className="filter-row">
<div className="filter-chips">
{filters.map((filter) => (
<button className="filter-chip" key={filter.label}>
{filter.icon}
{filter.label}
</button>
))}
</div>
<button className="reset-btn">Réinitialiser</button>
</div>
</section>
<div className="results-info">
<strong>{props.formations.length}</strong> formations · <strong>{totalAteliers}</strong> ateliers ouverts
</div>
<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>
</main>
<style>{local_css}</style>
</div>
);
}
const local_css = `
.formation-copy h2 {
text-align: justify;
font-family: DM Sans;
}
.formation-copy p {
text-align: justify;
}
`;

View File

@ -0,0 +1,428 @@
import React, { useMemo, useState, useEffect } from "react";
import {
Bell,
BookOpen,
Building2,
CalendarDays,
ChevronDown,
ChevronRight,
Clock3,
Heart,
Home,
Laptop,
MapPin,
Monitor,
Search,
SlidersHorizontal,
Sparkles,
Star,
Tag,
UsersRound,
} from "lucide-react";
import "./AteliersCatalogue.css";
const formations = [
{
_id: "f1",
title: "Poser des règles et des limites aux enfants accueillis",
description:
"Le fonctionnement émotionnel du petit et ses besoins en sécurité pour se développer. Apprenez à poser un cadre bienveillant et sécurisant adapté à chaque enfant.",
image:
"https://images.unsplash.com/photo-1516321497487-e288fb19713f?auto=format&fit=crop&w=900&q=80",
rating: "4,6",
reviews: 128,
price: "270 € HT",
duration: "7 heures",
audience: "Professionnels de la petite enfance",
badge: "Non CPF",
badgeType: "danger",
highlight: "Populaire",
icon: <UsersRound size={22} />,
iconTone: "blue",
ateliers: [
{
code: "ADF_20260421_A",
date: "21 avril 2026",
time: "9h00 17h00",
mode: "Présentiel",
city: "Lyon",
zip: "69003",
places: 6,
cta: "Voir les détails",
},
{
code: "ADF_20260512_D",
date: "12 mai 2026",
time: "9h00 17h00",
mode: "Distanciel",
city: "En ligne",
zip: "",
places: 10,
cta: "Voir les détails",
},
{
code: "ADF_20260616_H",
date: "16 juin 2026",
time: "9h00 17h00",
mode: "Hybride",
city: "Paris",
zip: "75011",
places: 7,
cta: "Sinscrire",
},
],
},
{
_id: "f2",
title: "Accueillir un enfant en situation de handicap",
description:
"Comprendre les différents types de handicap et leurs impacts au quotidien. Adapter laccueil et les pratiques pour favoriser linclusion et le bien-être.",
image:
"https://images.unsplash.com/photo-1544776193-352d25ca82cd?auto=format&fit=crop&w=900&q=80",
rating: "4,8",
reviews: 92,
price: "Gratuit",
duration: "7 heures",
audience: "Professionnels de la petite enfance",
badge: "CPF",
badgeType: "success",
highlight: "Nouveau",
icon: <Sparkles size={22} />,
iconTone: "green",
ateliers: [
{
code: "ADF_20260505_P",
date: "5 mai 2026",
time: "9h00 17h00",
mode: "Présentiel",
city: "Marseille",
zip: "13002",
places: 8,
cta: "Voir les détails",
},
{
code: "ADF_20260602_D",
date: "2 juin 2026",
time: "9h00 17h00",
mode: "Distanciel",
city: "En ligne",
zip: "",
places: 12,
cta: "Sinscrire",
},
],
},
{
_id: "f3",
title: "Développer le langage chez le jeune enfant",
description:
"Stimuler le langage oral et accompagner les premières acquisitions à travers des jeux, des histoires et des interactions adaptées.",
image:
"https://images.unsplash.com/photo-1503676260728-1c00da094a0b?auto=format&fit=crop&w=900&q=80",
rating: "4,5",
reviews: 76,
price: "210 € HT",
duration: "7 heures",
audience: "Professionnels de la petite enfance",
badge: "CPF",
badgeType: "success",
highlight: "Populaire",
icon: <BookOpen size={22} />,
iconTone: "purple",
ateliers: [
{
code: "ADF_20260428_L",
date: "28 avril 2026",
time: "9h00 17h00",
mode: "Présentiel",
city: "Lille",
zip: "59000",
places: 9,
cta: "Voir les détails",
},
{
code: "ADF_20260519_D",
date: "19 mai 2026",
time: "9h00 17h00",
mode: "Distanciel",
city: "En ligne",
zip: "",
places: 15,
cta: "Voir les détails",
},
{
code: "ADF_20260609_H",
date: "9 juin 2026",
time: "9h00 17h00",
mode: "Hybride",
city: "Toulouse",
zip: "31000",
places: 6,
cta: "Sinscrire",
},
],
},
];
const filters = [
{ label: "Tous les filtres", icon: <SlidersHorizontal size={16} /> },
{ label: "Présentiel", icon: <Building2 size={16} /> },
{ label: "Distanciel", icon: <Monitor size={16} /> },
{ label: "Hybride", icon: <Laptop size={16} /> },
{ label: "CPF", icon: <Sparkles size={16} /> },
{ label: "Gratuit", icon: <Tag size={16} /> },
{ label: "Payant", icon: <Tag size={16} /> },
];
function Stars() {
return (
<div className="module_atelier_catalogue rating-stars" aria-label="Note formation">
{[1, 2, 3, 4, 5].map((item) => (
<Star key={item} size={15} fill="currentColor" />
))}
</div>
);
}
function ModeIcon({ mode }) {
if (mode === "Distanciel") return <Monitor size={20} />;
if (mode === "Hybride") return <Laptop size={20} />;
return <Building2 size={20} />;
}
function FormationCard({ 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 className="formation-card__content">
<div className={`formation-icon formation-icon--${formation.iconTone}`}>
{formation.icon}
</div>
<div className="formation-copy">
<h2>{formation.title}</h2>
<p>{formation.description}</p>
<div className="rating-line">
<Stars />
<span>{formation.rating} ({formation.reviews} avis)</span>
</div>
</div>
</div>
<aside className="formation-card__meta">
<div className="badges">
<span className={`badge badge--${formation.badgeType}`}>{formation.badge}</span>
<span className="badge badge--soft">{formation.highlight}</span>
</div>
<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>
<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_ORIG(props) {
const [activeTab, setActiveTab] = useState("formations");
const totalAteliers = useMemo(
() => formations.reduce((acc, formation) => acc + formation.ateliers.length, 0),
[]
);
useEffect(() => {
console.log(" ### props.formations = ", props.formations)
}, [])
return (
<div className="module_atelier_catalogue" >
<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>
<div className="user-actions">
<button className="notification-btn" aria-label="Notifications">
<Bell size={19} />
<span>2</span>
</button>
<button className="avatar-btn">
AL <ChevronDown size={14} />
</button>
</div>
</header>
<section className="hero-section">
<div>
<h1>Nos ateliers</h1>
<p>Trouvez la formation qui vous correspond et inscrivez-vous à latelier de votre choix.</p>
</div>
<div className="segment-tabs" role="tablist" aria-label="Type de catalogue">
<button
className={activeTab === "formations" ? "active" : ""}
onClick={() => setActiveTab("formations")}
>
Les formations
</button>
<button
className={activeTab === "ateliers" ? "active" : ""}
onClick={() => setActiveTab("ateliers")}
>
Les ateliers
</button>
</div>
</section>
<section className="search-panel" aria-label="Recherche et filtres">
<div className="search-row">
<label className="search-input">
<Search size={22} />
<input placeholder="Rechercher une formation, un thème, un mot-clé…" />
</label>
<button className="sort-btn">
<span>Trier par</span>
<strong>Pertinence</strong>
<ChevronDown size={18} />
</button>
</div>
<div className="filter-row">
<div className="filter-chips">
{filters.map((filter) => (
<button className="filter-chip" key={filter.label}>
{filter.icon}
{filter.label}
</button>
))}
</div>
<button className="reset-btn">Réinitialiser</button>
</div>
</section>
<div className="results-info">
<strong>{formations.length}</strong> formations · <strong>{totalAteliers}</strong> ateliers ouverts
</div>
<section className="formation-list">
{formations.map((formation) => (
<FormationCard formation={formation} key={formation._id} />
))}
</section>
</main>
</div>
);
}

View File

@ -1196,6 +1196,7 @@ const Module_Session_Planification = (props) => {
setAdd_One_Sequence_Session_Ressource_result(res.data.message);
Getall_List_Sequence_Ressource(selected_sequence_id);
Getall_Sequence_Of_Session(selected_session_id);
setDialog_seq_ressource_1_selected_type_ressource("");
setDialog_seq_ressource_1_selected_ressource_id("");
@ -1275,7 +1276,7 @@ const Module_Session_Planification = (props) => {
setAdd_One_Ressource_Fom_Dialog_Sequence_result(res.data.message);
Getall_List_Sequence_Ressource(selected_sequence_id);
Getall_Sequence_Of_Session(selected_session_id);
setDialog_seq_ressource_1_selected_type_ressource("");
setDialog_seq_ressource_1_selected_ressource_id("");
setDialog_seq_ressource_1_selected_ressource_poste("");
@ -1668,7 +1669,7 @@ const Module_Session_Planification = (props) => {
setAdd_One_Sequence_Session_Ressource_Mass_result(res.data.message);
Getall_List_Sequence_Ressource(selected_sequence_id);
Getall_Sequence_Of_Session(selected_session_id);
setDialog_seq_ressource_1_selected_type_ressource("");
setDialog_seq_ressource_1_selected_ressource_id("");
setDialog_seq_ressource_1_selected_ressource_poste("");
@ -1824,7 +1825,7 @@ const Module_Session_Planification = (props) => {
local_session_color = "#3573CB"
}
// console.log(" ## PROMO local_session_color = ", local_session_color)
// console.log(" ## PROMO local_session_color = ", local_session_color)
//---
var node = {
"_id": local_id,
@ -2831,6 +2832,8 @@ const Module_Session_Planification = (props) => {
setGet_Ressource_Avabilities_avability_check("");
setcheck_ressource_avabilities("");
setDialog_seq_ressource_1_open(false);
};
const handleEventClick = (arg) => {
@ -7275,7 +7278,7 @@ const Module_Session_Planification = (props) => {
setp_detail_sequence_ue_id(value._id);
Get_List_Given_UE_Planif_lines(value._id);
setp_detail_sequence_title(Distinct_UE_New_Getall_Session_List_UE_result.filter((data) => (data)._id === String(value._id))[0].label);
// console.log(" domaine_competence_id = ", value.domaine_competence_id);
// console.log(" domaine_competence_id = ", value.domaine_competence_id);
setp_detail_sequence_domaine_competence_id(value.domaine_competence_id);
} else {
setp_detail_sequence_ue_id("");
@ -7341,32 +7344,32 @@ const Module_Session_Planification = (props) => {
<div className="session_caract_Dialog" style={{ width: '50%' }}> Groupe apprenants
{New_Getall_Partner_Groupe_Inscrit_result && New_Getall_Partner_Groupe_Inscrit_result.length > 0 &&
<Autocomplete
disablePortal
name="event_dialog_grp_apprenant"
id="event_dialog_grp_apprenant"
{New_Getall_Partner_Groupe_Inscrit_result && New_Getall_Partner_Groupe_Inscrit_result.length > 0 &&
<Autocomplete
disablePortal
name="event_dialog_grp_apprenant"
id="event_dialog_grp_apprenant"
fullWidth
// value={New_Getall_Partner_Groupe_Inscrit_result.filter((data) => (data)._id === String(p_detail_sequence_groupe_apprenant_id))[0].label}
options={New_Getall_Partner_Groupe_Inscrit_result}
fullWidth
// value={New_Getall_Partner_Groupe_Inscrit_result.filter((data) => (data)._id === String(p_detail_sequence_groupe_apprenant_id))[0].label}
options={New_Getall_Partner_Groupe_Inscrit_result}
multiple
onChange={(event, newValue) => {
setval_grp_apprenant([
...fixedVal_grp_apprenant,
...newValue.filter((i) => fixedVal_grp_apprenant.indexOf(i) === -1),
]);
multiple
onChange={(event, newValue) => {
setval_grp_apprenant([
...fixedVal_grp_apprenant,
...newValue.filter((i) => fixedVal_grp_apprenant.indexOf(i) === -1),
]);
}}
value={val_grp_apprenant}
}}
value={val_grp_apprenant}
renderInput={(params) => <TextField {...params} placeholder="Choisir une option " />
}
/>}
renderInput={(params) => <TextField {...params} placeholder="Choisir une option " />
}
/>}
</div>
@ -7628,8 +7631,8 @@ const Module_Session_Planification = (props) => {
</div>
)}
</Popup>
<Button onClick={Dialog_DIALOG_AGENDA_handleClose_buton} className="bton_annule_dialog" style={{ width: '40%', float: 'left' }}>Fermer</Button>
<Button onClick={Dialog_DIALOG_AGENDA_handleClose_buton} className="bton_annule_dialog" style={{ width: '40%', float: 'left' }}>Fermer</Button>
</div>}
</div>
@ -8005,14 +8008,14 @@ const Module_Session_Planification = (props) => {
{display_view && String(display_view) === "planning" && Getall_Sequence_Of_Session_result_planning_view &&
<div style={{ "border": "None" }} >
&nbsp;
&nbsp;
<div style={{ "width": "98%", "marginLeft": "5px", padding: '10px', fontFamily: 'DM Sans', fontSize: '14px', background: '#FFF' }} >
<FullCalendar
height={750}
locales={allLocales}
locale={'fr'}
locale={'fr'}
editable
selectable
//events={events}

View File

@ -3,7 +3,7 @@ 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 { IoAppsSharp, IoListSharp } from "react-icons/io5";
import Formation_Grid_2Col from "./Formation_Grid_2Col";
import Pagination from "./TestPagination";
@ -11,13 +11,15 @@ import Pagination from "./TestPagination";
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 Fotter_Catalog_Pub from "./Fotter_Catalog_Pub";
import img_header_jmg from "../mysy_img2/img_jmj_modif.jpg"
import Formation_Partner_Catalog_Special_JMJFormation from "./Jmj_Theme/Formation_Partner_Catalog_Special_JMJFormation";
import Session_Partner_Catalog_Special_Partner from "./Jmj_Theme/Session_Partner_Catalog_Special_Partner";
import Module_Atelier_Catalogue from "./Module_Atelier_Catalogue";
import "./Jmj_Theme/jmj_formation.css";
import { confirmAlert } from 'react-confirm-alert'; // Import
@ -28,6 +30,7 @@ import tick_ko from "../mysy_img/tick_KO.png";
import img_header from "../mysy_img2/img_header.png"
import { TbArrowsDownUp } from "react-icons/tb";
import { CiCircleRemove, CiCircleMinus } from "react-icons/ci";
import Button from "./marketplace_2026/Button";
let PageSize = 10;
const Mon_Catalogue_Public = (props) => {
@ -1041,16 +1044,11 @@ const Mon_Catalogue_Public = (props) => {
whosisconnected();
if (categorie) {
//console.log(" ### categorie = ", categorie);
setmymetier(categorie);
} else {
setmymetier();
}
//document.getElementById("_1234").checked = true;
}, [initAllfiter, categorie]);
@ -1319,7 +1317,7 @@ const Mon_Catalogue_Public = (props) => {
form.append("user_state", state);
form.append("subdomain", window.location.host.split(".")[0]);
var myurl = ""
if (displayAllClasses == true) {
myurl = process.env.REACT_APP_API_URL + "myclass/api/get_all_class_Given_partner_owner_recid_No_Login/";
@ -1333,7 +1331,7 @@ const Mon_Catalogue_Public = (props) => {
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 test res.data.message = " + res.data.message);
setmyApiResponse("True");
setResult(res.data.message)
@ -1397,7 +1395,7 @@ const Mon_Catalogue_Public = (props) => {
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/";
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])
@ -1475,11 +1473,11 @@ const Mon_Catalogue_Public = (props) => {
}
//alert("myurl = " + myurl);
// 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 DisplayXfirstClas res.data.message = " + res.data.message);
// console.log(" In DisplayXfirstClas res.data.message = " + res.data.message);
setmyApiResponse("True");
setResult(res.data.message)
@ -2528,11 +2526,11 @@ const Mon_Catalogue_Public = (props) => {
domain = url.split('://')[1];
}
// console.log(" ### local_url_subdomain = ", local_url_subdomain);
// console.log(" ### local_url_subdomain = ", local_url_subdomain);
const subdomain = domain.split('.')[0];
// console.log(" ### subdomain = ", subdomain);
// console.log(" ### subdomain = ", subdomain);
var form = new FormData();
@ -2543,8 +2541,8 @@ const Mon_Catalogue_Public = (props) => {
axios.post(myurl, form).then(res => {
if (String(res.data.status) === "true") {
// console.log(" In Get_Subdomain_Partner_Data res.data.status = " + res.data.status);
// console.log(" In Get_Subdomain_Partner_Data res.data.message r_class = " + res.data.message);
// console.log(" In Get_Subdomain_Partner_Data res.data.status = " + res.data.status);
// console.log(" In Get_Subdomain_Partner_Data res.data.message r_class = " + res.data.message);
setGet_Subdomain_Partner_Data_api("true");
setGet_Subdomain_Partner_Data_result(res.data.message);
@ -2723,7 +2721,7 @@ const Mon_Catalogue_Public = (props) => {
if (JSON.parse(x).affiche_contact)
catalog_pub_affiche_contact = JSON.parse(x).affiche_contact;
// console.log(" ### setmy_theme_code = ", theme_code);
// console.log(" ### setmy_theme_code = ", theme_code);
//---
@ -2789,7 +2787,7 @@ const Mon_Catalogue_Public = (props) => {
"affiche_contact": catalog_pub_affiche_contact,
};
// console.log(" --- node = ", node);
// console.log(" --- node = ", node);
new_data2.push(node);
});
@ -2834,6 +2832,8 @@ const Mon_Catalogue_Public = (props) => {
}
const [display_formation_session, setdisplay_formation_session] = useState("formation");
return (
@ -2876,7 +2876,7 @@ const Mon_Catalogue_Public = (props) => {
&nbsp;
</div>
</div>
<div className="bloc_milieu_model_2">
@ -2952,7 +2952,7 @@ const Mon_Catalogue_Public = (props) => {
</div>}
{String(New_Get_Subdomain_Partner_Data_result[0].affiche_contact) === "1" && <div className="bloc_milieu_text_model_2_droite">
<font className="bloc_logo_indic_contact_text_model_2"> Contact </font> <br />
@ -2973,7 +2973,7 @@ const Mon_Catalogue_Public = (props) => {
</div>
<div className="block_nos_formation">
<div style={{ "width": "100%", maxWidth:'1500px', margin:'auto' }}>
<div style={{ "width": "100%", maxWidth: '1500px', margin: 'auto' }}>
<div className="forma_et_tuto"> Nos Formations & Tutoriels</div>
{showelement === "true" && <div onClick={showdisplayfilter} className="recherchefilter">
@ -4823,7 +4823,24 @@ const Mon_Catalogue_Public = (props) => {
<div className="jmj_block_milieu_droite">
<div className="rech_middlebox" id="rech_middlebox" style={{ width: '100%' }}>
<div> <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' }}>
<Button style={{ "width": "40%", float: 'left' }}
onClick={(e) => {
setdisplay_formation_session("formation")
}}
> Les Ftion </Button>
<Button style={{ "width": "40%", float: 'left' }}
onClick={(e) => {
setdisplay_formation_session("session")
}}
> Les Ateliers </Button>
</div>
<div style={{
display: 'flex', flexDirection: 'row', justifyContent: 'center', width: '100%', flexWrap: 'wrap',
@ -4878,7 +4895,7 @@ const Mon_Catalogue_Public = (props) => {
</div>
<div style={{ width: '100%', marginBottom:"1rem" }}>
{display_formation_session !== "session" && <div style={{ width: '100%', marginBottom: "1rem" }}>
<div className="block_display_flex_formation" style={{ width: '100%' }}>
@ -4925,7 +4942,65 @@ const Mon_Catalogue_Public = (props) => {
))}
</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} />
</div>}
</div>

File diff suppressed because it is too large Load Diff

View File

@ -2429,7 +2429,7 @@ const Partner_Facture = (props) => {
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
console.log(" ### form = ", form)
// console.log(" ### form = ", form)
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_List_Partner_Invoice_with_filter/";
setLoading(true);

View File

@ -298,7 +298,7 @@ const Header_ENT_Student = () => {
removeCookie("tokenmysychapprenant");
removeCookie("tokenmysych");
// removeCookie("tokenmysych");
removeCookie("tokenmysychconnecteduserid");
removeCookie("tokenmysytypeconnexion");
@ -328,7 +328,7 @@ const Header_ENT_Student = () => {
removeCookie("tokenmysychapprenant");
removeCookie("tokenmysych");
removeCookie("tokenmysypart");
// removeCookie("tokenmysypart");
removeCookie("tokenmysytuteurrhid",);
removeCookie("tokenmysychconnecteduserid");
removeCookie("tokenmysytypeconnexion");

View File

@ -0,0 +1,719 @@
.module_atelier_catalogue {
width: 100%;
float: left;
:root {
--mysy-blue: #104277;
--mysy-blue-2: #0f56bd;
--mysy-blue-3: #eaf2ff;
--text: #071943;
--muted: #63708c;
--border: #dbe4f2;
--soft-border: #edf2fa;
--bg: #f3f6fc;
--card: #ffffff;
--green: #11985a;
--green-bg: #e9fbf2;
--red: #c8203a;
--red-bg: #ffedf1;
--shadow: 0 14px 40px rgba(16, 66, 119, 0.1);
--shadow-soft: 0 8px 22px rgba(16, 66, 119, 0.08);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: "DM Sans", Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: var(--bg);
color: var(--text);
}
button,
input {
font: inherit;
}
button {
cursor: pointer;
}
.catalogue-page {
min-height: 100vh;
padding-bottom: 56px;
}
.topbar {
height: 72px;
display: flex;
align-items: center;
gap: 32px;
padding: 0 56px;
background: rgba(255, 255, 255, 0.92);
border-bottom: 1px solid var(--soft-border);
position: sticky;
top: 0;
z-index: 20;
backdrop-filter: blur(14px);
}
.brand {
font-size: 28px;
font-weight: 900;
letter-spacing: -1px;
color: var(--mysy-blue);
white-space: nowrap;
}
.brand span {
font-weight: 700;
}
.nav-links {
display: flex;
align-items: stretch;
gap: 8px;
height: 100%;
flex: 1;
justify-content: center;
}
.nav-link {
display: flex;
align-items: center;
gap: 8px;
padding: 0 14px;
color: #697590;
text-decoration: none;
border-bottom: 3px solid transparent;
font-size: 14px;
font-weight: 700;
}
.nav-link--active {
color: var(--mysy-blue-2);
border-color: var(--mysy-blue-2);
}
.user-actions {
display: flex;
align-items: center;
gap: 14px;
}
.notification-btn,
.avatar-btn {
border: 0;
background: transparent;
}
.notification-btn {
position: relative;
width: 42px;
height: 42px;
display: grid;
place-items: center;
color: #31405f;
}
.notification-btn span {
position: absolute;
top: 7px;
right: 5px;
background: #e43145;
color: #fff;
min-width: 17px;
height: 17px;
border-radius: 999px;
display: grid;
place-items: center;
font-size: 10px;
font-weight: 800;
}
.avatar-btn {
display: inline-flex;
align-items: center;
gap: 7px;
background: var(--mysy-blue);
color: #fff;
padding: 10px 12px;
border-radius: 999px;
font-weight: 800;
}
.hero-section,
.search-panel,
.results-info,
.formation-list {
width: min(1320px, calc(100% - 64px));
margin-left: auto;
margin-right: auto;
}
.hero-section {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 24px;
padding: 42px 0 22px;
}
.hero-section h1 {
margin: 0;
font-size: clamp(34px, 4vw, 46px);
letter-spacing: -1.4px;
line-height: 1.05;
}
.hero-section p {
margin: 10px 0 0;
color: var(--muted);
font-size: 16px;
}
.segment-tabs {
display: flex;
padding: 5px;
border: 1px solid var(--border);
border-radius: 999px;
background: #fff;
min-width: 360px;
box-shadow: var(--shadow-soft);
}
.segment-tabs button {
flex: 1;
border: 0;
background: transparent;
color: var(--mysy-blue);
padding: 14px 26px;
border-radius: 999px;
font-weight: 800;
}
.segment-tabs button.active {
background: linear-gradient(135deg, var(--mysy-blue), #0d56c4);
color: #fff;
box-shadow: 0 10px 22px rgba(15, 86, 196, 0.22);
}
.search-panel {
background: #fff;
border: 1px solid var(--border);
border-radius: 18px;
padding: 20px;
box-shadow: var(--shadow);
}
.search-row {
display: grid;
grid-template-columns: 1fr 180px;
gap: 18px;
}
.search-input {
display: flex;
align-items: center;
gap: 12px;
height: 62px;
border: 1px solid #c8d7eb;
border-radius: 12px;
padding: 0 18px;
color: #71809b;
background: #fff;
}
.search-input input {
border: 0;
outline: 0;
flex: 1;
color: var(--text);
font-size: 15px;
}
.sort-btn {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
text-align: left;
gap: 2px 12px;
height: 62px;
border: 1px solid #c8d7eb;
background: #fff;
border-radius: 12px;
padding: 0 16px;
color: var(--text);
}
.sort-btn span {
font-size: 12px;
color: var(--muted);
}
.sort-btn svg {
grid-row: 1 / span 2;
grid-column: 2;
}
.filter-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
margin-top: 20px;
}
.filter-chips {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.filter-chip {
display: inline-flex;
align-items: center;
gap: 8px;
height: 44px;
padding: 0 16px;
border: 1px solid var(--border);
border-radius: 10px;
color: var(--mysy-blue-2);
background: linear-gradient(180deg, #fff, #f8fbff);
font-weight: 800;
font-size: 14px;
}
.filter-chip:hover {
border-color: #aac3e8;
box-shadow: 0 7px 16px rgba(16, 66, 119, 0.08);
}
.reset-btn,
.program-btn {
border: 0;
background: transparent;
color: var(--mysy-blue-2);
font-weight: 800;
}
.results-info {
margin-top: 22px;
color: var(--muted);
font-size: 15px;
}
.results-info strong {
color: var(--text);
}
.formation-list {
display: grid;
gap: 22px;
margin-top: 16px;
}
.formation-card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 18px;
box-shadow: var(--shadow-soft);
overflow: hidden;
}
.formation-card__main {
display: grid;
grid-template-columns: 320px 1fr 250px;
gap: 28px;
padding: 22px;
}
.formation-card__image-wrap {
position: relative;
min-height: 190px;
}
.formation-card__image {
display: block;
width: 100%;
height: 190px;
object-fit: cover;
border-radius: 14px;
}
.favorite-btn {
position: absolute;
top: 12px;
right: 12px;
width: 38px;
height: 38px;
border: 1px solid rgba(255, 255, 255, 0.8);
border-radius: 12px;
display: grid;
place-items: center;
background: rgba(255, 255, 255, 0.86);
color: #78859d;
backdrop-filter: blur(8px);
}
.favorite-btn:hover {
color: #e43145;
}
.formation-card__content {
display: grid;
grid-template-columns: 54px 1fr;
gap: 18px;
align-items: flex-start;
padding-top: 8px;
}
.formation-icon {
width: 54px;
height: 54px;
display: grid;
place-items: center;
border-radius: 18px;
color: var(--mysy-blue-2);
background: var(--mysy-blue-3);
}
.formation-icon--green {
color: #0f8b53;
background: #e9fbf2;
}
.formation-icon--purple {
color: #7457e7;
background: #f1edff;
}
.formation-copy h2 {
margin: 0 0 12px;
color: var(--mysy-blue);
font-size: 28px;
line-height: 1.15;
letter-spacing: -0.7px;
}
.formation-copy p {
max-width: 700px;
margin: 0;
color: #475572;
line-height: 1.55;
}
.rating-line {
display: flex;
align-items: center;
gap: 10px;
margin-top: 16px;
font-weight: 800;
color: #3e4b65;
font-size: 14px;
}
.rating-stars {
display: inline-flex;
gap: 2px;
color: #f6ad19;
}
.formation-card__meta {
padding-top: 6px;
}
.badges {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 22px;
}
.badge {
display: inline-flex;
align-items: center;
border-radius: 999px;
padding: 8px 12px;
font-size: 12px;
font-weight: 900;
}
.badge--danger {
color: var(--red);
background: var(--red-bg);
}
.badge--success {
color: var(--green);
background: var(--green-bg);
}
.badge--soft {
color: var(--mysy-blue-2);
background: var(--mysy-blue-3);
}
.meta-list {
display: grid;
gap: 16px;
}
.meta-item {
display: grid;
grid-template-columns: 24px 1fr;
gap: 12px;
align-items: flex-start;
color: #53617d;
}
.meta-item span,
.workshop-cell span {
display: block;
color: var(--muted);
font-size: 12px;
font-weight: 600;
}
.meta-item strong,
.workshop-cell strong {
display: block;
margin-top: 2px;
color: var(--text);
font-size: 14px;
line-height: 1.25;
}
.meta-item .price {
color: var(--mysy-blue-2);
font-size: 19px;
font-weight: 900;
}
.meta-item .price-free {
color: var(--green);
font-size: 19px;
font-weight: 900;
}
.workshops {
border-top: 1px solid var(--soft-border);
padding: 0 18px 18px;
}
.workshops__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
padding: 18px 0 12px;
}
.workshops__header>div {
display: flex;
align-items: center;
gap: 10px;
color: var(--mysy-blue);
font-size: 18px;
}
.workshops__header span {
min-width: 28px;
height: 26px;
padding: 0 9px;
border-radius: 999px;
display: inline-grid;
place-items: center;
background: var(--mysy-blue-3);
color: var(--mysy-blue-2);
font-weight: 900;
font-size: 13px;
}
.program-btn {
display: inline-flex;
align-items: center;
gap: 4px;
}
.workshops__list {
border: 1px solid var(--border);
border-radius: 14px;
overflow: hidden;
background: #fff;
}
.workshop-row {
display: grid;
grid-template-columns: 1.5fr 1.5fr 1.2fr 1.15fr 1.15fr 144px;
align-items: center;
gap: 16px;
min-height: 72px;
padding: 10px 14px;
}
.workshop-row+.workshop-row {
border-top: 1px solid var(--soft-border);
}
.workshop-row:hover {
background: #f8fbff;
}
.workshop-cell {
min-width: 0;
display: grid;
grid-template-columns: 24px 1fr;
align-items: center;
gap: 10px;
color: var(--mysy-blue-2);
}
.workshop-code {
display: block;
padding-left: 6px;
}
.workshop-code strong {
color: var(--mysy-blue);
}
.workshop-places span {
color: var(--green);
}
.details-btn {
border: 0;
background: linear-gradient(135deg, var(--mysy-blue), #0d56c4);
color: #fff;
height: 42px;
border-radius: 9px;
font-weight: 900;
box-shadow: 0 9px 18px rgba(16, 66, 119, 0.18);
}
.details-btn:hover {
filter: brightness(1.04);
transform: translateY(-1px);
}
@media (max-width: 1120px) {
.topbar {
padding: 0 24px;
}
.nav-links {
display: none;
}
.formation-card__main {
grid-template-columns: 240px 1fr;
}
.formation-card__meta {
grid-column: 1 / -1;
display: flex;
justify-content: space-between;
gap: 22px;
}
.meta-list {
grid-template-columns: repeat(3, 1fr);
flex: 1;
}
.workshop-row {
grid-template-columns: 1.2fr 1.4fr 1fr 1fr;
}
.workshop-row .workshop-cell:nth-of-type(5),
.details-btn {
grid-column: span 2;
}
}
@media (max-width: 760px) {
.hero-section,
.search-panel,
.results-info,
.formation-list {
width: min(100% - 28px, 1320px);
}
.topbar {
height: auto;
min-height: 68px;
}
.hero-section {
flex-direction: column;
padding-top: 26px;
}
.segment-tabs {
width: 100%;
min-width: 0;
}
.search-row {
grid-template-columns: 1fr;
}
.filter-row {
align-items: flex-start;
flex-direction: column;
}
.formation-card__main {
grid-template-columns: 1fr;
gap: 20px;
}
.formation-card__image {
height: 220px;
}
.formation-card__content {
grid-template-columns: 1fr;
}
.formation-card__meta {
display: block;
}
.meta-list {
grid-template-columns: 1fr;
}
.formation-copy h2 {
font-size: 24px;
}
.workshops__header {
align-items: flex-start;
flex-direction: column;
}
.workshop-row {
grid-template-columns: 1fr;
gap: 12px;
padding: 16px;
}
.workshop-row .workshop-cell:nth-of-type(5),
.details-btn {
grid-column: auto;
}
.details-btn {
width: 100%;
}
}
}

View File

@ -504,7 +504,7 @@
font-size: small !important;
color: black;
width: 90% !important;
height: 3.5rem !important;
height: 3rem !important;
margin: 5px !important;
//border: none !important;
border-radius: 5px;
@ -641,7 +641,7 @@
font-size: small !important;
color: black;
width: 90% !important;
height: 3.5rem !important;
height: 3rem !important;
margin: 5px !important;
//border: none !important;
border-radius: 5px;

View File

@ -224,6 +224,7 @@
@import "./components/module_gestion_stage";
@import "./components/module_inscrit_suivi_paiement";
@import "./components/module_relance_client_facture";
@import "./components/module_atelier_catalogue";
// New Design 2025