28 changed files with 2164 additions and 566 deletions
File diff suppressed because it is too large
@ -0,0 +1,20 @@ |
|||||
|
import VideoCard from "./VideoCard.jsx"; |
||||
|
|
||||
|
export default function ChannelLastVideos({ videos }) { |
||||
|
|
||||
|
return ( |
||||
|
<div className="grid grid-cols-4 gap-8"> |
||||
|
{ |
||||
|
videos && videos.length > 0 ? ( |
||||
|
videos.map((video) => ( |
||||
|
<VideoCard video={video} /> |
||||
|
) |
||||
|
) |
||||
|
) : ( |
||||
|
<p>Aucune vidéo trouvée</p> |
||||
|
) |
||||
|
} |
||||
|
</div> |
||||
|
) |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
import React, { useState } from 'react'; |
||||
|
|
||||
|
export default function TabLayout({ tabs }) { |
||||
|
|
||||
|
const [activeTab, setActiveTab] = useState(tabs[0].id); |
||||
|
const onTabChange = (tabId) => { |
||||
|
setActiveTab(tabId); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
|
||||
|
<div> |
||||
|
|
||||
|
{/* TABS */} |
||||
|
<div className='flex items-center mt-8 gap-3 mb-4' > |
||||
|
{ |
||||
|
tabs.map((tab) => ( |
||||
|
<button |
||||
|
key={tab.id} |
||||
|
onClick={() => onTabChange(tab.id)} |
||||
|
className={` px-4 py-2 font-montserrat font-medium text-lg cursor-pointer ${tab.id === activeTab ? 'bg-white text-black rounded-2xl border-2 border-white' : 'glassmorphism text-white'}`} |
||||
|
> |
||||
|
{tab.label} |
||||
|
</button> |
||||
|
)) |
||||
|
} |
||||
|
</div> |
||||
|
|
||||
|
{/* ELEMENT */} |
||||
|
|
||||
|
<div className="glassmorphism w-full p-4"> |
||||
|
{tabs.map((tab) => ( |
||||
|
<div key={tab.id} className={`tab-content ${tab.id === activeTab ? 'block' : 'hidden'}`}> |
||||
|
{tab.element()} |
||||
|
</div> |
||||
|
))} |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
) |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,100 @@ |
|||||
|
export function fetchChannelDetails(channelId, addAlert) { |
||||
|
return fetch(`/api/channels/${channelId}`) |
||||
|
.then(response => { |
||||
|
if (!response.ok) { |
||||
|
throw new Error('Network response was not ok'); |
||||
|
} |
||||
|
return response.json(); |
||||
|
}) |
||||
|
.catch(error => { |
||||
|
addAlert('error', "Erreur lors de la récupération des détails de la chaîne"); |
||||
|
throw error; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
export async function fetchChannelStats(channelId, token, addAlert) { |
||||
|
try { |
||||
|
const request = await fetch(`/api/channels/${channelId}/stats`, { |
||||
|
method: "GET", |
||||
|
headers: { |
||||
|
"Authorization": `Bearer ${token}` |
||||
|
} |
||||
|
}) |
||||
|
const result = await request.json(); |
||||
|
return result; |
||||
|
} catch (error) { |
||||
|
console.error("Error fetching channel stats", error); |
||||
|
addAlert('error', "Erreur lors de la récupération des statistiques de la chaîne"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function updateChannel(channelId, data, token, addAlert) { |
||||
|
try { |
||||
|
const response = await fetch(`/api/channels/${channelId}`, { |
||||
|
method: "PUT", |
||||
|
headers: { |
||||
|
"Content-Type": "application/json", |
||||
|
"Authorization": `Bearer ${token}` |
||||
|
}, |
||||
|
body: JSON.stringify(data) |
||||
|
}); |
||||
|
|
||||
|
if (response.ok) { |
||||
|
addAlert('success', 'Chaîne mise à jour avec succès'); |
||||
|
return response.json(); |
||||
|
} else { |
||||
|
console.error("Failed to update channel"); |
||||
|
const errorData = await response.json(); |
||||
|
addAlert('error', errorData.message || 'Erreur lors de la mise à jour de la chaîne'); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error("Error updating channel:", error); |
||||
|
addAlert('error', 'Erreur lors de la mise à jour de la chaîne'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function subscribe(channelId, addAlert) { |
||||
|
const token = localStorage.getItem('token'); |
||||
|
const user = JSON.parse(localStorage.getItem('user')); |
||||
|
console.log("Subscribing to channel with ID:", channelId, "for user:", user.id); |
||||
|
return fetch(`/api/channels/${channelId}/subscribe`, { |
||||
|
method: 'POST', |
||||
|
headers: { |
||||
|
'Authorization': `Bearer ${token}`, |
||||
|
'Content-Type': "application/json" |
||||
|
}, |
||||
|
body: JSON.stringify({ |
||||
|
userId: user.id |
||||
|
}) |
||||
|
}) |
||||
|
.then(response => { |
||||
|
if (!response.ok) { |
||||
|
throw new Error('Network response was not ok'); |
||||
|
} |
||||
|
return response.json(); |
||||
|
}) |
||||
|
.catch(error => { |
||||
|
addAlert('error', "Erreur lors de l'abonnement à la chaîne"); |
||||
|
throw error; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
export async function createChannel(body, token, addAlert) { |
||||
|
const request = await fetch(`/api/channels/`, { |
||||
|
method: 'POST', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json', |
||||
|
'Authorization': `Bearer ${token}`, |
||||
|
}, |
||||
|
body: JSON.stringify(body) |
||||
|
}) |
||||
|
|
||||
|
if (!request.ok) { |
||||
|
console.error("Not able to create channel"); |
||||
|
return; // Prevent further execution if the request failed
|
||||
|
} |
||||
|
|
||||
|
addAlert('success', 'Chaîne créée avec succès'); |
||||
|
const data = await request.json(); |
||||
|
return data; |
||||
|
} |
||||
@ -0,0 +1,67 @@ |
|||||
|
|
||||
|
export async function getCommentByVideo(id, addAlert) { |
||||
|
try { |
||||
|
const response = await fetch(`/api/comments/video/${id}`); |
||||
|
if (!response.ok) { |
||||
|
throw new Error('Network response was not ok'); |
||||
|
} |
||||
|
const commentsData = await response.json(); |
||||
|
return commentsData; |
||||
|
} catch (error) { |
||||
|
addAlert('error', 'Erreur lors de la récupération des commentaires'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function addComment(videoId, commentData, token, addAlert) { |
||||
|
try { |
||||
|
const response = await fetch(`/api/comments/`, { |
||||
|
method: 'POST', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json', |
||||
|
'Authorization': `Bearer ${token}` |
||||
|
}, |
||||
|
body: JSON.stringify({ |
||||
|
content: commentData, |
||||
|
video: videoId |
||||
|
}) |
||||
|
}); |
||||
|
|
||||
|
if (!response.ok) { |
||||
|
throw new Error('Failed to post comment'); |
||||
|
} |
||||
|
|
||||
|
const data = await response.json(); |
||||
|
return data; |
||||
|
} catch (error) { |
||||
|
addAlert('error', 'Erreur lors de l\'ajout du commentaire'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function updateComment(id, body, token, addAlert) { |
||||
|
const response = await fetch(`/api/comments/${id}`, { |
||||
|
method: 'PUT', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json', |
||||
|
'Authorization': `Bearer ${token}` |
||||
|
}, |
||||
|
body: JSON.stringify(body) |
||||
|
}); |
||||
|
|
||||
|
if (!response.ok) { |
||||
|
addAlert('error', 'Erreur lors de la mise à jour du commentaire'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function deleteComment(id, token, addAlert) { |
||||
|
const response = await fetch(`/api/comments/${id}`, { |
||||
|
method: 'DELETE', |
||||
|
headers: { |
||||
|
'Authorization': `Bearer ${token}` |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
if (!response.ok) { |
||||
|
addAlert('error', 'Erreur lors de la suppression du commentaire'); |
||||
|
} |
||||
|
return response; |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
|
||||
|
|
||||
|
export async function getRecommendations(addAlert) { |
||||
|
try { |
||||
|
const response = await fetch('/api/recommendations'); |
||||
|
const data = await response.json(); |
||||
|
return data.recommendations; |
||||
|
} catch (error) { |
||||
|
console.error('Error fetching data:', error); |
||||
|
addAlert('error', 'Erreur lors du chargement des recommandations'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function getTrendingVideos(addAlert) { |
||||
|
try { |
||||
|
const response = await fetch('/api/recommendations/trending'); |
||||
|
const data = await response.json(); |
||||
|
return data; |
||||
|
} catch (error) { |
||||
|
console.error('Error fetching data:', error); |
||||
|
addAlert('error', 'Erreur lors du chargement des vidéos tendance'); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,103 @@ |
|||||
|
export async function isSubscribed(channelId, addAlert) { |
||||
|
const token = localStorage.getItem('token'); |
||||
|
if (!token) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const headers = { |
||||
|
Authorization: `Bearer ${token}` |
||||
|
}; |
||||
|
|
||||
|
const request = await fetch(`/api/users/${channelId}/channel/subscribed`, { headers }) |
||||
|
const result = await request.json(); |
||||
|
|
||||
|
console.log("Subscription status for channel ID", channelId, ":", result); |
||||
|
return result.subscribed; |
||||
|
} |
||||
|
|
||||
|
export async function getChannel(userId, token, addAlert) { |
||||
|
try { |
||||
|
const response = await fetch(`/api/users/${userId}/channel`, { |
||||
|
method: "GET", |
||||
|
headers: { |
||||
|
"Authorization": `Bearer ${token}`, |
||||
|
} |
||||
|
}); |
||||
|
if (!response.ok) { |
||||
|
throw new Error("Failed to fetch user data"); |
||||
|
} |
||||
|
const data = await response.json(); |
||||
|
return data |
||||
|
} catch (error) { |
||||
|
console.error("Error fetching user channel:", error); |
||||
|
addAlert('error', "Erreur lors de la récupération des données de l'utilisateur."); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function getUserHistory(userId, token, addAlert) { |
||||
|
if (!userId || !token) { |
||||
|
console.warn("User ID or token missing, skipping history fetch"); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
const response = await fetch(`/api/users/${userId}/history`, { |
||||
|
method: "GET", |
||||
|
headers: { |
||||
|
"Authorization": `Bearer ${token}`, |
||||
|
} |
||||
|
}); |
||||
|
if (!response.ok) { |
||||
|
throw new Error("Failed to fetch user history"); |
||||
|
} |
||||
|
const data = await response.json(); |
||||
|
return data |
||||
|
} catch (error) { |
||||
|
console.error("Error fetching user history:", error); |
||||
|
addAlert('error', "Erreur lors de la récupération de l'historique de l'utilisateur."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function getPlaylists(userId, token, addAlert) { |
||||
|
if (!userId || !token) { |
||||
|
console.warn("User ID or token missing, skipping playlists fetch"); |
||||
|
return; |
||||
|
} |
||||
|
try { |
||||
|
const response = await fetch(`/api/playlists/user/${userId}`, { |
||||
|
method: "GET", |
||||
|
headers: { |
||||
|
"Authorization": `Bearer ${token}`, |
||||
|
} |
||||
|
}); |
||||
|
if (!response.ok) { |
||||
|
throw new Error("Failed to fetch user playlists"); |
||||
|
} |
||||
|
const data = await response.json(); |
||||
|
return data; |
||||
|
} catch (error) { |
||||
|
console.error("Error fetching user playlists:", error); |
||||
|
addAlert('error', "Erreur lors de la récupération des playlists de l'utilisateur."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function updateUser(userId, token, userData, addAlert) { |
||||
|
try { |
||||
|
const response = await fetch(`/api/users/${userId}`, { |
||||
|
method: "PUT", |
||||
|
headers: { |
||||
|
"Authorization": `Bearer ${token}`, |
||||
|
"Content-Type": "application/json" |
||||
|
}, |
||||
|
body: JSON.stringify(userData) |
||||
|
}); |
||||
|
if (!response.ok) { |
||||
|
throw new Error("Failed to update user"); |
||||
|
} |
||||
|
const data = await response.json(); |
||||
|
return data; |
||||
|
} catch (error) { |
||||
|
console.error("Error updating user:", error); |
||||
|
addAlert('error', "Erreur lors de la mise à jour des données de l'utilisateur."); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,212 @@ |
|||||
|
|
||||
|
|
||||
|
export async function uploadVideo(formData, token, addAlert) { |
||||
|
const request = await fetch("/api/videos", { |
||||
|
method: "POST", |
||||
|
headers: { |
||||
|
"Authorization": `Bearer ${token}` // Assuming you have a token for authentication
|
||||
|
}, |
||||
|
body: formData |
||||
|
}); |
||||
|
if (!request.ok) { |
||||
|
const errorData = await request.json(); |
||||
|
console.error("Backend validation errors:", errorData); |
||||
|
|
||||
|
// Display specific validation errors if available
|
||||
|
if (errorData.errors && errorData.errors.length > 0) { |
||||
|
const errorMessages = errorData.errors.map(error => |
||||
|
`${error.path}: ${error.msg}` |
||||
|
).join('\n'); |
||||
|
addAlert('error', `Erreurs de validation:\n${errorMessages}`); |
||||
|
} else { |
||||
|
addAlert('error', 'Erreurs inconnues'); |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
return request; |
||||
|
} |
||||
|
|
||||
|
export async function uploadThumbnail(formData, token, addAlert) { |
||||
|
|
||||
|
try { |
||||
|
const thumbnailRequest = await fetch("/api/videos/thumbnail", { |
||||
|
method: "POST", |
||||
|
headers: { |
||||
|
"Authorization": `Bearer ${token}` |
||||
|
}, |
||||
|
body: formData |
||||
|
}); |
||||
|
if (!thumbnailRequest.ok) { |
||||
|
const errorData = await thumbnailRequest.json(); |
||||
|
console.error("Backend validation errors:", errorData); |
||||
|
addAlert('error', 'Erreur lors de l\'envoie d la miniature'); |
||||
|
return; |
||||
|
} |
||||
|
addAlert('success', 'Miniature envoyée avec succès'); |
||||
|
return thumbnailRequest; |
||||
|
} catch (error) { |
||||
|
console.error("Error uploading thumbnail:", error); |
||||
|
addAlert('error', 'Erreur lors de l\'envoie de la miniature'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function uploadTags(body, videoId, token, addAlert) { |
||||
|
const tagsRequest = await fetch(`/api/videos/${videoId}/tags`, { |
||||
|
method: "PUT", |
||||
|
headers: { |
||||
|
"Content-Type": "application/json", |
||||
|
"Authorization": `Bearer ${token}` // Assuming you have a token for authentication
|
||||
|
}, |
||||
|
body: JSON.stringify(body) // Ensure channel ID is a string
|
||||
|
}); |
||||
|
addAlert('success', 'Tags mis à jour avec succès'); |
||||
|
if (!tagsRequest.ok) { |
||||
|
const errorData = await tagsRequest.json(); |
||||
|
console.error("Backend validation errors:", errorData); |
||||
|
addAlert('error', 'Erreur lors de l\'ajout des tags'); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function getVideoById(id, addAlert) { |
||||
|
try { |
||||
|
const request = await fetch(`/api/videos/${id}`, { |
||||
|
method: 'GET', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json', |
||||
|
} |
||||
|
}); |
||||
|
if (!request.ok) { |
||||
|
addAlert('error', 'Erreur lors de la récupération de la vidéo'); |
||||
|
} |
||||
|
const data = await request.json(); |
||||
|
return data; |
||||
|
} catch (error) { |
||||
|
console.error("Error fetching video:", error); |
||||
|
addAlert('error', 'Erreur lors de la récupération de la vidéo'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function getLikesPerDay(id, token, addAlert) { |
||||
|
try { |
||||
|
const request = await fetch(`/api/videos/${id}/likes/day`, { |
||||
|
method: 'GET', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json', |
||||
|
'Authorization': `Bearer ${token}` |
||||
|
} |
||||
|
}); |
||||
|
if (!request.ok) { |
||||
|
addAlert('error', 'Erreur lors de la récupération des likes par jour'); |
||||
|
} |
||||
|
const data = await request.json(); |
||||
|
return data; |
||||
|
} catch (error) { |
||||
|
console.error("Error fetching likes per day:", error); |
||||
|
addAlert('error', 'Erreur lors de la récupération des likes par jour'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function updateVideo(id, data, token, addAlert) { |
||||
|
try { |
||||
|
const request = await fetch(`/api/videos/${id}`, { |
||||
|
method: 'PUT', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json', |
||||
|
'Authorization': `Bearer ${token}` |
||||
|
}, |
||||
|
body: JSON.stringify(data) |
||||
|
}); |
||||
|
if (!request.ok) { |
||||
|
const errorData = await request.json(); |
||||
|
console.error("Backend validation errors:", errorData); |
||||
|
addAlert('error', 'Erreur lors de la mise à jour de la vidéo'); |
||||
|
return; |
||||
|
} |
||||
|
return request; |
||||
|
} catch (error) { |
||||
|
console.error("Error updating video:", error); |
||||
|
addAlert('error', 'Erreur lors de la mise à jour de la vidéo'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function updateVideoFile(id, formData, token, addAlert) { |
||||
|
try { |
||||
|
const videoRequest = await fetch(`/api/videos/${id}/video`, { |
||||
|
method: 'PUT', |
||||
|
headers: { |
||||
|
'Authorization': `Bearer ${token}` |
||||
|
}, |
||||
|
body: formData |
||||
|
}); |
||||
|
|
||||
|
if (!videoRequest.ok) { |
||||
|
addAlert('error', 'Erreur lors de la mise à jour de la vidéo'); |
||||
|
return; |
||||
|
} |
||||
|
return videoRequest.json(); |
||||
|
} catch (error) { |
||||
|
console.error("Error updating video file:", error); |
||||
|
addAlert('error', 'Erreur lors de la mise à jour de la vidéo'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function getSimilarVideos(id, addAlert) { |
||||
|
try { |
||||
|
const request = await fetch(`/api/videos/${id}/similar`, { |
||||
|
method: 'GET', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json', |
||||
|
} |
||||
|
}); |
||||
|
if (!request.ok) { |
||||
|
addAlert('error', 'Erreur lors de la récupération des vidéos similaires'); |
||||
|
return []; |
||||
|
} |
||||
|
const data = await request.json(); |
||||
|
return data; |
||||
|
} catch (error) { |
||||
|
console.error("Error fetching similar videos:", error); |
||||
|
addAlert('error', 'Erreur lors de la récupération des vidéos similaires'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function addView(id, addAlert) { |
||||
|
try { |
||||
|
const token = localStorage.getItem('token'); |
||||
|
if (token) { |
||||
|
await fetch(`/api/videos/${id}/views`, { |
||||
|
method: 'GET', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json', |
||||
|
'Authorization': `Bearer ${token}` |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
} catch (error) { |
||||
|
addAlert('error', 'Erreur lors de l\'ajout des vues à la vidéo'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export async function toggleLike(id, token, addAlert) { |
||||
|
try { |
||||
|
const response = await fetch(`/api/videos/${id}/like`, { |
||||
|
method: 'GET', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/json', |
||||
|
'Authorization': `Bearer ${token}` |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
if (!response.ok) { |
||||
|
throw new Error('Failed to like video'); |
||||
|
} |
||||
|
|
||||
|
const data = await response.json(); |
||||
|
return data; |
||||
|
} catch (error) { |
||||
|
console.error("Error toggling like:", error); |
||||
|
addAlert('error', 'Erreur lors du changement de like'); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue