0% found this document useful (0 votes)
5 views35 pages

Full-Stack Chess App with MERN

regonro ronro romo wroop prp ronowr worfnowr ornorg org[r pronje eprone pkgne[ e]rpgkg e]gkme [ ergmg

Uploaded by

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

Full-Stack Chess App with MERN

regonro ronro romo wroop prp ronowr worfnowr ornorg org[r pronje eprone pkgne[ e]rpgkg e]gkme [ ergmg

Uploaded by

22501a4411
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Date: Page.

No:
Capstone Project
AIM:
React, [Link], [Link], MongoDB
Develop a full-stack web application using React for the front-end, [Link] and
[Link] for the back-end, and MongoDB for data storage.
DESCRIPTION:
1. A web application named ChessMaster made using MERN.
2. Platform used for React is NodeJS
Command: npx create-react-app application_name
By using vite, we can make our application more optimized.
Command: npm create vite@latest
3. Open cmd in ‘project’ folder and type the command
press y
write the project name: frontend folder name
Select framework: React
Select variant: JavaScript
clear the codes in assets>[Link], [Link], [Link].
4. All the folders and files must be in src in frontend folder
5. To run the [Link] file, open terminal:
npm i
npm run dev
6. For react, install axios package (as express for node)
Command in terminal: npm i axios
7. For navigation:
npm i react-router-dom

PROGRAM:

FrontEnd:
Home/[Link]

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


import { useNavigate } from 'react-router-dom';
import { motion } from 'framer-motion';
import { Check as ChessKing, User, LogOut, Trophy, Settings } from 'lucide-react';
import { io } from '[Link]-client';

const socket = io("[Link] {


autoConnect: true,
transports: ['websocket']
});

function Home() {
const navigate = useNavigate();
const [showProfileMenu, setShowProfileMenu] = useState(false);
const [playerColor, setPlayerColor] = useState(null);
const [isWaiting, setIsWaiting] = useState(false);
const [roomId, setRoomId] = useState(null);
const [error, setError] = useState(null);

const user = [Link]('user');


const userData = user ? [Link](user) : {
username: '',
rating: 0,
matches: 0,
wins: 0,
losses: 0,
draws: 0
};

const { username, rating, matches, wins, losses, draws } = userData;

useEffect(() => {
// Set username when component mounts
if (username) {
[Link]('username', username);
}
[Link]("matchFound", (res) => {
const{opponent, roomId, color} = res;
[Link](`Match found: ${opponent} in room ${roomId}, you are playing as
${color}`);
setRoomId(roomId);
navigate(`/game/${roomId}`,{state:{opponent:opponent, color:color}});
});

// Listen for opponent joining


[Link]('gameStarted', (data) => {
// Access the roomId and color from the data object
const { roomId, color } = data;

// Now you can set the roomId in your application state


// For example, using React state:
setRoomId(roomId);
setPlayerColor(color);

// Or store it in a global variable:


// [Link] = roomId;

[Link](`Game started in room: ${roomId}, you are playing as: ${color}`);


});

// Listen for player disconnection


[Link]('playerDisconnected', (player) => {
setError(`${[Link]} disconnected`);
setIsWaiting(false);
setRoomId(null);
});

// Clean up socket listeners on unmount


return () => {
[Link]('opponentJoined');
[Link]('playerDisconnected');
[Link]('findMatchResponse');

};
}, [username, roomId, navigate]);

const handleLogout = () => {

[Link]('token');
[Link]('user');
navigate('/login');
};

const handlePlayOnline = () => {


setIsWaiting(true);
setError(null);

[Link]('findMatch', (response) => {


if ([Link]) {
[Link]([Link]);
} else if ([Link]) {
[Link]('New room created:', [Link]);
setRoomId([Link]);
navigate(`/game/${[Link]}`);
} else {
setError([Link]);
setIsWaiting(false);
}
});
};

const handleCancelMatchmaking = () => {


if (roomId) {
[Link]('closeRoom', { roomId });
setRoomId(null);
}
setIsWaiting(false);
};

return (
<div className="relative min-h-screen bg-[#1a1a1a] overflow-hidden">
{/* Chess-themed background */}
<div
className="absolute inset-0 opacity-20"
style={{
backgroundImage: "url('[Link]
1bad197a6461?q=80&w=2958&auto=format&fit=crop')",
backgroundSize: "cover",
backgroundPosition: "center",
backgroundBlendMode: "overlay"
}}
/>

{/* User Profile Icon */}


<div className="absolute top-4 right-4 z-50">
<[Link]
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className="bg-white/10 p-2 rounded-full"
onClick={() => setShowProfileMenu(!showProfileMenu)}
>
<User className="w-6 h-6 text-white" />
</[Link]>

{/* Profile Dropdown Menu */}


{showProfileMenu && (
<[Link]
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
className="absolute right-0 mt-2 w-48 bg-black/80 backdrop-blur-lg rounded-lg
shadow-lg py-2"
>
<div className="px-4 py-2 border-b border-white/10">
<p className="text-white font-semibold">{username}</p>
</div>
<button className="w-full text-left px-4 py-2 text-white hover:bg-white/10 flex
items-center gap-2">
<Trophy className="w-4 h-4" /> Statistics
</button>
<button className="w-full text-left px-4 py-2 text-white hover:bg-white/10 flex
items-center gap-2">
<Settings className="w-4 h-4" /> Settings
</button>
<button
onClick={handleLogout}
className="w-full text-left px-4 py-2 text-red-400 hover:bg-white/10 flex items-
center gap-2"
>
<LogOut className="w-4 h-4" /> Logout
</button>
</[Link]>
)}
</div>

{/* Main Content */}


<div className="relative min-h-screen flex items-center justify-center p-4">
<[Link]
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="text-center"
>
<[Link]
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ type: "spring", stiffness: 200, damping: 20 }}
className="w-20 h-20 bg-white rounded-full mx-auto mb-8 flex items-center
justify-center"
>
<ChessKing className="w-12 h-12 text-black" />
</[Link]>

<h1 className="text-4xl md:text-6xl font-bold text-white mb-6">


Welcome to ChessMaster
</h1>
<p className="text-gray-400 text-lg md:text-xl mb-12 max-w-2xl mx-auto">
Challenge players worldwide or improve your skills against our advanced AI.
Your next chess adventure begins here.
</p>

<div className="flex flex-col md:flex-row gap-4 justify-center">


{!isWaiting ? (
<[Link]
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={handlePlayOnline}
className="bg-white hover:bg-gray-100 text-black px-8 py-4 rounded-lg font-
semibold text-lg transition-colors"
>
Play Online
</[Link]>
):(
<div className="flex gap-4">
<[Link]
className="bg-white text-black px-8 py-4 rounded-lg font-semibold text-lg
flex items-center gap-2"
>
<div className="animate-spin h-4 w-4 border-2 border-black border-t-
transparent rounded-full"></div>
Waiting for opponent...
</[Link]>
<[Link]
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={handleCancelMatchmaking}
className="bg-red-500 text-white px-6 py-4 rounded-lg font-semibold text-lg
transition-colors"
>
Cancel
</[Link]>
</div>
)}

<[Link]
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={() => navigate('/play/ai')}
className="bg-transparent border-2 border-white text-white px-8 py-4 rounded-
lg font-semibold text-lg hover:bg-white/10 transition-colors"
>
Play vs AI
</[Link]>
</div>

{error && (
<[Link]
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="mt-4 text-red-500"
>
{error}
</[Link]>
)}

{/* Quick Stats */}


<div className="mt-16 grid grid-cols-2 md:grid-cols-4 gap-4 max-w-4xl mx-
auto">
{[
{ label: 'Games Played', value: matches },
{ label: 'Wins', value: wins },
{ label: 'Rating', value: rating },
{ label: 'Win Rate', value: `${matches === 0 ? 0 : [Link]((wins / matches) *
100)}%` }
].map((stat, index) => (
<[Link]
key={[Link]}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 + index * 0.1 }}
className="bg-white/10 backdrop-blur-lg rounded-lg p-4"
>
<h3 className="text-gray-400 text-sm">{[Link]}</h3>
<p className="text-white text-2xl font-bold">{[Link]}</p>
</[Link]>
))}
</div>
</[Link]>
</div>
</div>
);
}

export default Home


Login/[Link]

import { useState } from "react";


import { useNavigate } from "react-router-dom";
import { motion } from "framer-motion";
import axios from "axios";
import { Check as ChessKing, Mail, Lock, Loader2 } from "lucide-react";

const fadeIn = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
};

const inputAnimation = {
focus: { scale: 1.02, transition: { duration: 0.2 } },
blur: { scale: 1, transition: { duration: 0.2 } }
};

function Login() {
const navigate = useNavigate();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState("");

const handleLogin = async (e) => {


[Link]();
setIsLoading(true);
setError("");

try {
const response = await [Link]("http:localhost:5000/api/auth/login", {
email,
password,
});

if ([Link] === 200) {


[Link]("token", [Link]);
[Link]("user", [Link]([Link]));
navigate("/home");
}
} catch (err) {
setError("Invalid credentials. Please try again.");
} finally {
setIsLoading(false);
}
};

return (
<div
className="min-h-screen bg-[#1a1a1a] flex items-center justify-center p-4 sm:p-6
md:p-8"
style={{
backgroundImage: "url('[Link]
1bad197a6461?q=80&w=2958&auto=format&fit=crop')",
backgroundSize: "cover",
backgroundPosition: "center",
backgroundBlendMode: "overlay"
}}
>
<[Link]
initial="hidden"
animate="visible"
variants={fadeIn}
className="w-full max-w-md"
>
<div className="bg-black/80 backdrop-blur-lg rounded-2xl p-8 shadow-2xl border
border-white/10">
<[Link]
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{ type: "spring", stiffness: 200, damping: 20 }}
className="w-20 h-20 bg-white rounded-full mx-auto mb-8 flex items-center
justify-center shadow-lg"
>
<ChessKing className="w-12 h-12 text-black" />
</[Link]>

<h2 className="text-3xl font-bold text-center text-white mb-2">


Welcome to ChessMaster
</h2>
<p className="text-gray-400 text-center mb-8">Sign in to start playing</p>

<form onSubmit={handleLogin} className="space-y-6">


<div className="relative">
<[Link]
whileFocus="focus"
whileBlur="blur"
variants={inputAnimation}
>
<input
type="email"
value={email}
onChange={(e) => setEmail([Link])}
className="w-full px-4 py-3 bg-white/10 rounded-lg pl-12 text-white
placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-white/30 transition-all
border border-white/10"
placeholder="Email"
required
/>
<Mail className="absolute left-4 top-3.5 w-5 h-5 text-gray-400" />
</[Link]>
</div>

<div className="relative">
<[Link]
whileFocus="focus"
whileBlur="blur"
variants={inputAnimation}
>
<input
type="password"
value={password}
onChange={(e) => setPassword([Link])}
className="w-full px-4 py-3 bg-white/10 rounded-lg pl-12 text-white
placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-white/30 transition-all
border border-white/10"
placeholder="Password"
required
/>
<Lock className="absolute left-4 top-3.5 w-5 h-5 text-gray-400" />
</[Link]>
</div>

{error && (
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="text-red-400 text-sm text-center"
>
{error}
</motion.p>
)}

<[Link]
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
type="submit"
disabled={isLoading}
className="w-full bg-white text-black py-3 rounded-lg font-semibold hover:bg-
gray-100 transition-all disabled:opacity-70 flex items-center justify-center"
>
{isLoading ? (
<Loader2 className="w-5 h-5 animate-spin" />
):(
"Sign In"
)}
</[Link]>
<div className="flex items-center gap-4 my-6">
<div className="flex-1 h-px bg-white/10"></div>
<span className="text-gray-400 text-sm">or</span>
<div className="flex-1 h-px bg-white/10"></div>
</div>

<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.2 }}
className="text-center text-gray-400 text-sm"
>
New to ChessMaster?{" "}
<button
onClick={() => navigate("/signup")}
className="text-white font-semibold hover:text-gray-200 transition-colors"
>
Create an account
</button>
</motion.p>
</form>
</div>
</[Link]>
</div>
);
}

