0% found this document useful (0 votes)
2 views33 pages

temp backup code

The document contains a React application for a chat platform, featuring components for user authentication (Login, Register), profile management, and chat functionalities. It utilizes React Router for navigation and Axios for API requests, managing user sessions with local storage. The application includes a sidebar for navigation and allows users to send messages and manage contacts.

Uploaded by

lavyapunjabi2005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views33 pages

temp backup code

The document contains a React application for a chat platform, featuring components for user authentication (Login, Register), profile management, and chat functionalities. It utilizes React Router for navigation and Axios for API requests, managing user sessions with local storage. The application includes a sidebar for navigation and allows users to send messages and manage contacts.

Uploaded by

lavyapunjabi2005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 33

App.

js

import React, { useState, useEffect } from 'react';

import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';

import styled from 'styled-components';

import Sidebar from './components/Sidebar';

import Chat from './components/Chat';

import Login from './components/Login';

import Register from './components/Register';

import Profile from './components/Profile';

import Contacts from './components/Contacts'; // Import Contacts component

const AppContainer = styled.div`

display: flex;

height: 100vh;

background-color: #f0f2f5;

`;

const MainContent = styled.div`

flex: 1;

display: flex;

`;

function App() {

const [isAuthenticated, setIsAuthenticated] = useState(false);

useEffect(() => {

const token = localStorage.getItem('token');

setIsAuthenticated(!!token);

}, []);

const handleLogout = () => {


localStorage.removeItem('token');

localStorage.removeItem('userId');

localStorage.removeItem('name');

setIsAuthenticated(false);

};

return (

<Router>

<AppContainer>

{isAuthenticated && <Sidebar handleLogout={handleLogout} />}

<MainContent>

<Routes>

<Route path="/login" element={!isAuthenticated ? <Login


setIsAuthenticated={setIsAuthenticated} /> : <Navigate to="/" />} />

<Route path="/register" element={!isAuthenticated ? <Register /> : <Navigate to="/" />} />

<Route path="/chat/:contactId?" element={isAuthenticated ? <Chat /> : <Navigate


to="/login" />} />

<Route path="/profile" element={isAuthenticated ? <Profile handleLogout={handleLogout} /> :


<Navigate to="/login" />} />

<Route path="/contacts" element={isAuthenticated ? <Contacts /> : <Navigate to="/login"


/>} /> {/* Contacts Route */}

<Route path="/" element={isAuthenticated ? <Contacts /> : <Navigate to="/login" />} /> {/*
Default route */}

</Routes>

</MainContent>

</AppContainer>

</Router>

);

export default App;


Chat.js

import React, { useState, useEffect } from 'react';

import styled from 'styled-components';

import { useParams } from 'react-router-dom';

import { FaPaperPlane } from 'react-icons/fa';

import axios from 'axios';

const ChatContainer = styled.div`

flex: 1;

display: flex;

flex-direction: column;

`;

const ChatHeader = styled.div`

padding: 10px 16px;

background-color: #f0f2f5;

border-left: 1px solid #d1d7db;

`;

const ContactName = styled.h2`

font-size: 16px;

font-weight: 500;

color: #111b21;

`;

const MessagesContainer = styled.div`

flex: 1;

overflow-y: auto;

padding: 20px;

background-color: #efeae2;
`;

const Message = styled.div`

max-width: 65%;

padding: 6px 7px 8px 9px;

border-radius: 7.5px;

margin-bottom: 10px;

font-size: 14.2px;

line-height: 19px;

color: #111b21;

${props => props.sent ? `

background-color: #d9fdd3;

align-self: flex-end;

margin-left: auto;

`:`

background-color: #ffffff;

`}

`;

const InputContainer = styled.div`

display: flex;

align-items: center;

padding: 10px;

background-color: #f0f2f5;

`;

const Input = styled.input`

flex: 1;

padding: 9px 12px;

border: none;

border-radius: 8px;
font-size: 15px;

`;

const SendButton = styled.button`

background: none;

border: none;

color: #54656f;

font-size: 20px;

cursor: pointer;

margin-left: 10px;

`;

function Chat() {

const [messages, setMessages] = useState([]);

const [newMessage, setNewMessage] = useState('');

const [contact, setContact] = useState(null);

const { contactId } = useParams();

useEffect(() => {

if (contactId) {

fetchMessages();

fetchContactDetails();

}, [contactId]);

const fetchMessages = async () => {

try {

const response = await axios.get(`http://localhost:3001/messages/${contactId}`, {

headers: { Authorization: localStorage.getItem('token') }

});

setMessages(response.data);
} catch (error) {

console.error('Error fetching messages:', error);

};

const fetchContactDetails = async () => {

try {

const response = await axios.get(`http://localhost:3001/contacts`, {

headers: { Authorization: localStorage.getItem('token') }

});

const contactDetails = response.data.find(c => c.contact_id === parseInt(contactId));

setContact(contactDetails);

} catch (error) {

console.error('Error fetching contact details:', error);

};

const sendMessage = async () => {

if (!newMessage.trim()) return;

try {

await axios.post('http://localhost:3001/messages',

{ receiverId: contactId, content: newMessage },

{ headers: { Authorization: localStorage.getItem('token') } }

);

setNewMessage('');

fetchMessages(); // Fetch new messages after sending

} catch (error) {

console.error('Error sending message:', error);

};
return (

<ChatContainer>

<ChatHeader>

<ContactName>{contact ? contact.contact_name : 'Select a contact'}</ContactName>

</ChatHeader>

<MessagesContainer>

{messages.length > 0 ? (

messages.map((msg, index) => (

<Message key={index} sent={msg.sender_id === parseInt(localStorage.getItem('userId'))}>

{msg.content}

</Message>

))

):(

<p>No messages yet. Start chatting with {contact?.contact_name}!</p>

)}

</MessagesContainer>

<InputContainer>

<Input

type="text"

value={newMessage}

onChange={(e) => setNewMessage(e.target.value)}

placeholder="Type a message"

/>

<SendButton onClick={sendMessage}>

<FaPaperPlane />

</SendButton>

</InputContainer>

</ChatContainer>

);

}
Contacts.js

import React, { useState, useEffect } from 'react';

import axios from 'axios';

import { Link } from 'react-router-dom';

function Contacts() {

const [contacts, setContacts] = useState([]);

const [newContact, setNewContact] = useState({ mobile: '', name: '' });

const [error, setError] = useState('');

const [success, setSuccess] = useState('');

const [showForm, setShowForm] = useState(false); // To control the visibility of the form

useEffect(() => {

fetchContacts();

}, []);

const fetchContacts = async () => {

try {

const response = await axios.get('http://localhost:3001/contacts', {

headers: { Authorization: localStorage.getItem('token') },

});

setContacts(response.data);

} catch (error) {

console.error('Error fetching contacts:', error);

};

const addContact = async (e) => {


e.preventDefault();

setError(''); // Clear any previous errors

setSuccess(''); // Clear previous success message

try {

// Check if the user exists based on mobile number

const response = await axios.post('http://localhost:3001/contacts',

{ contactMobile: newContact.mobile, contactName: newContact.name },

{ headers: { Authorization: localStorage.getItem('token') } }

);

// If successful, fetch the updated contacts list

setNewContact({ mobile: '', name: '' });

setSuccess('Contact added successfully!');

setShowForm(false); // Hide the form after adding a contact

fetchContacts(); // Refresh contacts after adding

} catch (error) {

if (error.response && error.response.data.error) {

setError(error.response.data.error);

} else {

setError('An unexpected error occurred while adding the contact.');

};

return (

<div className="contacts-container">

<h2>Contacts</h2>

{/* Add Contact Button */}

<button onClick={() => setShowForm(!showForm)}>

{showForm ? "Cancel" : "Add New Contact"}


</button>

{/* Display the form if showForm is true */}

{showForm && (

<form onSubmit={addContact}>

<input

type="text"

placeholder="Contact's mobile number"

value={newContact.mobile}

onChange={(e) => setNewContact({ ...newContact, mobile: e.target.value })}

required

/>

<input

type="text"

placeholder="Contact's name"

value={newContact.name}

onChange={(e) => setNewContact({ ...newContact, name: e.target.value })}

required

/>

<button type="submit">Add Contact</button>

</form>

)}

{error && <p className="error">{error}</p>}

{success && <p className="success">{success}</p>}

{/* Display the contact list */}

<ul className="contact-list">

{contacts.map((contact) => (

<li key={contact.contact_id}>

<Link to={`/chat/${contact.contact_id}`}>{contact.contact_name}</Link>
</li>

))}

</ul>

</div>

);

export default Contacts;

Login.js

import React, { useState } from 'react';

import styled from 'styled-components';

import { useNavigate, Link } from 'react-router-dom';

import axios from 'axios';

const LoginContainer = styled.div`

display: flex;

flex-direction: column;

align-items: center;

justify-content: center;

height: 100%;

width: 100%;

background-color: #f0f2f5;

`;

const LoginForm = styled.form`

background-color: #ffffff;

padding: 20px;

border-radius: 8px;

box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);


width: 100%;

max-width: 350px;

`;

const Input = styled.input`

width: 100%;

padding: 10px;

margin-bottom: 10px;

border: 1px solid #ddd;

border-radius: 4px;

`;

const Button = styled.button`

width: 100%;

padding: 10px;

background-color: #00a884;

color: white;

border: none;

border-radius: 4px;

cursor: pointer;

`;

const ErrorMessage = styled.p`

color: red;

margin-bottom: 10px;

`;

function Login({ setIsAuthenticated }) {

const [mobile, setMobile] = useState('');

const [password, setPassword] = useState('');

const [error, setError] = useState('');


const navigate = useNavigate();

const handleSubmit = async (e) => {

e.preventDefault();

try {

const response = await axios.post('http://localhost:3001/login', { mobile, password });

localStorage.setItem('token', response.data.token);

localStorage.setItem('userId', response.data.userId);

localStorage.setItem('name', response.data.name);

setIsAuthenticated(true);

navigate('/');

} catch (error) {

setError('Invalid credentials');

};

return (

<LoginContainer>

<LoginForm onSubmit={handleSubmit}>

<h2>Login to WhatsApp</h2>

{error && <ErrorMessage>{error}</ErrorMessage>}

<Input

type="text"

placeholder="Mobile number"

value={mobile}

onChange={(e) => setMobile(e.target.value)}

required

/>

<Input

type="password"

placeholder="Password"
value={password}

onChange={(e) => setPassword(e.target.value)}

required

/>

<Button type="submit">Login</Button>

<p>Don't have an account? <Link to="/register">Register</Link></p>

</LoginForm>

</LoginContainer>

);

export default Login;

Profile.js

import React, { useState, useEffect } from 'react';

import styled from 'styled-components';

import axios from 'axios';

const ProfileContainer = styled.div`

flex: 1;

padding: 20px;

background-color: #fff;

`;

const ProfileInfo = styled.div`

margin-bottom: 20px;

`;

const LogoutButton = styled.button`

padding: 10px 20px;


background-color: #00a884;

color: white;

border: none;

border-radius: 4px;

cursor: pointer;

`;

function Profile({ handleLogout }) {

const [profile, setProfile] = useState(null);

useEffect(() => {

fetchProfile();

}, []);

const fetchProfile = async () => {

try {

const response = await axios.get('http://localhost:3001/profile', {

headers: { Authorization: localStorage.getItem('token') }

});

setProfile(response.data);

} catch (error) {

console.error('Error fetching profile:', error);

if (error.response && error.response.status === 401) {

handleLogout();

};

if (!profile) {

return <ProfileContainer>Loading profile...</ProfileContainer>;

}
return (

<ProfileContainer>

<h2>Profile</h2>

<ProfileInfo>

<p><strong>Name:</strong> {profile.name}</p>

<p><strong>Mobile:</strong> {profile.mobile}</p>

</ProfileInfo>

<LogoutButton onClick={handleLogout}>Logout</LogoutButton>

</ProfileContainer>

);

export default Profile;

Register.js

import React, { useState } from 'react';

import styled from 'styled-components';

import { useNavigate, Link } from 'react-router-dom';

import axios from 'axios';

const RegisterContainer = styled.div`

display: flex;

flex-direction: column;

align-items: center;

justify-content: center;

height: 100%;

width: 100%;

background-color: #f0f2f5;

`;
const RegisterForm = styled.form`

background-color: #ffffff;

padding: 20px;

border-radius: 8px;

box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

width: 100%;

max-width: 350px;

`;

const Input = styled.input`

width: 100%;

padding: 10px;

margin-bottom: 10px;

border: 1px solid #ddd;

border-radius: 4px;

`;

const Button = styled.button`

width: 100%;

padding: 10px;

background-color: #00a884;

color: white;

border: none;

border-radius: 4px;

cursor: pointer;

`;

const ErrorMessage = styled.p`

color: red;

margin-bottom: 10px;
`;

function Register() {

const [name, setName] = useState('');

const [mobile, setMobile] = useState('');

const [password, setPassword] = useState('');

const [error, setError] = useState('');

const navigate = useNavigate();

const handleSubmit = async (e) => {

e.preventDefault();

try {

await axios.post('http://localhost:3001/register', { name, mobile, password });

navigate('/login');

} catch (error) {

setError('Error registering user');

};

return (

<RegisterContainer>

<RegisterForm onSubmit={handleSubmit}>

<h2>Register for WhatsApp</h2>

{error && <ErrorMessage>{error}</ErrorMessage>}

<Input

type="text"

placeholder="Name"

value={name}

onChange={(e) => setName(e.target.value)}

required

/>
<Input

type="text"

placeholder="Mobile number"

value={mobile}

onChange={(e) => setMobile(e.target.value)}

required

/>

<Input

type="password"

placeholder="Password"

value={password}

onChange={(e) => setPassword(e.target.value)}

required

/>

<Button type="submit">Register</Button>

<p>Already have an account? <Link to="/login">Login</Link></p>

</RegisterForm>

</RegisterContainer>

);

export default Register;

Sidebar.js

import React, { useState, useEffect } from 'react';

import styled from 'styled-components';

import { Link } from 'react-router-dom';

import { FaUser, FaSearch, FaEllipsisV } from 'react-icons/fa';

import axios from 'axios';


const SidebarContainer = styled.div`

width: 35%;

max-width: 415px;

border-right: 1px solid #d1d7db;

background-color: #ffffff;

display: flex;

flex-direction: column;

`;

const LogoutButton = styled.button`

width: 100%;

padding: 10px 16px;

background-color: #f0f2f5;

color: #54656f;

border: none;

text-align: left;

font-size: 15px;

cursor: pointer;

transition: background-color 0.3s;

&:hover {

background-color: #e9edef;

`;

const Header = styled.div`

display: flex;

justify-content: space-between;

align-items: center;

padding: 10px 16px;

background-color: #f0f2f5;
`;

const ProfileIcon = styled(FaUser)`

font-size: 24px;

color: #54656f;

cursor: pointer;

`;

const MenuIcon = styled(FaEllipsisV)`

font-size: 22px;

color: #54656f;

cursor: pointer;

`;

const SearchContainer = styled.div`

padding: 8px 15px;

background-color: #f0f2f5;

`;

const SearchWrapper = styled.div`

display: flex;

align-items: center;

background-color: #ffffff;

border-radius: 8px;

padding: 0 8px;

`;

const SearchIcon = styled(FaSearch)`

font-size: 14px;

color: #54656f;

margin-right: 20px;
`;

const SearchInput = styled.input`

width: 100%;

padding: 8px 0;

border: none;

outline: none;

font-size: 15px;

&::placeholder {

color: #3b4a54;

`;

const ContactsList = styled.div`

overflow-y: auto;

flex: 1;

`;

const ContactItem = styled(Link)`

display: flex;

align-items: center;

padding: 10px 16px;

border-bottom: 1px solid #f0f2f5;

text-decoration: none;

color: inherit;

&:hover {

background-color: #f5f6f6;

`;
const ContactAvatar = styled.div`

width: 49px;

height: 49px;

border-radius: 50%;

background-color: #dfe5e7;

display: flex;

align-items: center;

justify-content: center;

margin-right: 15px;

`;

const ContactInfo = styled.div`

flex: 1;

`;

const ContactName = styled.div`

font-size: 17px;

color: #111b21;

margin-bottom: 3px;

`;

const LastMessage = styled.div`

font-size: 14px;

color: #667781;

`;

const ProfileLink = styled(Link)`

text-decoration: none;

color: inherit;

`;
function Sidebar({ handleLogout }) {

const [contacts, setContacts] = useState([]);

const [searchTerm, setSearchTerm] = useState('');

useEffect(() => {

fetchContacts();

}, []);

const fetchContacts = async () => {

try {

const response = await axios.get('http://localhost:3001/contacts', {

headers: { Authorization: localStorage.getItem('token') }

});

setContacts(response.data);

} catch (error) {

console.error('Error fetching contacts:', error);

};

const filteredContacts = contacts.filter(contact =>

contact.contact_name.toLowerCase().includes(searchTerm.toLowerCase())

);

return (

<SidebarContainer>

<Header>

<ProfileLink to="/profile">

<ProfileIcon />

</ProfileLink>

<MenuIcon />

</Header>
<SearchContainer>

<SearchWrapper>

<SearchIcon />

<SearchInput

placeholder="Search or start new chat"

value={searchTerm}

onChange={(e) => setSearchTerm(e.target.value)}

/>

</SearchWrapper>

</SearchContainer>

<ContactsList>

{/* Link to Contacts page */}

<ContactItem to="/contacts">

<ContactAvatar>

<FaUser color="#ffffff" size={25} />

</ContactAvatar>

<ContactInfo>

<ContactName>Contacts</ContactName>

</ContactInfo>

</ContactItem>

{filteredContacts.map((contact) => (

<ContactItem key={contact.contact_id} to={`/chat/${contact.contact_id}`}>

<ContactAvatar>

<FaUser color="#ffffff" size={25} />

</ContactAvatar>

<ContactInfo>

<ContactName>{contact.contact_name}</ContactName>

<LastMessage>Click to start chatting</LastMessage>

</ContactInfo>

</ContactItem>
))}

</ContactsList>

<LogoutButton onClick={handleLogout}>Logout</LogoutButton>

</SidebarContainer>

);

export default Sidebar;

Server.js

const express = require('express');

const mysql = require('mysql2');

const bcrypt = require('bcrypt');

const jwt = require('jsonwebtoken');

const cors = require('cors');

require('dotenv').config();

const app = express();

app.use(express.json());

app.use(cors());

// MySQL connection

const db = mysql.createConnection({

host: process.env.DB_HOST,

user: process.env.DB_USER,

password: process.env.DB_PASSWORD,

database: process.env.DB_NAME

});

db.connect((err) => {
if (err) {

console.error('Error connecting to MySQL:', err);

return;

console.log('Connected to MySQL database');

});

// Middleware to verify JWT

const verifyToken = (req, res, next) => {

const token = req.headers['authorization'];

if (!token) return res.status(403).json({ error: 'No token provided' });

jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {

if (err) return res.status(500).json({ error: 'Failed to authenticate token' });

req.userId = decoded.userId;

next();

});

};

// User registration

app.post('/register', async (req, res) => {

const { mobile, password, name } = req.body;

const hashedPassword = await bcrypt.hash(password, 10);

db.query('INSERT INTO users (mobile, password, name) VALUES (?, ?, ?)', [mobile, hashedPassword,
name], (err, result) => {

if (err) {

res.status(500).json({ error: 'Error registering user' });

} else {

res.status(201).json({ message: 'User registered successfully' });

}
});

});

// User login

app.post('/login', (req, res) => {

const { mobile, password } = req.body;

db.query('SELECT * FROM users WHERE mobile = ?', [mobile], async (err, results) => {

if (err || results.length === 0) {

res.status(401).json({ error: 'Invalid credentials' });

} else {

const user = results[0];

const passwordMatch = await bcrypt.compare(password, user.password);

if (passwordMatch) {

const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });

res.json({ token, userId: user.id, name: user.name });

} else {

res.status(401).json({ error: 'Invalid credentials' });

});

});

// Get user profile

app.get('/profile', verifyToken, (req, res) => {

db.query('SELECT id, mobile, name, profile_picture FROM users WHERE id = ?', [req.userId], (err,
results) => {

if (err) {

res.status(500).json({ error: 'Error fetching profile' });

} else {
res.json(results[0]);

});

});

// Corrected Add Contact Logic

app.post('/contacts', verifyToken, (req, res) => {

const { contactMobile, contactName } = req.body;

// Check if the user with the given mobile exists

db.query('SELECT id FROM users WHERE mobile = ?', [contactMobile], (err, results) => {

if (err) {

return res.status(500).json({ error: 'Database error while searching for the user.' });

if (results.length === 0) {

return res.status(404).json({ error: 'User with this mobile number does not exist.' });

const contactId = results[0].id;

// Check if the contact already exists in the user's contacts

db.query('SELECT * FROM contacts WHERE user_id = ? AND contact_id = ?', [req.userId, contactId],
(err, contactExists) => {

if (err) {

return res.status(500).json({ error: 'Error while checking if contact already exists.' });

if (contactExists.length > 0) {

return res.status(400).json({ error: 'Contact already exists in your contact list.' });

}
// Add the contact to the logged-in user's contacts

db.query(

'INSERT INTO contacts (user_id, contact_id, contact_name) VALUES (?, ?, ?)',

[req.userId, contactId, contactName],

(err, result) => {

if (err) {

return res.status(500).json({ error: 'Error adding contact to your contacts.' });

res.status(201).json({ message: 'Contact added successfully' });

);

});

});

});

// Get user's contacts

app.get('/contacts', verifyToken, (req, res) => {

db.query('SELECT c.contact_id, c.contact_name, u.mobile FROM contacts c JOIN users u ON


c.contact_id = u.id WHERE c.user_id = ?', [req.userId], (err, results) => {

if (err) {

res.status(500).json({ error: 'Error fetching contacts' });

} else {

res.json(results);

});

});

// Send a message

app.post('/messages', verifyToken, (req, res) => {

const { receiverId, content } = req.body;


db.query('INSERT INTO messages (sender_id, receiver_id, content) VALUES (?, ?, ?)', [req.userId,
receiverId, content], (err, result) => {

if (err) {

res.status(500).json({ error: 'Error sending message' });

} else {

res.status(201).json({ message: 'Message sent successfully' });

});

});

// Get messages between two users

app.get('/messages/:contactId', verifyToken, (req, res) => {

const { contactId } = req.params;

db.query('SELECT * FROM messages WHERE (sender_id = ? AND receiver_id = ?) OR (sender_id = ?


AND receiver_id = ?) ORDER BY sent_at ASC',

[req.userId, contactId, contactId, req.userId], (err, results) => {

if (err) {

res.status(500).json({ error: 'Error fetching messages' });

} else {

res.json(results);

});

});

// Start the server

const PORT = process.env.PORT || 3001;

app.listen(PORT, () => {

console.log(`Server is running on port ${PORT}`);

});
Database Schema

USE whatapp_db;

-- Create users table

CREATE TABLE IF NOT EXISTS users (

id INT AUTO_INCREMENT PRIMARY KEY,

mobile VARCHAR(15) UNIQUE NOT NULL,

password VARCHAR(255) NOT NULL,

name VARCHAR(50),

profile_picture VARCHAR(255),

created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

);

-- Create messages table

CREATE TABLE IF NOT EXISTS messages (

id INT AUTO_INCREMENT PRIMARY KEY,

sender_id INT NOT NULL,

receiver_id INT NOT NULL,

content TEXT NOT NULL,

sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

FOREIGN KEY (sender_id) REFERENCES users(id) ON DELETE CASCADE,

FOREIGN KEY (receiver_id) REFERENCES users(id) ON DELETE CASCADE

);

-- Create contacts table

CREATE TABLE IF NOT EXISTS contacts (

user_id INT NOT NULL,

contact_id INT NOT NULL,

contact_name VARCHAR(50),

added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY (user_id, contact_id),


FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,

FOREIGN KEY (contact_id) REFERENCES users(id) ON DELETE CASCADE

);

-- Create indexes for faster lookup

CREATE INDEX idx_sender_receiver ON messages(sender_id, receiver_id);

CREATE INDEX idx_user_contact ON contacts(user_id, contact_id);

select * from users;

You might also like