maintenant le problème c’est que lorsqu’on clique sur un artiste appartenant a un groupe et qu’on fait retour, toutes les cardes avec l’id de ce groupe font retour arrière aussi, il faut différencier la card avec quelque chose en plus que l’id groupe : import { useEffect, useState, useRef, useLayoutEffect } from “react”;
import SearchBar from “…/…/components/form/SearchBar”;
import Combo from “…/…/components/form/Combo”;
import CarteArtiste from “…/…/components/Artiste/CarteProgrammation”;
import { motion } from “framer-motion”;
import { useLocation } from “react-router-dom”;
import axios from “axios”;
import Footer from “…/…/components/footer”;
import CarteProgrammation from “…/…/components/Artiste/CarteProgrammation”;
import { AnimatePresence } from “framer-motion”;


type Props = {
isNavInFocus: boolean;
setIsNavTransparent: (isNavTransparent: boolean) => void;
};

type Groupe = {
idG: number;
nomG: string;
descriptionG: string;
datePassage: string;
heurePassage: string;
};

type Artiste = {
descriptionA?: string;
idMG?: number;
idG: number;
nomDeSceneMG: string;
nomMG: string;
prenomMG?: string;
datePassage?: string;
heurePassage?: string;
};

type Evenement = {
dateDebutE: string;
dateFinE: string;
heureDebutE: string;
heureFinE: string;
idE: number;
idG: number;
idL: number | null;
nomE: string;
};

type Programme = Groupe | Evenement | Artiste;

export default function Programmation(props: Props) {
const location = useLocation();
const idArtistComingFrom = location.state?.comesFromPageArtist;
const oldX = location.state?.oldX;
const oldY = location.state?.oldY;
const oldGroupes = location.state?.oldGroupes;
const [searchTerm, setSearchTerm] = useState(“”);

window.history.replaceState({}, document.title);
const [lesGroupes, setLesGroupes] = useState<Groupe[]>(location.state ? oldGroupes : []);
const [lesArtistes, setLesArtistes] = useState<Artiste[]>([]);
const groupePassageMap = useRef<
Map<number, { datePassage: string; heurePassage: string }>
>(new Map());

useEffect(() => {
axios.get(“http://localhost:8080/getGroupesWithEvenements”).then((res) => {
const groupedData = res.data as Programme[][];
console.log(“groupedData”)
console.log(groupedData);

const listeGroupes: Groupe[] = [];
const groupSet = new Set<number>();
const listeArtistes: Artiste[] = [];

groupedData.forEach((groupArray) => {
let groupeObj: Partial<Groupe> = {};
let artisteObj: Partial<Artiste> = {};

groupArray.forEach((item) => {
if (“nomG” in item) {
groupeObj = { …groupeObj, …item };
} else if (“nomDeSceneMG” in item) {
artisteObj = { …artisteObj, …item };
} else if (“dateDebutE” in item) {
const datePassage = item.dateDebutE;
const heurePassage = item.heureDebutE;
if (groupeObj.idG === item.idG) {
groupeObj.datePassage = datePassage;
groupeObj.heurePassage = heurePassage;
}
if (artisteObj.idG === item.idG) {
artisteObj.datePassage = datePassage;
artisteObj.heurePassage = heurePassage;
}
}
});

// si l’id n’a pas encore était ajoutée à la liste on ajoute le groupe
if (groupeObj.idG !== undefined && !groupSet.has(groupeObj.idG)) {
listeGroupes.push(groupeObj as Groupe);
groupSet.add(groupeObj.idG);
}
if (artisteObj.nomDeSceneMG !== undefined) {
listeArtistes.push(artisteObj as Artiste);
}
});

setLesGroupes(listeGroupes);
// console.log(listeGroupes);
groupePassageMap.current.clear();
listeGroupes.forEach((groupe) => {
groupePassageMap.current.set(groupe.idG, {
datePassage: groupe.datePassage,
heurePassage: groupe.heurePassage,
});
});

setLesArtistes(listeArtistes);
});
}, []);

