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