Ajout de la modification des user avec photo de profil etc et des informations de profil dans les messages

This commit is contained in:
Bilal Dieumegard 2024-12-09 21:51:56 +01:00
parent 2d4cea3c4e
commit ab3e81d020
7 changed files with 186 additions and 97 deletions

View file

@ -6,19 +6,19 @@
export let myMessage: boolean; // Si c'est le message de l'utilisateur courant
export let user = null; // Infos utilisateur
export let messageContent = ""; // Contenu du message
export let createdAt = new Date(); // Date de création du message
export let message = null; // Contenu du message
let defaultProfilePicture = "/images/default-profile.png";
let showProfileInfo = false; // Contrôle la visibilité des informations de profil
export let setActiveProfile;
export let activeProfileId = null;
// Temps écoulé (calculé périodiquement)
let timeElapsed: string;
// Fonction pour mettre à jour le temps écoulé
const updateElapsed = () => {
timeElapsed = formatDistanceToNow(createdAt);
timeElapsed = formatDistanceToNow(message.createdAt);
};
// Initialisation de l'intervalle
@ -30,6 +30,17 @@
clearInterval(interval); // Nettoyage lors du démontage
};
});
function toggleProfileInfo() {
if (activeProfileId === message.id) {
// Si le profil cliqué est déjà actif, le fermer
setActiveProfile(null);
} else {
// Sinon, afficher ce profil et masquer les autres
setActiveProfile(message.id);
}
}
</script>
<Card.Root class="relative">
@ -45,25 +56,24 @@
<div class="flex items-center gap-3 {myMessage ? 'flex-row-reverse' : 'flex-row'}">
<div
class="relative"
on:mouseenter={() => (showProfileInfo = true)}
on:mouseleave={() => (showProfileInfo = false)}
on:click={toggleProfileInfo}
>
<!-- Image de profil -->
<img
src={user.profilePicture ? `http://localhost:5173/${user.profilePicture}` : defaultProfilePicture}
src={message.user.profilePicture ? `http://localhost:5173/${message.user.profilePicture}` : defaultProfilePicture}
alt="Profile Picture"
class="h-10 w-10 rounded-full border border-gray-300"
class="h-10 w-10 rounded-full border border-gray-300 cursor-pointer"
/>
<!-- Infos du profil (affichées au survol) -->
<ProfileInfo user={user} show={showProfileInfo} position={myMessage ? "right" : "left"} />
<ProfileInfo user={message.user} show={activeProfileId === message.id} position={myMessage} />
</div>
<div class="flex flex-col text-right {myMessage ? 'text-right' : 'text-left'}">
<Card.Title
class="text-gray-800 text-sm sm:text-base md:text-lg truncate {myMessage ? 'font-black' : ''}"
class="text-gray-800 text-sm sm:text-base md:text-lg truncate {myMessage ? 'font-bold' : ''}"
>
{myMessage ? "(Moi)" : ""} {user.username}
{myMessage ? "(Moi)" : ""} {message.user.username}
</Card.Title>
</div>
</div>
@ -71,7 +81,7 @@
<!-- Contenu du message -->
<Card.Content class="text-sm sm:text-base md:text-lg text-gray-700">
<p>{messageContent}</p>
<p>{message.text}</p>
</Card.Content>
</Card.Root>

View file