// let filteredGroupes = lesGroupes;
// if (searchTerm) {
// filteredGroupes = lesGroupes.filter((groupe) =>
// groupe.nomG.toLowerCase().includes(searchTerm.toLowerCase())
// );
// }
// let filteredArtistes = lesArtistes;
// if (searchTerm) {
// filteredArtistes = lesArtistes.filter((artiste) =>
// artiste.nomDeSceneMG.toLowerCase().includes(searchTerm.toLowerCase())
// )
// }



const [filtreDate, setFiltreDate] = useState(“Tout”);
console.log(filtreDate)
let termeRechercher = ‘Tout’;

if (filtreDate === ‘21 Juillet’) {
termeRechercher = ‘07-21’;
}
else if (filtreDate === ‘22 Juillet’) {
termeRechercher = ‘07-22’;
}
else if (filtreDate === ‘23 Juillet’) {
termeRechercher = ‘07-23’;
}


let filteredGroupes = lesGroupes;
if (searchTerm) {
filteredGroupes = filteredGroupes.filter((groupe) =>
groupe.nomG.toLowerCase().includes(searchTerm.toLowerCase())
);
}
if (filtreDate !== ‘Tout’) {
console.log(termeRechercher)
filteredGroupes = filteredGroupes.filter((groupe) => {
console.log(groupe.datePassage);
return groupe.datePassage.includes(termeRechercher);
});
}

let filteredArtistes = lesArtistes;
if (searchTerm) {
filteredArtistes = filteredArtistes.filter((artiste) =>
artiste.nomDeSceneMG.toLowerCase().includes(searchTerm.toLowerCase())
);
}
if (filtreDate !== ‘Tout’) {
filteredArtistes = filteredArtistes.filter((artiste) => {
const groupeInfo = groupePassageMap.current.get(artiste.idG);
return groupeInfo?.datePassage.includes(termeRechercher);
});
}

console.log(filteredGroupes);
console.log(filteredArtistes);
const [filtreAffichage, setFiltreAffichage] = useState(“Grille”);
const [filtreGenre, setFiltreGenre] = useState(“Tout”);

const pageRef = useRef<HTMLDivElement>(null);

const contentVariants = {
visible: {
filter: “blur(0px)”,
scale: 1,
zIndex: 1,
transition: {
duration: 0.5,
ease: [1, 0, 0, 1],
},
},
hidden: {
filter: “blur(10px)”,
scale: 0.8,
zIndex: -1,
transition: {
duration: 0.5,
ease: [1, 0, 0, 1],
},
},
};

useEffect(() => {
window.scrollTo(0, 0);
props.setIsNavTransparent(false);
}, []);