export default Login;


Pages/[Link]:
import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
import { useLocation,useParams ,useNavigate} from 'react-router-dom';
import { io } from '[Link]-client';
import { Chessboard } from "react-chessboard";
import { Chess } from "[Link]";
import {
Card,
CardContent,
List,
ListItem,
ListItemText,
ListSubheader,
Stack,
Typography,
Box,
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions,
Button
} from "@mui/material";

// Assuming your [Link] server is running on the same host


const socket = io('[Link]

// Custom Dialog Component

const Game = () => {


// User and connection state
const navigate = useNavigate();
const user = [Link]('user');
const userData = user ? [Link](user) : {
username: '',
rating: 0,
matches: 0,
wins: 0,
losses: 0,
draws: 0
};

const { username, rating, matches, wins, losses, draws } = userData;

const [isConnected, setIsConnected] = useState(false);


const [gameState, setGameState] = useState({
status: 'idle', // idle, waiting, playing
opponent: null,
roomId: null,
message: ''
});
const usernameInputRef = useRef(null);
const locate = useLocation();
const roomId = useParams().roomId;
const color = [Link]?.color
// Chess game state
const chess = useMemo(() => new Chess(), []);
const [fen, setFen] = useState([Link]());
const [over, setOver] = useState("");
const [players, setPlayers] = useState([]);
const [orientation, setOrientation] = useState("white");

// Connect to socket
useEffect(() => {
[Link]('connect', () => {
setIsConnected(true);
});

[Link]('disconnect', () => {
setIsConnected(false);
setGameState({
status: 'idle',
opponent: null,
roomId: roomId,
message: 'Disconnected from server'
});
setPlayers([]);
});

// Listen for opponent match


[Link]('matchFound', (data) => {
setGameState({
status: 'playing',
opponent: [Link],
roomId: [Link],
message: `Playing against ${[Link]}`
});

// Reset the chess board


[Link]();
setFen([Link]());
setOver("");
// Set players
const playersList = [
{ id: [Link], username: username },
{ id: [Link], username: [Link] }
];
setPlayers(playersList);

// Set orientation (black or white) based on player's position


setOrientation([Link] || "white");
});

// Listen for moves from opponent


[Link]('move', (moveData) => {
makeAMove([Link]);

if ([Link]()) {
setOver(`${[Link]} wins!`);
alert("Game over!");
navigate("/home")
}

[Link](over)
});

// Listen for opponent disconnection


[Link]('playerDisconnected', (player) => {
setOver(`${[Link]} has disconnected`);
setGameState(prev => ({
...prev,
status: 'idle',
message: `${[Link]} disconnected. Game ended.`
}));
});

// Listen for opponent leaving


[Link]('opponentLeft', (player) => {
setOver(`${[Link]} left the game`);
setGameState(prev => ({
...prev,
status: 'idle',
message: `${[Link]} left the game.`
}));
});

// Listen for room closure


[Link]('closeRoom', ({ roomId }) => {
if (roomId === [Link]) {
handleCleanup();
}
});

// Cleanup on component unmount


return () => {
[Link]('connect');
[Link]('disconnect');
[Link]('matchFound');
[Link]('move');
[Link]('playerDisconnected');
[Link]('opponentLeft');
[Link]('closeRoom');
};
}, [chess, [Link], username]);

// Handle game cleanup


const handleCleanup = () => {
[Link]();
setFen([Link]());
setOver("");
setPlayers([]);
setGameState({
status: 'idle',
opponent: null,
roomId: null,
message: 'Game ended'
});
};

// Chess move handling


const makeAMove = useCallback(
(move) => {
try {
const result = [Link](move);
setFen([Link]());

if ([Link]()) {
if ([Link]()) {
setOver(
`Checkmate! ${[Link]() === "w" ? "black" : "white"} wins!`
);
} else if ([Link]()) {
setOver("Draw");
} else {
setOver("Game over");
}
}

return result;
} catch (e) {
return null;
}
},
[chess]
);

// onDrop function for chess pieces


function onDrop(sourceSquare, targetSquare) {
if ([Link]() !== orientation[0]) return false;
if ([Link] < 2) return false;
if ([Link] !== 'playing') return false;

const moveData = {
from: sourceSquare,
to: targetSquare,
color: [Link](),
promotion: "q",
};

const move = makeAMove(moveData);

if (move === null) return false;

[Link]("move", {
move,
room: [Link],
});
if ([Link]()) {
setOver(`you wins!`);
alert("Game over! you win");
navigate("/home")
}

return true;
}

// Set username
const handleSetUsername = () => {
if ([Link]()) {
[Link]('username', username);
if ([Link]) {
[Link]();
}
}
};

// Find match
const handleFindMatch = () => {
if (![Link]()) {
alert('Please set a username first');
return;
}

setGameState({
status: 'waiting',
opponent: null,
roomId: null,
message: 'Looking for an opponent...'
});

[Link]('findMatch', (response) => {


if ([Link]) {
setGameState({
status: 'waiting',
opponent: null,
roomId: null,
message: [Link] || 'Waiting for opponent...'
});
}
});
};

// Cancel matchmaking
const handleCancelMatchmaking = () => {
[Link]('cancelMatchmaking');
setGameState({
status: 'idle',
opponent: null,
roomId: null,
message: 'Matchmaking cancelled'
});
};

// Leave game
const handleLeaveGame = () => {
[Link]('leaveGame');
handleCleanup();
};

// Handle game over dialog continue button


const handleGameOverContinue = () => {
[Link]("closeRoom", { roomId: [Link] });
handleCleanup();
};

return (
<div className="game-container p-4 max-w-4xl mx-auto bg-gray-100 rounded-
lg shadow-md">
<h1 className="text-2xl font-bold mb-4">Chess Game</h1>

{/* Connection Status */}


<div className="mb-4">
<span className={`inline-block w-3 h-3 rounded-full mr-2 ${isConnected ?
'bg-green-500' : 'bg-red-500'}`}></span>
<span>{isConnected ? 'Connected' : 'Disconnected'}</span>
</div>

{/* Username Input */}


<div className="mb-4 flex">
<input
type="text"
value={username}
onChange={(e) => setUsername([Link])}
placeholder="Enter username"
className="flex-1 p-2 border rounded-l"
disabled={[Link] === 'playing'}
ref={usernameInputRef}
/>
<button
onClick={handleSetUsername}
className="bg-blue-500 text-white px-4 py-2 rounded-r"
disabled={[Link] === 'playing' || ![Link]()}
>
Set
</button>
</div>

{/* Game Status */}


<div className="mb-4 p-3 bg-white rounded shadow-sm">
<p className="font-semibold">Status: {[Link]}</p>
{[Link] && (
<p>Playing against: {[Link]}</p>
)}
{[Link] && (
<p>Room ID: {[Link]}</p>
)}
{[Link] && (
<p className="mt-2 text-sm text-gray-600">{[Link]}</p>
)}
</div>

{/* Game Controls */}


<div className="mb-4 flex gap-2">
{[Link] === 'idle' && (
<button
onClick={handleFindMatch}
className="bg-green-500 text-white px-4 py-2 rounded flex-1"
disabled={![Link]()}
>
Find Match
</button>
)}

{[Link] === 'waiting' && (


<button
onClick={handleCancelMatchmaking}
className="bg-yellow-500 text-white px-4 py-2 rounded flex-1"
>
Cancel
</button>
)}

{[Link] === 'playing' && (


<button
onClick={handleLeaveGame}
className="bg-red-500 text-white px-4 py-2 rounded flex-1"
>
Leave Game
</button>
)}
</div>

{/* Chess Game */}


{[Link] === 'playing' && (
<Stack>
<Stack flexDirection="row" sx={{ pt: 2 }}>
<div className="board" style={{
maxWidth: 600,
maxHeight: 600,
flexGrow: 1,
}}>
<Chessboard
position={fen}
onPieceDrop={onDrop}
boardOrientation={orientation}
/>
</div>
{[Link] > 0 && (
<Box>
<List>
<ListSubheader>Players</ListSubheader>
{[Link]((p) => (
<ListItem key={[Link]}>
<ListItemText
primary={[Link]}
secondary={[Link] === [Link] ? "(You)" : ""}
/>
</ListItem>
))}
</List>
</Box>
)}
</Stack>
</Stack>
)}

{/* Game Over Dialog */}

</div>
);
};
export default Game;
Register/[Link]

import { useState } from "react";


import { useNavigate } from "react-router-dom";
import { motion } from "framer-motion";
import axios from "axios";
import { Check as ChessKing, Mail, Lock, User, Phone, Loader2 } from "lucide-react";

const fadeIn = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
};

