You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
12 KiB
252 lines
12 KiB
import Navbar from "../components/Navbar.jsx";
|
|
import {useEffect, useState} from "react";
|
|
import PlaylistCard from "../components/PlaylistCard.jsx";
|
|
import VideoCard from "../components/VideoCard.jsx";
|
|
import {useNavigate} from "react-router-dom";
|
|
import CreateChannelModal from "../modals/CreateChannelModal.jsx";
|
|
import { getChannel, getUserHistory, getPlaylists, updateUser } from "../services/user.service.js";
|
|
|
|
|
|
export default function Account() {
|
|
|
|
let user = JSON.parse(localStorage.getItem("user")) || {};
|
|
let token = localStorage.getItem("token") || "";
|
|
|
|
const [username, setUsername] = useState(user.username || "");
|
|
const [email, setEmail] = useState(user.email || "");
|
|
const [password, setPassword] = useState("");
|
|
const [confirmPassword, setConfirmPassword] = useState("");
|
|
const [isPictureEditActive, setIsPictureEditActive] = useState(false);
|
|
const [userHistory, setUserHistory] = useState([]);
|
|
const [userPlaylists, setUserPlaylists] = useState([]);
|
|
const [userChannel, setUserChannel] = useState(null);
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
const [alerts, setAlerts] = useState([]);
|
|
|
|
const navigation = useNavigate();
|
|
|
|
const fetchUserChannel = async () => {
|
|
setUserChannel(await getChannel(user.id, token, addAlert)); // Reset before fetching
|
|
}
|
|
const fetchUserHistory = async () => {
|
|
setUserHistory(await getUserHistory(user.id, token, addAlert));
|
|
}
|
|
const fetchUserPlaylists = async () => {
|
|
setUserPlaylists(await getPlaylists(user.id, token, addAlert));
|
|
}
|
|
|
|
useEffect(() => {
|
|
fetchUserChannel();
|
|
fetchUserHistory();
|
|
fetchUserPlaylists();
|
|
}, []);
|
|
|
|
|
|
const [editMode, setEditMode] = useState(false);
|
|
|
|
const nonEditModeClasses = "text-2xl font-bold text-white p-2 focus:text-white focus:outline-none w-full font-montserrat";
|
|
const editModeClasses = nonEditModeClasses + " glassmorphism";
|
|
|
|
const handlePlaylistClick = (playlistId) => {
|
|
navigation(`/playlist/${playlistId}`);
|
|
}
|
|
|
|
const handleUpdateUser = async () => {
|
|
if (password !== confirmPassword) {
|
|
addAlert('error', "Les mots de passe ne correspondent pas.");
|
|
return;
|
|
}
|
|
|
|
const updatedUser = {
|
|
username,
|
|
email,
|
|
password: password || undefined, // Only send password if it's not empty
|
|
};
|
|
|
|
const result = await updateUser(user.id, token, updatedUser, addAlert);
|
|
if (result) {
|
|
localStorage.setItem("user", JSON.stringify(result));
|
|
setEditMode(false);
|
|
addAlert('success', "Profil mis à jour avec succès.");
|
|
}
|
|
}
|
|
|
|
const addAlert = (type, message) => {
|
|
const newAlert = { type, message, id: Date.now() }; // Add unique ID
|
|
setAlerts([...alerts, newAlert]);
|
|
};
|
|
|
|
const onCloseAlert = (alertToRemove) => {
|
|
setAlerts(alerts.filter(alert => alert !== alertToRemove));
|
|
};
|
|
|
|
const closeModal = () => {
|
|
setIsModalOpen(false);
|
|
fetchUserChannel();
|
|
}
|
|
|
|
return (
|
|
<div className="min-w-screen min-h-screen bg-linear-to-br from-left-gradient to-right-gradient">
|
|
<Navbar isSearchPage={false} alerts={alerts} onCloseAlert={onCloseAlert} />
|
|
|
|
<main className="px-36 pt-[118px] flex justify-between items-start">
|
|
{/* Left side */}
|
|
|
|
{/* Profile / Edit profile */}
|
|
<form className="glassmorphism w-1/3 p-10">
|
|
<div className="relative w-1/3 aspect-square overflow-hidden mb-3 mx-auto" onMouseEnter={() => setIsPictureEditActive(true)} onMouseLeave={() => setIsPictureEditActive(false)} >
|
|
<label htmlFor="image">
|
|
<img
|
|
src={user.picture}
|
|
className="w-full aspect-square rounded-full object-cover"
|
|
/>
|
|
<div className={`absolute w-full h-full bg-[#000000EF] flex items-center justify-center top-0 left-0 rounded-full ${(isPictureEditActive && editMode) ? "opacity-100 cursor-pointer" : "opacity-0 cursor-default"} ` } >
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" className="fill-white" viewBox="0 0 24 24">
|
|
<path d="M19.045 7.401c.378-.378.586-.88.586-1.414s-.208-1.036-.586-1.414l-1.586-1.586c-.378-.378-.88-.586-1.414-.586s-1.036.208-1.413.585L4 13.585V18h4.413L19.045 7.401zm-3-3 1.587 1.585-1.59 1.584-1.586-1.585 1.589-1.584zM6 16v-1.585l7.04-7.018 1.586 1.586L7.587 16H6zm-2 4h16v2H4z"></path>
|
|
</svg>
|
|
</div>
|
|
</label>
|
|
<input type="file" accept="image/*" id="image" className="absolute inset-0 w-full h-full opacity-0 cursor-pointer" disabled={!editMode}/>
|
|
</div>
|
|
<label htmlFor="name" className="text-2xl text-white mb-1 block font-montserrat">
|
|
Nom d'utilisateur
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="name"
|
|
value={username}
|
|
className={(editMode ? editModeClasses : nonEditModeClasses)}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
placeholder="Nom d'utilisateur"
|
|
disabled={!editMode}
|
|
/>
|
|
|
|
<label htmlFor="email" className="text-2xl text-white mb-1 mt-4 block font-montserrat">
|
|
Adresse e-mail
|
|
</label>
|
|
<input
|
|
type="email"
|
|
id="email"
|
|
value={email}
|
|
className={(editMode ? editModeClasses : nonEditModeClasses)}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
placeholder="Adresse mail"
|
|
disabled={!editMode}
|
|
/>
|
|
|
|
{ editMode && (
|
|
<>
|
|
<label htmlFor="password" className="text-2xl text-white mb-1 mt-4 block font-montserrat">
|
|
Mot de passe
|
|
</label>
|
|
<input
|
|
type="password"
|
|
id="password"
|
|
value={password}
|
|
className={(editMode ? editModeClasses : nonEditModeClasses)}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
placeholder="**************"
|
|
disabled={!editMode}
|
|
/>
|
|
|
|
<label htmlFor="confirm-password" className="text-2xl text-white mb-1 mt-4 block font-montserrat">
|
|
Confirmer le mot de passe
|
|
</label>
|
|
<input
|
|
type="password"
|
|
id="confirm-password"
|
|
value={confirmPassword}
|
|
className={(editMode ? editModeClasses : nonEditModeClasses)}
|
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
placeholder=""
|
|
disabled={!editMode}
|
|
/>
|
|
</>
|
|
)
|
|
|
|
}
|
|
|
|
<div className="flex justify-center mt-5">
|
|
{
|
|
editMode ? (
|
|
<div>
|
|
<button
|
|
type="button"
|
|
className="bg-primary p-3 rounded-sm text-white font-montserrat text-2xl font-black cursor-pointer"
|
|
onClick={handleUpdateUser}
|
|
>
|
|
Enregistrer
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="bg-red-500 p-3 rounded-sm text-white font-montserrat text-2xl font-black cursor-pointer ml-3"
|
|
onClick={() => setEditMode(!editMode)}
|
|
>
|
|
Annuler
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<button
|
|
type="button"
|
|
className="bg-primary p-3 rounded-sm text-white font-montserrat text-2xl font-black cursor-pointer"
|
|
onClick={() => setEditMode(!editMode)}
|
|
>
|
|
Modifier le profil
|
|
</button>
|
|
)
|
|
}
|
|
</div>
|
|
</form>
|
|
|
|
{ /* Right side */}
|
|
|
|
<div className="w-2/3 flex flex-col items-start pl-10">
|
|
{/* Channel */}
|
|
{userChannel ? (
|
|
<div className="glassmorphism p-10 w-full flex justify-between">
|
|
<p className="text-3xl text-white mb-2 font-montserrat font-bold">{userChannel.channel.name}</p>
|
|
<button>
|
|
<span onClick={() => navigation(`/manage-channel/${userChannel.channel.id}`)} className="bg-primary p-3 rounded-sm text-white font-montserrat text-2xl font-semibold cursor-pointer">
|
|
Gérer la chaîne
|
|
</span>
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<div className="glassmorphism p-10 w-full">
|
|
<h2 className="text-3xl font-bold text-white mb-4">Chaîne</h2>
|
|
<p className="text-xl text-white mb-2">Aucune chaîne associée à ce compte.</p>
|
|
<button className=" mt-4">
|
|
<a onClick={() => setIsModalOpen(true)} className="bg-primary p-3 rounded-sm text-white font-montserrat text-2xl font-semibold cursor-pointer">
|
|
Créer une chaîne
|
|
</a>
|
|
</button>
|
|
</div>
|
|
)}
|
|
{/* Playlists */}
|
|
<h2 className="font-montserrat font-bold text-3xl text-white mt-10" >Playlists</h2>
|
|
<div className="w-full mt-5 flex flex-wrap" >
|
|
{
|
|
userPlaylists && userPlaylists.map((playlist, index) => (
|
|
<PlaylistCard playlist={playlist} key={index} onClick={handlePlaylistClick} />
|
|
))
|
|
}
|
|
</div>
|
|
{/* History */}
|
|
<h2 className="font-montserrat font-bold text-3xl text-white mt-10" >Historique</h2>
|
|
<div className="w-full mt-5 flex flex-wrap gap-2" >
|
|
{
|
|
userHistory && userHistory.map((video, index) => (
|
|
<div className="w-1/3" key={index}>
|
|
<VideoCard video={video}/>
|
|
</div>
|
|
))
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
</main>
|
|
<CreateChannelModal isOpen={isModalOpen} onClose={() => closeModal()} addAlert={addAlert} />
|
|
</div>
|
|
)
|
|
|
|
}
|