return (
<>
<motion.div
id=“Programmation”
className=“page-defaut”
variants={contentVariants}
animate={props.isNavInFocus ? “hidden” : “visible”}
ref={pageRef}
>
<header>
<div className=“title”>
<h2>PROGRAMMATION</h2>
<svg
width=“64”
height=“64”
viewBox=“0 0 64 64”
fill=“none”
xmlns=“http://www.w3.org/2000/svg”
>
<path
d=“M62.9991 27.739L42.1815 27.7675L56.8787 13.0286L50.7001 6.86056L36.0029 21.5994L35.9744 0.785744L27.2406 0.797718L27.2692 21.6114L12.5316 6.91288L6.36413 13.0979L21.1017 27.7964L0.289932 27.825L0.301899 36.5537L21.1137 36.5251L6.41646 51.2641L12.6009 57.4321L27.2981 42.6932L27.3266 63.5069L36.0603 63.4949L36.0318 42.6812L50.7694 57.3798L56.931 51.1948L42.1934 36.4962L63.011 36.4677L62.9991 27.739Z”
fill=“#FFD600”
/>
</svg>
</div>
<div className=“filters-container”>
<div className=“filters”>
<Combo
title=“DATE”
choices={[“Tout”, “21 Juillet”, “22 Juillet”, “23 Juillet”]}
currentChoice={filtreDate}
setCurrentChoice={setFiltreDate}
/>
<Combo
title=“AFFICHAGE”
choices={[“Grille”, “Horaires”]}
currentChoice={filtreAffichage}
setCurrentChoice={setFiltreAffichage}
/>
<Combo
title=“GENRE”
choices={[“Tout”, “Rap”, “Rock”, “Pop”]}
currentChoice={filtreGenre}
setCurrentChoice={setFiltreGenre}
/>
</div>
<SearchBar text=“Rechercher un artiste” onSearch={setSearchTerm} />
</div>
</header>
<main className=“liste-artistes”>
<AnimatePresence>
{filteredGroupes.map((groupe) => {
console.log(‘idArtistComingFrom for groupe:’, idArtistComingFrom);
console.log(“groupe.idG : “);
console.log(groupe.idG);
return (
<CarteProgrammation
key={groupe.idG}
id={groupe.idG}
nomArtiste={groupe.nomG}
description={groupe.descriptionG}
date={groupe.datePassage}
heure={groupe.heurePassage}
setIsNavTransparent={props.setIsNavTransparent}
oldGroupes={lesGroupes}
oldX={idArtistComingFrom == groupe.idG ? oldX : null} oldY={idArtistComingFrom == groupe.idG ? oldY : null} comesFromPageArtist={idArtistComingFrom == groupe.idG}
/>
);
})}
{filteredArtistes.map((artiste) => {
console.log(‘idArtistComingFrom for artiste:’, idArtistComingFrom);
const groupeInfo = groupePassageMap.current.get(artiste.idG);
console.log(“artiste.idMG : “);
console.log(artiste.idMG);
return (
<CarteProgrammation

key={artiste.idG}
id={artiste.idG}
nomArtiste={artiste.nomDeSceneMG}
description={artiste.descriptionA}
date={groupeInfo?.datePassage ?? “Date inconnue”}
heure={groupeInfo?.heurePassage ?? “Heure inconnue”}
setIsNavTransparent={props.setIsNavTransparent}
oldGroupes={lesGroupes}

oldX={idArtistComingFrom == artiste.idG ? oldX : null} oldY={idArtistComingFrom == artiste.idG ? oldY : null} comesFromPageArtist={idArtistComingFrom == artiste.idG}

/>
);
})}
</AnimatePresence>
</main>
</motion.div>
<Footer />
</>
);
}
import { motion } from ‘framer-motion’
import {useState,useRef, useEffect} from ‘react’
import { Link } from ‘react-router-dom’

type Props = {
id:number|undefined,
date: string,
heure: string,
nomArtiste: string,
setIsNavTransparent: (isNavTransparent : boolean) => void;
comesFromPageArtist?: boolean;
oldX?: number;
oldY?: number;
oldGroupes?: Groupe[];
description?: string;
}

type Groupe = {
idG: number;
nomG: string;
descriptionG: string;
datePassage: string;
heurePassage: string;
}

