From 1c967dd1dba2e36b1cc861fa9df4052434229fc1 Mon Sep 17 00:00:00 2001 From: Bilal Dieumegard Date: Sun, 1 Dec 2024 15:04:54 +0100 Subject: [PATCH 1/3] Ajouts du front de la page contenant les chats, de la creation de chat, des composants d'alerte, de profil et la page de modification de profil. --- package.json | 2 + src/lib/components/ui/Alert.svelte | 49 ++++ src/lib/components/ui/ChatItem.svelte | 19 ++ src/lib/components/ui/ChoosePicture.svelte | 105 ++++++++ src/lib/components/ui/ProfileCard.svelte | 28 ++ src/lib/components/ui/ProfileModal.svelte | 36 +++ src/lib/components/ui/Search.svelte | 16 ++ src/routes/api/canal/[id]/+page.server.ts | 123 +++++++++ .../api/canal/[id]/messages/+page.server.ts | 149 +++++++++++ src/routes/api/canals/+page.server.ts | 47 ++++ src/routes/api/user/[id]/+page.server.ts | 241 ++++++++++++++++++ src/routes/api/users/+page.server.ts | 27 ++ src/routes/chat/+page.svelte | 54 +++- src/routes/chats/+page.svelte | 32 +++ src/routes/user/edit/+page.svelte | 140 ++++++++++ static/profile-default.svg | 4 + 16 files changed, 1070 insertions(+), 2 deletions(-) create mode 100644 src/lib/components/ui/Alert.svelte create mode 100644 src/lib/components/ui/ChatItem.svelte create mode 100644 src/lib/components/ui/ChoosePicture.svelte create mode 100644 src/lib/components/ui/ProfileCard.svelte create mode 100644 src/lib/components/ui/ProfileModal.svelte create mode 100644 src/lib/components/ui/Search.svelte create mode 100644 src/routes/api/canal/[id]/+page.server.ts create mode 100644 src/routes/api/canal/[id]/messages/+page.server.ts create mode 100644 src/routes/api/canals/+page.server.ts create mode 100644 src/routes/api/user/[id]/+page.server.ts create mode 100644 src/routes/api/users/+page.server.ts create mode 100644 src/routes/chats/+page.svelte create mode 100644 src/routes/user/edit/+page.svelte create mode 100644 static/profile-default.svg diff --git a/package.json b/package.json index fb08de5..1f27afd 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,8 @@ "vite": "^5.0.3" }, "dependencies": { + "lucide-svelte": "^0.462.0", + "multer": "^1.4.5-lts.1", "svelte-radix": "^2.0.1" } } diff --git a/src/lib/components/ui/Alert.svelte b/src/lib/components/ui/Alert.svelte new file mode 100644 index 0000000..0558081 --- /dev/null +++ b/src/lib/components/ui/Alert.svelte @@ -0,0 +1,49 @@ + + + +
+ + {message} + + + +
+ + diff --git a/src/lib/components/ui/ChatItem.svelte b/src/lib/components/ui/ChatItem.svelte new file mode 100644 index 0000000..5afb5ee --- /dev/null +++ b/src/lib/components/ui/ChatItem.svelte @@ -0,0 +1,19 @@ + + +
+
+

{title}

+

{lastMessage}

+
+

{time}

+
+ + \ No newline at end of file diff --git a/src/lib/components/ui/ChoosePicture.svelte b/src/lib/components/ui/ChoosePicture.svelte new file mode 100644 index 0000000..ede5fcd --- /dev/null +++ b/src/lib/components/ui/ChoosePicture.svelte @@ -0,0 +1,105 @@ + + + + + +
+ + Image de profil + + + + +
+ + +
+
diff --git a/src/lib/components/ui/ProfileCard.svelte b/src/lib/components/ui/ProfileCard.svelte new file mode 100644 index 0000000..65faf27 --- /dev/null +++ b/src/lib/components/ui/ProfileCard.svelte @@ -0,0 +1,28 @@ + + +
+ + Photo de profil + + +
+

{name}

+

{bio}

+
+
+ + diff --git a/src/lib/components/ui/ProfileModal.svelte b/src/lib/components/ui/ProfileModal.svelte new file mode 100644 index 0000000..36d195a --- /dev/null +++ b/src/lib/components/ui/ProfileModal.svelte @@ -0,0 +1,36 @@ + + +
+
+
+

{name}

+ +
+ +
+ Photo de profil +

{bio}

