Compare commits
24 Commits
f57f9fe1d5
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f223974fd2 | |||
| 12a14e3956 | |||
| 00ac59722f | |||
| 059fe0f13a | |||
| f1473456b5 | |||
| f49aeccd09 | |||
| ac2fac2a86 | |||
| 373ee1e971 | |||
| 538aef63c7 | |||
| 2a41b77a84 | |||
| 078fc3937c | |||
| 34aa001f5f | |||
| 21d51ac65b | |||
| 8650ec2a56 | |||
| e58e799edd | |||
| 5b647a47f7 | |||
| 05f7f5c12b | |||
| dc68d20a85 | |||
| c567e5edac | |||
| fd11bcc9ce | |||
| 0248a8f784 | |||
| f506fd4b32 | |||
| 0109146731 | |||
| 5463a3220a |
@@ -0,0 +1 @@
|
|||||||
|
AAAAAAAAAA
|
||||||
@@ -1,82 +1,206 @@
|
|||||||
|
:root {
|
||||||
|
--bg-color: #050b16;
|
||||||
|
--deep-blue: #0a192f;
|
||||||
|
--glass-light: rgba(255, 255, 255, 0.08);
|
||||||
|
--glass-border: rgba(255, 255, 255, 0.25);
|
||||||
|
--accent-yellow: #fcd53f;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Noto Sans', sans-serif;
|
font-family: 'Noto Sans', sans-serif;
|
||||||
background-color: #333;
|
background-color: var(--bg-color);
|
||||||
color: #fff;
|
background-image: radial-gradient(at 10% 10%, rgba(10, 25, 47, 0.8) 0px, transparent 50%), radial-gradient(at 90% 90%, rgba(62, 202, 248, 0.15) 0px, transparent 50%), linear-gradient(135deg, #050b16 0%, #1a3c6f 100%);
|
||||||
}
|
color: #e6f1ff;
|
||||||
.container {
|
margin: 0;
|
||||||
width: 80%;
|
|
||||||
margin: auto;
|
|
||||||
border: 2px solid #2ecccc;
|
|
||||||
border-radius: 25px;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #444;
|
|
||||||
}
|
}
|
||||||
.nav a {
|
|
||||||
text-decoration: none;
|
.container {
|
||||||
color: #fff;
|
background: rgba(10, 25, 47, 0.08);
|
||||||
padding: 10px 20px;
|
backdrop-filter: blur(20px) saturate(180%);
|
||||||
border: 2px solid #2ecccc;
|
border-radius: 30px;
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
|
||||||
|
width: 80%;
|
||||||
|
margin: 40px auto;
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
height: 2px;
|
||||||
|
width: 80%;
|
||||||
|
margin: 40px auto;
|
||||||
|
background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.2) 50%, transparent 100%);
|
||||||
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -5px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 0 15px rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links, .projects {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links a {
|
||||||
|
background: var(--glass-light);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 20px;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links a:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links img {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Projects --- */
|
||||||
|
.projects {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||||
|
gap: 25px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
backdrop-filter: blur(15px);
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
border-radius: 25px;
|
border-radius: 25px;
|
||||||
background-color: #333;
|
padding: 25px;
|
||||||
transition: all 0.3s ease-in-out;
|
transition: 0.3s;
|
||||||
}
|
}
|
||||||
.nav a:hover {
|
|
||||||
background-color: #2ecccc;
|
.project-header {
|
||||||
color: #333;
|
display: flex;
|
||||||
cursor: pointer;
|
align-items: center;
|
||||||
transition: all 0.3s ease-in-out;
|
gap: 20px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-header img {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border-radius: 15px;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-info h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Etiquettes (Tags) --- */
|
||||||
|
.tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.purple-tag {
|
||||||
|
background: rgba(147, 51, 234, 0.2);
|
||||||
|
color: #d8b4fe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yellow-tag {
|
||||||
|
background: rgba(234, 179, 8, 0.2);
|
||||||
|
color:#fde047;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-container {
|
.video-container {
|
||||||
margin: 20px auto;
|
width: 100%;
|
||||||
border: 2px solid #2ecccc;
|
aspect-ratio: 16 / 9;
|
||||||
border-radius: 25px;
|
|
||||||
overflow: hidden;
|
|
||||||
padding-bottom: 56.25%;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 25px;
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-container iframe {
|
.video-container iframe {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
.nav a {
|
||||||
text-align: left;
|
text-decoration: none;
|
||||||
}
|
color: #fff;
|
||||||
.logo {
|
padding: 15px 35px;
|
||||||
height: 60px;
|
margin: 0 10px;
|
||||||
width: 60px;
|
border-radius: 50px;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
transition: 0.3s;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav a:hover {
|
||||||
|
background-color: var(--accent-yellow);
|
||||||
|
color: var(--deep-blue);
|
||||||
|
border-color: var(--accent-yellow);
|
||||||
|
box-shadow: 0 0 20px var(--accent-yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 128px;
|
||||||
|
width: 128px;
|
||||||
|
vertical-align: middle;
|
||||||
|
background: var(--glass-light);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border-radius: 25px;
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 48px;
|
font-size: 64px;
|
||||||
line-height: 60px;
|
line-height: 128px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.footer {
|
div.footer {
|
||||||
|
background: rgba(10, 25, 47, 0.2);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border-radius: 30px;
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
width: 80%;
|
width: 80%;
|
||||||
margin: auto;
|
margin: 40px auto;
|
||||||
border: 2px solid #2ecccc;
|
|
||||||
border-radius: 25px;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #444;
|
text-align: center;
|
||||||
display: flex;
|
}
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.flash {
|
|
||||||
display: inline-block;
|
|
||||||
width: 128px;
|
|
||||||
transition: 0.4s;
|
|
||||||
};
|
|
||||||
|
|
||||||
img.flash:hover {
|
|
||||||
transition: 0.4s;
|
|
||||||
width: 800px
|
|
||||||
};
|
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 615 KiB |
|
After Width: | Height: | Size: 140 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 797 KiB After Width: | Height: | Size: 953 KiB |
|
After Width: | Height: | Size: 239 KiB |
@@ -0,0 +1,25 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" width="100%" height="100%">
|
||||||
|
<!-- Fond Noir -->
|
||||||
|
|
||||||
|
<!-- Style pour la police large et grasse -->
|
||||||
|
<style>
|
||||||
|
.logo-text {
|
||||||
|
font-family: 'Arial Black', 'Impact', sans-serif;
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: -2px;
|
||||||
|
}
|
||||||
|
.watch {
|
||||||
|
fill: #FFFFFF;
|
||||||
|
}
|
||||||
|
.gether {
|
||||||
|
fill: #60a5fa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
x="50" et textLength="400" force les deux mots à faire
|
||||||
|
exactement la même largeur (400px), alignés au millimètre.
|
||||||
|
-->
|
||||||
|
<text x="50" y="220" font-size="140" textLength="400" lengthAdjust="spacingAndGlyphs" class="logo-text watch">WATCH</text>
|
||||||
|
<text x="50" y="370" font-size="140" textLength="400" lengthAdjust="spacingAndGlyphs" class="logo-text gether">GETHER</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 798 B |
|
After Width: | Height: | Size: 9.4 KiB |
@@ -0,0 +1,115 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap" rel="stylesheet">
|
||||||
|
<link href="css/style.css?v=1.0.5" rel="stylesheet">
|
||||||
|
<link rel="icon" href="img/logo.png">
|
||||||
|
<title>Whykioh.fr - Mon Portefolio</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<a href="https://www.youtube.com/@whykioh" target="_blank">
|
||||||
|
<img class="logo" src="img/logo.png" alt="Logo">
|
||||||
|
</a>
|
||||||
|
<h1 class="title">Whykioh.fr</h1>
|
||||||
|
</header>
|
||||||
|
<div class="nav">
|
||||||
|
<a href="https://ko-fi.com/whykioh" target="_blank">Ko-Fi</a>
|
||||||
|
<a href="https://watchgether.whykioh.fr" target="_blank">WatchGether</a>
|
||||||
|
<a href="https://gamel0ver.whykioh.fr" target="_blank">GameL0ver</a>
|
||||||
|
<a href="https://vod.whykioh.fr" target="_blank">Jellyfin</a>
|
||||||
|
<a href="https://voj.whykioh.fr" target="_blank">Viens On Jette</a>
|
||||||
|
<a href="https://git.whykioh.fr/" target="_blank">Mes Repos</a>
|
||||||
|
</div>
|
||||||
|
<p><br></p>
|
||||||
|
<hr>
|
||||||
|
<h1>Bienvenue sur Whykioh.fr !</h1>
|
||||||
|
<p>Le centre de tous mes projets webs, applications, et autres.<br>N'hésitez pas à explorer ! Mais aussi à me soutenir via un avis, ou un don.</p>
|
||||||
|
<hr>
|
||||||
|
<h1>Mes Réseaux :</h1>
|
||||||
|
<p>Retrouvez-moi sur mes réseaux sociaux, et n'hésitez pas à me suivre !</p>
|
||||||
|
<div class="social-links">
|
||||||
|
<a href="https://www.youtube.com/@whykioh" target="_blank"><img src="img/youtube.png" alt="YouTube"></a>
|
||||||
|
<a href="https://www.instagram.com/whykioh/" target="_blank"><img src="img/instagram.webp" alt="Instagram"></a>
|
||||||
|
<a href="https://discord.gg/DaCAdCktCv" target="_blank"><img src="img/discord.webp" alt="Discord"></a>
|
||||||
|
<a href="https://ko-fi.com/whykioh" target="_blank"><img src="img/ko-fi.png" alt="Ko-fi"></a>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<h1>Mes Projets :</h1>
|
||||||
|
<p>Voici quelques-uns de mes projets :</p>
|
||||||
|
<div class="projects">
|
||||||
|
|
||||||
|
<div class="project">
|
||||||
|
<a href="https://watchgether.whykioh.fr" target="_blank" style="text-decoration: none; color: inherit;">
|
||||||
|
<div class="project-header">
|
||||||
|
<img src="img/watchgether.svg" alt="WatchGether">
|
||||||
|
<div class="project-info">
|
||||||
|
<h2>WatchGether</h2>
|
||||||
|
<span class="tag purple-tag">In Progress</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<p>
|
||||||
|
WatchGether est une liste de film à regarder en duo, WatchGether analyse et compare les listes du duo pour trouver des films en commun et en rapport avec les thèmes et genre apprécié de chaque utilisateur. Pour l'instant WatchGether n'est utilisable que par moi, mais sera ouvert au public prochainement.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project">
|
||||||
|
<a href="https://gamel0ver.whykioh.fr" target="_blank" style="text-decoration: none; color: inherit;">
|
||||||
|
<div class="project-header">
|
||||||
|
<img src="img/gamel0ver.png" alt="GameL0ver">
|
||||||
|
<div class="project-info">
|
||||||
|
<h2>GameL0ver</h2>
|
||||||
|
<span class="tag yellow-tag">Coming Soon</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<p>
|
||||||
|
GameL0ver est un site de rencontre pour les joueurs, il permet de trouver des personnes avec qui jouer, voire même peut être l'amour, à des jeux vidéo en fonction de leurs préférences et de leurs jeux favoris. GameL0ver permet de discuter publiquement et même en privé et intègre un système de match avec des Likes et des Pass. GameL0ver est actuellement en développement et sera bientôt disponible.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project">
|
||||||
|
<a href="https://whykioh.fr/blindtube" target="_blank" style="text-decoration: none; color: inherit;">
|
||||||
|
<div class="project-header">
|
||||||
|
<img src="img/BlindTube.png" alt="BlindTube">
|
||||||
|
<div class="project-info">
|
||||||
|
<h2>BlindTube</h2>
|
||||||
|
<span class="tag purple-tag">In Progress</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<p>
|
||||||
|
BlindTube est une application de Blind Test pour YouTube Music, elle permet d'effectuer un blind test seul ou à plusieurs en partant de vos playlists YouTube Music. BlindTube est actuellement en développement et sera disponible.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project">
|
||||||
|
<a href="https://voj.whykioh.fr" target="_blank" style="text-decoration: none; color: inherit;">
|
||||||
|
<div class="project-header">
|
||||||
|
<img src="img/viensonjette.png" alt="Viens On Jette">
|
||||||
|
<div class="project-info">
|
||||||
|
<h2>Viens On Jette</h2>
|
||||||
|
<span class="tag green-tag">Disponible</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<p>
|
||||||
|
Viens On Jette est un duo avec mon ami <a href="https://www.youtube.com/@naxo175_" target="_blank">Naxo</a> sur YouTube, nous faisons des vidéos de jeux vidéo, des courts-métrages et d'autres contenus. Regardez dès maintenant !
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<h1>Voici la dernière vidéo de <a href="https://www.youtube.com/@whykioh">Whykioh</a> :</h1>
|
||||||
|
<div class="video-container">
|
||||||
|
<iframe width="100%" height="100%" src="https://www.youtube.com/embed/q1rJG0Ue3d0?si=maK0gmAaMX2IDL67" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
Copyright | Whykioh® 2021-2026 | CIBOT NOËL Noah | <a href="https://ko-fi.com/whykioh" target="_blank">Ko-fi</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap" rel="stylesheet">
|
|
||||||
<link href="css/style.css" rel="stylesheet">
|
|
||||||
<link rel="icon" href="img/logo.png">
|
|
||||||
<title>love</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<header>
|
|
||||||
<a href="https://www.youtube.com/@whykioh" target="_blank">
|
|
||||||
<img class="logo" src="img/logo.png" alt="Logo">
|
|
||||||
</a>
|
|
||||||
<h1 class="title">WhyKorp</h1>
|
|
||||||
</header>
|
|
||||||
<div class="nav">
|
|
||||||
<a href="#">Accueil</a>
|
|
||||||
<a href="infos/index.php">Infos</a>
|
|
||||||
<a href="https://artists.magroove.com/en/lt/whykioh/" target="_blank">Link Tree</a>
|
|
||||||
<a href="tools/index.html">Outils</a>
|
|
||||||
<a href="ruty/index.php">Ruty</a>
|
|
||||||
<a href="lolivator/index.php">LoLivator</a>
|
|
||||||
<a href="jpc/index.html">JPC</a>
|
|
||||||
<a href="archives/index.php">Archives</a>
|
|
||||||
</div>
|
|
||||||
<p><br></p>
|
|
||||||
<hr>
|
|
||||||
<h1>Bienvenue sur le site officiel de la WhyKorp !</h1>
|
|
||||||
<p>Vous y trouverez tout sur Whykioh aka Noah, et la WhyKorp.<br>Attention ! Site en cours de développement !<br>Si un disfonctionnement est trouvé veuillez le signaler.</p>
|
|
||||||
<hr>
|
|
||||||
<h1>Flash Info !</h1>
|
|
||||||
<div class="flash">
|
|
||||||
<p class="flash">Noah a enfin terminé l'EP 4 Elements, <br>il sera disponible sur toutes les plateformes <br>le 25 Décembre 2023</p>
|
|
||||||
<img class="flash" src="img/last cover.png">
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<h1>Voici la dernière vidéo de <a href="https://www.youtube.com/@whykioh">Whykioh</a> :</h1>
|
|
||||||
<div class="video-container">
|
|
||||||
<iframe width="557,55" height="315" src="https://www.youtube.com/embed/-ZPjXjvdZFc?si=ldsNogAHy636GnzU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="footer">
|
|
||||||
Copyright | Whykorp® 2021-2024 | ajoute le nom du site après l'url et un /
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,201 +1,201 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
// --- CONFIGURATION BDD ---
|
// --- CONFIGURATION BDD ---
|
||||||
$host = 'localhost';
|
$host = 'localhost';
|
||||||
$db = 'watchgether';
|
$db = 'watchgether';
|
||||||
$user = 'root';
|
$user = 'root';
|
||||||
$pass = ''; // Vide par défaut sur Wamp
|
$pass = ''; // Vide par défaut sur Wamp
|
||||||
|
|
||||||
$options = [
|
$options = [
|
||||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||||
PDO::ATTR_EMULATE_PREPARES => false,
|
PDO::ATTR_EMULATE_PREPARES => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
$apiKey = '23af653f99d2e7ac884415805e7ca84c';
|
$apiKey = '23af653f99d2e7ac884415805e7ca84c';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $pass, $options);
|
$pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $pass, $options);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(['success' => false, 'error' => 'Connexion BDD échouée']);
|
echo json_encode(['success' => false, 'error' => 'Connexion BDD échouée']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- LECTURE DE L'INPUT ---
|
// --- LECTURE DE L'INPUT ---
|
||||||
$json = file_get_contents('php://input');
|
$json = file_get_contents('php://input');
|
||||||
$data = json_decode($json, true);
|
$data = json_decode($json, true);
|
||||||
|
|
||||||
if (!$data || !isset($data['action'])) {
|
if (!$data || !isset($data['action'])) {
|
||||||
echo json_encode(['success' => false, 'error' => 'Aucune action spécifiée']);
|
echo json_encode(['success' => false, 'error' => 'Aucune action spécifiée']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$action = $data['action'];
|
$action = $data['action'];
|
||||||
$params = $data['params'] ?? [];
|
$params = $data['params'] ?? [];
|
||||||
|
|
||||||
// Simulation d'un utilisateur connecté (à remplacer par ton système de login plus tard)
|
// Simulation d'un utilisateur connecté (à remplacer par ton système de login plus tard)
|
||||||
$current_user_id = $_SESSION['user_id'] ?? 1;
|
$current_user_id = $_SESSION['user_id'] ?? 1;
|
||||||
|
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
|
|
||||||
// --- RECHERCHE TMDB ---
|
// --- RECHERCHE TMDB ---
|
||||||
case 'searchTMDB':
|
case 'searchTMDB':
|
||||||
$query = urlencode($params['query']);
|
$query = urlencode($params['query']);
|
||||||
$url = "https://api.themoviedb.org/3/search/multi?api_key=$apiKey&language=fr-FR&query=$query";
|
$url = "https://api.themoviedb.org/3/search/multi?api_key=$apiKey&language=fr-FR&query=$query";
|
||||||
|
|
||||||
$response = file_get_contents($url);
|
$response = file_get_contents($url);
|
||||||
if ($response) {
|
if ($response) {
|
||||||
echo $response; // On renvoie directement le JSON de TMDB au front
|
echo $response; // On renvoie directement le JSON de TMDB au front
|
||||||
} else {
|
} else {
|
||||||
echo json_encode(['success' => false, 'error' => 'Erreur API TMDB']);
|
echo json_encode(['success' => false, 'error' => 'Erreur API TMDB']);
|
||||||
}
|
}
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
// --- GESTION DES FILMS ---
|
// --- GESTION DES FILMS ---
|
||||||
case 'addMovie':
|
case 'addMovie':
|
||||||
// On cherche si le film existe déjà pour cet utilisateur
|
// On cherche si le film existe déjà pour cet utilisateur
|
||||||
$stmt = $pdo->prepare("SELECT id FROM movies WHERE tmdb_id = ? AND user_id = ?");
|
$stmt = $pdo->prepare("SELECT id FROM movies WHERE tmdb_id = ? AND user_id = ?");
|
||||||
$stmt->execute([$params['tmdb_id'], $current_user_id]);
|
$stmt->execute([$params['tmdb_id'], $current_user_id]);
|
||||||
if ($stmt->fetch()) {
|
if ($stmt->fetch()) {
|
||||||
echo json_encode(['success' => false, 'error' => 'Film déjà dans la liste']);
|
echo json_encode(['success' => false, 'error' => 'Film déjà dans la liste']);
|
||||||
exit;
|
exit;
|
||||||
} else {
|
} else {
|
||||||
$stmt = $pdo->prepare("INSERT INTO movies (tmdb_id, titre, affiche_path, type, user_id, vu) VALUES (?, ?, ?, ?, ?, 0)");
|
$stmt = $pdo->prepare("INSERT INTO movies (tmdb_id, titre, affiche_path, type, user_id, vu) VALUES (?, ?, ?, ?, ?, 0)");
|
||||||
$success = $stmt->execute([
|
$success = $stmt->execute([
|
||||||
$params['tmdb_id'],
|
$params['tmdb_id'],
|
||||||
$params['titre'],
|
$params['titre'],
|
||||||
$params['affiche_path'],
|
$params['affiche_path'],
|
||||||
$params['type'], // 'film' ou 'serie'
|
$params['type'], // 'film' ou 'serie'
|
||||||
$current_user_id
|
$current_user_id
|
||||||
]);
|
]);
|
||||||
echo json_encode(['success' => $success]);
|
echo json_encode(['success' => $success]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'getMyList':
|
case 'getMyList':
|
||||||
// Récupère les films ajoutés par l'utilisateur
|
// Récupère les films ajoutés par l'utilisateur
|
||||||
$stmt = $pdo->prepare("SELECT * FROM movies WHERE user_id = ? ORDER BY date_ajout DESC");
|
$stmt = $pdo->prepare("SELECT * FROM movies WHERE user_id = ? ORDER BY date_ajout DESC");
|
||||||
$stmt->execute([$current_user_id]);
|
$stmt->execute([$current_user_id]);
|
||||||
echo json_encode(['success' => true, 'movies' => $stmt->fetchAll()]);
|
echo json_encode(['success' => true, 'movies' => $stmt->fetchAll()]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'getCommonList':
|
case 'getCommonList':
|
||||||
// LA MAGIE : On cherche les doublons de tmdb_id entre deux utilisateurs
|
// LA MAGIE : On cherche les doublons de tmdb_id entre deux utilisateurs
|
||||||
// On part du principe que tu es l'ID 1 et ta copine l'ID 2 (à adapter)
|
// On part du principe que tu es l'ID 1 et ta copine l'ID 2 (à adapter)
|
||||||
$partner_id = ($current_user_id == 1) ? 2 : 1;
|
$partner_id = ($current_user_id == 1) ? 2 : 1;
|
||||||
|
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT m1.* FROM movies m1
|
SELECT m1.* FROM movies m1
|
||||||
INNER JOIN movies m2 ON m1.tmdb_id = m2.tmdb_id
|
INNER JOIN movies m2 ON m1.tmdb_id = m2.tmdb_id
|
||||||
WHERE m1.user_id = ? AND m2.user_id = ?
|
WHERE m1.user_id = ? AND m2.user_id = ?
|
||||||
");
|
");
|
||||||
$stmt->execute([$current_user_id, $partner_id]);
|
$stmt->execute([$current_user_id, $partner_id]);
|
||||||
echo json_encode(['success' => true, 'common_movies' => $stmt->fetchAll()]);
|
echo json_encode(['success' => true, 'common_movies' => $stmt->fetchAll()]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'getPartnerList':
|
case 'getPartnerList':
|
||||||
$partner_id = ($current_user_id == 1) ? 2 : 1;
|
$partner_id = ($current_user_id == 1) ? 2 : 1;
|
||||||
$stmt = $pdo->prepare("SELECT * FROM movies WHERE user_id = ? ORDER BY date_ajout DESC");
|
$stmt = $pdo->prepare("SELECT * FROM movies WHERE user_id = ? ORDER BY date_ajout DESC");
|
||||||
$stmt->execute([$partner_id]);
|
$stmt->execute([$partner_id]);
|
||||||
echo json_encode(['success' => true, 'movies' => $stmt->fetchAll()]);
|
echo json_encode(['success' => true, 'movies' => $stmt->fetchAll()]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
// --- ACTIONS SUR LE FILM ---
|
// --- ACTIONS SUR LE FILM ---
|
||||||
case 'toggleViewed':
|
case 'toggleViewed':
|
||||||
// Alterne entre vu (1) et non vu (0)
|
// Alterne entre vu (1) et non vu (0)
|
||||||
$stmt = $pdo->prepare("UPDATE movies SET vu = !vu WHERE id = ?");
|
$stmt = $pdo->prepare("UPDATE movies SET vu = !vu WHERE id = ?");
|
||||||
$success = $stmt->execute([(int)$params['movie_id']]);
|
$success = $stmt->execute([(int)$params['movie_id']]);
|
||||||
echo json_encode(['success' => $success]);
|
echo json_encode(['success' => $success]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'deleteMovie':
|
case 'deleteMovie':
|
||||||
$stmt = $pdo->prepare("DELETE FROM movies WHERE id = ? AND user_id = ?");
|
$stmt = $pdo->prepare("DELETE FROM movies WHERE id = ? AND user_id = ?");
|
||||||
$success = $stmt->execute([(int)$params['movie_id'], $current_user_id]);
|
$success = $stmt->execute([(int)$params['movie_id'], $current_user_id]);
|
||||||
echo json_encode(['success' => $success]);
|
echo json_encode(['success' => $success]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
// --- COMMENTAIRES ---
|
// --- COMMENTAIRES ---
|
||||||
case 'addComment':
|
case 'addComment':
|
||||||
$stmt = $pdo->prepare("INSERT INTO commentaires (movie_id, user_id, contenu) VALUES (?, ?, ?)");
|
$stmt = $pdo->prepare("INSERT INTO commentaires (movie_id, user_id, contenu) VALUES (?, ?, ?)");
|
||||||
$success = $stmt->execute([
|
$success = $stmt->execute([
|
||||||
(int)$params['movie_id'],
|
(int)$params['movie_id'],
|
||||||
$current_user_id,
|
$current_user_id,
|
||||||
$params['text']
|
$params['text']
|
||||||
]);
|
]);
|
||||||
echo json_encode(['success' => $success]);
|
echo json_encode(['success' => $success]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'getComments':
|
case 'getComments':
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT c.*, u.pseudo FROM commentaires c
|
SELECT c.*, u.pseudo FROM commentaires c
|
||||||
JOIN users u ON c.user_id = u.id
|
JOIN users u ON c.user_id = u.id
|
||||||
WHERE c.movie_id = ? ORDER BY c.date_ajout DESC
|
WHERE c.movie_id = ? ORDER BY c.date_ajout DESC
|
||||||
");
|
");
|
||||||
$stmt->execute([(int)$params['movie_id']]);
|
$stmt->execute([(int)$params['movie_id']]);
|
||||||
echo json_encode(['success' => true, 'comments' => $stmt->fetchAll()]);
|
echo json_encode(['success' => true, 'comments' => $stmt->fetchAll()]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'getMovieDetails':
|
case 'getMovieDetails':
|
||||||
$id = $params['id'];
|
$id = $params['id'];
|
||||||
$type = $params['type']; // 'movie' ou 'tv'
|
$type = $params['type']; // 'movie' ou 'tv'
|
||||||
// On demande les détails + les crédits (acteurs) en une seule fois
|
// On demande les détails + les crédits (acteurs) en une seule fois
|
||||||
$url = "https://api.themoviedb.org/3/$type/$id?api_key=$apiKey&language=fr-FR&append_to_response=credits";
|
$url = "https://api.themoviedb.org/3/$type/$id?api_key=$apiKey&language=fr-FR&append_to_response=credits";
|
||||||
|
|
||||||
$response = file_get_contents($url);
|
$response = file_get_contents($url);
|
||||||
echo $response;
|
echo $response;
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'setStarsRating':
|
case 'setStarsRating':
|
||||||
$stmt = $pdo->prepare("INSERT INTO movies (rating) VALUES (?) WHERE id = ?");
|
$stmt = $pdo->prepare("INSERT INTO movies (rating) VALUES (?) WHERE id = ?");
|
||||||
$success = $stmt->execute([
|
$success = $stmt->execute([
|
||||||
(int)$params['movie_id'],
|
(int)$params['movie_id'],
|
||||||
(int)$params['rating']
|
(int)$params['rating']
|
||||||
]);
|
]);
|
||||||
echo json_encode(['success' => $success]);
|
echo json_encode(['success' => $success]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'getStarsRating':
|
case 'getStarsRating':
|
||||||
$stmt = $pdo->prepare("SELECT rating FROM movies WHERE id = ?");
|
$stmt = $pdo->prepare("SELECT rating FROM movies WHERE id = ?");
|
||||||
$stmt->execute([(int)$params['movie_id']]);
|
$stmt->execute([(int)$params['movie_id']]);
|
||||||
$rating = $stmt->fetchColumn();
|
$rating = $stmt->fetchColumn();
|
||||||
echo json_encode(['success' => true, 'rating' => $rating]);
|
echo json_encode(['success' => true, 'rating' => $rating]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'register':
|
case 'register':
|
||||||
$pseudo = $params['pseudo'];
|
$pseudo = $params['pseudo'];
|
||||||
$pass = password_hash($params['password'], PASSWORD_DEFAULT);
|
$pass = password_hash($params['password'], PASSWORD_DEFAULT);
|
||||||
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO users (pseudo, password) VALUES (?, ?)");
|
$stmt = $pdo->prepare("INSERT INTO users (pseudo, password) VALUES (?, ?)");
|
||||||
try {
|
try {
|
||||||
$stmt->execute([$pseudo, $pass]);
|
$stmt->execute([$pseudo, $pass]);
|
||||||
echo json_encode(['success' => true]);
|
echo json_encode(['success' => true]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(['success' => false, 'error' => 'Pseudo déjà pris']);
|
echo json_encode(['success' => false, 'error' => 'Pseudo déjà pris']);
|
||||||
}
|
}
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'login':
|
case 'login':
|
||||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE pseudo = ?");
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE pseudo = ?");
|
||||||
$stmt->execute([$params['pseudo']]);
|
$stmt->execute([$params['pseudo']]);
|
||||||
$user = $stmt->fetch();
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
if ($user && password_verify($params['password'], $user['password'])) {
|
if ($user && password_verify($params['password'], $user['password'])) {
|
||||||
$_SESSION['user_id'] = $user['id'];
|
$_SESSION['user_id'] = $user['id'];
|
||||||
$_SESSION['pseudo'] = $user['pseudo'];
|
$_SESSION['pseudo'] = $user['pseudo'];
|
||||||
echo json_encode(['success' => true]);
|
echo json_encode(['success' => true]);
|
||||||
} else {
|
} else {
|
||||||
echo json_encode(['success' => false, 'error' => 'Identifiants incorrects']);
|
echo json_encode(['success' => false, 'error' => 'Identifiants incorrects']);
|
||||||
}
|
}
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
case 'logout':
|
case 'logout':
|
||||||
session_destroy();
|
session_destroy();
|
||||||
echo json_encode(['success' => true]);
|
echo json_encode(['success' => true]);
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
echo json_encode(['success' => false, 'error' => 'Action inconnue']);
|
echo json_encode(['success' => false, 'error' => 'Action inconnue']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -1,43 +1,43 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>WatchGether - Connexion</title>
|
<title>WatchGether - Connexion</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-slate-900 text-white flex items-center justify-center min-h-screen">
|
<body class="bg-slate-900 text-white flex items-center justify-center min-h-screen">
|
||||||
|
|
||||||
<div class="bg-slate-800 p-8 rounded-2xl shadow-xl w-full max-w-md border border-white/5">
|
<div class="bg-slate-800 p-8 rounded-2xl shadow-xl w-full max-w-md border border-white/5">
|
||||||
<h1 class="text-3xl font-black text-center mb-8 text-blue-400 italic">WATCHGETHER</h1>
|
<h1 class="text-3xl font-black text-center mb-8 text-blue-400 italic">WATCHGETHER</h1>
|
||||||
|
|
||||||
<div id="authForm">
|
<div id="authForm">
|
||||||
<input type="text" id="pseudo" placeholder="Pseudo" class="w-full p-4 mb-4 bg-slate-900 rounded-lg border border-slate-700 focus:border-blue-500 outline-none">
|
<input type="text" id="pseudo" placeholder="Pseudo" class="w-full p-4 mb-4 bg-slate-900 rounded-lg border border-slate-700 focus:border-blue-500 outline-none">
|
||||||
<input type="password" id="password" placeholder="Mot de passe" class="w-full p-4 mb-6 bg-slate-900 rounded-lg border border-slate-700 focus:border-blue-500 outline-none">
|
<input type="password" id="password" placeholder="Mot de passe" class="w-full p-4 mb-6 bg-slate-900 rounded-lg border border-slate-700 focus:border-blue-500 outline-none">
|
||||||
|
|
||||||
<button onclick="handleAuth('login')" class="w-full bg-blue-600 hover:bg-blue-500 py-4 rounded-xl font-bold mb-4 transition">Se connecter</button>
|
<button onclick="handleAuth('login')" class="w-full bg-blue-600 hover:bg-blue-500 py-4 rounded-xl font-bold mb-4 transition">Se connecter</button>
|
||||||
<button onclick="handleAuth('register')" class="w-full bg-slate-700 hover:bg-slate-600 py-4 rounded-xl font-bold transition">Créer un compte</button>
|
<button onclick="handleAuth('register')" class="w-full bg-slate-700 hover:bg-slate-600 py-4 rounded-xl font-bold transition">Créer un compte</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
async function handleAuth(action) {
|
async function handleAuth(action) {
|
||||||
const pseudo = document.getElementById('pseudo').value;
|
const pseudo = document.getElementById('pseudo').value;
|
||||||
const password = document.getElementById('password').value;
|
const password = document.getElementById('password').value;
|
||||||
|
|
||||||
const response = await fetch('RequestHandler.php', {
|
const response = await fetch('RequestHandler.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ action, params: { pseudo, password } })
|
body: JSON.stringify({ action, params: { pseudo, password } })
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
if (action === 'register') alert("Compte créé ! Connecte-toi maintenant.");
|
if (action === 'register') alert("Compte créé ! Connecte-toi maintenant.");
|
||||||
else window.location.href = 'search/index.php';
|
else window.location.href = 'search/index.php';
|
||||||
} else {
|
} else {
|
||||||
alert(data.error);
|
alert(data.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,300 +1,300 @@
|
|||||||
let allMovies = []; // Stockage local de la liste entière
|
let allMovies = []; // Stockage local de la liste entière
|
||||||
|
|
||||||
window.onload = () => {
|
window.onload = () => {
|
||||||
loadList();
|
loadList();
|
||||||
document.getElementById('sortOrder').addEventListener('change', renderList);
|
document.getElementById('sortOrder').addEventListener('change', renderList);
|
||||||
document.getElementById('filterType').addEventListener('change', renderList);
|
document.getElementById('filterType').addEventListener('change', renderList);
|
||||||
document.getElementById('filterStatus').addEventListener('change', renderList);
|
document.getElementById('filterStatus').addEventListener('change', renderList);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function apiRequest(action, params = {}) {
|
async function apiRequest(action, params = {}) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('../RequestHandler.php', {
|
const response = await fetch('../RequestHandler.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ action, params })
|
body: JSON.stringify({ action, params })
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur API:", error);
|
console.error("Erreur API:", error);
|
||||||
return { success: false, error: "Erreur de connexion au serveur" };
|
return { success: false, error: "Erreur de connexion au serveur" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addMovie(tmdbId, title, posterPath, type) {
|
async function addMovie(tmdbId, title, posterPath, type) {
|
||||||
const result = await apiRequest('addMovie', {
|
const result = await apiRequest('addMovie', {
|
||||||
tmdb_id: tmdbId,
|
tmdb_id: tmdbId,
|
||||||
titre: title,
|
titre: title,
|
||||||
affiche_path: posterPath,
|
affiche_path: posterPath,
|
||||||
type: type
|
type: type
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
alert(`"${title}" a été ajouté à votre liste ! 🍿`);
|
alert(`"${title}" a été ajouté à votre liste ! 🍿`);
|
||||||
closeModal();
|
closeModal();
|
||||||
} else {
|
} else {
|
||||||
alert('Erreur lors de l\'ajout. Vérifie si le film n\'est pas déjà présent.');
|
alert('Erreur lors de l\'ajout. Vérifie si le film n\'est pas déjà présent.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadList() {
|
async function loadList() {
|
||||||
const response = await fetch('../RequestHandler.php', {
|
const response = await fetch('../RequestHandler.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ action: 'getMyList' })
|
body: JSON.stringify({ action: 'getMyList' })
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
allMovies = data.movies;
|
allMovies = data.movies;
|
||||||
renderList();
|
renderList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderList() {
|
function renderList() {
|
||||||
const grid = document.getElementById('myListGrid');
|
const grid = document.getElementById('myListGrid');
|
||||||
const sort = document.getElementById('sortOrder').value;
|
const sort = document.getElementById('sortOrder').value;
|
||||||
const type = document.getElementById('filterType').value;
|
const type = document.getElementById('filterType').value;
|
||||||
const status = document.getElementById('filterStatus').value;
|
const status = document.getElementById('filterStatus').value;
|
||||||
|
|
||||||
// 1. Filtrage
|
// 1. Filtrage
|
||||||
let filtered = allMovies.filter(m => {
|
let filtered = allMovies.filter(m => {
|
||||||
const matchType = (type === 'all' || m.type === type);
|
const matchType = (type === 'all' || m.type === type);
|
||||||
const matchStatus = (status === 'all' || m.vu == status);
|
const matchStatus = (status === 'all' || m.vu == status);
|
||||||
return matchType && matchStatus;
|
return matchType && matchStatus;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Tri
|
// 2. Tri
|
||||||
filtered.sort((a, b) => {
|
filtered.sort((a, b) => {
|
||||||
if (sort === 'titre_asc') return a.titre.localeCompare(b.titre);
|
if (sort === 'titre_asc') return a.titre.localeCompare(b.titre);
|
||||||
if (sort === 'date_ajout_asc') return new Date(a.date_ajout) - new Date(b.date_ajout);
|
if (sort === 'date_ajout_asc') return new Date(a.date_ajout) - new Date(b.date_ajout);
|
||||||
if (sort === 'date_ajout_desc') return new Date(b.date_ajout) - new Date(a.date_ajout);
|
if (sort === 'date_ajout_desc') return new Date(b.date_ajout) - new Date(a.date_ajout);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. Affichage
|
// 3. Affichage
|
||||||
grid.innerHTML = '';
|
grid.innerHTML = '';
|
||||||
document.getElementById('movieCount').innerText = filtered.length;
|
document.getElementById('movieCount').innerText = filtered.length;
|
||||||
|
|
||||||
filtered.forEach(m => {
|
filtered.forEach(m => {
|
||||||
const card = document.createElement('div');
|
const card = document.createElement('div');
|
||||||
// On ajoute 'flex flex-col' pour que le contenu s'empile proprement
|
// On ajoute 'flex flex-col' pour que le contenu s'empile proprement
|
||||||
card.className = `relative group bg-slate-800 rounded-xl overflow-hidden border ${m.vu == 1 ? 'border-green-500/50' : 'border-slate-700'} flex flex-col h-full`;
|
card.className = `relative group bg-slate-800 rounded-xl overflow-hidden border ${m.vu == 1 ? 'border-green-500/50' : 'border-slate-700'} flex flex-col h-full`;
|
||||||
|
|
||||||
if (currentView === 'partner') {
|
if (currentView === 'partner') {
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<div class="relative aspect-[2/3] overflow-hidden cursor-pointer" onclick="showDetails(${m.tmdb_id}, '${m.type}', ${m.id}, ${m.vu})">
|
<div class="relative aspect-[2/3] overflow-hidden cursor-pointer" onclick="showDetails(${m.tmdb_id}, '${m.type}', ${m.id}, ${m.vu})">
|
||||||
<img src="https://image.tmdb.org/t/p/w500${m.affiche_path}"
|
<img src="https://image.tmdb.org/t/p/w500${m.affiche_path}"
|
||||||
class="w-full h-full object-cover transition-transform group-hover:scale-110 ${m.vu == 1 ? 'opacity-40 grayscale' : ''}">
|
class="w-full h-full object-cover transition-transform group-hover:scale-110 ${m.vu == 1 ? 'opacity-40 grayscale' : ''}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-3 flex flex-col justify-between flex-grow bg-slate-800">
|
<div class="p-3 flex flex-col justify-between flex-grow bg-slate-800">
|
||||||
<h3 class="font-bold text-sm text-white truncate mb-2" title="${m.titre}">${m.titre}</h3>
|
<h3 class="font-bold text-sm text-white truncate mb-2" title="${m.titre}">${m.titre}</h3>
|
||||||
|
|
||||||
<div class="flex gap-2 mt-auto">
|
<div class="flex gap-2 mt-auto">
|
||||||
<button onclick="addMovie(${m.tmdb_id}, '${m.titre}', '${m.affiche_path}', '${m.type}')" class="w-full bg-blue-600 hover:bg-blue-500 text-white py-4 rounded-xl font-black shadow-lg transition-all active:scale-95">
|
<button onclick="addMovie(${m.tmdb_id}, '${m.titre}', '${m.affiche_path}', '${m.type}')" class="w-full bg-blue-600 hover:bg-blue-500 text-white py-4 rounded-xl font-black shadow-lg transition-all active:scale-95">
|
||||||
+ AJOUTER À LA LISTE
|
+ AJOUTER À LA LISTE
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
} else if (currentView === 'common') {
|
} else if (currentView === 'common') {
|
||||||
|
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<div class="relative aspect-[2/3] overflow-hidden cursor-pointer" onclick="showDetails(${m.tmdb_id}, '${m.type}', ${m.id}, ${m.vu})">
|
<div class="relative aspect-[2/3] overflow-hidden cursor-pointer" onclick="showDetails(${m.tmdb_id}, '${m.type}', ${m.id}, ${m.vu})">
|
||||||
<img src="https://image.tmdb.org/t/p/w500${m.affiche_path}"
|
<img src="https://image.tmdb.org/t/p/w500${m.affiche_path}"
|
||||||
class="w-full h-full object-cover transition-transform group-hover:scale-110 ${m.vu == 1 ? 'opacity-40 grayscale' : ''}">
|
class="w-full h-full object-cover transition-transform group-hover:scale-110 ${m.vu == 1 ? 'opacity-40 grayscale' : ''}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-3 flex flex-col justify-between flex-grow bg-slate-800">
|
<div class="p-3 flex flex-col justify-between flex-grow bg-slate-800">
|
||||||
<h3 class="font-bold text-sm text-white truncate mb-2" title="${m.titre}">${m.titre}</h3>
|
<h3 class="font-bold text-sm text-white truncate mb-2" title="${m.titre}">${m.titre}</h3>
|
||||||
|
|
||||||
<div class="flex gap-2 mt-auto">
|
<div class="flex gap-2 mt-auto">
|
||||||
<button onclick="toggleVu(${m.id})" class="flex-grow py-2 rounded text-[10px] font-black tracking-wider transition-colors ${m.vu == 1 ? 'bg-green-600 text-white' : 'bg-slate-700 text-gray-300 hover:bg-slate-600'}">
|
<button onclick="toggleVu(${m.id})" class="flex-grow py-2 rounded text-[10px] font-black tracking-wider transition-colors ${m.vu == 1 ? 'bg-green-600 text-white' : 'bg-slate-700 text-gray-300 hover:bg-slate-600'}">
|
||||||
${m.vu == 1 ? 'VU' : 'À VOIR'}
|
${m.vu == 1 ? 'VU' : 'À VOIR'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<div class="relative aspect-[2/3] overflow-hidden cursor-pointer" onclick="showDetails(${m.tmdb_id}, '${m.type}', ${m.id}, ${m.vu})">
|
<div class="relative aspect-[2/3] overflow-hidden cursor-pointer" onclick="showDetails(${m.tmdb_id}, '${m.type}', ${m.id}, ${m.vu})">
|
||||||
<img src="https://image.tmdb.org/t/p/w500${m.affiche_path}"
|
<img src="https://image.tmdb.org/t/p/w500${m.affiche_path}"
|
||||||
class="w-full h-full object-cover transition-transform group-hover:scale-110 ${m.vu == 1 ? 'opacity-40 grayscale' : ''}">
|
class="w-full h-full object-cover transition-transform group-hover:scale-110 ${m.vu == 1 ? 'opacity-40 grayscale' : ''}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-3 flex flex-col justify-between flex-grow bg-slate-800">
|
<div class="p-3 flex flex-col justify-between flex-grow bg-slate-800">
|
||||||
<h3 class="font-bold text-sm text-white truncate mb-2" title="${m.titre}">${m.titre}</h3>
|
<h3 class="font-bold text-sm text-white truncate mb-2" title="${m.titre}">${m.titre}</h3>
|
||||||
|
|
||||||
<div class="flex gap-2 mt-auto">
|
<div class="flex gap-2 mt-auto">
|
||||||
<button onclick="showDetails(${m.tmdb_id}, '${m.type}', ${m.id}, ${m.vu})" class="flex-grow py-2 rounded text-[10px] font-black tracking-wider transition-colors bg-slate-700 text-gray-300 hover:bg-slate-600">
|
<button onclick="showDetails(${m.tmdb_id}, '${m.type}', ${m.id}, ${m.vu})" class="flex-grow py-2 rounded text-[10px] font-black tracking-wider transition-colors bg-slate-700 text-gray-300 hover:bg-slate-600">
|
||||||
Voir plus
|
Voir plus
|
||||||
</button>
|
</button>
|
||||||
<button onclick="deleteMovie(${m.id})" class="bg-red-900/30 hover:bg-red-600 text-red-500 hover:text-white px-3 py-2 rounded transition-colors text-[10px]">
|
<button onclick="deleteMovie(${m.id})" class="bg-red-900/30 hover:bg-red-600 text-red-500 hover:text-white px-3 py-2 rounded transition-colors text-[10px]">
|
||||||
🗑️
|
🗑️
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
grid.appendChild(card);
|
grid.appendChild(card);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actions rapides
|
// Actions rapides
|
||||||
async function toggleVu(id) {
|
async function toggleVu(id) {
|
||||||
const res = await fetch('../RequestHandler.php', {
|
const res = await fetch('../RequestHandler.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ action: 'toggleViewed', params: { movie_id: id } })
|
body: JSON.stringify({ action: 'toggleViewed', params: { movie_id: id } })
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
// On met à jour localement pour ne pas recharger toute l'API
|
// On met à jour localement pour ne pas recharger toute l'API
|
||||||
const movie = allMovies.find(m => m.id == id);
|
const movie = allMovies.find(m => m.id == id);
|
||||||
movie.vu = movie.vu == 1 ? 0 : 1;
|
movie.vu = movie.vu == 1 ? 0 : 1;
|
||||||
renderList();
|
renderList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteMovie(id) {
|
async function deleteMovie(id) {
|
||||||
if(!confirm("Supprimer ce film de ta liste ?")) return;
|
if(!confirm("Supprimer ce film de ta liste ?")) return;
|
||||||
const res = await fetch('../RequestHandler.php', {
|
const res = await fetch('../RequestHandler.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ action: 'deleteMovie', params: { movie_id: id } })
|
body: JSON.stringify({ action: 'deleteMovie', params: { movie_id: id } })
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
allMovies = allMovies.filter(m => m.id != id);
|
allMovies = allMovies.filter(m => m.id != id);
|
||||||
renderList();
|
renderList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentView = 'my'; // 'my', 'common', ou 'partner'
|
let currentView = 'my'; // 'my', 'common', ou 'partner'
|
||||||
|
|
||||||
async function switchTab(view) {
|
async function switchTab(view) {
|
||||||
currentView = view;
|
currentView = view;
|
||||||
|
|
||||||
// Mise à jour visuelle des boutons
|
// Mise à jour visuelle des boutons
|
||||||
const tabs = ['my', 'common', 'partner'];
|
const tabs = ['my', 'common', 'partner'];
|
||||||
tabs.forEach(t => {
|
tabs.forEach(t => {
|
||||||
const btn = document.getElementById(`tab-${t}`);
|
const btn = document.getElementById(`tab-${t}`);
|
||||||
if (t === view) {
|
if (t === view) {
|
||||||
btn.classList.replace('bg-slate-700/50', 'bg-slate-800');
|
btn.classList.replace('bg-slate-700/50', 'bg-slate-800');
|
||||||
btn.classList.replace('text-gray-400', 'text-white');
|
btn.classList.replace('text-gray-400', 'text-white');
|
||||||
btn.classList.replace('border-transparent', 'border-blue-500');
|
btn.classList.replace('border-transparent', 'border-blue-500');
|
||||||
} else {
|
} else {
|
||||||
btn.classList.replace('bg-slate-800', 'bg-slate-700/50');
|
btn.classList.replace('bg-slate-800', 'bg-slate-700/50');
|
||||||
btn.classList.replace('text-white', 'text-gray-400');
|
btn.classList.replace('text-white', 'text-gray-400');
|
||||||
btn.classList.replace('border-blue-500', 'border-transparent');
|
btn.classList.replace('border-blue-500', 'border-transparent');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// On recharge les données selon la vue
|
// On recharge les données selon la vue
|
||||||
let action = 'getMyList';
|
let action = 'getMyList';
|
||||||
if (view === 'common') action = 'getCommonList';
|
if (view === 'common') action = 'getCommonList';
|
||||||
if (view === 'partner') action = 'getPartnerList'; // Il faudra créer cette action dans RequestHandler
|
if (view === 'partner') action = 'getPartnerList'; // Il faudra créer cette action dans RequestHandler
|
||||||
|
|
||||||
const response = await apiRequest(action);
|
const response = await apiRequest(action);
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
allMovies = response.movies || response.common_movies;
|
allMovies = response.movies || response.common_movies;
|
||||||
renderList();
|
renderList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showDetails(tmdbId, type, localId = null, isVu = 0) {
|
async function showDetails(tmdbId, type, localId = null, isVu = 0) {
|
||||||
// 1. On récupère les détails complets via TMDB (comme dans search.js)
|
// 1. On récupère les détails complets via TMDB (comme dans search.js)
|
||||||
const mediaType = (type === 'serie') ? 'tv' : 'movie';
|
const mediaType = (type === 'serie') ? 'tv' : 'movie';
|
||||||
|
|
||||||
// On appelle ton RequestHandler pour avoir les détails + acteurs
|
// On appelle ton RequestHandler pour avoir les détails + acteurs
|
||||||
const movie = await apiRequest('getMovieDetails', { id: tmdbId, type: mediaType });
|
const movie = await apiRequest('getMovieDetails', { id: tmdbId, type: mediaType });
|
||||||
if (!movie) return;
|
if (!movie) return;
|
||||||
|
|
||||||
// 2. On remplit la modal avec les infos fraîches
|
// 2. On remplit la modal avec les infos fraîches
|
||||||
document.getElementById('modalTitle').innerText = movie.title || movie.name;
|
document.getElementById('modalTitle').innerText = movie.title || movie.name;
|
||||||
|
|
||||||
const year = (movie.release_date || movie.first_air_date || "").substring(0, 4);
|
const year = (movie.release_date || movie.first_air_date || "").substring(0, 4);
|
||||||
const duration = movie.runtime ? `${movie.runtime} min` : (movie.number_of_seasons ? `${movie.number_of_seasons} Saison(s)` : "");
|
const duration = movie.runtime ? `${movie.runtime} min` : (movie.number_of_seasons ? `${movie.number_of_seasons} Saison(s)` : "");
|
||||||
const genres = movie.genres.map(g => g.name).join(', ');
|
const genres = movie.genres.map(g => g.name).join(', ');
|
||||||
document.getElementById('modalMeta').innerText = `${year} • ${genres} ${duration ? '• ' + duration : ''}`;
|
document.getElementById('modalMeta').innerText = `${year} • ${genres} ${duration ? '• ' + duration : ''}`;
|
||||||
|
|
||||||
document.getElementById('modalOverview').innerText = movie.overview || "Aucun synopsis disponible.";
|
document.getElementById('modalOverview').innerText = movie.overview || "Aucun synopsis disponible.";
|
||||||
document.getElementById('modalVote').innerText = movie.vote_average ? movie.vote_average.toFixed(1) : "N/A";
|
document.getElementById('modalVote').innerText = movie.vote_average ? movie.vote_average.toFixed(1) : "N/A";
|
||||||
|
|
||||||
// Image de bannière
|
// Image de bannière
|
||||||
const bannerUrl = movie.backdrop_path ? `https://image.tmdb.org/t/p/original${movie.backdrop_path}` : '';
|
const bannerUrl = movie.backdrop_path ? `https://image.tmdb.org/t/p/original${movie.backdrop_path}` : '';
|
||||||
document.getElementById('modalBanner').style.backgroundImage = `url(${bannerUrl})`;
|
document.getElementById('modalBanner').style.backgroundImage = `url(${bannerUrl})`;
|
||||||
|
|
||||||
// Réalisateur
|
// Réalisateur
|
||||||
const director = movie.credits.crew.find(person => person.job === 'Director');
|
const director = movie.credits.crew.find(person => person.job === 'Director');
|
||||||
document.getElementById('modalDirector').innerText = director ? director.name : "Non renseigné";
|
document.getElementById('modalDirector').innerText = director ? director.name : "Non renseigné";
|
||||||
|
|
||||||
// Casting
|
// Casting
|
||||||
const castContainer = document.getElementById('modalCast');
|
const castContainer = document.getElementById('modalCast');
|
||||||
castContainer.innerHTML = movie.credits.cast.slice(0, 8).map(actor => `
|
castContainer.innerHTML = movie.credits.cast.slice(0, 8).map(actor => `
|
||||||
<div class="min-w-[110px] text-center flex-shrink-0">
|
<div class="min-w-[110px] text-center flex-shrink-0">
|
||||||
<img src="${actor.profile_path ? 'https://image.tmdb.org/t/p/w185' + actor.profile_path : 'https://via.placeholder.com/185x278?text=No+Image'}"
|
<img src="${actor.profile_path ? 'https://image.tmdb.org/t/p/w185' + actor.profile_path : 'https://via.placeholder.com/185x278?text=No+Image'}"
|
||||||
class="w-20 h-20 object-cover rounded-full mx-auto mb-2 border-2 border-slate-700 shadow-lg">
|
class="w-20 h-20 object-cover rounded-full mx-auto mb-2 border-2 border-slate-700 shadow-lg">
|
||||||
<p class="text-[10px] font-bold text-white">${actor.name}</p>
|
<p class="text-[10px] font-bold text-white">${actor.name}</p>
|
||||||
</div>
|
</div>
|
||||||
`).join('');
|
`).join('');
|
||||||
|
|
||||||
// 3. LOGIQUE DU BOUTON (Vu / Pas Vu)
|
// 3. LOGIQUE DU BOUTON (Vu / Pas Vu)
|
||||||
const btn = document.getElementById('modalMainBtn');
|
const btn = document.getElementById('modalMainBtn');
|
||||||
const ratingZone = document.getElementById('ratingZone');
|
const ratingZone = document.getElementById('ratingZone');
|
||||||
|
|
||||||
if (localId) {
|
if (localId) {
|
||||||
ratingZone.classList.remove('hidden'); // On montre les étoiles
|
ratingZone.classList.remove('hidden'); // On montre les étoiles
|
||||||
|
|
||||||
if (isVu == 1) {
|
if (isVu == 1) {
|
||||||
btn.innerText = "NE PLUS MARQUER COMME VU";
|
btn.innerText = "NE PLUS MARQUER COMME VU";
|
||||||
btn.className = "w-full bg-slate-700 hover:bg-slate-600 text-white py-4 rounded-xl font-black transition-all";
|
btn.className = "w-full bg-slate-700 hover:bg-slate-600 text-white py-4 rounded-xl font-black transition-all";
|
||||||
} else {
|
} else {
|
||||||
btn.innerText = "MARQUER COMME VU";
|
btn.innerText = "MARQUER COMME VU";
|
||||||
btn.className = "w-full bg-green-600 hover:bg-green-500 text-white py-4 rounded-xl font-black transition-all";
|
btn.className = "w-full bg-green-600 hover:bg-green-500 text-white py-4 rounded-xl font-black transition-all";
|
||||||
}
|
}
|
||||||
|
|
||||||
btn.onclick = async () => {
|
btn.onclick = async () => {
|
||||||
await toggleVu(localId); // Ta fonction qui change le statut en BDD
|
await toggleVu(localId); // Ta fonction qui change le statut en BDD
|
||||||
closeModal();
|
closeModal();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. LOGIQYUE DES ÉTOILES
|
// 4. LOGIQYUE DES ÉTOILES
|
||||||
// On récupère la note actuelle pour ce film (si elle existe)
|
// On récupère la note actuelle pour ce film (si elle existe)
|
||||||
apiRequest('getStarsRating', { movie_id: localId }).then(res => {
|
apiRequest('getStarsRating', { movie_id: localId }).then(res => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
const currentRating = res.rating || 0;
|
const currentRating = res.rating || 0;
|
||||||
setRating(currentRating); // On affiche la note actuelle
|
setRating(currentRating); // On affiche la note actuelle
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Affichage final
|
// Affichage final
|
||||||
document.getElementById('movieModal').classList.remove('hidden');
|
document.getElementById('movieModal').classList.remove('hidden');
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fonction pour les étoiles
|
// Fonction pour les étoiles
|
||||||
function setRating(note) {
|
function setRating(note) {
|
||||||
const currentMovieId = document.getElementById('modalMainBtn').onclick.toString().match(/toggleVu\((\d+)\)/)[1]; // Extraction de l'ID du film
|
const currentMovieId = document.getElementById('modalMainBtn').onclick.toString().match(/toggleVu\((\d+)\)/)[1]; // Extraction de l'ID du film
|
||||||
const stars = document.querySelectorAll('#starContainer span');
|
const stars = document.querySelectorAll('#starContainer span');
|
||||||
stars.forEach((star, index) => {
|
stars.forEach((star, index) => {
|
||||||
if (index < note) {
|
if (index < note) {
|
||||||
star.classList.replace('text-gray-600', 'text-yellow-400');
|
star.classList.replace('text-gray-600', 'text-yellow-400');
|
||||||
} else {
|
} else {
|
||||||
star.classList.replace('text-yellow-400', 'text-gray-600');
|
star.classList.replace('text-yellow-400', 'text-gray-600');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
apiRequest('setStarsRating', { movie_id: currentMovieId, rating: note }); // currentMovieId doit être défini lors de l'ouverture de la modal
|
apiRequest('setStarsRating', { movie_id: currentMovieId, rating: note }); // currentMovieId doit être défini lors de l'ouverture de la modal
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
document.getElementById('movieModal').classList.add('hidden');
|
document.getElementById('movieModal').classList.add('hidden');
|
||||||
document.body.style.overflow = 'auto';
|
document.body.style.overflow = 'auto';
|
||||||
}
|
}
|
||||||
|
|
||||||
loadList();
|
loadList();
|
||||||
@@ -1,180 +1,180 @@
|
|||||||
// --- CONFIGURATION & UTILITAIRES ---
|
// --- CONFIGURATION & UTILITAIRES ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fonction universelle pour parler à ton RequestHandler
|
* Fonction universelle pour parler à ton RequestHandler
|
||||||
* @param {string} action - L'action à exécuter (ex: 'searchTMDB')
|
* @param {string} action - L'action à exécuter (ex: 'searchTMDB')
|
||||||
* @param {object} params - Les données à envoyer
|
* @param {object} params - Les données à envoyer
|
||||||
*/
|
*/
|
||||||
async function apiRequest(action, params = {}) {
|
async function apiRequest(action, params = {}) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('../RequestHandler.php', {
|
const response = await fetch('../RequestHandler.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ action, params })
|
body: JSON.stringify({ action, params })
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur API:", error);
|
console.error("Erreur API:", error);
|
||||||
return { success: false, error: "Erreur de connexion au serveur" };
|
return { success: false, error: "Erreur de connexion au serveur" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('ratingZone').classList.add('hidden');
|
document.getElementById('ratingZone').classList.add('hidden');
|
||||||
|
|
||||||
// --- RECHERCHE ---
|
// --- RECHERCHE ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lance la recherche TMDB et affiche les résultats sous forme de cartes
|
* Lance la recherche TMDB et affiche les résultats sous forme de cartes
|
||||||
*/
|
*/
|
||||||
async function performSearch() {
|
async function performSearch() {
|
||||||
const query = document.getElementById('searchInput').value;
|
const query = document.getElementById('searchInput').value;
|
||||||
if (!query) return;
|
if (!query) return;
|
||||||
|
|
||||||
const grid = document.getElementById('resultsGrid');
|
const grid = document.getElementById('resultsGrid');
|
||||||
grid.innerHTML = '<p class="col-span-full text-center py-10 opacity-50">Recherche de pépites en cours...</p>';
|
grid.innerHTML = '<p class="col-span-full text-center py-10 opacity-50">Recherche de pépites en cours...</p>';
|
||||||
|
|
||||||
const data = await apiRequest('searchTMDB', { query: query });
|
const data = await apiRequest('searchTMDB', { query: query });
|
||||||
|
|
||||||
grid.innerHTML = ''; // On vide
|
grid.innerHTML = ''; // On vide
|
||||||
|
|
||||||
if (data.results && data.results.length > 0) {
|
if (data.results && data.results.length > 0) {
|
||||||
data.results.forEach(item => {
|
data.results.forEach(item => {
|
||||||
// On ignore les résultats sans image ou qui ne sont pas film/série
|
// On ignore les résultats sans image ou qui ne sont pas film/série
|
||||||
if (!item.poster_path || (item.media_type !== 'movie' && item.media_type !== 'tv')) return;
|
if (!item.poster_path || (item.media_type !== 'movie' && item.media_type !== 'tv')) return;
|
||||||
|
|
||||||
const title = item.title || item.name;
|
const title = item.title || item.name;
|
||||||
const poster = `https://image.tmdb.org/t/p/w500${item.poster_path}`;
|
const poster = `https://image.tmdb.org/t/p/w500${item.poster_path}`;
|
||||||
const type = item.media_type === 'tv' ? 'serie' : 'film';
|
const type = item.media_type === 'tv' ? 'serie' : 'film';
|
||||||
const year = (item.release_date || item.first_air_date || "").substring(0, 4);
|
const year = (item.release_date || item.first_air_date || "").substring(0, 4);
|
||||||
|
|
||||||
const card = document.createElement('div');
|
const card = document.createElement('div');
|
||||||
card.className = 'bg-slate-800 rounded-xl overflow-hidden border border-slate-700 hover:scale-105 transition-transform cursor-pointer group';
|
card.className = 'bg-slate-800 rounded-xl overflow-hidden border border-slate-700 hover:scale-105 transition-transform cursor-pointer group';
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<div class="relative overflow-hidden" onclick="showDetails(${item.id}, '${item.media_type}')">
|
<div class="relative overflow-hidden" onclick="showDetails(${item.id}, '${item.media_type}')">
|
||||||
<img src="${poster}" class="w-full h-auto">
|
<img src="${poster}" class="w-full h-auto">
|
||||||
<div class="absolute inset-0 bg-black/60 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
<div class="absolute inset-0 bg-black/60 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
||||||
<span class="bg-white text-black px-4 py-2 rounded-full font-bold text-xs uppercase tracking-wider">Voir la fiche</span>
|
<span class="bg-white text-black px-4 py-2 rounded-full font-bold text-xs uppercase tracking-wider">Voir la fiche</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-3">
|
<div class="p-3">
|
||||||
<h3 class="font-bold text-sm truncate">${title}</h3>
|
<h3 class="font-bold text-sm truncate">${title}</h3>
|
||||||
<div class="flex justify-between items-center mt-1">
|
<div class="flex justify-between items-center mt-1">
|
||||||
<span class="text-[10px] text-gray-400 uppercase">${type}</span>
|
<span class="text-[10px] text-gray-400 uppercase">${type}</span>
|
||||||
<span class="text-[10px] text-blue-400 font-bold">${year}</span>
|
<span class="text-[10px] text-blue-400 font-bold">${year}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
grid.appendChild(card);
|
grid.appendChild(card);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
grid.innerHTML = '<p class="col-span-full text-center py-10 text-gray-500">Aucun résultat trouvé pour cette recherche.</p>';
|
grid.innerHTML = '<p class="col-span-full text-center py-10 text-gray-500">Aucun résultat trouvé pour cette recherche.</p>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- FICHE DÉTAILLÉE (MODAL) ---
|
// --- FICHE DÉTAILLÉE (MODAL) ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Récupère les détails complets d'un film et ouvre la modal
|
* Récupère les détails complets d'un film et ouvre la modal
|
||||||
*/
|
*/
|
||||||
async function showDetails(id, type) {
|
async function showDetails(id, type) {
|
||||||
// TMDB utilise 'movie' ou 'tv', on s'assure d'avoir le bon type
|
// TMDB utilise 'movie' ou 'tv', on s'assure d'avoir le bon type
|
||||||
const mediaType = (type === 'serie') ? 'tv' : type;
|
const mediaType = (type === 'serie') ? 'tv' : type;
|
||||||
|
|
||||||
const movie = await apiRequest('getMovieDetails', { id: id, type: mediaType });
|
const movie = await apiRequest('getMovieDetails', { id: id, type: mediaType });
|
||||||
if (!movie) return;
|
if (!movie) return;
|
||||||
|
|
||||||
const modal = document.getElementById('movieModal');
|
const modal = document.getElementById('movieModal');
|
||||||
|
|
||||||
// 1. Textes de base
|
// 1. Textes de base
|
||||||
document.getElementById('modalTitle').innerText = movie.title || movie.name;
|
document.getElementById('modalTitle').innerText = movie.title || movie.name;
|
||||||
const year = (movie.release_date || movie.first_air_date || "").substring(0, 4);
|
const year = (movie.release_date || movie.first_air_date || "").substring(0, 4);
|
||||||
const duration = movie.runtime ? `${movie.runtime} min` : (movie.number_of_seasons ? `${movie.number_of_seasons} Saison(s)` : "");
|
const duration = movie.runtime ? `${movie.runtime} min` : (movie.number_of_seasons ? `${movie.number_of_seasons} Saison(s)` : "");
|
||||||
const genres = movie.genres.map(g => g.name).join(', ');
|
const genres = movie.genres.map(g => g.name).join(', ');
|
||||||
|
|
||||||
document.getElementById('modalMeta').innerText = `${year} • ${genres} ${duration ? '• ' + duration : ''}`;
|
document.getElementById('modalMeta').innerText = `${year} • ${genres} ${duration ? '• ' + duration : ''}`;
|
||||||
document.getElementById('modalOverview').innerText = movie.overview || "Aucun synopsis disponible pour le moment.";
|
document.getElementById('modalOverview').innerText = movie.overview || "Aucun synopsis disponible pour le moment.";
|
||||||
document.getElementById('modalVote').innerText = movie.vote_average ? movie.vote_average.toFixed(1) : "N/A";
|
document.getElementById('modalVote').innerText = movie.vote_average ? movie.vote_average.toFixed(1) : "N/A";
|
||||||
|
|
||||||
// 2. Images (Bannière)
|
// 2. Images (Bannière)
|
||||||
const bannerUrl = movie.backdrop_path ? `https://image.tmdb.org/t/p/original${movie.backdrop_path}` : '';
|
const bannerUrl = movie.backdrop_path ? `https://image.tmdb.org/t/p/original${movie.backdrop_path}` : '';
|
||||||
document.getElementById('modalBanner').style.backgroundImage = `url(${bannerUrl})`;
|
document.getElementById('modalBanner').style.backgroundImage = `url(${bannerUrl})`;
|
||||||
|
|
||||||
// 3. Réalisateur
|
// 3. Réalisateur
|
||||||
const director = movie.credits.crew.find(person => person.job === 'Director');
|
const director = movie.credits.crew.find(person => person.job === 'Director');
|
||||||
document.getElementById('modalDirector').innerText = director ? director.name : "Non renseigné";
|
document.getElementById('modalDirector').innerText = director ? director.name : "Non renseigné";
|
||||||
|
|
||||||
// 4. Casting (Les 8 premiers)
|
// 4. Casting (Les 8 premiers)
|
||||||
const castContainer = document.getElementById('modalCast');
|
const castContainer = document.getElementById('modalCast');
|
||||||
castContainer.innerHTML = movie.credits.cast.slice(0, 8).map(actor => `
|
castContainer.innerHTML = movie.credits.cast.slice(0, 8).map(actor => `
|
||||||
<div class="min-w-[110px] text-center flex-shrink-0">
|
<div class="min-w-[110px] text-center flex-shrink-0">
|
||||||
<img src="${actor.profile_path ? 'https://image.tmdb.org/t/p/w185' + actor.profile_path : 'https://via.placeholder.com/185x278?text=No+Image'}"
|
<img src="${actor.profile_path ? 'https://image.tmdb.org/t/p/w185' + actor.profile_path : 'https://via.placeholder.com/185x278?text=No+Image'}"
|
||||||
class="w-20 h-20 object-cover rounded-full mx-auto mb-2 border-2 border-slate-700 shadow-lg">
|
class="w-20 h-20 object-cover rounded-full mx-auto mb-2 border-2 border-slate-700 shadow-lg">
|
||||||
<p class="text-[10px] font-bold leading-tight text-white">${actor.name}</p>
|
<p class="text-[10px] font-bold leading-tight text-white">${actor.name}</p>
|
||||||
<p class="text-[9px] text-gray-500 italic">${actor.character}</p>
|
<p class="text-[9px] text-gray-500 italic">${actor.character}</p>
|
||||||
</div>
|
</div>
|
||||||
`).join('');
|
`).join('');
|
||||||
|
|
||||||
// 5. Bouton Ajouter (on passe les infos pour la BDD)
|
// 5. Bouton Ajouter (on passe les infos pour la BDD)
|
||||||
const simplifiedType = (mediaType === 'tv') ? 'serie' : 'film';
|
const simplifiedType = (mediaType === 'tv') ? 'serie' : 'film';
|
||||||
const btn = document.getElementById('modalMainBtn');
|
const btn = document.getElementById('modalMainBtn');
|
||||||
btn.innerText = "+ AJOUTER À LA LISTE";
|
btn.innerText = "+ AJOUTER À LA LISTE";
|
||||||
btn.className = "w-full bg-blue-600 hover:bg-blue-500 text-white py-4 rounded-xl font-black shadow-lg transition-all active:scale-95";
|
btn.className = "w-full bg-blue-600 hover:bg-blue-500 text-white py-4 rounded-xl font-black shadow-lg transition-all active:scale-95";
|
||||||
btn.onclick = () => addMovie(movie.id, movie.title || movie.name, movie.poster_path, simplifiedType);
|
btn.onclick = () => addMovie(movie.id, movie.title || movie.name, movie.poster_path, simplifiedType);
|
||||||
|
|
||||||
// Cache les étoiles en mode recherche
|
// Cache les étoiles en mode recherche
|
||||||
document.getElementById('ratingZone').classList.add('hidden');
|
document.getElementById('ratingZone').classList.add('hidden');
|
||||||
|
|
||||||
// Affichage
|
// Affichage
|
||||||
modal.classList.remove('hidden');
|
modal.classList.remove('hidden');
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ferme la modal
|
* Ferme la modal
|
||||||
*/
|
*/
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
document.getElementById('movieModal').classList.add('hidden');
|
document.getElementById('movieModal').classList.add('hidden');
|
||||||
document.body.style.overflow = 'auto';
|
document.body.style.overflow = 'auto';
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- ACTIONS BDD ---
|
// --- ACTIONS BDD ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ajoute un film dans la base de données MySQL
|
* Ajoute un film dans la base de données MySQL
|
||||||
*/
|
*/
|
||||||
async function addMovie(tmdbId, title, posterPath, type) {
|
async function addMovie(tmdbId, title, posterPath, type) {
|
||||||
const result = await apiRequest('addMovie', {
|
const result = await apiRequest('addMovie', {
|
||||||
tmdb_id: tmdbId,
|
tmdb_id: tmdbId,
|
||||||
titre: title,
|
titre: title,
|
||||||
affiche_path: posterPath,
|
affiche_path: posterPath,
|
||||||
type: type
|
type: type
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
alert(`"${title}" a été ajouté à votre liste ! 🍿`);
|
alert(`"${title}" a été ajouté à votre liste ! 🍿`);
|
||||||
closeModal();
|
closeModal();
|
||||||
} else {
|
} else {
|
||||||
alert('Erreur lors de l\'ajout. Vérifie si le film n\'est pas déjà présent.');
|
alert('Erreur lors de l\'ajout. Vérifie si le film n\'est pas déjà présent.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Permettre la recherche avec la touche "Entrée"
|
// Permettre la recherche avec la touche "Entrée"
|
||||||
document.getElementById('searchInput').addEventListener('keypress', function (e) {
|
document.getElementById('searchInput').addEventListener('keypress', function (e) {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
performSearch();
|
performSearch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function LogOut() {
|
async function LogOut() {
|
||||||
const res = await fetch('../RequestHandler.php', {
|
const res = await fetch('../RequestHandler.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ action: 'logout' })
|
body: JSON.stringify({ action: 'logout' })
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
window.location.href = '../index.php';
|
window.location.href = '../index.php';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,82 +1,82 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
if (!isset($_SESSION['user_id'])) {
|
if (!isset($_SESSION['user_id'])) {
|
||||||
header('Location: ../index.php'); // Redirige vers le login si pas de session
|
header('Location: ../index.php'); // Redirige vers le login si pas de session
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Ma Liste - WatchGether</title>
|
<title>Ma Liste - WatchGether</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-slate-900 text-white p-8">
|
<body class="bg-slate-900 text-white p-8">
|
||||||
|
|
||||||
<div class="max-w-6xl mx-auto">
|
<div class="max-w-6xl mx-auto">
|
||||||
<div class="flex justify-between items-center mb-10">
|
<div class="flex justify-between items-center mb-10">
|
||||||
<h1 class="text-3xl font-bold text-blue-400">Ma Liste 🍿</h1>
|
<h1 class="text-3xl font-bold text-blue-400">Ma Liste 🍿</h1>
|
||||||
<a href="../search/index.php" class="bg-slate-800 px-4 py-2 rounded-lg hover:bg-slate-700 transition">← Retour à la recherche</a>
|
<a href="../search/index.php" class="bg-slate-800 px-4 py-2 rounded-lg hover:bg-slate-700 transition">← Retour à la recherche</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-end mb-0 border-b border-slate-700">
|
<div class="flex items-end mb-0 border-b border-slate-700">
|
||||||
<button onclick="switchTab('my')" id="tab-my"
|
<button onclick="switchTab('my')" id="tab-my"
|
||||||
class="px-8 py-4 bg-slate-800 text-white font-bold text-sm uppercase tracking-widest border-b-4 border-blue-500 transition-all">
|
class="px-8 py-4 bg-slate-800 text-white font-bold text-sm uppercase tracking-widest border-b-4 border-blue-500 transition-all">
|
||||||
Ma Liste
|
Ma Liste
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button onclick="switchTab('common')" id="tab-common"
|
<button onclick="switchTab('common')" id="tab-common"
|
||||||
class="px-8 py-4 bg-slate-700/50 text-gray-400 font-bold text-sm uppercase tracking-widest border-b-4 border-transparent hover:bg-slate-800 hover:text-white transition-all">
|
class="px-8 py-4 bg-slate-700/50 text-gray-400 font-bold text-sm uppercase tracking-widest border-b-4 border-transparent hover:bg-slate-800 hover:text-white transition-all">
|
||||||
Notre Liste
|
Notre Liste
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button onclick="switchTab('partner')" id="tab-partner"
|
<button onclick="switchTab('partner')" id="tab-partner"
|
||||||
class="px-8 py-4 bg-slate-700/50 text-gray-400 font-bold text-sm uppercase tracking-widest border-b-4 border-transparent hover:bg-slate-800 hover:text-white transition-all">
|
class="px-8 py-4 bg-slate-700/50 text-gray-400 font-bold text-sm uppercase tracking-widest border-b-4 border-transparent hover:bg-slate-800 hover:text-white transition-all">
|
||||||
Sa Liste
|
Sa Liste
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-slate-800 p-4 rounded-xl mb-8 flex flex-wrap gap-4 items-center">
|
<div class="bg-slate-800 p-4 rounded-xl mb-8 flex flex-wrap gap-4 items-center">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label class="text-xs text-gray-400 mb-1 uppercase font-bold">Trier par</label>
|
<label class="text-xs text-gray-400 mb-1 uppercase font-bold">Trier par</label>
|
||||||
<select id="sortOrder" onchange="renderList()" class="bg-slate-700 border-none rounded p-2 focus:ring-2 focus:ring-blue-500">
|
<select id="sortOrder" onchange="renderList()" class="bg-slate-700 border-none rounded p-2 focus:ring-2 focus:ring-blue-500">
|
||||||
<option value="date_ajout_desc">Date d'ajout (Récent)</option>
|
<option value="date_ajout_desc">Date d'ajout (Récent)</option>
|
||||||
<option value="date_ajout_asc">Date d'ajout (Ancien)</option>
|
<option value="date_ajout_asc">Date d'ajout (Ancien)</option>
|
||||||
<option value="titre_asc">Ordre Alphabétique</option>
|
<option value="titre_asc">Ordre Alphabétique</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label class="text-xs text-gray-400 mb-1 uppercase font-bold">Type</label>
|
<label class="text-xs text-gray-400 mb-1 uppercase font-bold">Type</label>
|
||||||
<select id="filterType" onchange="renderList()" class="bg-slate-700 border-none rounded p-2">
|
<select id="filterType" onchange="renderList()" class="bg-slate-700 border-none rounded p-2">
|
||||||
<option value="all">Tout voir</option>
|
<option value="all">Tout voir</option>
|
||||||
<option value="film">Films uniquement</option>
|
<option value="film">Films uniquement</option>
|
||||||
<option value="serie">Séries uniquement</option>
|
<option value="serie">Séries uniquement</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label class="text-xs text-gray-400 mb-1 uppercase font-bold">Statut</label>
|
<label class="text-xs text-gray-400 mb-1 uppercase font-bold">Statut</label>
|
||||||
<select id="filterStatus" onchange="renderList()" class="bg-slate-700 border-none rounded p-2">
|
<select id="filterStatus" onchange="renderList()" class="bg-slate-700 border-none rounded p-2">
|
||||||
<option value="all">Tout</option>
|
<option value="all">Tout</option>
|
||||||
<option value="0">À voir</option>
|
<option value="0">À voir</option>
|
||||||
<option value="1">Déjà vus</option>
|
<option value="1">Déjà vus</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ml-auto text-sm text-gray-400">
|
<div class="ml-auto text-sm text-gray-400">
|
||||||
<span id="movieCount">0</span> éléments
|
<span id="movieCount">0</span> éléments
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="myListGrid" class="grid grid-cols-2 md:grid-cols-5 gap-6">
|
<div id="myListGrid" class="grid grid-cols-2 md:grid-cols-5 gap-6">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php include '../modal-template.php';?>
|
<?php include '../modal-template.php';?>
|
||||||
|
|
||||||
<script src="../js/list.js"></script>
|
<script src="../js/list.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,60 +1,60 @@
|
|||||||
<div id="movieModal" class="fixed inset-0 bg-black/95 z-50 hidden overflow-y-auto">
|
<div id="movieModal" class="fixed inset-0 bg-black/95 z-50 hidden overflow-y-auto">
|
||||||
<div class="relative w-full max-w-5xl mx-auto min-h-screen bg-slate-900 shadow-2xl border-x border-white/10">
|
<div class="relative w-full max-w-5xl mx-auto min-h-screen bg-slate-900 shadow-2xl border-x border-white/10">
|
||||||
|
|
||||||
<button onclick="closeModal()" class="absolute top-6 right-6 z-50 bg-black/50 text-white p-2 rounded-full hover:bg-red-600 transition">
|
<button onclick="closeModal()" class="absolute top-6 right-6 z-50 bg-black/50 text-white p-2 rounded-full hover:bg-red-600 transition">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div id="modalBanner" class="w-full h-[300px] md:h-[450px] bg-cover bg-center relative">
|
<div id="modalBanner" class="w-full h-[300px] md:h-[450px] bg-cover bg-center relative">
|
||||||
<div class="absolute inset-0 bg-gradient-to-t from-slate-900 via-slate-900/20 to-transparent"></div>
|
<div class="absolute inset-0 bg-gradient-to-t from-slate-900 via-slate-900/20 to-transparent"></div>
|
||||||
<div class="absolute bottom-10 left-6 md:left-10 right-6">
|
<div class="absolute bottom-10 left-6 md:left-10 right-6">
|
||||||
<h2 id="modalTitle" class="text-4xl md:text-6xl font-black text-white drop-shadow-lg"></h2>
|
<h2 id="modalTitle" class="text-4xl md:text-6xl font-black text-white drop-shadow-lg"></h2>
|
||||||
<p id="modalMeta" class="text-lg text-blue-400 font-semibold mt-2"></p>
|
<p id="modalMeta" class="text-lg text-blue-400 font-semibold mt-2"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-6 md:p-10 grid md:grid-cols-3 gap-10">
|
<div class="p-6 md:p-10 grid md:grid-cols-3 gap-10">
|
||||||
<div class="md:col-span-2">
|
<div class="md:col-span-2">
|
||||||
<h3 class="text-xl font-bold mb-3 text-white border-b border-white/10 pb-2">Synopsis</h3>
|
<h3 class="text-xl font-bold mb-3 text-white border-b border-white/10 pb-2">Synopsis</h3>
|
||||||
<p id="modalOverview" class="text-gray-300 leading-relaxed text-lg mb-8"></p>
|
<p id="modalOverview" class="text-gray-300 leading-relaxed text-lg mb-8"></p>
|
||||||
|
|
||||||
<h3 class="text-xl font-bold mb-4 text-white border-b border-white/10 pb-2">Casting principal</h3>
|
<h3 class="text-xl font-bold mb-4 text-white border-b border-white/10 pb-2">Casting principal</h3>
|
||||||
<div id="modalCast" class="flex gap-4 overflow-x-auto pb-6 scrollbar-hide"></div>
|
<div id="modalCast" class="flex gap-4 overflow-x-auto pb-6 scrollbar-hide"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<div class="bg-slate-800/80 p-6 rounded-2xl border border-white/5">
|
<div class="bg-slate-800/80 p-6 rounded-2xl border border-white/5">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<span class="text-gray-400 text-xs uppercase tracking-widest block mb-1">Note TMDB</span>
|
<span class="text-gray-400 text-xs uppercase tracking-widest block mb-1">Note TMDB</span>
|
||||||
<div class="flex items-baseline gap-1">
|
<div class="flex items-baseline gap-1">
|
||||||
<span id="modalVote" class="text-4xl font-black text-yellow-500"></span>
|
<span id="modalVote" class="text-4xl font-black text-yellow-500"></span>
|
||||||
<span class="text-gray-500 font-bold">/ 10</span>
|
<span class="text-gray-500 font-bold">/ 10</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<span class="text-gray-400 text-xs uppercase tracking-widest block mb-1">Réalisateur</span>
|
<span class="text-gray-400 text-xs uppercase tracking-widest block mb-1">Réalisateur</span>
|
||||||
<span id="modalDirector" class="text-xl font-bold text-white"></span>
|
<span id="modalDirector" class="text-xl font-bold text-white"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="ratingZone" class="mb-6 hidden">
|
<div id="ratingZone" class="mb-6 hidden">
|
||||||
<span class="text-gray-400 text-xs uppercase tracking-widest block mb-2">Ta note</span>
|
<span class="text-gray-400 text-xs uppercase tracking-widest block mb-2">Ta note</span>
|
||||||
<div class="flex gap-2 text-2xl" id="starContainer">
|
<div class="flex gap-2 text-2xl" id="starContainer">
|
||||||
<span onclick="setRating(1)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
<span onclick="setRating(1)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
||||||
<span onclick="setRating(2)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
<span onclick="setRating(2)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
||||||
<span onclick="setRating(3)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
<span onclick="setRating(3)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
||||||
<span onclick="setRating(4)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
<span onclick="setRating(4)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
||||||
<span onclick="setRating(5)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
<span onclick="setRating(5)" class="cursor-pointer hover:text-yellow-400 transition text-gray-600">★</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="modalMainBtn" class="w-full py-4 rounded-xl font-black text-lg shadow-lg transition-all active:scale-95 text-white bg-blue-600 hover:bg-blue-500">
|
<button id="modalMainBtn" class="w-full py-4 rounded-xl font-black text-lg shadow-lg transition-all active:scale-95 text-white bg-blue-600 hover:bg-blue-500">
|
||||||
ACTION
|
ACTION
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,45 +1,45 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
if (!isset($_SESSION['user_id'])) {
|
if (!isset($_SESSION['user_id'])) {
|
||||||
header('Location: ../index.php'); // Redirige vers le login si pas de session
|
header('Location: ../index.php'); // Redirige vers le login si pas de session
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>WatchGether - Recherche</title>
|
<title>WatchGether - Recherche</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-slate-900 text-white p-8">
|
<body class="bg-slate-900 text-white p-8">
|
||||||
|
|
||||||
<div class="max-w-4xl mx-auto">
|
<div class="max-w-4xl mx-auto">
|
||||||
<div class="flex justify-between items-center mb-8">
|
<div class="flex justify-between items-center mb-8">
|
||||||
<a href="../ma-liste" class="bg-slate-800 hover:bg-slate-700 text-white px-6 py-3 rounded-xl font-bold border border-white/5 transition-all active:scale-95 shadow-lg">
|
<a href="../ma-liste" class="bg-slate-800 hover:bg-slate-700 text-white px-6 py-3 rounded-xl font-bold border border-white/5 transition-all active:scale-95 shadow-lg">
|
||||||
🍿 Ma liste
|
🍿 Ma liste
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<h1 class="text-5xl md:text-6xl font-black tracking-tighter italic">
|
<h1 class="text-5xl md:text-6xl font-black tracking-tighter italic">
|
||||||
<span class="text-blue-500">WATCH</span><span class="text-white">GETHER</span>
|
<span class="text-blue-500">WATCH</span><span class="text-white">GETHER</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<button onclick="LogOut()" class="bg-red-600 hover:bg-red-500 text-white px-6 py-3 rounded-xl font-bold shadow-lg shadow-red-900/20 transition-all active:scale-95">
|
<button onclick="LogOut()" class="bg-red-600 hover:bg-red-500 text-white px-6 py-3 rounded-xl font-bold shadow-lg shadow-red-900/20 transition-all active:scale-95">
|
||||||
👤 Se déconnecter
|
👤 Se déconnecter
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-2 mb-10">
|
<div class="flex gap-2 mb-10">
|
||||||
<input type="text" id="searchInput" placeholder="Chercher un film ou une série..."
|
<input type="text" id="searchInput" placeholder="Chercher un film ou une série..."
|
||||||
class="flex-grow p-4 rounded-lg bg-slate-800 border border-slate-700 focus:outline-none focus:border-blue-500 text-white">
|
class="flex-grow p-4 rounded-lg bg-slate-800 border border-slate-700 focus:outline-none focus:border-blue-500 text-white">
|
||||||
<button onclick="performSearch()" class="bg-blue-600 px-8 py-4 rounded-lg font-bold hover:bg-blue-500 transition shadow-lg">
|
<button onclick="performSearch()" class="bg-blue-600 px-8 py-4 rounded-lg font-bold hover:bg-blue-500 transition shadow-lg">
|
||||||
Chercher
|
Chercher
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="resultsGrid" class="grid grid-cols-2 md:grid-cols-4 gap-6"></div>
|
<div id="resultsGrid" class="grid grid-cols-2 md:grid-cols-4 gap-6"></div>
|
||||||
</div>
|
</div>
|
||||||
<?php include '../modal-template.php';?>
|
<?php include '../modal-template.php';?>
|
||||||
<script src="../js/search.js"></script>
|
<script src="../js/search.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||