export default function CarteProgrammation(props: Props) {
const nomArtiste = props.nomArtiste.toUpperCase().split(” “)
const[isHovered, setIsHovered] = useState(false)
const[isSwitching, setIsSwitching] = useState(false)
const[delay, setDelay] = useState(props.comesFromPageArtist? 0.2 : 0)
const refCarte = useRef<HTMLDivElement>(null);
const[zIndexCard, setZIndexCard] = useState(props.comesFromPageArtist ? 99 : 1)

useEffect(() => {
console.log(‘oldX:’, props.oldX);
console.log(‘oldY:’, props.oldY);

setTimeout(() => {
console.log(props.date)
console.log(props.heure)

setZIndexCard(1)
setDelay(0)
}, 600);
}, [])


const titleVariants = {
hover:{
fontSize: “2.3rem”,
color:”#FFD600”,
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
},
default:{
fontSize: “2.3rem”,
color:”#FFFBEE”,
transition:{
delay:delay,
duration:0.4,
ease: [1, 0, 0,1]
}
},
exit:{
fontSize: “7.625rem”,
color:“#FFD600”,
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
}
}

// fais le variant pour l’image de l’artiste (scale 1.2 sur hover)
const imageVariants = {
hover:{
scale:1.3,
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
},
default:{
scale:1,
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
}
}

// fais le variant pour le texte de dateHeure (x 2rem sur hover)

const dateHeureVariants = {
hover:{
y:“0rem”,
fontSize: “1.875rem”,
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
},
default:{
y:(window.innerWidth <= 576 ? 3.1 : 2.9).toString() + “rem”,
fontSize: “1.875rem”,
transition:{
delay:delay,
duration:0.4,
ease: [1, 0, 0,1]
}
},
exit:{
y:“0rem”,
fontSize: “4.6875rem”,
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
}
}

// default font-size: 1.875rem;
// exit font-size: 4.6875rem;

const heureVariants = {
hover:{
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
},
default:{
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
},
}

const carteVariants = {
default:{
zIndex:zIndexCard,
width: “24rem”,
height: “15.5rem”,
y:0,
x:0,
transition:{
delay:0.2,
duration:0.4,
ease: [1, 0, 0,1]
}
},
exit:{
x: refCarte.current? -refCarte.current.offsetLeft : props.oldX? -props.oldX : 0,
y: refCarte.current? -refCarte.current.offsetTop : props.oldY? -props.oldY : 0,
height: “100vh”,
width: “100vw”,
zIndex:99,
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
}
}

const textVariants = {
default:{
padding: “0.5rem 1rem”,
transition:{
delay:delay2,
duration:0.4,
ease: [1, 0, 0,1]
}
},
exit:{
padding: “3rem”,
transition:{
duration:0.4,
ease: [1, 0, 0,1]
}
}
}


return (
<motion.div
className=“outer-carte-artiste”
ref={refCarte}
variants={carteVariants}
initial={props.comesFromPageArtist ? “exit” : “default”}
animate=“default”
exit={isSwitching ? “exit” : “default”}
onClick={() => window.scrollTo(0,0)}
>
<Link className=“carte-artiste”
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
to={{
pathname:“/artiste”,
search:?id=${props.id},
}}
state={{
nomArtiste: props.nomArtiste,
date: props.date,
heure: props.heure,
oldX: refCarte.current?.offsetLeft,
oldY: refCarte.current?.offsetTop,
oldGroupes: props.oldGroupes,
description: props.description
}}
onClick={() => {props.setIsNavTransparent(true); setIsSwitching(true)}}
>
<motion.img
src={“http://localhost:8080/getImageArtiste/” + props.id}
alt=“image de l’artiste”
variants={imageVariants}
initial=“default”
animate={isHovered ? “hover” : “default”}
exit=“default”
/>
<motion.div className=“texts”
variants={textVariants}
initial={props.comesFromPageArtist ? “exit” : “default”}
animate=“default”
exit={isSwitching ? “exit” : “default”}
>
<motion.h3
variants={titleVariants}
initial={props.comesFromPageArtist ? “exit” : “default”}
animate={isHovered ? “hover” : “default”}
exit={isSwitching ? “exit” : “default”}
>{
nomArtiste.map((mot, index) => {
return(
<span key={index}>{mot}<br/></span>
)
})
}</motion.h3>

<motion.div className=“date-heure”
variants={dateHeureVariants}
initial={props.comesFromPageArtist ? “exit” : “default”}
animate={isHovered ? “hover” : “default”}
exit={isSwitching ? “exit” : “default”}
>
<h4
>{props.date}</h4>

<motion.h4
variants={heureVariants}
initial=“default”
animate={isHovered ? “hover” : “default”}
exit={isSwitching ? “exit” : “default”}
>{props.heure}</motion.h4>

</motion.div>
</motion.div>
</Link>
</motion.div>
)
}
import { useEffect, useState, useRef } from “react”;
import { Link, useLocation } from “react-router-dom”;
import BoutonReseau from “…/…/components/Artiste/BoutonReseau”;
import { motion } from “framer-motion”;
import axios from “axios”;

export default function PageEvenement() {
const location = useLocation();
const oldX = location.state?.oldX;
const oldY = location.state?.oldY;
const oldGroupes = location.state?.oldGroupes;
const [nomArtiste, setNomArtiste] = useState(location.state?.nomArtiste);
const [date, setDate] = useState(location.state?.date);
const [heure, setHeure] = useState(location.state?.heure);
const titleRef = useRef<HTMLHeadingElement>(null);
const [description, setDescription] = useState(
location.state?.description ||
“Description par défaut si aucune description n’est passée.”
);
const [socialLinks, setSocialLinks] = useState<{ reseau: string }[]>([]);
const params = new URLSearchParams(window.location.search);
const idArtiste = params.get(“id”);

const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const [infosGridPosition, setInfosGridPosition] = useState<“top” | “bottom”>(
“top”
);



function getSocialNetworkType(
url: string
):
| “soundcloud”
| “spotify”
| “instagram”
| “twitter”
| “youtube”
| “inconnu” {
if (url.includes(“soundcloud”)) {
return “soundcloud”;
} else if (url.includes(“spotify”)) {
return “spotify”;
} else if (url.includes(“instagram”)) {
return “instagram”;
} else if (url.includes(“twitter”)) {
return “twitter”;
} else if (url.includes(“youtube”)) {
return “youtube”;
} else {
return “inconnu”;
}
}

useEffect(() => {
axios
.get(“http://localhost:8080/getSocialLinks/” + idArtiste)
.then((response) => {
setSocialLinks(response.data);
})
.catch((error) => {
console.error(
“Erreur lors de la récupération des liens de réseaux sociaux”,
error
);
});

const handleResize = () => {
setWindowWidth(window.innerWidth);
};

window.addEventListener(“resize”, handleResize);

return () => {
window.removeEventListener(“resize”, handleResize);
};
}, []);

useEffect(() => {
console.log(‘oldXEvenement:’, oldX);
console.log(‘oldYEvenement:’, oldY);
if (titleRef.current) {
// regarde si la width du titre est plus grande que 25% de la width de la fenetre - 23rem
if (titleRef.current.offsetWidth > windowWidth / 4 - 2 * 3 * 16) {
setInfosGridPosition(“top”);
} else {
setInfosGridPosition(“bottom”);
}
}
}, [titleRef, windowWidth]);

const infosVariants = {
initial: {
opacity: 0,
transition: {
duration: 0.1,
ease: “easeInOut”,
},
},
visible: {
opacity: 1,
transition: {
delay: 0.8,
duration: 0.6,
ease: “easeInOut”,
},
},
};

const overlayVariants = {
initial: {
background:
“linear-gradient(to top, rgba(0, 0, 0, 0.7) 20%, rgba(0, 0, 0, 0) 60%)”,
transition: {
duration: 0.1,
ease: “easeInOut”,
},
},
extended: {
background:
“linear-gradient(to top, rgba(0, 0, 0, 0.7) 40%, rgba(0, 0, 0, 0) 100%)”,
transition: {
delay: 0.6,
duration: 0.6,
ease: “easeInOut”,
},
},
};

return (
<div id=“PageArtiste”>
<motion.div
className=“overlay”
variants={overlayVariants}
initial=“initial”
animate={infosGridPosition === “top” ? “extended” : “initial”}
/>

<img
src={“http://localhost:8080/getImageArtiste/” + idArtiste}
alt=“image de fond”
/>
<div
className=“content”
style={{
columnGap: infosGridPosition === “top” ? “0” : “5rem”,
rowGap: windowWidth > 991 ? “0” : “5rem”,
}}
>
<h3 ref={titleRef}>
{nomArtiste
.toUpperCase()
.split(" “)
.map((mot: string, index: number) => {
return (
<span key={index}>
{mot}
<br />
</span>
);
})}
</h3>
<motion.div
className=“infos”
variants={infosVariants}
initial=“initial”
animate=“visible”
exit=“initial”
style={{ gridArea: infosGridPosition }}
>
<p className=“description”>{description}</p>
<div className=“les-reseaux”>
{socialLinks.map((link, index) => {
const type = getSocialNetworkType(link.reseau);
if (type) {
return (
<BoutonReseau key={index} href={link.reseau} type={type} />
);
}
return null;
})}
</div>
<Link
to=”/programmation"
state={{
comesFromPageArtist: idArtiste,
oldX: oldX,
oldY: oldY,
oldGroupes: oldGroupes,
}}
className=“btn-retour”
>
<svg
width=“36”
height=“28”
viewBox=“0 0 36 28”
fill=“none”
xmlns=“http://www.w3.org/2000/svg”
>
<rect
x=“6.52539”
y=“0.321533”
width=“35.8974”
height=“3.58974”
rx=“1.79487”
transform=“rotate(45 6.52539 0.321533)”
/>
<rect
x=“3.87891”
y=“25.5957”
width=“35.8974”
height=“3.58974”
rx=“1.79487”
transform=“rotate(-45 3.87891 25.5957)”
/>
</svg>
</Link>
</motion.div>
<div className=“date-heure”>
<h4>{date}</h4>
<h4>{heure}</h4>
</div>
</div>
</div>
);
}