+
+ +
+ +
+
+
+ + diff --git a/src/lib/components/ui/Search.svelte b/src/lib/components/ui/Search.svelte new file mode 100644 index 0000000..749d684 --- /dev/null +++ b/src/lib/components/ui/Search.svelte @@ -0,0 +1,16 @@ + + +
+ + + +
+ diff --git a/src/routes/api/canal/[id]/+page.server.ts b/src/routes/api/canal/[id]/+page.server.ts new file mode 100644 index 0000000..cfdb6f3 --- /dev/null +++ b/src/routes/api/canal/[id]/+page.server.ts @@ -0,0 +1,123 @@ +import { json } from '@sveltejs/kit'; +import prisma from '$lib/prismaClient'; +import redisClient from '$lib/redisClient'; // Assurez-vous d'importer le client Redis + +// Récupérer les informations du canal et le dernier message (avec cache Redis) +export async function GET({ params }) { + const canalId = parseInt(params.id); + + // Clé cache pour les informations du canal et le dernier message + const canalCacheKey = `canal:${canalId}:info`; + + try { + // Vérifier si les informations du canal et le dernier message sont dans le cache Redis + const cachedCanalData = await redisClient.get(canalCacheKey); + if (cachedCanalData) { + console.log('✅ Cache hit pour les informations du canal et le dernier message'); + return json(JSON.parse(cachedCanalData)); + } + + console.log('❌ Cache miss'); + // Si non, récupérer les informations du canal et le dernier message depuis Prisma + const canal = await prisma.canal.findUnique({ + where: { id: canalId }, + include: { + users: true, // Inclut les utilisateurs associés au canal + }, + }); + + if (!canal) { + return json({ error: 'Canal non trouvé' }, { status: 404 }); + } + + // Récupérer le dernier message + const lastMessage = await prisma.message.findFirst({ + where: { canalId }, + include: { + user: { select: { id: true, pseudo: true } }, + }, + orderBy: { createdAt: 'desc' }, // Trie par date décroissante, donc le dernier message est récupéré en premier + }); + + // Créer un objet combiné pour le canal et le dernier message + const canalData = { + canal, + lastMessage, // Inclure uniquement le dernier message + }; + + // Mettre en cache les informations du canal et le dernier message pendant 5 minutes + await redisClient.set(canalCacheKey, JSON.stringify(canalData), 'EX', 300); // Cache pendant 5 minutes + + console.log('❌ Cache miss - Mise en cache des résultats'); + return json(canalData); + } catch (err) { + console.error(err); + return json({ error: 'Erreur lors de la récupération du canal ou du dernier message' }, { status: 500 }); + } +} + +// Supprimer un canal et invalider le cache associé +export async function DELETE({ params }) { + const canalId = parseInt(params.id); + + try { + // Supprimer le canal de la base de données + await prisma.canal.delete({ + where: { id: canalId }, + }); + + // Invalider le cache + await redisClient.del(`canal:${canalId}:info`); + + return json({ message: 'Canal supprimé avec succès' }); + } catch (err) { + console.error(err); + return json({ error: 'Erreur lors de la suppression du canal' }, { status: 500 }); + } +} + +// Modifier un canal +export async function PUT({ params, request }) { + const canalId = parseInt(params.id); + const { nom, domaine } = await request.json(); // On suppose que ce sont les champs à mettre à jour + + // Clé cache pour les informations du canal et le dernier message + const canalCacheKey = `canal:${canalId}:info`; + + try { + // Mettre à jour les informations du canal dans la base de données + const updatedCanal = await prisma.canal.update({ + where: { id: canalId }, + data: { + nom, // Nom du canal + domaine, // Domaine du canal + }, + include: { + users: true, // Inclut les utilisateurs associés au canal + }, + }); + + // Récupérer le dernier message associé au canal après mise à jour + const lastMessage = await prisma.message.findFirst({ + where: { canalId }, + include: { + user: { select: { id: true, pseudo: true } }, + }, + orderBy: { createdAt: 'desc' }, + }); + + // Créer un objet combiné pour les nouvelles informations du canal et le dernier message + const canalData = { + canal: updatedCanal, + lastMessage, // Inclure uniquement le dernier message + }; + + // Mettre en cache les nouvelles informations pendant 5 minutes + await redisClient.set(canalCacheKey, JSON.stringify(canalData), 'EX', 60 * 5); // Cache pendant 5 minutes + + return json(canalData); + } catch (err) { + console.error(err); + return json({ error: 'Erreur lors de la mise à jour du canal' }, { status: 500 }); + } +} diff --git a/src/routes/api/canal/[id]/messages/+page.server.ts b/src/routes/api/canal/[id]/messages/+page.server.ts new file mode 100644 index 0000000..9fd337b --- /dev/null +++ b/src/routes/api/canal/[id]/messages/+page.server.ts @@ -0,0 +1,149 @@ +import { json } from '@sveltejs/kit'; +import prisma from '$lib/prismaClient'; +import redisClient from '$lib/redisClient'; // Assure-toi d'importer ton client Redis + +export async function GET({ params, url }) { + const canalId = parseInt(params.id); + + // Gestion de la pagination avec des paramètres optionnels `page` et `limit` + const page = parseInt(url.searchParams.get('page')) || 1; + const limit = parseInt(url.searchParams.get('limit')) || 10; + const offset = (page - 1) * limit; + + // Générer une clé cache Redis unique en fonction du canal et des paramètres de pagination + const cacheKey = `canal:${canalId}:messages:page:${page}:limit:${limit}`; + + try { + // 1. Vérifier si les messages sont déjà dans le cache Redis + const cachedMessages = await redisClient.get(cacheKey); + if (cachedMessages) { + console.log('✅ Cache hit'); + return json(JSON.parse(cachedMessages)); // Si les données sont en cache, les retourner + } + + // 2. Si les messages ne sont pas en cache, récupérer depuis la base de données + const messages = await prisma.message.findMany({ + where: { canalId }, + include: { + user: { + select: { id: true, pseudo: true }, // Inclut uniquement l’ID et le pseudo de l’utilisateur + }, + }, + orderBy: { + createdAt: 'asc', // Trie par date croissante + }, + skip: offset, + take: limit, + }); + + // 3. Compter le nombre total de messages pour la pagination + const totalMessages = await prisma.message.count({ + where: { canalId }, + }); + + const response = { + messages, + pagination: { + page, + limit, + totalMessages, + totalPages: Math.ceil(totalMessages / limit), + }, + }; + + // 4. Mettre en cache les messages avec une expiration (par exemple 5 minutes) + await redisClient.set(cacheKey, JSON.stringify(response), 'EX', 60 * 5); // Cache pendant 5 minutes + + console.log('❌ Cache miss - Mise en cache des résultats'); + return json(response); // Retourner les données récupérées + } catch (err) { + console.error(err); + return json({ error: 'Erreur lors de la récupération des messages' }, { status: 500 }); + } +} + +export async function POST({ params, request }) { + const canalId = parseInt(params.id); + const { userId, text } = await request.json(); + + try { + // Créer un nouveau message dans la base de données + const newMessage = await prisma.message.create({ + data: { + userId, + canalId, + text, + }, + include: { user: { select: { id: true, pseudo: true } } }, + }); + + updateCaches(); // Mettre à jour les caches après la création d’un nouveau message + + return json(newMessage, { status: 201 }); + } catch (err) { + console.error(err); + return json({ error: 'Erreur lors de la création du message' }, { status: 500 }); + } +} + +export async function DELETE({ params }) { + const messageId = parseInt(params.id); + + try { + // Supprimer le message de la base de données + await prisma.message.delete({ + where: { id: messageId }, + }); + + updateCaches(); // Mettre à jour les caches après la suppression d’un message + + return json({ message: 'Message supprimé avec succès' }); + } catch (err) { + console.error(err); + return json({ error: 'Erreur lors de la suppression du message' }, { status: 500 }); + } +} + +// Fonction pour mettre à jour tous les caches des messages +function updateCaches(canalId) { + // Mettre à jour tous les caches + // Mettre à jour toutes les pages dans le cache + let page : number = 1; + let limit : number = 10; + let offset : number = (page - 1) * limit; + while (true) { + const cacheKey = `canal:${canalId}:messages:page:${page}:limit:${limit}`; + const cachedMessages = await redisClient.get(cacheKey); + if (!cachedMessages) { + break; + } + const totalMessages = await prisma.message.count({ + where: { canalId }, + }); + const messages = await prisma.message.findMany({ + where: { canalId }, + include: { + user: { + select: { id: true, pseudo: true }, + }, + }, + orderBy: { + createdAt: 'asc', + }, + skip: offset, + take: limit, + }); + const response = { + messages, + pagination: { + page, + limit, + totalMessages, + totalPages: Math.ceil(totalMessages / limit), + }, + }; + await redisClient.set(cacheKey, JSON.stringify(response), 'EX', 60 * 5); + page++; + offset = (page - 1) * limit; + } +} diff --git a/src/routes/api/canals/+page.server.ts b/src/routes/api/canals/+page.server.ts new file mode 100644 index 0000000..b154366 --- /dev/null +++ b/src/routes/api/canals/+page.server.ts @@ -0,0 +1,47 @@ +import { json } from '@sveltejs/kit'; +import prisma from '$lib/prismaClient'; +import redisClient from '$lib/redisClient'; + +// GET: Liste tous les canaux +export async function GET() { + try { + const cachedCanaux = await redisClient.get('canaux'); + if (cachedCanaux) { + console.log('✅ Cache hit'); + return json(JSON.parse(cachedCanaux)); + } + + console.log('❌ Cache miss'); + const canaux = await prisma.canal.findMany({ + include: { users: true, messages: true }, // Inclut les relations + }); + + await redisClient.set('canaux', JSON.stringify(canaux), { EX: 600 }); // Met en cache + return json(canaux); + } catch (err) { + console.error(err); + return json({ error: 'Erreur serveur' }, { status: 500 }); + } +} + +export async function POST({ request }) { + const { nom, domaine, userIds } = await request.json(); + + try { + const canal = await prisma.canal.create({ + data: { + nom, + domaine, + users: { + connect: userIds.map((id) => ({ id })), // Associe des utilisateurs au canal + }, + }, + }); + + return json(canal, { status: 201 }); + } catch (err) { + console.error(err); + return json({ error: 'Erreur lors de la création du canal' }, { status: 500 }); + } +} + diff --git a/src/routes/api/user/[id]/+page.server.ts b/src/routes/api/user/[id]/+page.server.ts new file mode 100644 index 0000000..5052a08 --- /dev/null +++ b/src/routes/api/user/[id]/+page.server.ts @@ -0,0 +1,241 @@ +import { json } from '@sveltejs/kit'; +import redisClient from '$lib/redisClient'; +import prisma from '$lib/prismaClient'; +import multer from 'multer'; +import path from 'path'; +import fs from 'fs'; + +const destinationDir = '/uploads'; + +const storage = multer.diskStorage({ + destination: (req, file, cb) => { + cb(null, `.${destinationDir}'); // Dossier où les images sont stockées` + }, + filename: (req, file, cb) => { + cb(null, `${Date.now()}-${file.originalname}`); + }, + fileFilter(req, file, cb) { + const fileExtension = path.extname(file.originalname).toLowerCase(); + if (fileExtension !== '.jpg' && fileExtension !== '.jpeg' && fileExtension !== '.png') { + return cb(new Error('Seules les images JPG, JPEG et PNG sont autorisées.')); + } + cb(null, true); + } +}); + +const upload = multer({ storage }); + +export async function GET({ params }) { + const userId = params.id; + + try { + // Vérifier si l'utilisateur est dans le cache Redis + const cachedUser = await redisClient.get(`user:${userId}`); + if (cachedUser) { + console.log('✅ Cache hit'); + return json(JSON.parse(cachedUser)); + } + + console.log('❌ Cache miss'); + // Si non, récupérer depuis MongoDB via Prisma + const user = await prisma.user.findUnique({ + where: { id: parseInt(userId) }, + }); + + if (!user) { + return json({ error: 'Utilisateur non trouvé' }, { status: 404 }); + } + + // Mettre l'utilisateur en cache + await redisClient.set(`user:${userId}`, JSON.stringify(user), { EX: 3600 }); + + return json(user); + } catch (err) { + console.error(err); + return json({ error: 'Erreur serveur' }, { status: 500 }); + } +} + +export async function POST({ request }) { + return new Promise((resolve, reject) => { + // Utilisation de multer pour récupérer le fichier + upload.single('profilePicture')(request.raw, request.raw, async (err) => { + if (err) { + console.error('Erreur de téléchargement:', err); + return reject(json({ error: 'Erreur lors du téléchargement du fichier' }, { status: 500 })); + } + + // Récupérer les données du formulaire (sans le fichier) + const { pseudo, nom, prenom, email, password } = await request.json(); + + // L'URL de l'image sera le chemin relatif à partir du dossier uploads + const imageUrl = request.file ? `${destinationDir}/${request.file.filename}` : null; + + try { + // Créer un nouvel utilisateur avec l'URL de l'image + const user = await prisma.user.create({ + data: { + pseudo, + nom, + prenom, + email, + password, + profilePictureUrl: imageUrl, // Stocker l'URL de l'image + }, + }); + + // Mettre l'utilisateur dans le cache Redis + await redisClient.set(`user:${user.id}`, JSON.stringify(user), { EX: 3600 }); + + // Réponse avec les données de l'utilisateur + return resolve(json(user, { status: 201 })); + } catch (error) { + console.error('Erreur lors de la création de l\'utilisateur:', error); + return reject(json({ error: 'Erreur lors de la création de l\'utilisateur' }, { status: 500 })); + } + }); + }); +} + +// Mettre à jour un utilisateur avec PUT +export async function PUT({ params, request }) { + const userId = parseInt(params.id); + + const cachedUser = await redisClient.get(`user:${userId}`); + // Récupérer l'utilisateur à partir de la base de données + let existingUser; + + if (cachedUser) { + console.log('✅ Cache hit'); + // Si l'utilisateur est dans le cache, on le parse + existingUser = JSON.parse(cachedUser); + } else { + // Si l'utilisateur n'est pas dans le cache, on le récupère de la base de données + console.log('❌ Cache miss'); + existingUser = await prisma.user.findUnique({ + where: { id: userId }, + }); + + if (!existingUser) { + return json({ error: 'Utilisateur non trouvé' }, { status: 404 }); + } + + // Utilisation de multer pour récupérer l'image (si présente) + return new Promise((resolve, reject) => { + upload.single('profilePicture')(request.raw, request.raw, async (err) => { + if (err) { + console.error('Erreur de téléchargement:', err); + return reject(json({ error: 'Erreur lors du téléchargement du fichier' }, { status: 500 })); + } + + // Extraire les autres données (pseudo, nom, etc.) du body de la requête + const { pseudo, nom, prenom, email, password } = await request.json(); + + let updatedUserData = { + pseudo, + nom, + prenom, + email, + password, // Assurez-vous de bien sécuriser les mots de passe + }; + + // Si une nouvelle image est envoyée + if (request.file) { + // Vérifiez si l'utilisateur a déjà une image + if (existingUser.profilePictureUrl) { + // Supprimer l'ancienne image + const oldImagePath = `.${destinationDir}/${path.basename(existingUser.profilePictureUrl)}`; + if (fs.existsSync(oldImagePath)) { + fs.unlinkSync(oldImagePath); // Suppression du fichier + } + } + + // Ajouter la nouvelle image à la base de données + updatedUserData.profilePictureUrl = `${destinationDir}/${request.file.filename}`; + } else if (!request.file && existingUser.profilePictureUrl) { + // Si aucune image n'est envoyée, supprimer l'image actuelle + const oldImagePath = `.${destinationDir}/${path.basename(existingUser.profilePictureUrl)}`; + if (fs.existsSync(oldImagePath)) { + fs.unlinkSync(oldImagePath); // Supprimer l'ancienne image + } + + // Mettre à jour l'URL de l'image en null + updatedUserData.profilePictureUrl = null; + } + + try { + // Mettre à jour l'utilisateur dans la base de données + const updatedUser = await prisma.user.update({ + where: { id: userId }, + data: updatedUserData, + }); + + // Mettre à jour l'utilisateur dans le cache Redis + await redisClient.set(`user:${userId}`, JSON.stringify(updatedUser), 'EX', 3600); // Cache pendant 1 heure (3600 secondes) + + // Réponse avec l'utilisateur mis à jour + return resolve(json(updatedUser)); + } catch (error) { + console.error('Erreur lors de la mise à jour de l\'utilisateur:', error); + return reject(json({ error: 'Erreur lors de la mise à jour de l\'utilisateur' }, { status: 500 })); + } + }); + }); +} + + +export async function DELETE({ params }) { + const userId = parseInt(params.id); + + try { + // Vérifier si l'utilisateur est dans le cache Redis + const cachedUser = await redisClient.get(`user:${userId}`); + let userToDelete; + + if (cachedUser) { + console.log('✅ Cache hit'); + // Si l'utilisateur est dans le cache, on le parse + userToDelete = JSON.parse(cachedUser); + } else { + // Si l'utilisateur n'est pas dans le cache, on le récupère de la base de données + console.log('❌ Cache miss'); + userToDelete = await prisma.user.findUnique({ + where: { id: userId }, + }); + + if (!userToDelete) { + return json({ error: 'Utilisateur non trouvé' }, { status: 404 }); + } + + // Mettre l'utilisateur dans le cache Redis + await redisClient.set(`user:${userId}`, JSON.stringify(userToDelete), { EX: 3600 }); // Cache pendant 1 heure + } + + // Si l'utilisateur a une image de profil, la supprimer + if (userToDelete.profilePictureUrl) { + // Calculer le chemin du fichier à supprimer + const imagePath = `.${destinationDir}/${path.basename(userToDelete.profilePictureUrl)}`; + if (fs.existsSync(imagePath)) { + fs.unlinkSync(imagePath); // Supprimer le fichier image + } + } + + // Supprimer l'utilisateur de la base de données + await prisma.user.delete({ + where: { id: userId }, + }); + + // Supprimer l'utilisateur du cache Redis + await redisClient.del(`user:${userId}`); + + // Réponse après suppression réussie + return json({ message: 'Utilisateur et image supprimés avec succès' }); + } catch (err) { + console.error(err); + return json({ error: 'Erreur lors de la suppression de l’utilisateur' }, { status: 500 }); + } +} + + + + diff --git a/src/routes/api/users/+page.server.ts b/src/routes/api/users/+page.server.ts new file mode 100644 index 0000000..0d7b259 --- /dev/null +++ b/src/routes/api/users/+page.server.ts @@ -0,0 +1,27 @@ +// src/routes/api/users/+server.js +import { json } from '@sveltejs/kit'; +import redisClient from '$lib/redisClient'; +import prisma from '$lib/prismaClient'; + +export async function GET() { + try { + // Vérifier si les utilisateurs sont dans le cache Redis + const cachedUsers = await redisClient.get('users'); + if (cachedUsers) { + console.log('✅ Cache hit'); + return json(JSON.parse(cachedUsers)); + } + + console.log('❌ Cache miss'); + // Sinon, récupérer les utilisateurs depuis MongoDB + const users = await prisma.user.findMany(); + + // Mettre les utilisateurs en cache + await redisClient.set('users', JSON.stringify(users), { EX: 600 }); + + return json(users); + } catch (err) { + console.error(err); + return json({ error: 'Erreur serveur' }, { status: 500 }); + } +} diff --git a/src/routes/chat/+page.svelte b/src/routes/chat/+page.svelte index 6e7ab5b..eacda00 100644 --- a/src/routes/chat/+page.svelte +++ b/src/routes/chat/+page.svelte @@ -1,3 +1,53 @@ - + + + +
+
+