@ -1,21 +1,62 @@
<script lang="ts">
export let profilePicture: File | null = null;
const defaultImage = '/profile-default.svg'; // Remplacez par votre image par défaut
import { onMount } from 'svelte';
// Gérer le changement de fichier sélectionné
export let profilePicture: File | null = null;
export let defaultImage = '/profile-default.svg'; // Image par défaut si aucune image n'est sélectionnée
let clientPicture: string | null = profilePicture ? `/${profilePicture}` : defaultImage;
// Fonction exécutée lorsque l'utilisateur sélectionne une image
const handleFileChange = (event: Event) => {
const input = event.target as HTMLInputElement;
if (input.files?.length) {
profilePicture = input.files[0];
profilePicture = input.files[0]; // Affectation du fichier sélectionné
clientPicture = URL.createObjectURL(profilePicture); // Prévisualisation de l'image
} else {
clientPicture = null;
profilePicture = null;
}
};
// Supprimer l'image
const handleDelete = () => {
profilePicture = null;
};
</script>
<!-- Conteneur principal -->
<div class="container">
<!-- Image de profil ou image par défaut -->
<img
src={clientPicture}
alt="Image de profil"
class="image-preview mb-10"
/>
<!-- Sélectionner une image -->
<label for="profilePicture" class="file-upload-btn">
Sélectionner une image
<input
type="file"
id="profilePicture"
class="file-input"
accept="image/*"
on:change={handleFileChange}
/>
</label>
<div class="action-buttons">
<!-- Bouton Supprimer l'image -->
<button
type="button"
class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600"
on:click={handleDelete}
disabled={!profilePicture}
>
Supprimer l'image
</button>
</div>
</div>
<style>
.container {
display: flex;
@ -69,37 +110,3 @@
cursor: not-allowed;
}
</style>
<!-- Conteneur principal -->
<div class="container">
<!-- Image de profil ou image par défaut -->
<img
src={profilePicture ? URL.createObjectURL(profilePicture) : defaultImage}
alt="Image de profil"
class="image-preview mb-10"
/>
<!-- Sélectionner une image -->
<label for="profilePicture" class="file-upload-btn">
Sélectionner une image
<input
type="file"
id="profilePicture"
class="file-input"
accept="image/*"
on:change={handleFileChange}
/>
</label>
<div class="action-buttons">
<!-- Bouton Supprimer l'image -->
<button
type="button"
class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600"
on:click={handleDelete}
disabled={!profilePicture}
>
Supprimer l'image
</button>
</div>
</div>

View file

