voici ta mission :
Listes des changements a faire :

faire en sorte que l'on puisse cliquer sur le profil des autres utilisateur pour voires leurs bios 

corrigé les photos de profiles qui fonctionne vraiment pas bien rendre l'interface des conversation beaucoup plus modern et pas grosse car la ça fait bancale

rendre le tout beaucoup plus instinctif et user friendly 

me faire des recomandation sur les choses a améliorer 

voici mon code :


// frontend/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { AuthProvider } from './contexts/AuthContext';
import './index.css';

ReactDOM.render(
  <AuthProvider>
    <App />
  </AuthProvider>,
  document.getElementById('root')
);

/* frontend/src/index.css */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');

:root {
  --background-color: #ffffff;
  --text-color: #333333;
  --header-background: rgba(28, 28, 30, 0.8);
  --input-background: rgba(255, 255, 255, 0.1);
  --button-background: linear-gradient(45deg, #FF416C, #FF4B2B);
  --button-hover: linear-gradient(45deg, #FF4B2B, #FF416C);
}

[data-theme="dark"] {
  --background-color: #121212;
  --text-color: #ffffff;
  --header-background: rgba(0, 0, 0, 0.8);
  --input-background: rgba(255, 255, 255, 0.05);
  --button-background: linear-gradient(45deg, #FF4B2B, #FF416C);
  --button-hover: linear-gradient(45deg, #FF416C, #FF4B2B);
}

body {
  font-family: 'Inter', sans-serif;
  background-color: var(--background-color);
  color: var(--text-color);
  margin: 0;
  padding: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font-family: inherit;
}

import React, { useContext } from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { AuthContext } from './contexts/AuthContext';
import Login from './components/Auth/Login';
import Signup from './components/Auth/Signup';
import Home from './components/Home';
import Chat from './components/Chat/Chat';
import Profile from './components/Profile/Profile';
import Navbar from './components/Navbar';


function App() {
  const { user } = useContext(AuthContext);

  return (
    <Router>
      <Navbar />
      <Routes>
        <Route path="/" element={user.name ? <Navigate to="/conversations" /> : <Home />} />
        <Route path="/login" element={user.name ? <Navigate to="/conversations" /> : <Login />} />
        <Route path="/signup" element={user.name ? <Navigate to="/conversations" /> : <Signup />} />
        <Route path="/profile" element={user.name ? <Profile /> : <Navigate to="/login" />} />
        <Route path="/conversations" element={user.name ? <Chat /> : <Navigate to="/login" />} />
        <Route path="/chat/:conversationId" element={user.name ? <Chat /> : <Navigate to="/login" />} />
        {/* Redirection pour les chemins non définis */}
        <Route path="*" element={<Navigate to="/" replace />} />
      </Routes>
    </Router>
  );
}

export default App;

.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

// src/utils/api.js
import axios from 'axios';

const instance = axios.create({
  baseURL: process.env.REACT_APP_API_URL,
});

export default instance;

// frontend/src/contexts/AuthContext.jsx
import React, { createContext, useState, useEffect } from 'react';
import axios from '../utils/api';

export const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState({
    id: '',
    name: '',
    bio: '',
    avatar_url: ''
  });

  // Load user from localStorage on mount
  useEffect(() => {
    const storedUser = localStorage.getItem('user');
    const storedToken = localStorage.getItem('token');
    if (storedUser && storedToken) {
      const parsedUser = JSON.parse(storedUser);
      setUser({
        id: parsedUser.id || '',
        name: parsedUser.name || '',
        bio: parsedUser.bio || '',
        avatar_url: parsedUser.avatar_url || ''
      });
      axios.defaults.headers.common['Authorization'] = `Bearer ${storedToken}`;
    }
  }, []);

  const login = async (username, password) => {
    const response = await axios.post('/login', {
      name: username,
      password: password,
    });
    const { access_token } = response.data;
    localStorage.setItem('token', access_token);
    axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`;

    // Fetch current user data
    const userResponse = await axios.get('/users/me');
    const fetchedUser = userResponse.data;
    localStorage.setItem('user', JSON.stringify(fetchedUser));
    setUser({
      id: fetchedUser.id || '',
      name: fetchedUser.name || '',
      bio: fetchedUser.bio || '',
      avatar_url: fetchedUser.avatar_url || ''
    });
  };

  const signup = async (username, password) => {
    await axios.post('/signup', {
      name: username,
      password: password,
    });
    // After signup, login the user
    await login(username, password);
  };

  const logout = () => {
    localStorage.removeItem('user');
    localStorage.removeItem('token');
    delete axios.defaults.headers.common['Authorization'];
    setUser({
      id: '',
      name: '',
      bio: '',
      avatar_url: ''
    });
  };

  return (
    <AuthContext.Provider value={{ user, login, signup, logout, setUser }}>
      {children}
    </AuthContext.Provider>
  );
};

// frontend/src/components/ThemeToggle.jsx
import React, { useEffect, useState } from 'react';
import { IoSunny, IoMoon } from 'react-icons/io5';
import styles from './ThemeToggle.module.css';

function ThemeToggle() {
  const [theme, setTheme] = useState('light');

  useEffect(() => {
    // Check for saved user preference
    const storedTheme = localStorage.getItem('app-theme') || 'light';
    setTheme(storedTheme);
    document.documentElement.setAttribute('data-theme', storedTheme);
  }, []);

  const toggleTheme = () => {
    const newTheme = theme === 'light' ? 'dark' : 'light';
    setTheme(newTheme);
    document.documentElement.setAttribute('data-theme', newTheme);
    localStorage.setItem('app-theme', newTheme);
  };

  return (
    <button className={styles.toggleButton} onClick={toggleTheme} aria-label="Toggle Theme">
      {theme === 'light' ? <IoMoon /> : <IoSunny />}
    </button>
  );
}

export default ThemeToggle;

/* frontend/src/components/ThemeToggle.module.css */
.toggleButton {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.5rem;
    color: var(--text-color);
    transition: color 0.3s ease;
  }
  
  .toggleButton:hover {
    color: #FF4B2B;
  }

/* frontend/src/components/Navbar/Navbar.module.css */

.navbar {
  background: rgba(28, 28, 30, 0.8); /* Slightly lighter than the main container */
  backdrop-filter: blur(15px);
  padding: 1rem 2rem;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: space-between;
  transition: all 0.3s ease;
}

.navbarContainer {
  max-width: 1200px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0 auto;
}

.navbarLogo {
  font-size: 1.8rem;
  font-weight: 700;
  text-decoration: none;
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  transition: opacity 0.3s ease;
}

.navbarLogo:hover {
  opacity: 0.8;
}

.navbarContent {
  display: flex;
  align-items: center;
}

.authenticatedNav {
  display: flex;
  align-items: center;
}

.navLinks {
  display: flex;
  gap: 1.5rem;
  margin-right: 1.5rem;
}

.navLink {
  color: #FFFFFF;
  text-decoration: none;
  font-weight: 500;
  position: relative;
  transition: color 0.3s ease;
}

.navLink::after {
  content: '';
  position: absolute;
  width: 0%;
  height: 2px;
  left: 0;
  bottom: -4px;
  background: linear-gradient(90deg, #FF416C, #FF4B2B);
  transition: width 0.3s ease;
}

.navLink:hover::after {
  width: 100%;
}

.userSection {
  display: flex;
  align-items: center;
}

.userInfo {
  display: flex;
  align-items: center;
  margin-right: 1rem;
}

.userAvatar {
  width: 40px;
  height: 40px;
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  color: white;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  margin-right: 0.5rem;
  transition: box-shadow 0.3s ease;
}

.avatarImage {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}

.userAvatar:hover {
  box-shadow: 0 0 10px rgba(255, 65, 108, 0.6);
}

.userName {
  color: white;
  font-size: 1rem;
  font-weight: 500;
}

.logoutButton, .loginButton, .signupButton {
  padding: 0.5rem 1rem;
  border-radius: 20px;
  font-weight: 600;
  border: none;
  cursor: pointer;
  transition: background 0.3s ease, transform 0.3s ease;
  margin-left: 0.5rem;
}

.logoutButton {
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  color: white;
}

.logoutButton:hover {
  background: linear-gradient(135deg, #FF4B2B, #FF416C);
  transform: translateY(-2px);
  box-shadow: 0 4px 6px rgba(255, 65, 108, 0.3);
}

.loginButton, .signupButton {
  background: rgba(255, 255, 255, 0.1);
  color: white;
}

.loginButton:hover, .signupButton:hover {
  background: rgba(255, 255, 255, 0.2);
  transform: translateY(-2px);
  box-shadow: 0 4px 6px rgba(255, 255, 255, 0.3);
}
/* frontend/src/components/Navbar/Navbar.module.css */

.navbar {
  background: var(--header-background); /* Use CSS variable */
  /* Rest of the styles remain the same */
}

.loginButton, .signupButton {
  background: rgba(255, 255, 255, 0.1);
  color: var(--text-color);
}

.logoutButton {
  background: var(--button-background);
  color: white;
}

.logoutButton:hover {
  background: var(--button-hover);
}

.navLink::after {
  background: var(--button-background);
}

/* Similarly, update other components to use CSS variables */

// frontend/src/components/Navbar/Navbar.jsx
import React, { useContext } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { AuthContext } from '../contexts/AuthContext';
import { motion, AnimatePresence } from 'framer-motion';
import styles from './Navbar.module.css';
import ThemeToggle from './ThemeToggle';

function Navbar() {
  const { user, logout } = useContext(AuthContext);
  const location = useLocation();

  // Define routes where navbar should not be displayed
  const hideNavbarRoutes = ['/chat']; // Add other routes if necessary
  const shouldHideNavbar = hideNavbarRoutes.some(route => location.pathname.startsWith(route));

  return (
    <AnimatePresence>
      {!shouldHideNavbar && (
        <motion.nav
          className={styles.navbar}
          initial={{ y: -100, opacity: 0 }}
          animate={{ y: 0, opacity: 1 }}
          exit={{ y: -100, opacity: 0 }}
          transition={{ duration: 0.5 }}
        >
          <div className={styles.navbarContainer}>
            <Link to="/" className={styles.navbarLogo}>
              ChatApp
            </Link>

            <div className={styles.navbarContent}>
              <ThemeToggle />
              {user.name ? (
                <div className={styles.authenticatedNav}>
                  <div className={styles.navLinks}>
                    <Link to="/conversations" className={styles.navLink}>
                      Conversations
                    </Link>
                    <Link to="/profile" className={styles.navLink}>
                      Profile
                    </Link>
                  </div>

                  <div className={styles.userSection}>
                    <div className={styles.userInfo}>
                      <div className={styles.userAvatar}>
                        {user.avatar_url ? (
                          <img src={user.avatar_url} alt="Avatar" className={styles.avatarImage} />
                        ) : (
                          user.name.charAt(0).toUpperCase()
                        )}
                      </div>
                      <span className={styles.userName}>{user.name}</span>
                    </div>
                    <button onClick={logout} className={styles.logoutButton}>
                      Logout
                    </button>
                  </div>
                </div>
              ) : (
                <div className={styles.authButtons}>
                  <Link to="/login" className={styles.loginButton}>
                    Login
                  </Link>
                  <Link to="/signup" className={styles.signupButton}>
                    Signup
                  </Link>
                </div>
              )}
            </div>
          </div>
        </motion.nav>
      )}
    </AnimatePresence>
  );
}

export default Navbar;

/* Home.module.css */
.mainContainer {
  position: relative;
  min-height: 100vh;
  color: #FFFFFF;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
}

/* Progress Line */
.progressLine {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: rgba(255, 255, 255, 0.1);
  z-index: 1000;
}

.progressFill {
  height: 100%;
  background: linear-gradient(90deg, #FF416C, #FF4B2B);
  transition: width 0.1s ease-out;
}

/* Video Background */
.backgroundVideo {
  position: fixed;
  right: 0;
  bottom: 0;
  min-width: 100%;
  min-height: 100%;
  width: auto;
  height: auto;
  z-index: -2;
  object-fit: cover;
}

.videoOverlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #000;
  z-index: -1;
  transition: opacity 0.5s ease;
}

/* Sections Common Styles */
.section {
  min-height: 100vh;
  padding: 80px 20px;
  opacity: 0;
  transform: translateY(50px);
  transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
}

.section.revealed {
  opacity: 1;
  transform: translateY(0);
}

.contentWrapper {
  max-width: 1200px;
  margin: 0 auto;
  position: relative;
}

/* Hero Section */
.heroSection {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.heroTitle {
  font-size: 3.5rem;
  margin-bottom: 1rem;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.2s;
}

.revealed .heroTitle {
  opacity: 1;
  transform: translateY(0);
}

.heroText {
  font-size: 1.5rem;
  margin-bottom: 2rem;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.4s;
}

.revealed .heroText {
  opacity: 1;
  transform: translateY(0);
}

/* Features Section */
.featuresGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 30px;
  margin-top: 50px;
}

.featureCard {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  border-radius: 20px;
  padding: 30px;
  text-align: center;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.revealed .featureCard {
  opacity: 1;
  transform: translateY(0);
}

.featureCard:hover {
  transform: translateY(-10px);
  background: rgba(255, 255, 255, 0.15);
}

.featureIcon {
  font-size: 3rem;
  margin-bottom: 1rem;
  display: block;
}

/* Stats Section */
.statsGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 30px;
  margin-top: 50px;
}

.statCard {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  border-radius: 20px;
  padding: 30px;
  text-align: center;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.revealed .statCard {
  opacity: 1;
  transform: translateY(0);
}

.statNumber {
  font-size: 3rem;
  font-weight: bold;
  background: linear-gradient(45deg, #FF416C, #FF4B2B);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  display: block;
  margin-bottom: 0.5rem;
}

.statLabel {
  font-size: 1.2rem;
  color: rgba(255, 255, 255, 0.8);
}

/* Contact Section */
.contactSection {
  text-align: center;
}

.contactContent {
  max-width: 600px;
  margin: 0 auto;
}

.contactText {
  font-size: 1.5rem;
  margin-bottom: 2rem;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.2s;
}

.revealed .contactText {
  opacity: 1;
  transform: translateY(0);
}

/* Section Titles */
.sectionTitle {
  font-size: 2.5rem;
  margin-bottom: 2rem;
  text-align: center;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.revealed .sectionTitle {
  opacity: 1;
  transform: translateY(0);
}

/* Buttons */
.mainButton {
  padding: 15px 30px;
  font-size: 1.1rem;
  font-weight: 600;
  border: none;
  border-radius: 25px;
  background: linear-gradient(45deg, #FF416C, #FF4B2B);
  color: white;
  cursor: pointer;
  transition: all 0.3s ease;
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.6s;
}

.revealed .mainButton {
  opacity: 1;
  transform: translateY(0);
}

.mainButton:hover {
  transform: translateY(-5px);
  box-shadow: 0 10px 20px rgba(255, 65, 108, 0.3);
}

.actionButtons {
  display: flex;
  gap: 20px;
  justify-content: center;
  margin-top: 2rem;
}

/* Responsive Design */
@media (max-width: 768px) {
  .heroTitle {
    font-size: 2.5rem;
  }
  
  .heroText {
    font-size: 1.2rem;
  }
  
  .section {
    padding: 60px 20px;
  }
  
  .statNumber {
    font-size: 2.5rem;
  }
  
  .actionButtons {
    flex-direction: column;
  }
}

/* Animation Keyframes */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes scaleIn {
  from {
    opacity: 0;
    transform: scale(0.9);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* Smooth Scroll */
html {
  scroll-behavior: smooth;
}


// frontend/src/components/Home.jsx
import React, { useState, useEffect, useRef, useContext } from 'react';
import { AuthContext } from '../contexts/AuthContext';
import { useNavigate } from 'react-router-dom';
import styles from './Home.module.css';
import backgroundVideo from './Space.mp4';

function Home() {
  const { user } = useContext(AuthContext);
  const navigate = useNavigate();
  const [scrollProgress, setScrollProgress] = useState(0);
  const sectionsRef = useRef([]);

  const handleLogin = () => navigate('/login');
  const handleSignUp = () => navigate('/signup');
  const handleStartChat = () => navigate('/conversations');

  useEffect(() => {
    const handleScroll = () => {
      // Calculate scroll progress (0 to 1)
      const totalHeight = document.documentElement.scrollHeight - window.innerHeight;
      const progress = window.scrollY / totalHeight;
      setScrollProgress(progress);

      // Check each section for visibility
      sectionsRef.current.forEach(section => {
        if (!section) return;
        const rect = section.getBoundingClientRect();
        const isVisible = rect.top < window.innerHeight * 0.75;
        if (isVisible) {
          section.classList.add(styles.revealed);
        }
      });
    };

    window.addEventListener('scroll', handleScroll);
    handleScroll(); // Initial check

    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  // Progress line width calculation
  const progressWidth = `${scrollProgress * 100}%`;

  return (
    <div className={styles.mainContainer}>
      {/* Progress Line */}
      <div className={styles.progressLine}>
        <div className={styles.progressFill} style={{ width: progressWidth }} />
      </div>

      {/* Background Video */}
      <div className={styles.videoOverlay} style={{ 
        opacity: Math.min(0.4 + scrollProgress * 0.4, 0.8) 
      }} />
      <video
        autoPlay
        muted
        loop
        playsInline
        className={styles.backgroundVideo}
      >
        <source src={backgroundVideo} type="video/mp4" />
      </video>

      {/* Hero Section */}
      <section 
        className={`${styles.section} ${styles.heroSection}`}
        ref={el => sectionsRef.current[0] = el}
      >
        <div className={styles.contentWrapper}>
          {user.name ? (
            <div className={styles.authenticatedContent}>
              <div className={styles.avatarWrapper}>
                <div className={styles.avatar}>
                  {user.name.charAt(0).toUpperCase()}
                </div>
              </div>
              <h1 className={styles.welcomeText}>
                Welcome back, <span className={styles.userName}>{user.name}</span>
              </h1>
              <button className={styles.mainButton} onClick={handleStartChat}>
                Go to Conversations
              </button>
            </div>
          ) : (
            <div className={styles.unauthenticatedContent}>
              <h1 className={styles.heroTitle}>Connect to Start Chatting</h1>
              <p className={styles.heroText}>
                Join a dynamic community and communicate in real-time
              </p>
              <div className={styles.actionButtons}>
                <button className={styles.mainButton} onClick={handleLogin}>
                  Login
                </button>
                <button className={styles.mainButton} onClick={handleSignUp}>
                  Signup
                </button>
              </div>
            </div>
          )}
        </div>
      </section>

      {/* Features Section */}
      <section 
        className={`${styles.section} ${styles.featuresSection}`}
        ref={el => sectionsRef.current[1] = el}
      >
        <div className={styles.contentWrapper}>
          <h2 className={styles.sectionTitle}>Our Features</h2>
          <div className={styles.featuresGrid}>
            {[
              { icon: '🔒', title: 'Secure', desc: 'End-to-end encryption' },
              { icon: '⚡', title: 'Fast', desc: 'Real-time communication' },
              { icon: '🌐', title: 'Global', desc: 'Accessible everywhere' },
              { icon: '📱', title: 'Responsive', desc: 'Mobile-friendly interface' },
              { icon: '🎨', title: 'Customizable', desc: 'Themes and avatars' },
              { icon: '📂', title: 'Media Sharing', desc: 'Share images, videos, and documents' },
            ].map((feature, index) => (
              <div 
                key={index}
                className={styles.featureCard}
                style={{ transitionDelay: `${index * 0.1}s` }}
              >
                <span className={styles.featureIcon}>{feature.icon}</span>
                <h3>{feature.title}</h3>
                <p>{feature.desc}</p>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Stats Section */}
      <section 
        className={`${styles.section} ${styles.statsSection}`}
        ref={el => sectionsRef.current[2] = el}
      >
        <div className={styles.contentWrapper}>
          <h2 className={styles.sectionTitle}>Our Stats</h2>
          <div className={styles.statsGrid}>
            {[
              { number: '10k+', label: 'Active Users' },
              { number: '500k+', label: 'Messages Sent' },
              { number: '99.9%', label: 'Uptime' },
            ].map((stat, index) => (
              <div 
                key={index}
                className={styles.statCard}
                style={{ transitionDelay: `${index * 0.1}s` }}
              >
                <span className={styles.statNumber}>{stat.number}</span>
                <span className={styles.statLabel}>{stat.label}</span>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Contact Section */}
      <section 
        className={`${styles.section} ${styles.contactSection}`}
        ref={el => sectionsRef.current[3] = el}
      >
        <div className={styles.contentWrapper}>
          <h2 className={styles.sectionTitle}>Get in Touch</h2>
          <div className={styles.contactContent}>
            <p className={styles.contactText}>
              Ready to join us?
            </p>
            <button className={styles.mainButton}>
              Start Chatting
            </button>
          </div>
        </div>
      </section>
    </div>
  );
}

export default Home;

/* frontend/src/components/Chat/MessageReactions.module.css */
.reactionsContainer {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.5rem;
  }
  
  .reactionButton {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.2rem;
    transition: transform 0.2s ease, color 0.2s ease;
  }
  
  .reactionButton:hover {
    transform: scale(1.2);
    color: #FF4B2B;
  }

// frontend/src/components/Chat/MessageReactions.jsx
import React from 'react';
import { IoHappy, IoThumbsUp, IoHeart } from 'react-icons/io5';
import styles from './MessageReactions.module.css';

const availableReactions = [
  { emoji: '😊', label: 'Happy' },
  { emoji: '👍', label: 'Thumbs Up' },
  { emoji: '❤️', label: 'Heart' },
];

function MessageReactions({ onAddReaction }) {
  return (
    <div className={styles.reactionsContainer}>
      {availableReactions.map((reaction) => (
        <button
          key={reaction.emoji}
          className={styles.reactionButton}
          onClick={() => onAddReaction(reaction.emoji)}
          aria-label={reaction.label}
        >
          {reaction.emoji}
        </button>
      ))}
    </div>
  );
}

export default MessageReactions;

/* frontend/src/components/Chat/CreateConversationModal.module.css */
.overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.75);
  backdrop-filter: blur(12px);
  z-index: 50;
  display: grid;
  place-items: center;
  padding: 1rem;
}

.modal {
  background: #1e1e1e;
  border-radius: 24px;
  padding: 2.5rem;
  width: min(90vw, 480px);
  color: #ffffff;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.modal h2 {
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.025em;
  margin-bottom: 2rem;
  color: #ffffff;
}

.inputGroup {
  margin-bottom: 2rem;
}

.inputGroup label {
  display: block;
  font-size: 0.875rem;
  font-weight: 500;
  margin-bottom: 0.75rem;
  color: rgba(255, 255, 255, 0.7);
  letter-spacing: 0.025em;
}

.inputGroup input {
  width: 100%;
  padding: 1rem;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 12px;
  color: #ffffff;
  font-size: 1rem;
  transition: all 0.2s ease;
}

.inputGroup input:focus {
  outline: none;
  border-color: #FF416C;
  background: rgba(255, 255, 255, 0.08);
}

.usersList {
  max-height: 200px;
  overflow-y: auto;
  margin-top: 1rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.03);
  padding: 0.75rem;
}

.usersList::-webkit-scrollbar {
  width: 4px;
}

.usersList::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 4px;
}

.userItem,
.participantItem {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem;
  margin-bottom: 0.75rem;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  transition: all 0.2s ease;
}

.userItem:hover,
.participantItem:hover {
  background: rgba(255, 255, 255, 0.08);
}

.userItem span,
.participantItem span {
  color: #ffffff;
  font-weight: 500;
}

.userItem button,
.participantItem button {
  border: none;
  padding: 0.5rem 1rem;
  border-radius: 8px;
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s ease;
}

.userItem button {
  background: #FF416C;
  color: #ffffff;
}

.userItem button:hover {
  background: #FF4B2B;
  transform: translateY(-1px);
}

.participantItem button {
  background: rgba(255, 68, 68, 0.2);
  color: #ff4444;
  border: 1px solid rgba(255, 68, 68, 0.3);
}

.participantItem button:hover {
  background: rgba(255, 68, 68, 0.3);
}

.participants {
  margin: 2rem 0;
}

.participants h3 {
  font-size: 0.875rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.7);
  margin-bottom: 1rem;
  letter-spacing: 0.025em;
}

.error {
  color: #ff4444;
  font-size: 0.875rem;
  margin-bottom: 1.5rem;
}

.buttonGroup {
  display: flex;
  justify-content: flex-end;
  gap: 1rem;
  margin-top: 2.5rem;
}

.cancelButton {
  padding: 0.875rem 1.5rem;
  background: rgba(255, 255, 255, 0.05);
  color: #ffffff;
  border: none;
  border-radius: 12px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-weight: 500;
}

.createButton {
  padding: 0.875rem 1.5rem;
  background: #FF416C;
  color: #ffffff;
  border: none;
  border-radius: 12px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-weight: 500;
}

.cancelButton:hover {
  background: rgba(255, 255, 255, 0.1);
}

.createButton:hover {
  background: #FF4B2B;
  transform: translateY(-1px);
}

// frontend/src/components/Chat/CreateConversationModal.jsx

import React, { useState, useEffect, useContext } from 'react';
import { motion } from 'framer-motion';
import styles from './CreateConversationModal.module.css';
import axios from '../../utils/api';
import { AuthContext } from '../../contexts/AuthContext';

function CreateConversationModal({ onClose, onCreate }) {
  const { user } = useContext(AuthContext);
  const [name, setName] = useState('');
  const [participants, setParticipants] = useState([]);
  const [allUsers, setAllUsers] = useState([]);
  const [searchUser, setSearchUser] = useState('');
  const [error, setError] = useState('');

  useEffect(() => {
    fetchAllUsers();
  }, []);

  const fetchAllUsers = async () => {
    try {
      const response = await axios.get('/users');
      // Exclude current user from participants
      const otherUsers = response.data.filter(u => u.name !== user.name);
      setAllUsers(otherUsers);
    } catch (error) {
      console.error('Error fetching users:', error);
      setError('Error loading users.');
    }
  };

  const handleToggleParticipant = (userName) => {
    if (participants.includes(userName)) {
      setParticipants(participants.filter(p => p !== userName));
    } else {
      setParticipants([...participants, userName]);
    }
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (participants.length === 0) {
      setError('Please add at least one participant.');
      return;
    }
    try {
      const conversationData = {
        name: name.trim() || null,
        participants
      };
      await axios.post('/conversations', conversationData);
      onCreate();
      onClose();
    } catch (error) {
      console.error('Error creating conversation:', error);
      setError('Failed to create conversation.');
    }
  };

  const filteredUsers = allUsers.filter(u =>
    u.name.toLowerCase().includes(searchUser.toLowerCase())
  );

  return (
    <div className={styles.overlay}>
      <motion.div
        className={styles.modal}
        initial={{ opacity: 0, scale: 0.9 }}
        animate={{ opacity: 1, scale: 1 }}
        exit={{ opacity: 0, scale: 0.9 }}
        transition={{ duration: 0.3 }}
      >
        <h2>Create a New Conversation</h2>
        <form onSubmit={handleSubmit}>
          <div className={styles.inputGroup}>
            <label>Conversation Name (Optional)</label>
            <input
              type="text"
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="Enter conversation name"
            />
          </div>

          <div className={styles.inputGroup}>
            <label>Add Participants</label>
            <input
              type="text"
              placeholder="Search users..."
              value={searchUser}
              onChange={(e) => setSearchUser(e.target.value)}
            />
            <div className={styles.usersList}>
              {filteredUsers.map(user => (
                <div key={user.id} className={styles.userItem}>
                  <label>
                    <input
                      type="checkbox"
                      checked={participants.includes(user.name)}
                      onChange={() => handleToggleParticipant(user.name)}
                    />
                    {user.name}
                  </label>
                </div>
              ))}
            </div>
          </div>

          <div className={styles.participants}>
            <h3>Selected Participants:</h3>
            {participants.map(name => (
              <div key={name} className={styles.participantItem}>
                <span>{name}</span>
                <button type="button" onClick={() => handleToggleParticipant(name)}>
                  Remove
                </button>
              </div>
            ))}
          </div>

          {error && <div className={styles.error}>{error}</div>}

          <div className={styles.buttonGroup}>
            <button type="button" onClick={onClose} className={styles.cancelButton}>
              Cancel
            </button>
            <button type="submit" className={styles.createButton}>
              Create
            </button>
          </div>
        </form>
      </motion.div>
    </div>
  );
}

export default CreateConversationModal;

/* Chat.module.css */

.container {
  min-height: 100vh;
  width: 100%;
  background: #1e1e1e; /* Darker background for a sleek look */
  display: flex;
  position: relative;
  overflow: hidden;
  font-family: 'Inter', sans-serif; /* Modern sans-serif font */
}

/* Animated Background with Smooth Gradients */
.background {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  overflow: hidden;
}

.gradient1, .gradient2, .gradient3 {
  position: absolute;
  border-radius: 50%;
  filter: blur(100px);
  opacity: 0.6; /* Reduced opacity for subtlety */
}

.gradient1 {
  width: 60%;
  height: 60%;
  background: linear-gradient(45deg, #4facfe, #00f2fe);
  top: -20%;
  left: -20%;
  animation: moveGradient1 25s infinite alternate;
}

.gradient2 {
  width: 70%;
  height: 70%;
  background: linear-gradient(45deg, #bc4e9c, #f80759);
  top: 50%;
  right: -30%;
  animation: moveGradient2 30s infinite alternate;
}

.gradient3 {
  width: 50%;
  height: 50%;
  background: linear-gradient(45deg, #f093fb, #f5576c);
  bottom: -20%;
  left: 30%;
  animation: moveGradient3 28s infinite alternate;
}

/* Sidebar with Enhanced Glassmorphism */
.sidebar {
  width: 300px;
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(15px);
  border-right: 1px solid rgba(255, 255, 255, 0.2);
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  transition: all 0.3s ease;
}

/* Active Sidebar (for responsive design if needed) */
.sidebarOpen {
  transform: translateX(0);
}

.sidebarHeader {
  padding: 2rem;
  text-align: center;
  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}

.userProfile {
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform 0.3s ease;
}

.userProfile:hover {
  transform: scale(1.05);
}

.userAvatar {
  width: 60px;
  height: 60px;
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  color: white;
  border-radius: 50%;
  font-size: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 1rem;
  transition: box-shadow 0.3s ease;
}

.userAvatar:hover {
  box-shadow: 0 0 15px rgba(255, 65, 108, 0.6);
}

.userProfile h3 {
  color: white;
  font-size: 1.5rem;
  font-weight: 600;
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.searchContainer {
  padding: 1rem 2rem;
  display: flex;
  align-items: center;
  position: relative;
}

.searchIcon {
  position: absolute;
  left: 2.5rem;
  font-size: 1.2rem;
  color: rgba(255, 255, 255, 0.6);
}

.searchInput {
  width: 100%;
  padding: 0.75rem 1rem 0.75rem 3rem; /* Increased left padding for icon */
  background: rgba(255, 255, 255, 0.05);
  border: none;
  border-radius: 25px;
  color: white;
  font-size: 1rem;
  transition: all 0.3s ease;
}

.searchInput::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.searchInput:focus {
  outline: none;
  border: 1px solid #FF416C;
  box-shadow: 0 0 10px rgba(255, 65, 108, 0.3);
}

.conversationsList {
  flex-grow: 1;
  overflow-y: auto;
  padding: 1rem;
}

.conversationItem {
  display: flex;
  align-items: center;
  padding: 1rem;
  border-radius: 12px;
  margin-bottom: 0.75rem;
  cursor: pointer;
  transition: background 0.3s ease, transform 0.3s ease;
}

.conversationItem:hover {
  background: rgba(255, 255, 255, 0.1);
  transform: translateY(-2px);
}

.active {
  background: rgba(255, 255, 255, 0.15);
}

.conversationAvatar {
  width: 50px;
  height: 50px;
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  color: white;
  border-radius: 50%;
  font-size: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 1rem;
  transition: box-shadow 0.3s ease;
}

.conversationAvatar:hover {
  box-shadow: 0 0 10px rgba(255, 65, 108, 0.6);
}

.conversationInfo h4 {
  color: white;
  font-size: 1rem;
  margin-bottom: 0.3rem;
  font-weight: 600;
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.conversationInfo p {
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.9rem;
}

.unreadBadge {
  background: #FF416C;
  color: white;
  border-radius: 12px;
  padding: 0.3rem 0.6rem;
  font-size: 0.75rem;
  margin-left: auto;
  transition: background 0.3s ease;
}

.unreadBadge:hover {
  background: #e63946;
}

/* Main Chat Area */
.chatArea {
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  background: #121212;
  position: relative;
}

/* Chat Header */
.chatHeader {
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(15px);
  padding: 1.5rem 2rem;
  display: flex;
  align-items: center;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  position: relative;
}

.menuButton, .optionsButton {
  background: none;
  border: none;
  color: white;
  font-size: 1.5rem;
  cursor: pointer;
  transition: transform 0.3s ease;
}

.menuButton:hover, .optionsButton:hover {
  transform: scale(1.1);
}

.chatInfo {
  flex-grow: 1;
  text-align: center;
}

.chatInfo h2 {
  color: white;
  font-size: 1.5rem;
  margin: 0;
  font-weight: 600;
}

.chatInfo span {
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.9rem;
}

/* Messages Container */
.messagesContainer {
  flex-grow: 1;
  overflow-y: auto;
  padding: 2rem;
  background: #0a0a0a;
  position: relative;
  animation: fadeIn 1s ease-out;
}

.message {
  max-width: 70%;
  margin-bottom: 1.5rem;
  padding: 0.75rem 1.5rem;
  border-radius: 20px;
  position: relative;
  animation: slideIn 0.5s ease-out;
  color: white;
}

.sent {
  margin-left: auto;
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
}

.received {
  margin-right: auto;
  background: rgba(255, 255, 255, 0.1);
}

.message p {
  margin: 0;
  font-size: 1rem;
  line-height: 1.4;
}

.timestamp {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.7);
  text-align: right;
}

/* Message Form */
.messageForm {
  display: flex;
  align-items: center;
  padding: 1.5rem 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(15px);
}

.messageForm input[type="text"] {
  flex-grow: 1;
  padding: 0.75rem 1.5rem;
  border: none;
  border-radius: 25px;
  background: rgba(255, 255, 255, 0.1);
  color: white;
  font-size: 1rem;
  transition: all 0.3s ease;
}

.messageForm input[type="text"]::placeholder {
  color: rgba(255, 255, 255, 0.7);
}

.messageForm input[type="text"]:focus {
  outline: none;
  border: 1px solid #FF416C;
  box-shadow: 0 0 10px rgba(255, 65, 108, 0.3);
}

.messageForm button {
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  border: none;
  border-radius: 50%;
  color: white;
  width: 50px;
  height: 50px;
  margin-left: 1rem;
  cursor: pointer;
  font-size: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.messageForm button:hover {
  box-shadow: 0 5px 15px rgba(255, 65, 108, 0.4);
}

.messageForm button:active {
  transform: scale(0.95);
}

.messageForm button:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(255, 65, 108, 0.3);
}

/* Welcome Screen */
.welcomeScreen {
  flex-grow: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  text-align: center;
  animation: fadeIn 1s ease-out;
}

.welcomeContent h2 {
  font-size: 2rem;
  color: white;
  margin-bottom: 1rem;
}

.welcomeContent p {
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.7);
}

/* Mobile Overlay */
.overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  z-index: 2;
}

/* Keyframes Animations */
@keyframes moveGradient1 {
  0% { transform: translate(0, 0); }
  100% { transform: translate(100px, 50px); }
}

@keyframes moveGradient2 {
  0% { transform: translate(0, 0); }
  100% { transform: translate(-100px, -50px); }
}

@keyframes moveGradient3 {
  0% { transform: translate(0, 0); }
  100% { transform: translate(50px, -100px); }
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slideIn {
  from { opacity: 0; transform: translateX(50px); }
  to { opacity: 1; transform: translateX(0); }
}

/* Custom Scrollbar */
::-webkit-scrollbar {
  width: 8px;
}

::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 4px;
}

::-webkit-scrollbar-thumb {
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(135deg, #FF4B2B, #FF416C);
}

/* Text Selection */
::selection {
  background: rgba(255, 65, 108, 0.3);
  color: white;
}

/* Global Transitions */
* {
  transition: all 0.3s ease;
}

/* Responsive Design */
@media (max-width: 768px) {
  .sidebar {
    position: fixed;
    left: -300px;
    top: 0;
    height: 100%;
    z-index: 3;
    transition: transform 0.3s ease;
  }

  .sidebarOpen {
    transform: translateX(300px);
  }

  .chatHeader {
    padding: 1rem 1.5rem;
  }

  .chatInfo h2 {
    font-size: 1.2rem;
  }

  .chatInfo span {
    font-size: 0.8rem;
  }

  .messagesContainer {
    padding: 1rem;
  }

  .messageForm {
    padding: 1rem;
  }

  .messageForm input[type="text"] {
    font-size: 0.9rem;
  }

  .messageForm button {
    width: 40px;
    height: 40px;
    font-size: 1rem;
  }
}

@media (max-width: 480px) {
  .userAvatar {
    width: 50px;
    height: 50px;
    font-size: 1rem;
  }

  .userProfile h3 {
    font-size: 1rem;
  }

  .searchInput {
    font-size: 0.9rem;
  }

  .conversationInfo h4 {
    font-size: 0.9rem;
  }

  .conversationInfo p {
    font-size: 0.8rem;
  }

  .chatHeader {
    padding: 0.5rem 1rem;
  }

  .chatInfo h2 {
    font-size: 1.2rem;
  }

  .messagesContainer {
    padding: 0.5rem 1rem;
  }

  .messageForm {
    padding: 0.5rem 1rem;
  }

  .messageForm input[type="text"] {
    font-size: 0.9rem;
  }

  .messageForm button {
    width: 40px;
    height: 40px;
    font-size: 1rem;
  }
}
/* frontend/src/components/Chat/Chat.module.css */

/* Existing styles... */

.searchResults {
  position: absolute;
  top: 60px;
  left: 320px; /* Adjust based on sidebar width */
  width: 300px;
  max-height: 400px;
  overflow-y: auto;
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  border-radius: 12px;
  padding: 1rem;
  z-index: 10;
}

.searchResultItem {
  display: flex;
  align-items: center;
  padding: 0.75rem;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.3s ease;
}

.searchResultItem:hover {
  background: rgba(255, 255, 255, 0.2);
}

.conversationAvatar {
  width: 40px;
  height: 40px;
  background: linear-gradient(135deg, #FF416C, #FF4B2B);
  color: white;
  border-radius: 50%;
  font-size: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 1rem;
}
/* Accessibility: Reduced Motion */
@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

// frontend/src/components/Chat/Chat.jsx

import React, { useEffect, useState, useContext, useRef } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { motion, AnimatePresence } from 'framer-motion';
import axios from '../../utils/api';
import { AuthContext } from '../../contexts/AuthContext';
import {
  IoSend,
  IoMenu,
  IoSearch,
  IoEllipsisVertical,
  IoAdd,
  IoImage,
  IoDocument
} from 'react-icons/io5';
import styles from './Chat.module.css';

// Import Modal and other components
import CreateConversationModal from './CreateConversationModal';
import MessageReactions from './MessageReactions';

function Chat() {
  const { conversationId } = useParams();
  const { user } = useContext(AuthContext);
  const navigate = useNavigate();

  const [conversations, setConversations] = useState([]);
  const [currentConversation, setCurrentConversation] = useState(null);
  const [message, setMessage] = useState('');
  const [searchQuery, setSearchQuery] = useState('');
  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
  const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
  const messagesEndRef = useRef(null);
  const [selectedFile, setSelectedFile] = useState(null);
  const [usersMap, setUsersMap] = useState({});
  const [loadingConversations, setLoadingConversations] = useState(true);
  const [loadingMessages, setLoadingMessages] = useState(true);
  const [fetchInterval, setFetchInterval] = useState(null);
  const [lastMessageId, setLastMessageId] = useState(null);
  const [typingStatus, setTypingStatus] = useState('');

  // Animation variants
  const sidebarVariants = {
    hidden: { x: -300, opacity: 0 },
    visible: { x: 0, opacity: 1, transition: { type: 'spring', damping: 25 } }
  };

  const messageVariants = {
    hidden: { opacity: 0, y: 20 },
    visible: { opacity: 1, y: 0 },
    exit: { opacity: 0, x: -100 }
  };

  // Fetch all users to map usernames to their avatars
  useEffect(() => {
    const fetchUsers = async () => {
      try {
        const response = await axios.get('/users');
        const map = {};
        response.data.forEach(user => {
          map[user.name] = user.avatar_url;
        });
        setUsersMap(map);
      } catch (error) {
        console.error('Error fetching users:', error);
      }
    };

    fetchUsers();
  }, []);

  useEffect(() => {
    fetchConversations();
    const interval = setInterval(fetchConversations, 5000);
    return () => clearInterval(interval);
  }, []);

  useEffect(() => {
    if (conversationId) {
      fetchCurrentConversation();
      // Set up polling for new messages
      if (fetchInterval) clearInterval(fetchInterval);
      const interval = setInterval(fetchNewMessages, 3000);
      setFetchInterval(interval);
      return () => {
        clearInterval(interval);
        setFetchInterval(null);
      };
    } else {
      setCurrentConversation(null); // Reset if no conversation selected
    }
  }, [conversationId]);

  useEffect(() => {
    scrollToBottom();
  }, [currentConversation?.messages]);

  const fetchConversations = async () => {
    setLoadingConversations(true);
    try {
      const response = await axios.get('/conversations');
      setConversations(response.data);
    } catch (error) {
      console.error('Error fetching conversations:', error);
    } finally {
      setLoadingConversations(false);
    }
  };

  const fetchCurrentConversation = async () => {
    setLoadingMessages(true);
    try {
      const response = await axios.get(`/conversations/${conversationId}`);
      setCurrentConversation(response.data);
      const messages = response.data.messages;
      if (messages && messages.length > 0) {
        setLastMessageId(messages[messages.length - 1].id);
      }
    } catch (error) {
      console.error('Error fetching conversation:', error);
    } finally {
      setLoadingMessages(false);
    }
  };

  const fetchNewMessages = async () => {
    try {
      const response = await axios.get(`/conversations/${conversationId}/messages`);
      const messages = response.data;
      if (messages && messages.length > 0) {
        // If lastMessageId is set, get new messages
        if (lastMessageId) {
          const lastMessageIndex = messages.findIndex(msg => msg.id === lastMessageId);
          if (lastMessageIndex !== -1 && lastMessageIndex < messages.length - 1) {
            const newMessages = messages.slice(lastMessageIndex + 1);
            setCurrentConversation(prev => ({
              ...prev,
              messages: [...prev.messages, ...newMessages]
            }));
            setLastMessageId(messages[messages.length - 1].id);
          }
        } else {
          // If no lastMessageId, set it
          setCurrentConversation(prev => ({
            ...prev,
            messages
          }));
          setLastMessageId(messages[messages.length - 1].id);
        }
      }
    } catch (error) {
      console.error('Error fetching new messages:', error);
    }
  };

  const handleSendMessage = async (e) => {
    e.preventDefault();
    if (!message.trim() && !selectedFile) return;

    let mediaUrl = null;
    if (selectedFile) {
      try {
        const formData = new FormData();
        formData.append('file', selectedFile);

        const uploadResponse = await axios.post('/upload/avatar/', formData, {
          headers: { 'Content-Type': 'multipart/form-data' }
        });

        mediaUrl = uploadResponse.data.avatar_url;
        setSelectedFile(null);
      } catch (error) {
        console.error('Error uploading media:', error);
        alert('Failed to upload media.');
        return;
      }
    }

    const payload = {
      content: message.trim(),
      media: mediaUrl
    };

    try {
      // Send message via POST request
      const response = await axios.post(`/conversations/${conversationId}/messages`, payload);
      const newMessage = response.data;

      // Update the conversation locally
      setCurrentConversation(prev => ({
        ...prev,
        messages: [...prev.messages, newMessage]
      }));
      setLastMessageId(newMessage.id);
      setMessage('');
    } catch (error) {
      console.error('Error sending message:', error);
    }
  };

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  };

  const filteredConversations = conversations.filter(conv => {
    const conversationName = conv.name || conv.participants.join(', ');
    return conversationName.toLowerCase().includes(searchQuery.toLowerCase());
  });

  const formatTime = (timestamp) => {
    const date = new Date(timestamp);
    return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
  };

  // Typing Indicators (Optional)
  const handleTyping = () => {
    // Implement typing indicators if desired
  };

  // Handle File Selection
  const handleFileChange = (e) => {
    const file = e.target.files[0];
    setSelectedFile(file);
  };

  // Modal handlers
  const openCreateModal = () => {
    setIsCreateModalOpen(true);
  };

  const closeCreateModal = () => {
    setIsCreateModalOpen(false);
  };

  return (
    <motion.div
      className={styles.container}
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      transition={{ duration: 0.5 }}
    >
      {/* Sidebar */}
      <motion.aside
        className={`${styles.sidebar} ${isMobileMenuOpen ? styles.sidebarOpen : ''}`}
        variants={sidebarVariants}
        initial="hidden"
        animate="visible"
      >
        <div className={styles.sidebarHeader}>
          <motion.div
            className={styles.userProfile}
            whileHover={{ scale: 1.05 }}
            whileTap={{ scale: 0.95 }}
            onClick={() => navigate('/profile')}
          >
            <div className={styles.userAvatar}>
              {user.avatar_url ? (
                <img src={user.avatar_url} alt="Avatar" className={styles.avatarImage} />
              ) : (
                user.name.charAt(0).toUpperCase()
              )}
            </div>
            <h3>{user.name}</h3>
          </motion.div>
        </div>

        <div className={styles.searchContainer}>
          <IoSearch className={styles.searchIcon} />
          <input
            type="text"
            placeholder="Search conversations..."
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            className={styles.searchInput}
          />
        </div>

        <div className={styles.newConversationButton}>
          <button onClick={openCreateModal}>
            <IoAdd /> New Conversation
          </button>
        </div>

        {loadingConversations ? (
          <div className={styles.loader}>Loading conversations...</div>
        ) : (
          <div className={styles.conversationsList}>
            <AnimatePresence>
              {filteredConversations.map((conv) => (
                <motion.div
                  key={conv.id}
                  className={`${styles.conversationItem} ${conv.id === conversationId ? styles.active : ''}`}
                  variants={messageVariants}
                  initial="hidden"
                  animate="visible"
                  exit="exit"
                  whileHover={{ x: 5 }}
                  onClick={() => {
                    navigate(`/chat/${conv.id}`);
                    setIsMobileMenuOpen(false);
                  }}
                >
                  <div className={styles.conversationAvatar}>
                    {conv.name
                      ? conv.name.charAt(0).toUpperCase()
                      : conv.participants[0].charAt(0).toUpperCase()}
                  </div>
                  <div className={styles.conversationInfo}>
                    <h4>{conv.name || conv.participants.join(', ')}</h4>
                    <p>
                      {conv.messages && conv.messages.length > 0
                        ? `${conv.messages[conv.messages.length - 1].content.substring(0, 20)}...`
                        : 'No messages yet'}
                    </p>
                  </div>
                </motion.div>
              ))}
            </AnimatePresence>
          </div>
        )}
      </motion.aside>

      {/* Main Chat Area */}
      <main className={styles.chatArea}>
        {currentConversation ? (
          <>
            <header className={styles.chatHeader}>
              <button
                className={styles.menuButton}
                onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
              >
                <IoMenu />
              </button>
              <div className={styles.chatInfo}>
                <h2>{currentConversation.name || currentConversation.participants.join(', ')}</h2>
                <span>{currentConversation.participants.length} participants</span>
              </div>
              <button className={styles.optionsButton}>
                <IoEllipsisVertical />
              </button>
            </header>

            <div className={styles.messagesContainer}>
              {loadingMessages ? (
                <div className={styles.loader}>Loading messages...</div>
              ) : (
                <>
                  <AnimatePresence>
                    {currentConversation.messages.map((msg) => (
                      <motion.div
                        key={msg.id}
                        className={`${styles.message} ${msg.sender === user.name ? styles.sent : styles.received}`}
                        variants={messageVariants}
                        initial="hidden"
                        animate="visible"
                        exit="exit"
                      >
                        <div className={styles.userAvatar}>
                          {msg.sender === user.name ? (
                            user.avatar_url ? (
                              <img src={user.avatar_url} alt="Your Avatar" className={styles.avatarImage} />
                            ) : (
                              user.name.charAt(0).toUpperCase()
                            )
                          ) : (
                            usersMap[msg.sender] ? (
                              <img src={usersMap[msg.sender]} alt={`${msg.sender} Avatar`} className={styles.avatarImage} />
                            ) : (
                              msg.sender.charAt(0).toUpperCase()
                            )
                          )}
                        </div>
                        <div className={styles.messageContent}>
                          {msg.media && (
                            <div className={styles.mediaContent}>
                              {/\.(jpeg|jpg|gif|png)$/.test(msg.media) ? (
                                <img src={msg.media} alt="Media" className={styles.mediaImage} />
                              ) : (
                                <a href={msg.media} target="_blank" rel="noopener noreferrer" className={styles.mediaLink}>
                                  View Document <IoDocument />
                                </a>
                              )}
                            </div>
                          )}
                          <p>{msg.content}</p>
                          {msg.reactions && Object.keys(msg.reactions).length > 0 && (
                            <div className={styles.reactions}>
                              {Object.entries(msg.reactions).map(([emoji, count]) => (
                                <span key={emoji}>{emoji} {count}</span>
                              ))}
                            </div>
                          )}
                          <span className={styles.timestamp}>
                            {formatTime(msg.timestamp)}
                          </span>
                          {/* Implement reactions if desired */}
                          {/* <MessageReactions onAddReaction={(emoji) => handleAddReaction(msg.id, emoji)} /> */}
                        </div>
                      </motion.div>
                    ))}
                  </AnimatePresence>
                  <div ref={messagesEndRef} />
                </>
              )}
            </div>

            {/* Typing Status (Optional) */}
            {typingStatus && <div className={styles.typingStatus}>{typingStatus}</div>}

            <form onSubmit={handleSendMessage} className={styles.messageForm}>
              <input
                type="text"
                value={message}
                onChange={(e) => {
                  setMessage(e.target.value);
                  handleTyping();
                }}
                placeholder="Write your message..."
                className={styles.messageInput}
              />
              <input
                type="file"
                accept="image/*,video/*,application/pdf"
                onChange={handleFileChange}
                className={styles.fileInput}
                id="file-upload"
                style={{ display: 'none' }}
              />
              <label htmlFor="file-upload" className={styles.uploadButton}>
                <IoImage />
              </label>
              <button type="submit" disabled={!message.trim() && !selectedFile} className={styles.sendButton}>
                <IoSend />
              </button>
            </form>
          </>
        ) : (
          <motion.div
            className={styles.welcomeScreen}
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ duration: 0.5 }}
          >
            <div className={styles.welcomeContent}>
              <h2>Welcome to your Messenger</h2>
              <p>Select a conversation to start chatting</p>
            </div>
          </motion.div>
        )}
      </main>

      {/* Mobile Overlay */}
      {isMobileMenuOpen && (
        <motion.div
          className={styles.overlay}
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          onClick={() => setIsMobileMenuOpen(false)}
        />
      )}

      {/* Modal for Creating Conversation */}
      {isCreateModalOpen && (
        <CreateConversationModal
          onClose={closeCreateModal}
          onCreate={() => {
            fetchConversations();
            setIsCreateModalOpen(false);
          }}
        />
      )}
    </motion.div>
  );
}

export default Chat;



voici le backend :
# api/models.py

from pydantic import BaseModel, Field
from typing import List, Optional, Dict
from datetime import datetime
from bson import ObjectId

# Existing models...

# Add MessageCreate model
class MessageCreate(BaseModel):
    content: Optional[str] = None
    media: Optional[str] = None
# User Models
class UserBase(BaseModel):
    name: str
    bio: Optional[str] = None  # Bio field

class UserCreate(UserBase):
    password: str

class UserInDB(UserBase):
    hashed_password: str
    avatar_url: Optional[str] = None  # Avatar URL

class User(UserBase):
    id: str
    avatar_url: Optional[str] = None

# Message Models
class Message(BaseModel):
    sender: str
    content: str
    timestamp: datetime = Field(default_factory=datetime.utcnow)
    media: Optional[str] = None  # URL to the media file
    reactions: Dict[str, int] = {}  # Emoji reactions

# Conversation Models
class ConversationCreate(BaseModel):
    participants: List[str]
    name: Optional[str] = None

class Conversation(BaseModel):
    id: str
    name: Optional[str] = None  # Optional group name
    participants: List[str]
    messages: List[Message] = []

# api/database.py
from pymongo import MongoClient, ASCENDING, TEXT
from config import MONGODB_URI

client = MongoClient(MONGODB_URI)
db = client["FIRSTSERv"]
users_collection = db["users"]
conversations_collection = db["conversations"]

# Créer des index si ils n'existent pas
users_collection.create_index([("name", ASCENDING)], unique=True)
conversations_collection.create_index([("participants", ASCENDING)])
conversations_collection.create_index([("messages.content", TEXT)])

# api/config.py
import os
from dotenv import load_dotenv

load_dotenv()

MONGODB_URI = os.environ.get("MONGODB_URI")
SECRET_KEY = os.environ.get("SECRET_KEY")
ALGORITHM = os.environ.get("ALGORITHM", "HS256")
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES", 30))

# api/authentication.py
from datetime import datetime, timedelta
from typing import Optional
import jwt
from jwt.exceptions import PyJWTError as JWTError
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from database import users_collection
from models import UserInDB
from config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
import bcrypt

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")

def verify_password(plain_password, hashed_password):
    return bcrypt.checkpw(plain_password.encode('utf-8'), hashed_password.encode('utf-8'))

def get_user(db, username: str):
    user = db.find_one({"name": username})
    if user:
        return UserInDB(name=user["name"], hashed_password=user["password"], avatar_url=user.get("avatar_url"))
    return None

def authenticate_user(db, username: str, password: str):
    user = get_user(db, username)
    if not user:
        return False
    if not verify_password(password, user.hashed_password):
        return False
    return user

def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    expire = datetime.utcnow() + (expires_delta if expires_delta else timedelta(minutes=15))
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Unable to validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        user = get_user(users_collection, username)
        if user is None:
            raise credentials_exception
        return user
    except JWTError:
        raise credentials_exception

# api/app.py
import os
import json
from datetime import datetime, timedelta
from typing import Dict, Set, List, Optional

from fastapi import FastAPI, Depends, HTTPException, status, WebSocket, WebSocketDisconnect, UploadFile, File
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel, Field
from pymongo import MongoClient, ASCENDING, TEXT
from bson.objectid import ObjectId
import bcrypt
import jwt
from jwt.exceptions import PyJWTError as JWTError

from models import *
from authentication import get_current_user, authenticate_user, create_access_token, get_user
from config import MONGODB_URI, SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES

# Initialization of FastAPI app
app = FastAPI()

# CORS Configuration
origins = [
    "http://localhost:3000",  # Frontend development
    "https://your-frontend-domain.com",  # Replace with your frontend domain in production
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # List of allowed origins
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Directory for uploaded files
UPLOAD_DIRECTORY = "uploads"

if not os.path.exists(UPLOAD_DIRECTORY):
    os.makedirs(UPLOAD_DIRECTORY)

app.mount("/uploads", StaticFiles(directory=UPLOAD_DIRECTORY), name="uploads")

# MongoDB Database connection
client = MongoClient(MONGODB_URI)
db = client["FIRSTSERv"]
users_collection = db["users"]
conversations_collection = db["conversations"]

# Create indexes if necessary
users_collection.create_index([("name", ASCENDING)], unique=True)
conversations_collection.create_index([("participants", ASCENDING)])
conversations_collection.create_index([("messages.content", TEXT)])

# Dictionary to store WebSocket connections per conversation
connections: Dict[str, Set[WebSocket]] = {}

# Model for updating bio
class BioUpdate(BaseModel):
    bio: str

# Signup endpoint
@app.post("/signup", response_model=User)
def signup(user: UserCreate):
    # Check if the user already exists
    if users_collection.find_one({"name": user.name}):
        raise HTTPException(status_code=400, detail="A user with that name already exists.")

    # Hash the password
    hashed_password = bcrypt.hashpw(user.password.encode('utf-8'), bcrypt.gensalt())

    # Create the user
    user_doc = {
        "name": user.name,
        "password": hashed_password.decode('utf-8'),
        "bio": user.bio or "",  # Initialize bio
        "avatar_url": None
    }
    result = users_collection.insert_one(user_doc)
    return User(
        id=str(result.inserted_id),
        name=user.name,
        bio=user.bio or "",
        avatar_url=None
    )

# Login endpoint
@app.post("/login")
def login(form_data: UserCreate):
    user = authenticate_user(users_collection, form_data.name, form_data.password)
    if not user:
        raise HTTPException(status_code=400, detail="Incorrect username or password")

    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.name}, expires_delta=access_token_expires
    )
    return {
        "access_token": access_token,
        "token_type": "bearer"
    }

# Endpoint to get current user's profile
@app.get("/users/me", response_model=User)
def read_current_user(current_user: UserInDB = Depends(get_current_user)):
    user = users_collection.find_one({"name": current_user.name})
    return User(
        id=str(user["_id"]),
        name=user["name"],
        bio=user.get("bio", ""),
        avatar_url=user.get("avatar_url")
    )

# Endpoint to update current user's bio
@app.put("/users/me/bio", response_model=UserBase)
def update_bio(bio_update: BioUpdate, current_user: UserInDB = Depends(get_current_user)):
    users_collection.update_one(
        {"name": current_user.name},
        {"$set": {"bio": bio_update.bio}}
    )
    updated_user = users_collection.find_one({"name": current_user.name})
    return UserBase(
        name=updated_user["name"],
        bio=updated_user.get("bio", "")
    )

# Endpoint to get a user's profile by username
@app.get("/users/{username}", response_model=UserBase)
def get_user_profile(username: str, current_user: UserInDB = Depends(get_current_user)):
    user = users_collection.find_one({"name": username})
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return UserBase(
        name=user["name"],
        bio=user.get("bio", "")
    )

# Endpoint to get all users
@app.get("/users", response_model=List[UserBase])
def get_all_users(current_user: UserInDB = Depends(get_current_user)):
    users = users_collection.find({})
    return [UserBase(name=user["name"], bio=user.get("bio", ""), avatar_url=user.get("avatar_url")) for user in users]

# Endpoint to create a conversation
@app.post("/conversations", response_model=Conversation)
def create_conversation(convo: ConversationCreate, current_user: UserInDB = Depends(get_current_user)):
    participants = convo.participants
    if current_user.name not in participants:
        participants.append(current_user.name)

    # Verify that users exist
    for name in participants:
        if not users_collection.find_one({"name": name}):
            raise HTTPException(status_code=404, detail=f"User {name} not found")

    # If it's a one-on-one conversation without a name, check if it exists
    if len(participants) == 2 and not convo.name:
        existing_convo = conversations_collection.find_one({
            "participants": {"$all": participants},
            "name": {"$exists": False}
        })
        if existing_convo:
            raise HTTPException(status_code=400, detail="Conversation already exists")

    # Create the conversation
    conversation_doc = {
        "participants": participants,
        "messages": [],
    }
    if convo.name:
        conversation_doc["name"] = convo.name

    result = conversations_collection.insert_one(conversation_doc)
    return Conversation(
        id=str(result.inserted_id),
        name=convo.name,
        participants=participants
    )

# Endpoint to get conversations for current user
@app.get("/conversations", response_model=List[Conversation])
def get_user_conversations(current_user: UserInDB = Depends(get_current_user)):
    conversations = conversations_collection.find({"participants": current_user.name})
    convo_list = []
    for convo in conversations:
        convo_list.append(Conversation(
            id=str(convo['_id']),
            name=convo.get("name"),
            participants=convo["participants"],
            messages=[]
        ))
    return convo_list

# Endpoint to get a conversation by ID
@app.get("/conversations/{conversation_id}", response_model=Conversation)
def get_conversation(conversation_id: str, current_user: UserInDB = Depends(get_current_user)):
    try:
        conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    except:
        raise HTTPException(status_code=400, detail="Invalid conversation ID")
    if not conversation:
        raise HTTPException(status_code=404, detail="Conversation not found")
    if current_user.name not in conversation["participants"]:
        raise HTTPException(status_code=403, detail="Access denied")
    messages = [Message(**msg) for msg in conversation.get("messages", [])]
    return Conversation(
        id=str(conversation['_id']),
        name=conversation.get("name"),
        participants=conversation["participants"],
        messages=messages
    )

# Endpoint to send a message to a conversation via REST (optional)
@app.post("/conversations/{conversation_id}/messages", response_model=Message)
def send_message(conversation_id: str, message_create: MessageCreate, current_user: UserInDB = Depends(get_current_user)):
    try:
        conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    except Exception:
        raise HTTPException(status_code=400, detail="Invalid conversation ID")
    if not conversation:
        raise HTTPException(status_code=404, detail="Conversation not found")
    if current_user.name not in conversation["participants"]:
        raise HTTPException(status_code=403, detail="Access denied")
    
    # Create the message
    message = Message(
        sender=current_user.name,
        content=message_create.content or "",
        timestamp=datetime.utcnow(),
        media=message_create.media or "",
        reactions={}
    )
    # Save the message to the database
    message_doc = message.dict()
    message_doc["timestamp"] = message.timestamp  # Ensure timestamp is serializable

    conversations_collection.update_one(
        {"_id": ObjectId(conversation_id)},
        {"$push": {"messages": message_doc}}
    )

    return message
# Add the endpoint to get messages
@app.get("/conversations/{conversation_id}/messages", response_model=List[Message])
def get_messages(conversation_id: str, current_user: UserInDB = Depends(get_current_user)):
    try:
        conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    except Exception:
        raise HTTPException(status_code=400, detail="Invalid conversation ID")
    if not conversation:
        raise HTTPException(status_code=404, detail="Conversation not found")
    if current_user.name not in conversation["participants"]:
        raise HTTPException(status_code=403, detail="Access denied")
    messages = [Message(**msg) for msg in conversation.get("messages", [])]
    return messages
# Endpoint to delete a conversation
@app.delete("/conversations/{conversation_id}")
def delete_conversation(conversation_id: str, current_user: UserInDB = Depends(get_current_user)):
    conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    if not conversation:
        raise HTTPException(status_code=404, detail="Conversation not found")
    if current_user.name not in conversation["participants"]:
        raise HTTPException(status_code=403, detail="Access denied")

    conversations_collection.delete_one({"_id": ObjectId(conversation_id)})
    return {"detail": "Conversation deleted"}

# Endpoint to upload an avatar or other media
@app.post("/upload/avatar/", response_model=dict)
async def upload_avatar(file: UploadFile = File(...), current_user: UserInDB = Depends(get_current_user)):
    # Check file type
    if not file.content_type.startswith('image/'):
        raise HTTPException(status_code=400, detail="Only image files are allowed.")

    # Check file size (limited to 5MB)
    contents = await file.read()
    MAX_FILE_SIZE = 5 * 1024 * 1024  # 5 MB
    if len(contents) > MAX_FILE_SIZE:
        raise HTTPException(status_code=400, detail="File size exceeds the limit of 5MB.")
    await file.seek(0)  # Reset file pointer after reading

    # Generate a unique filename
    timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
    filename = f"{current_user.name}_{timestamp}_{file.filename}"
    file_path = os.path.join(UPLOAD_DIRECTORY, filename)

    # Save the file
    with open(file_path, "wb") as buffer:
        buffer.write(await file.read())

    # Generate the file URL
    file_url = f"/uploads/{filename}"

    # Update the user's avatar_url
    users_collection.update_one(
        {"name": current_user.name},
        {"$set": {"avatar_url": file_url}}
    )
    return {"avatar_url": file_url}

# WebSocket endpoint for a conversation
@app.websocket("/ws/chat/{conversation_id}")
async def websocket_endpoint(websocket: WebSocket, conversation_id: str):
    token = websocket.query_params.get("token")
    if not token:
        await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
        return

    # Authenticate the token
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
            return
        user = get_user(users_collection, username)
        if user is None:
            await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
            return
    except JWTError:
        await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
        return

    # Verify that the user is a participant in the conversation
    try:
        conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
    except:
        await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
        return

    if not conversation:
        await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
        return
    if user.name not in conversation["participants"]:
        await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
        return

    await websocket.accept()

    if conversation_id not in connections:
        connections[conversation_id] = set()
    connections[conversation_id].add(websocket)

    try:
        while True:
            data = await websocket.receive_text()
            message_data = json.loads(data)
            event = message_data.get('event')

            if event == 'typing':
                # Broadcast typing event to other clients
                if conversation_id in connections:
                    for connection in connections[conversation_id]:
                        if connection != websocket:
                            await connection.send_json({'event': 'typing', 'data': {'user': user.name}})
            else:
                content = message_data.get("content")
                media = message_data.get("media")

                if not content and not media:
                    continue

                message = Message(
                    sender=user.name,
                    content=content or "",
                    timestamp=datetime.utcnow(),
                    media=media or "",
                    reactions={}
                )

                # Save the message to the database
                message_doc = message.dict()
                message_doc["timestamp"] = message.timestamp

                conversations_collection.update_one(
                    {"_id": ObjectId(conversation_id)},
                    {"$push": {"messages": message_doc}}
                )

                # Send the message to all connected clients
                if conversation_id in connections:
                    for connection in connections[conversation_id]:
                        await connection.send_json(message.dict())

    except WebSocketDisconnect:
        connections[conversation_id].remove(websocket)
        if not connections[conversation_id]:
            del connections[conversation_id]
    except Exception as e:
        print(f"WebSocket error: {e}")
        connections[conversation_id].remove(websocket)
        if not connections[conversation_id]:
            del connections[conversation_id]

# Include other necessary files (authentication.py, config.py, database.py, models.py) as before