Créer un nouveau chat

+ + + + + + +
+
+ + +{#if showAlert} + showAlert = false} /> +{/if} + + diff --git a/src/routes/chats/+page.svelte b/src/routes/chats/+page.svelte new file mode 100644 index 0000000..fabf379 --- /dev/null +++ b/src/routes/chats/+page.svelte @@ -0,0 +1,32 @@ + + +
+
+
+
+ +
+
+ +
+ +
+ + +
+
+ + \ No newline at end of file diff --git a/src/routes/user/edit/+page.svelte b/src/routes/user/edit/+page.svelte new file mode 100644 index 0000000..ce54044 --- /dev/null +++ b/src/routes/user/edit/+page.svelte @@ -0,0 +1,140 @@ + + +
+
+

Modifier les informations du compte

+ + + {#if showMessage} +
+ {message} +
+ {/if} + + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ + {#if profilePicture} +
Image sélectionnée : {profilePicture.name}
+ {/if} +
+ +
+ +
+
+
+
+ + diff --git a/static/profile-default.svg b/static/profile-default.svg new file mode 100644 index 0000000..726ac6f --- /dev/null +++ b/static/profile-default.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 7872310c6002eb290936032a505543e86478b2a0 Mon Sep 17 00:00:00 2001 From: Bilal Dieumegard Date: Sun, 1 Dec 2024 15:06:30 +0100 Subject: [PATCH 2/3] Deplacement de la requete post d'utilisateur vers le chemin users au lieu de user/[id] --- src/routes/api/user/[id]/+page.server.ts | 41 ------------------------ src/routes/api/users/+page.server.ts | 41 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/routes/api/user/[id]/+page.server.ts b/src/routes/api/user/[id]/+page.server.ts index 5052a08..3282d88 100644 --- a/src/routes/api/user/[id]/+page.server.ts +++ b/src/routes/api/user/[id]/+page.server.ts @@ -56,47 +56,6 @@ export async function GET({ params }) { } } -export async function POST({ request }) { - return new Promise((resolve, reject) => { - // Utilisation de multer pour récupérer le fichier - upload.single('profilePicture')(request.raw, request.raw, async (err) => { - if (err) { - console.error('Erreur de téléchargement:', err); - return reject(json({ error: 'Erreur lors du téléchargement du fichier' }, { status: 500 })); - } - - // Récupérer les données du formulaire (sans le fichier) - const { pseudo, nom, prenom, email, password } = await request.json(); - - // L'URL de l'image sera le chemin relatif à partir du dossier uploads - const imageUrl = request.file ? `${destinationDir}/${request.file.filename}` : null; - - try { - // Créer un nouvel utilisateur avec l'URL de l'image - const user = await prisma.user.create({ - data: { - pseudo, - nom, - prenom, - email, - password, - profilePictureUrl: imageUrl, // Stocker l'URL de l'image - }, - }); - - // Mettre l'utilisateur dans le cache Redis - await redisClient.set(`user:${user.id}`, JSON.stringify(user), { EX: 3600 }); - - // Réponse avec les données de l'utilisateur - return resolve(json(user, { status: 201 })); - } catch (error) { - console.error('Erreur lors de la création de l\'utilisateur:', error); - return reject(json({ error: 'Erreur lors de la création de l\'utilisateur' }, { status: 500 })); - } - }); - }); -} - // Mettre à jour un utilisateur avec PUT export async function PUT({ params, request }) { const userId = parseInt(params.id); diff --git a/src/routes/api/users/+page.server.ts b/src/routes/api/users/+page.server.ts index 0d7b259..4de2048 100644 --- a/src/routes/api/users/+page.server.ts +++ b/src/routes/api/users/+page.server.ts @@ -25,3 +25,44 @@ export async function GET() { return json({ error: 'Erreur serveur' }, { status: 500 }); } } + +export async function POST({ request }) { + return new Promise((resolve, reject) => { + // Utilisation de multer pour récupérer le fichier + upload.single('profilePicture')(request.raw, request.raw, async (err) => { + if (err) { + console.error('Erreur de téléchargement:', err); + return reject(json({ error: 'Erreur lors du téléchargement du fichier' }, { status: 500 })); + } + + // Récupérer les données du formulaire (sans le fichier) + const { pseudo, nom, prenom, email, password } = await request.json(); + + // L'URL de l'image sera le chemin relatif à partir du dossier uploads + const imageUrl = request.file ? `${destinationDir}/${request.file.filename}` : null; + + try { + // Créer un nouvel utilisateur avec l'URL de l'image + const user = await prisma.user.create({ + data: { + pseudo, + nom, + prenom, + email, + password, + profilePictureUrl: imageUrl, // Stocker l'URL de l'image + }, + }); + + // Mettre l'utilisateur dans le cache Redis + await redisClient.set(`user:${user.id}`, JSON.stringify(user), { EX: 3600 }); + + // Réponse avec les données de l'utilisateur + return resolve(json(user, { status: 201 })); + } catch (error) { + console.error('Erreur lors de la création de l\'utilisateur:', error); + return reject(json({ error: 'Erreur lors de la création de l\'utilisateur' }, { status: 500 })); + } + }); + }); +} From 99b10188bd470b262fa9c9186d6f1b61f4e2df74 Mon Sep 17 00:00:00 2001 From: Bilal Dieumegard Date: Sun, 1 Dec 2024 18:16:40 +0100 Subject: [PATCH 3/3] Ajout des pages de modification de profil, des composant de profil et de creation de channel --- pnpm-lock.yaml | 162 ++++++++++++++++++++++ src/lib/components/ui/Alert.svelte | 41 ++++-- src/lib/components/ui/CreateChat.svelte | 73 ++++++++++ src/lib/components/ui/ProfileCard.svelte | 81 ++++++++--- src/lib/components/ui/ProfileInfo.svelte | 34 +++++ src/lib/components/ui/ProfileModal.svelte | 36 ----- src/routes/api/users/+page.server.ts | 19 +++ src/routes/chat/+page.server.ts | 0 src/routes/chat/+page.svelte | 53 ------- src/routes/chats/+page.svelte | 65 ++++++++- 10 files changed, 437 insertions(+), 127 deletions(-) create mode 100644 src/lib/components/ui/CreateChat.svelte create mode 100644 src/lib/components/ui/ProfileInfo.svelte delete mode 100644 src/lib/components/ui/ProfileModal.svelte delete mode 100644 src/routes/chat/+page.server.ts delete mode 100644 src/routes/chat/+page.svelte diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80bcfdc..9abe09f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,12 @@ importers: .: dependencies: + lucide-svelte: + specifier: ^0.462.0 + version: 0.462.0(svelte@5.2.7) + multer: + specifier: ^1.4.5-lts.1 + version: 1.4.5-lts.1 svelte-radix: specifier: ^2.0.1 version: 2.0.1(svelte@5.2.7) @@ -576,6 +582,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + append-field@1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -624,6 +633,13 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -665,10 +681,17 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -923,6 +946,9 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -950,6 +976,9 @@ packages: is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1011,6 +1040,11 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lucide-svelte@0.462.0: + resolution: {integrity: sha512-BTY44UyXEhlakuPMS4w7NayKhDYARzmhEv3E2YchTiNZ/aySS0F2ktPscTlXRgSZ9xwqoozhnhO1oKhm/nnmqg==} + peerDependencies: + svelte: ^3 || ^4 || ^5.0.0-next.42 + magic-string@0.30.13: resolution: {integrity: sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g==} @@ -1019,6 +1053,10 @@ packages: peerDependencies: svelte: ^3.56.0 || ^4.0.0 || ^5.0.0-next.120 + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1027,6 +1065,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1034,10 +1080,17 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -1049,6 +1102,10 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + multer@1.4.5-lts.1: + resolution: {integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==} + engines: {node: '>= 6.0.0'} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -1275,6 +1332,9 @@ packages: resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} engines: {node: '>=6'} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1285,6 +1345,9 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -1317,6 +1380,9 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -1345,6 +1411,10 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -1353,6 +1423,9 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1456,6 +1529,13 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + typescript-eslint@8.15.0: resolution: {integrity: sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1545,6 +1625,10 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} @@ -1986,6 +2070,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + append-field@1.0.0: {} + arg@5.0.2: {} argparse@2.0.1: {} @@ -2035,6 +2121,12 @@ snapshots: node-releases: 2.0.18 update-browserslist-db: 1.1.1(browserslist@4.24.2) + buffer-from@1.1.2: {} + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + callsites@3.1.0: {} camelcase-css@2.0.1: {} @@ -2074,8 +2166,17 @@ snapshots: concat-map@0.0.1: {} + concat-stream@1.6.2: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + typedarray: 0.0.6 + cookie@0.6.0: {} + core-util-is@1.0.3: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -2352,6 +2453,8 @@ snapshots: imurmurhash@0.1.4: {} + inherits@2.0.4: {} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -2374,6 +2477,8 @@ snapshots: dependencies: '@types/estree': 1.0.6 + isarray@1.0.0: {} + isexe@2.0.0: {} jackspeak@3.4.3: @@ -2423,6 +2528,10 @@ snapshots: lru-cache@10.4.3: {} + lucide-svelte@0.462.0(svelte@5.2.7): + dependencies: + svelte: 5.2.7 + magic-string@0.30.13: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -2435,6 +2544,8 @@ snapshots: svelte: 5.2.7 vfile-message: 2.0.4 + media-typer@0.3.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -2442,6 +2553,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -2450,14 +2567,30 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: {} + minipass@7.1.2: {} + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + mri@1.2.0: {} mrmime@2.0.0: {} ms@2.1.3: {} + multer@1.4.5-lts.1: + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 1.6.2 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -2593,6 +2726,8 @@ snapshots: prismjs@1.29.0: {} + process-nextick-args@2.0.1: {} + punycode@2.3.1: {} queue-microtask@1.2.3: {} @@ -2601,6 +2736,16 @@ snapshots: dependencies: pify: 2.3.0 + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -2649,6 +2794,8 @@ snapshots: dependencies: mri: 1.2.0 + safe-buffer@5.1.2: {} + semver@7.6.3: {} set-cookie-parser@2.7.1: {} @@ -2669,6 +2816,8 @@ snapshots: source-map-js@1.2.1: {} + streamsearch@1.1.0: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -2681,6 +2830,10 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -2816,6 +2969,13 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + typedarray@0.0.6: {} + typescript-eslint@8.15.0(eslint@9.15.0(jiti@1.21.6))(typescript@5.7.2): dependencies: '@typescript-eslint/eslint-plugin': 8.15.0(@typescript-eslint/parser@8.15.0(eslint@9.15.0(jiti@1.21.6))(typescript@5.7.2))(eslint@9.15.0(jiti@1.21.6))(typescript@5.7.2) @@ -2880,6 +3040,8 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + xtend@4.0.2: {} + yaml@1.10.2: {} yaml@2.6.1: {} diff --git a/src/lib/components/ui/Alert.svelte b/src/lib/components/ui/Alert.svelte index 0558081..8b40d1d 100644 --- a/src/lib/components/ui/Alert.svelte +++ b/src/lib/components/ui/Alert.svelte @@ -1,30 +1,46 @@ - -
+{#if show} +
- {message} - - - -
+ {message} +
+{/if} diff --git a/src/lib/components/ui/ProfileCard.svelte b/src/lib/components/ui/ProfileCard.svelte index 65faf27..89b1737 100644 --- a/src/lib/components/ui/ProfileCard.svelte +++ b/src/lib/components/ui/ProfileCard.svelte @@ -1,28 +1,71 @@ - -
- - Photo de profil - - -
-

{name}

-

{bio}

+{#if show} + -
+{/if} diff --git a/src/lib/components/ui/ProfileInfo.svelte b/src/lib/components/ui/ProfileInfo.svelte new file mode 100644 index 0000000..8b1d168 --- /dev/null +++ b/src/lib/components/ui/ProfileInfo.svelte @@ -0,0 +1,34 @@ + + + + + diff --git a/src/lib/components/ui/ProfileModal.svelte b/src/lib/components/ui/ProfileModal.svelte deleted file mode 100644 index 36d195a..0000000 --- a/src/lib/components/ui/ProfileModal.svelte +++ /dev/null @@ -1,36 +0,0 @@ - - -
-
-
-

{name}

- -
- -
- Photo de profil -

{bio}

-
- -
- -
-
-
- - diff --git a/src/routes/api/users/+page.server.ts b/src/routes/api/users/+page.server.ts index 4de2048..7444e4e 100644 --- a/src/routes/api/users/+page.server.ts +++ b/src/routes/api/users/+page.server.ts @@ -2,6 +2,25 @@ import { json } from '@sveltejs/kit'; import redisClient from '$lib/redisClient'; import prisma from '$lib/prismaClient'; +import multer from 'multer'; + +const destinationDir = '/uploads'; + +const storage = multer.diskStorage({ + destination: (req, file, cb) => { + cb(null, `.${destinationDir}'); // Dossier où les images sont stockées` + }, + filename: (req, file, cb) => { + cb(null, `${Date.now()}-${file.originalname}`); + }, + fileFilter(req, file, cb) { + const fileExtension = path.extname(file.originalname).toLowerCase(); + if (fileExtension !== '.jpg' && fileExtension !== '.jpeg' && fileExtension !== '.png') { + return cb(new Error('Seules les images JPG, JPEG et PNG sont autorisées.')); + } + cb(null, true); + } +}); export async function GET() { try { diff --git a/src/routes/chat/+page.server.ts b/src/routes/chat/+page.server.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/routes/chat/+page.svelte b/src/routes/chat/+page.svelte deleted file mode 100644 index eacda00..0000000 --- a/src/routes/chat/+page.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - - -
-
-

Créer un nouveau chat

- - - - - - -
-
- - -{#if showAlert} - showAlert = false} /> -{/if} - - diff --git a/src/routes/chats/+page.svelte b/src/routes/chats/+page.svelte index fabf379..1cab2a3 100644 --- a/src/routes/chats/+page.svelte +++ b/src/routes/chats/+page.svelte @@ -3,16 +3,64 @@ import Plus from "svelte-radix/Plus.svelte"; // Icône pour "Ajouter" import Search from "$lib/components/ui/Search.svelte"; import ChatItem from "$lib/components/ui/ChatItem.svelte"; + import ProfileCard from "$lib/components/ui/ProfileCard.svelte"; // Importer le composant ProfileCard + import CreateChat from "$lib/components/ui/CreateChat.svelte"; // Importer le composant CreateChat + + let showProfileCard = false; // État pour afficher ou masquer le ProfileCard + let showCreateChat = false; // État pour afficher ou masquer CreateChat + let user = { + pseudo: 'JohnDoe', + prenom: 'John', + nom: 'Doe', + description: 'Développeur passionné', + profilePictureUrl: 'path/to/profile-picture.jpg', // URL de l'image de profil + }; + + function openProfileCard() { + console.log('openProfileCard'); + showProfileCard = true; // Inverser l'état pour afficher/masquer le ProfilCard + } + + function closeProfileCard() { + console.log('closeProfileCard'); + showProfileCard = false; // Inverser l'état pour afficher/masquer le ProfilCard + } + + function openCreateChat() { + console.log('openCreateChat'); + showCreateChat = true; // Afficher le composant CreateChat + } + + function closeCreateChat() { + console.log('closeCreateChat'); + showCreateChat = false; // Fermer le composant CreateChat + }
-
+ + + +
- @@ -22,11 +70,14 @@
+
+ + \ No newline at end of file + .h-full { + height: 100%; + background-color: #f9f9f9; + } +