@ -23,18 +23,29 @@
console.error('Erreur lors de la déconnexion:', error);
}
};
const editProfile = () => {
window.location.href = '/user/edit';
};
</script>
{#if show}
<div class="overlay" role="dialog" aria-labelledby="profile-card-title" on:click={onClose}>
<div class="profile-card" on:click|stopPropagation>
<div class="profile-header">
<!-- Image de profil -->
<img src={user.profilePicture} alt="Profile" class="profile-image" />
<h2 id="profile-card-title" class="profile-name">{user.username}</h2>
<div class="profile-card flex flex-col gap-5" on:click|stopPropagation>
<div class="flex flex-col gap-2">
<div class="profile-header">
<!-- Image de profil -->
<img src={user.profilePicture} alt="Profile" class="profile-image" />
<h2 id="profile-card-title" class="profile-name">{user.username}</h2>
</div>
<p>{user.name} {user.surname}</p>
</div>
<p>{user.name} {user.surname}</p>
<Button on:click={disconnect}>Deconnecter</Button>
<div class="flex flex-col gap-3">
<Button on:click={editProfile}>Editer</Button>
<Button on:click={disconnect} variant="destructive">Déconnexion</Button>
</div>
</div>
</div>
{/if}
@ -65,7 +76,7 @@
.profile-header {
display: flex;
justify-content: center;
justify-content: left;
align-items: center;
margin-bottom: 20px;
}

View file

@ -5,10 +5,10 @@
</script>
{#if show}
<div class="user-info" style="left: {position === 'left' ? 'auto' : '0'}; right: {position === 'right' ? '0' : 'auto'};">
<h3>{user.pseudo}</h3>
<p>{user.name} {user.surname}</p>
<p>{user.description}</p>
<div class="user-info {position ? 'left' : 'right' }">
<h2 class="text-lg font-semibold">{user.username}</h2>
<p class="text-sm text-gray-500">{user.email}</p>
<p class="text-sm text-gray-500">{user.name} {user.surname}</p>
</div>
{/if}
@ -18,12 +18,13 @@
top: 0; /* Aligner en haut */
left: auto;
right: auto;
width: 200px; /* Largeur appropriée */
width: 200px; /* Largeur par défaut */
background: rgba(255, 255, 255, 0.95); /* Fond semi-transparent */
padding: 15px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
z-index: 10; /* Gérer les priorités d'affichage */
transition: all 0.3s ease-in-out; /* Animation fluide pour les changements */
}
.user-info.left {
@ -33,5 +34,32 @@
.user-info.right {
left: 110%; /* Position à droite avec un espace */
}
/* Media Queries pour adapter le style */
@media (max-width: 768px) {
.user-info {
width: 150px; /* Réduire la largeur sur les écrans plus petits */
padding: 10px; /* Réduire le padding */
font-size: 0.9rem; /* Réduire la taille de la police */
}
}
@media (max-width: 480px) {
.user-info {
position: fixed; /* Position fixe pour éviter les débordements */
left: 10px; /* Centrer avec un padding interne */
right: 10px;
width: auto; /* Utiliser toute la largeur disponible */
max-width: 90%; /* Limiter la largeur pour éviter les débordements */
padding: 8px; /* Réduire le padding davantage */
font-size: 0.8rem; /* Police encore plus petite */
}
.user-info.left,
.user-info.right {
left: 10px; /* Ignorer les positionnements relatifs */
right: 10px;
}
}
</style>

View file

@ -15,6 +15,12 @@
let scrollContainer: HTMLElement;
let messageText = '';
let activeProfileId = null;
function setActiveProfile(id) {
activeProfileId = id;
}
let socket = initSocket(); // Initialiser le socket
async function sendMessage() {
@ -144,7 +150,12 @@
<!-- Afficher les messages (mock d'un utilisateur sélectionné ou aucun message par défaut) -->
{#if messages !== undefined && messages.length > 0}
{#each messages as message}
<Message myMessage={data.userId == message.user.id} user={message.user} messageContent={message.text} createdAt={message.createdAt} />
<Message
myMessage={data.userId == message.user.id}
message={message}
activeProfileId={activeProfileId}
setActiveProfile={setActiveProfile}
/>
{/each}
{:else}
<div class="text-center text-gray-500 mt-10">Sélectionnez un message le chat est vide.</div>

View file

@ -0,0 +1,23 @@
export async function load({ fetch, locals }) {
try {
// Appel API ou récupération de données
const res = await fetch(`/api/users/${locals.userId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
const user = await res.json();
// Retourner les données à la page sous forme de props
return {
user
};
} catch (error) {
console.error('Erreur lors du chargement des canaux:', error);
return {
user : null
};
}
}

View file

@ -2,11 +2,16 @@
import { onMount } from 'svelte';
import ChoosePicture from "$lib/components/ui/ChoosePicture.svelte"; // Import du composant
let pseudo = '';
let firstName = '';
let lastName = '';
let email = '';
let profilePicture: File | null = null;
export let data;
const user = data.user;
console.log(user);
let pseudo = user.username;
let firstName = user.name;
let lastName = user.surname;
let email = user.email;
let profilePicture = user.profilePicture; // Chemin initial ou valeur null
let message = '';
let showMessage = false;
@ -26,28 +31,31 @@
message = 'L\'email est invalide.';
showMessage = true;
} else {
// Vous pouvez ici envoyer les données à un serveur via une API
updateUser();
message = 'Informations mises à jour avec succès!';
showMessage = true;
}
};
// Fonction pour gérer le téléchargement de l'image de profil
const handleFileChange = (event: Event) => {
const input = event.target as HTMLInputElement;
if (input.files?.length) {
profilePicture = input.files[0];
}
};
async function updateUser() {
const formData = new FormData();
formData.append('username', pseudo);
formData.append('name', firstName);
formData.append('surname', lastName);
formData.append('email', email);
if (profilePicture) {
formData.append('profilePicture', profilePicture);
}
const res = await fetch(`/api/users/${user.id}`, {
method: 'PUT',
body: formData, // Transmet les données comme multipart/form-data
});
const result = await res.json();
console.log(result);
}
// Simulation de données au chargement
onMount(() => {
pseudo = '';
firstName = '';
lastName = '';
email = '';
profilePicture = null; // ou une valeur par défaut si vous en avez une
});
</script>
<div class="flex items-center justify-center min-h-screen bg-gray-100 mg-10">
@ -109,10 +117,7 @@
<!-- Intégration du composant de photo de profil -->
<div class="mb-4">
<ChoosePicture profilePicture={profilePicture} onFileChange={handleFileChange} />
{#if profilePicture}
<div class="mt-2 text-sm text-gray-600">Image sélectionnée : {profilePicture.name}</div>
{/if}
<ChoosePicture bind:profilePicture={profilePicture} />
</div>
<div class="mt-6 flex justify-center">
@ -128,12 +133,6 @@
</div>
<style>
/* Supprimez le sélecteur body si non utilisé */
/* body {
background-color: #f8fafc;
font-family: sans-serif;
} */
input, button {
font-family: inherit;
}