const inputAnimation = {
focus: { scale: 1.02, transition: { duration: 0.2 } },
blur: { scale: 1, transition: { duration: 0.2 } }
};

function Signup() {
const navigate = useNavigate();
const [username, setUsername] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [mobile, setMobile] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState("");

const handleSignup = async (e) => {


[Link]();
setIsLoading(true);
setError("");

const user = {
username,
email,
password,
mobile,
rating: 0,
wins: 0,
losses: 0,
draws: 0,
matches: 0
};

try {
const response = await [Link]("http:localhost:5000/api/auth/signup", user);
if ([Link] === 201) {
navigate("/login");
}
} catch (err) {
setError([Link]?.data?.message || "Signup failed. Please try again.");
} finally {
setIsLoading(false);
}
};

return (
<div
className="min-h-screen bg-[#1a1a1a] flex items-center justify-center p-4 sm:p-6
md:p-8"
style={{
backgroundImage: "url('[Link]
1bad197a6461?q=80&w=2958&auto=format&fit=crop')",
backgroundSize: "cover",
backgroundPosition: "center",
backgroundBlendMode: "overlay"
}}
>
<[Link]
initial="hidden"
animate="visible"
variants={fadeIn}
className="w-full max-w-md"
>
<div className="bg-black/80 backdrop-blur-lg rounded-2xl p-8 shadow-2xl border
border-white/10">
<[Link]
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{ type: "spring", stiffness: 200, damping: 20 }}
className="w-20 h-20 bg-white rounded-full mx-auto mb-8 flex items-center
justify-center shadow-lg"
>
<ChessKing className="w-12 h-12 text-black" />
</[Link]>

<h2 className="text-3xl font-bold text-center text-white mb-2">


Join ChessMaster
</h2>
<p className="text-gray-400 text-center mb-8">Create your account to start your
chess journey</p>
<form onSubmit={handleSignup} className="space-y-6">
<div className="relative">
<[Link]
whileFocus="focus"
whileBlur="blur"
variants={inputAnimation}
>
<input
type="text"
value={username}
onChange={(e) => setUsername([Link])}
className="w-full px-4 py-3 bg-white/10 rounded-lg pl-12 text-white
placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-white/30 transition-all
border border-white/10"
placeholder="Username"
required
/>
<User className="absolute left-4 top-3.5 w-5 h-5 text-gray-400" />
</[Link]>
</div>

<div className="relative">
<[Link]
whileFocus="focus"
whileBlur="blur"
variants={inputAnimation}
>
<input
type="email"
value={email}
onChange={(e) => setEmail([Link])}
className="w-full px-4 py-3 bg-white/10 rounded-lg pl-12 text-white
placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-white/30 transition-all
border border-white/10"
placeholder="Email"
required
/>
<Mail className="absolute left-4 top-3.5 w-5 h-5 text-gray-400" />
</[Link]>
</div>

<div className="relative">
<[Link]
whileFocus="focus"
whileBlur="blur"
variants={inputAnimation}
>
<input
type="tel"
value={mobile}
onChange={(e) => setMobile([Link])}
className="w-full px-4 py-3 bg-white/10 rounded-lg pl-12 text-white
placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-white/30 transition-all
border border-white/10"
placeholder="Mobile Number"
required
/>
<Phone className="absolute left-4 top-3.5 w-5 h-5 text-gray-400" />
</[Link]>
</div>

<div className="relative">
<[Link]
whileFocus="focus"
whileBlur="blur"
variants={inputAnimation}
>
<input
type="password"
value={password}
onChange={(e) => setPassword([Link])}
className="w-full px-4 py-3 bg-white/10 rounded-lg pl-12 text-white
placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-white/30 transition-all
border border-white/10"
placeholder="Password"
required
/>
<Lock className="absolute left-4 top-3.5 w-5 h-5 text-gray-400" />
</[Link]>
</div>

{error && (
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="text-red-400 text-sm text-center"
>
{error}
</motion.p>
)}

<[Link]
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
type="submit"
disabled={isLoading}
className="w-full bg-white text-black py-3 rounded-lg font-semibold hover:bg-
gray-100 transition-all disabled:opacity-70 flex items-center justify-center"
>
{isLoading ? (
<Loader2 className="w-5 h-5 animate-spin" />
):(
"Create Account"
)}
</[Link]>

<div className="flex items-center gap-4 my-6">


<div className="flex-1 h-px bg-white/10"></div>
<span className="text-gray-400 text-sm">or</span>
<div className="flex-1 h-px bg-white/10"></div>
</div>

<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.2 }}
className="text-center text-gray-400 text-sm"
>
Already have an account?{" "}
<button
onClick={() => navigate("/login")}
className="text-white font-semibold hover:text-gray-200 transition-colors"
>
Sign In
</button>
</motion.p>
</form>
</div>
</[Link]>
</div>
);
}

export default Signup;


[Link]

import React from 'react'


import Home from './pages/Home'
import Login from './components/Login'
import Signup from './components/Register'
import NotFound from './pages/NotFound'
import Game from './pages/Game'
import PrivateRoute from './components/PrivateRoute'
import {BrowserRouter, Routes, Route} from 'react-router-dom'
// import "aceternity-ui/[Link]";

export default function App() {


return (
<div>
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
{/* Protected routes */}
<Route
path="/"
element={
<PrivateRoute>
<Home />
</PrivateRoute>
}
/>

<Route
path="/game/:roomId"
element={
<PrivateRoute>
<Game />
</PrivateRoute>
}
/>

<Route
path="/play/ai"
element={
<PrivateRoute>
{/* AI Game component would go here */}
<div>AI Game - To be implemented</div>
</PrivateRoute>
}
/>

{/* Redirect any unknown paths to home */}


<Route path="*" element={<NotFound />} />
[Link]
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './[Link]'
import App from './[Link]'

createRoot([Link]('root')).render(
<StrictMode>
<App />
</StrictMode>,
)

Backend:
Models/[Link]
const mongoose = require("mongoose")

const userSchema= new [Link]({


username:{
type:String,
required:true
},
email:{
type:String,
required:true,
unique:true
},
password:{
type:String,
required:true
},
rating:{
type:Number,
default:0
},
matches:{
type:Number,
default:0
},
wins:{
type:Number,
default:0
},
losses:{
type:Number,
default:0
},
draws:{
type:Number,
default:0
},
mobile:{
type:String,
required:true
}
})

[Link]=[Link]("User",userSchema)

routes/[Link]

// [Link]
const { v4: uuidv4 } = require('uuid');

[Link] = function(io) {
// Store for active users and their socket connections
const users = {};

// Queue for matchmaking


let waitingPlayers = [];

// Active game rooms


const rooms = {};

[Link]('connection', (socket) => {


[Link](`Socket connected: ${[Link]}`);

// Set username
[Link]('joinRoom', ({ roomId, username }, callback) => {
const user = users[[Link]];

if (!user) {
callback({ success: false, message: 'Please set a username first' });
return;
}

if (rooms[roomId]) {
// Room exists, join it
[Link](roomId);
rooms[roomId].[Link]([Link]);

// Find opponent
const opponentId = rooms[roomId].[Link](id => id !== [Link]);
const opponent = users[opponentId] ? { id: opponentId, username:
users[opponentId].username } : null;

callback({ success: true, opponent, color: opponent ? "black" : "white" });

[Link](`${username} joined existing room ${roomId}`);


} else {
// Room doesn't exist, create it
rooms[roomId] = { roomId, players: [[Link]] };
[Link](roomId);
callback({ success: true, opponent: null, color: "white" });

[Link](`${username} created and joined room ${roomId}`);


}
});

[Link]('username', (username) => {


users[[Link]] = {
id: [Link],
username: username,
inGame: false,
roomId: null
};
[Link](`User ${username} (${[Link]}) set their username`);
});

// Find match
[Link]('findMatch', (callback) => {
const user = users[[Link]];

if (!user) {
callback({ waiting: false, message: 'Please set a username first' });
return;
}

if ([Link]) {
callback({ waiting: false, message: 'You are already in a game' });
return;
}

// Add to waiting queue


[Link]([Link]);
callback({ waiting: true, message: 'Waiting for an opponent...' });

// Check if we can match players


if ([Link] >= 2) {
const player1Id = [Link]();
const player2Id = [Link]();

// Make sure both players are still connected


if (!users[player1Id] || !users[player2Id]) {
if (users[player1Id]) [Link](player1Id);
if (users[player2Id]) [Link](player2Id);
return;
}

const player1 = users[player1Id];


const player2 = users[player2Id];

// Create a new room


const roomId = uuidv4();
rooms[roomId] = {
roomId: roomId,
players: [player1Id, player2Id],
gameState: 'playing'
};

// Update user status


[Link] = true;
[Link] = roomId;
[Link] = true;
[Link] = roomId;

// Join socket room


[Link](player1Id)?.join(roomId);
[Link](player2Id)?.join(roomId);

// Notify both players about the match


[Link](player1Id).emit('matchFound', {
opponent: player2,
roomId: roomId,
color: 'white'
});

[Link](player2Id).emit('matchFound', {
opponent: player1,
roomId: roomId,
color: 'black'
});

[Link](`Match created: ${[Link]} vs ${[Link]} in room


${roomId}`);
}
});

// Cancel matchmaking
[Link]('cancelMatchmaking', () => {
const index = [Link]([Link]);
if (index !== -1) {
[Link](index, 1);
[Link](`User ${users[[Link]]?.username || [Link]} canceled matchmaking`);
}
});

// Leave game
[Link]('leaveGame', () => {
const user = users[[Link]];
if (!user || ![Link] || ![Link]) return;

const roomId = [Link];


const room = rooms[roomId];

if (room) {
// Notify other player
const otherPlayerId = [Link](id => id !== [Link]);
if (otherPlayerId && users[otherPlayerId]) {
[Link](otherPlayerId).emit('opponentLeft', user);

// Update other player status


users[otherPlayerId].inGame = false;
users[otherPlayerId].roomId = null;
}

// Clean up room
delete rooms[roomId];
}

// Update user status


[Link] = false;
[Link] = null;

[Link](roomId);
[Link](`User ${[Link]} left game in room ${roomId}`);
});

// Close room
[Link]('closeRoom', ({ roomId }) => {
[Link]([Link])
if (!roomId || !rooms[roomId]) return;

const room = rooms[roomId];

// Update player statuses


[Link](playerId => {
if (users[playerId]) {
users[playerId].inGame = false;
users[playerId].roomId = null;
[Link](playerId)?.leave(roomId);
}
});

// Clean up room
delete rooms[roomId];
[Link](roomId).emit('closeRoom', { roomId });

[Link](`Room ${roomId} closed`);


});

// Handle chess moves


[Link]('move', ({ move, room }) => {
[Link](rooms);
if (!room || !rooms[room]) {
[Link](`Invalid room for move: ${room}`);
return;
}

[Link](`Broadcasting move to room ${room}: ${[Link](move)}`);


[Link](`Room players: ${[Link](rooms[room].players)}`);
[Link](room).emit('move', { move });
[Link](`Move broadcast complete`);
});;

// Disconnect
[Link]('disconnect', () => {
const user = users[[Link]];

// Remove from waiting queue if present


const waitingIndex = [Link]([Link]);
if (waitingIndex !== -1) {
[Link](waitingIndex, 1);
}

// Notify opponent if in game


if (user && [Link] && [Link]) {
const roomId = [Link];
const room = rooms[roomId];

if (room) {
const otherPlayerId = [Link](id => id !== [Link]);
if (otherPlayerId && users[otherPlayerId]) {
[Link](otherPlayerId).emit('playerDisconnected', user);

// Update other player status


users[otherPlayerId].inGame = false;
users[otherPlayerId].roomId = null;
}

// Clean up room
delete rooms[roomId];
}
}

// Remove user from users object


`
routes/[Link]
const User = require("../models/User");
const bcrypt = require("bcryptjs");
const { generateToken } = require("../config/jwt");
const express = require("express");
const router = [Link]();
[Link]("/signup", async (req, res) => {
[Link]("Signup Request:", [Link]);
try {
const { username, email, password, rating, matches, wins, losses, mobile } =
[Link];

let existingUser = await [Link]({ email });


if (existingUser) return [Link](400).json({ message: "User already exists" });

const hashedPassword = await [Link](password, 10);

// Default role to "user" unless specified as "admin" (only for manually added
admins)
const newUser = await [Link]({
username,
email,
password:hashedPassword,
rating,
matches,
wins,
losses,
mobile
});

const token = generateToken(newUser._id);


[Link](201).json({ message: "User created successfully", token, role:
[Link] });
} catch (error) {
[Link](500).json({ message: "Server error", error });
}
});

[Link]("/login", async (req, res) => {


try {
const { email, password } = [Link];

const user = await [Link]({ email });


if (!user) return [Link](400).json({ message: "Invalid credentials" });

const isMatch = await [Link](password, [Link]);


if (!isMatch) return [Link](400).json({ message: "Invalid credentials" });

const token = generateToken(user._id);


[Link]("from login ", user)
[Link](200).json({ message: "Login successful", token, user: { username:
[Link], email: [Link], rating: [Link], matches: [Link], wins:
[Link], losses: [Link], draws: [Link], mobile: [Link] } });
} catch (error) {
[Link](500).json({ message: "Server error", error });
}
});

[Link] = router;

[Link]

const express = require("express");


const { Server } = require("[Link]");
const cors = require("cors");
require("dotenv").config();
const connectDB = require("./config/db");
const authRoutes = require("./routes/AuthRoutes");
const http = require("http");

const app = express();


const server = [Link](app);
connectDB();
const port = [Link] || 8080;

// Initialize [Link]
const io = new Server(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});

[Link]([Link]());
[Link](cors());
[Link]("/api/auth", authRoutes);

// Pass `io` to socketRoutes


require("./routes/SocketRoutes")(io);

[Link](port, () => {
[Link](`listening on *:${port}`);
});
Output:
Result:

Hence, I have successfully created a full-stack web application for Sharing the
Stories.

You might also like