bug fixes
This commit is contained in:
+2
-2
@@ -44,8 +44,8 @@ app.use((error, req, res, next) => {
|
||||
const status = error.status || 500;
|
||||
console.log(error);
|
||||
res.status(status).json({
|
||||
userMessage: "Something went wrong",
|
||||
devMessage: error?.message || "Internal server error",
|
||||
message: "Something went wrong",
|
||||
description: error?.message || "Internal server error",
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ router.post("/signup", async (req, res, next) => {
|
||||
});
|
||||
} catch (err) {
|
||||
if (err instanceof ZodError) {
|
||||
return res.status(400).json({ userMessage: "Invalid data submitted", devMessage: "Invalid schema" });
|
||||
return res.status(400).json({ message: "Invalid data submitted", description: "Invalid schema" });
|
||||
}
|
||||
next(err);
|
||||
}
|
||||
@@ -84,16 +84,16 @@ router.post("/login", async (req, res, next) => {
|
||||
user = await User.findOne({ username });
|
||||
if (!user)
|
||||
return res.status(404).json({
|
||||
userMessage: "User does not exist",
|
||||
devMessage: "'username' not found in db",
|
||||
message: "User does not exist",
|
||||
description: "'username' not found in db",
|
||||
});
|
||||
|
||||
const pwIsValid = await isValidPassword(password, user.password_hash);
|
||||
if (!pwIsValid) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
userMessage: "Invalid credentials",
|
||||
devMessage: "Invalid credentials",
|
||||
message: "Invalid credentials",
|
||||
description: "Invalid credentials",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ router.post("/login", async (req, res, next) => {
|
||||
.json({ token, user: { id: user.id, username: user.username, email: user.email }, success: true });
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return res.status(401).json({ userMessage: "Invalid Credentials", devMessage: "Invalid schema" });
|
||||
return res.status(401).json({ message: "Invalid Credentials", description: "Invalid schema" });
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
|
||||
@@ -4,20 +4,22 @@ const { createRoom } = require("../socket");
|
||||
const { checkAuth } = require("../util/auth");
|
||||
const { Challenge } = require("../models/challenge");
|
||||
|
||||
async function fetchChallenge({ challenger, challenged }) {}
|
||||
// async function fetchChallenge({ challenger, challenged }) {}
|
||||
|
||||
// rooms can only be created through HTTP requests and destroyed only by socket.io server
|
||||
// and vice versa is not true
|
||||
router.post("/create", checkAuth, async (req, res, next) => {
|
||||
router.post("/", checkAuth, async (req, res, next) => {
|
||||
console.log(req.body);
|
||||
// challenger and challenged are username, color is the color played by challenger, timeLimit is the timeLimit for one player
|
||||
const { challenger, challenged, color, timeLimit } = req.body;
|
||||
|
||||
let challenge = await Challenge.findOne({ challenger });
|
||||
|
||||
// a user can create only one challenge at a time
|
||||
if (challenge) {
|
||||
return res.status(405).json({ success: false, error: { message: "Cannot create new challenge" } });
|
||||
return res.status(405).json({
|
||||
message: "Cannot create new challenge",
|
||||
description: "User already created a challenge",
|
||||
});
|
||||
}
|
||||
|
||||
// get email of the challenged person
|
||||
@@ -45,7 +47,8 @@ router.post("/create", checkAuth, async (req, res, next) => {
|
||||
// `Challenge from ${challenger}`,
|
||||
// `To accept the challenge follow the link: http://192.168.136.99:5173/game/challenges/${challenged}/${roomID} \n login through: http://192.168.136.99:5173/login \n roomid:${roomID}`
|
||||
// );
|
||||
res.json({ roomID });
|
||||
console.log(roomID);
|
||||
res.status(201).json({ roomID });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
+186
-135
@@ -5,177 +5,228 @@ const { User } = require("../models/user");
|
||||
const { checkAuth } = require("../util/auth");
|
||||
const { catchAsync } = require("../util/errors");
|
||||
|
||||
// TO BE TESTED
|
||||
// attaches user data to the route object
|
||||
router.use(
|
||||
catchAsync(async (req, res, next) => {
|
||||
let userID = req.url.split("/")[1];
|
||||
if (userID?.length !== 24)
|
||||
return res.status(404).json({ userMessage: "User not found", devMessage: "Invalid user ID" });
|
||||
let userData = await User.findById(userID);
|
||||
if (userData) {
|
||||
req.userData = userData;
|
||||
next();
|
||||
} else {
|
||||
res.status(404).json({
|
||||
success: false,
|
||||
userMessage: "User not found",
|
||||
devMessage: "User ID does not exists",
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// TO BE TESTED
|
||||
// get user details
|
||||
router.get(
|
||||
"/:userid",
|
||||
catchAsync(async (req, res, next) => {
|
||||
let userData = req.userData;
|
||||
let { id, username, email, fname, lname, country, location } = userData;
|
||||
let friends = await userData.getFriends();
|
||||
let games = await userData.getGames();
|
||||
// get the logged in user details
|
||||
router.get("/", checkAuth, async (req, res, next) => {
|
||||
try {
|
||||
let { userId } = req;
|
||||
const user = await User.findById(userId);
|
||||
let { id, username, email, fname, lname, country, location } = user;
|
||||
let friends = await user.getFriends();
|
||||
let games = await user.getGames();
|
||||
return res.status(200).json({ id, username, email, friends, fname, lname, country, location, games });
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/friends", checkAuth, async (req, res, next) => {
|
||||
try {
|
||||
let { userId } = req;
|
||||
let user = await User.findById(userId);
|
||||
let friends = await user.getFriends();
|
||||
return res.status(200).json(friends);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/challenges", checkAuth, async (req, res, next) => {
|
||||
try {
|
||||
let { userId } = req;
|
||||
let user = await User.findById(userId);
|
||||
let challenges = await Challenge.find({ challenged: user.username });
|
||||
challenges = challenges.map((challenge) => {
|
||||
let { id, challenged, challenger, color, roomID, timeLimit } = challenge;
|
||||
return { id, challenged, challenger, color, roomID, timeLimit };
|
||||
});
|
||||
console.log(challenges);
|
||||
res.status(200).json(challenges);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO
|
||||
// get history of games played
|
||||
router.get("/games", checkAuth, async (req, res, next) => {
|
||||
try {
|
||||
let { userId } = req;
|
||||
const user = await User.findById(userId);
|
||||
let games = await user.getGames();
|
||||
if (!games) games = [];
|
||||
return res.status(200).json(gamesData);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO
|
||||
router.get("/games/:gameid", checkAuth, async (req, res, next) => {
|
||||
try {
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO
|
||||
router.get("");
|
||||
|
||||
// TO BE TESTED
|
||||
// update user details
|
||||
router.patch(
|
||||
"/:userid",
|
||||
checkAuth,
|
||||
catchAsync(async (req, res, next) => {
|
||||
let { userid } = req.params;
|
||||
router.patch("/", checkAuth, async (req, res, next) => {
|
||||
try {
|
||||
let { userId } = req;
|
||||
let updatedData = req.body;
|
||||
console.log("Updated data: ", updatedData);
|
||||
// console.log(updatedData)
|
||||
await User.findByIdAndUpdate(userid, { ...updatedData });
|
||||
let { id, username, email, fname, lname, location, country, fullName } = await User.findById(userid);
|
||||
// console.log(req.userData);
|
||||
console.log({ id, username, email, fname, lname, location, country, fullName });
|
||||
return res.json({ success: true, user: { id, username, email, fname, lname, location, country, fullName } });
|
||||
})
|
||||
);
|
||||
await User.findByIdAndUpdate(userId, { ...updatedData });
|
||||
let { id, username, email, fname, lname, location, country, fullName } = await User.findById(userId);
|
||||
return res.status(200).json({ user: { id, username, email, fname, lname, location, country, fullName } });
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// TO BE TESTED
|
||||
// delete the user
|
||||
router.delete(
|
||||
"/:userid",
|
||||
checkAuth,
|
||||
catchAsync(async (req, res, next) => {
|
||||
let { userData } = req;
|
||||
await userData.deleteOne();
|
||||
})
|
||||
);
|
||||
router.delete("/", checkAuth, async (req, res, next) => {
|
||||
try {
|
||||
let { userId } = req;
|
||||
let user = await User.findById(userId);
|
||||
await user.deleteOne();
|
||||
return res.status(204).json({ message: "Account deleted succesfully" });
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// get friends of the user
|
||||
router.get(
|
||||
"/:userid/friends",
|
||||
checkAuth,
|
||||
catchAsync(async (req, res, next) => {
|
||||
const friends = await req.userData.getFriends();
|
||||
return res.json({ success: true, friends });
|
||||
})
|
||||
);
|
||||
// TO BE TESTED
|
||||
// TODO: add some logic to notify the challenger if the challenged user declines the challenge
|
||||
// accept or decline a challenge
|
||||
// challengeID here refers to the roomID associated with the challenge
|
||||
router.delete("/challenges/:challengeID", checkAuth, async (req, res, next) => {
|
||||
try {
|
||||
let { challengeID } = req.params;
|
||||
let challenge = await Challenge.findById(challengeID);
|
||||
if (!challenge)
|
||||
return res
|
||||
.status(404)
|
||||
.json({ message: "Challenge not found", description: "Challenge ID does not exists" });
|
||||
await challenge.deleteOne();
|
||||
return res.status(200).json({});
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// TO BE TESTED
|
||||
// add a friend
|
||||
router.post(
|
||||
"/:userid/friends/:friendusername",
|
||||
checkAuth,
|
||||
catchAsync(async (req, res, next) => {
|
||||
let { friendusername } = req.params;
|
||||
if (req.userData.username === friendusername)
|
||||
res.json({ success: false, error: { message: "Cannot add yourself as friend" } });
|
||||
let friendData = await User.findOne({ username: friendusername });
|
||||
if (friendData) {
|
||||
if (friendData.friends.includes(req.userData._id)) {
|
||||
res.json({ success: false, error: { message: "User is already added as a friend" } });
|
||||
} else {
|
||||
friendData.friends.push(req.userData._id);
|
||||
await friendData.save();
|
||||
req.userData.friends.push(friendData._id);
|
||||
await req.userData.save();
|
||||
res.json({ success: true });
|
||||
}
|
||||
router.post("/friends/:friendusername", checkAuth, async (req, res, next) => {
|
||||
let { friendusername } = req.params;
|
||||
let { userId } = req;
|
||||
const user = await User.findById(userId);
|
||||
if (req.user.username === friendusername)
|
||||
res.json({
|
||||
error: { description: "Cannot add yourself as friend", message: "Cannot add this user as friends" },
|
||||
});
|
||||
let friendData = await User.findOne({ username: friendusername });
|
||||
if (friendData) {
|
||||
if (friendData.friends.includes(req.user._id)) {
|
||||
res.json({
|
||||
error: {
|
||||
message: "User is already added as a friend",
|
||||
description: "User is already added as a friend",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
res.status(404).json({ success: false, error: { message: "username does not exist" } });
|
||||
friendData.friends.push(req.user._id);
|
||||
await friendData.save();
|
||||
req.user.friends.push(friendData._id);
|
||||
await req.user.save();
|
||||
res.status(204).json(null);
|
||||
}
|
||||
})
|
||||
);
|
||||
} else {
|
||||
res.status(404).json({
|
||||
error: { message: "User not found", description: "username not found in DB" },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// TODO
|
||||
// remove a user from friends list
|
||||
router.delete(
|
||||
"/:userid/friends/:friendid",
|
||||
"/friends/:friendid",
|
||||
checkAuth,
|
||||
catchAsync(async (req, res, next) => {
|
||||
const { friendid } = req.params;
|
||||
const { userData } = req;
|
||||
const { userId } = req;
|
||||
const user = await User.findById(userId);
|
||||
|
||||
// Find the friend user to be removed
|
||||
const friendData = await User.findById(friendid);
|
||||
if (!friendData) {
|
||||
return res.status(404).json({ success: false, error: { message: "Friend user not found" } });
|
||||
return res.status(404).json({ error: { message: "Friend user not found" } });
|
||||
}
|
||||
|
||||
// Remove the friend from the user's friends list
|
||||
const friendIndex = userData.friends.indexOf(friendData._id);
|
||||
const friendIndex = user.friends.indexOf(friendData._id);
|
||||
if (friendIndex === -1) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ success: false, error: { message: "Friend user not found in the friends list" } });
|
||||
return res.status(400).json({ error: { message: "Friend user not found in the friends list" } });
|
||||
}
|
||||
userData.friends.splice(friendIndex, 1);
|
||||
await userData.save();
|
||||
user.friends.splice(friendIndex, 1);
|
||||
await user.save();
|
||||
|
||||
// Remove the user from the friend's friends list
|
||||
const userIndex = friendData.friends.indexOf(userData._id);
|
||||
const userIndex = friendData.friends.indexOf(user._id);
|
||||
if (userIndex === -1) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ success: false, error: { message: "User not found in the friend's friends list" } });
|
||||
return res.status(400).json({ error: { message: "User not found in the friend's friends list" } });
|
||||
}
|
||||
friendData.friends.splice(userIndex, 1);
|
||||
await friendData.save();
|
||||
|
||||
return res.json({ success: true });
|
||||
return res.json({});
|
||||
})
|
||||
);
|
||||
|
||||
// get current challenges of the user
|
||||
router.get(
|
||||
"/:userid/challenges",
|
||||
checkAuth,
|
||||
catchAsync(async (req, res, next) => {
|
||||
let { userData } = req;
|
||||
let challenges = await Challenge.find({ challenged: userData.username });
|
||||
if (!challenges) challenges = [];
|
||||
console.log("Challenges to", userData.username, challenges);
|
||||
res.json({ success: true, challenges: challenges });
|
||||
})
|
||||
);
|
||||
// =============================================================
|
||||
|
||||
// TO BE TESTED
|
||||
// accept or decline a challenge
|
||||
// challengeID here refers to the roomID associated with the challenge
|
||||
router.delete(
|
||||
"/:userid/challenges/:challengeID",
|
||||
checkAuth,
|
||||
catchAsync(async (req, res) => {
|
||||
let challengeResponse = req.query.response;
|
||||
let { challengeID } = req.params;
|
||||
if (challengeResponse === "accept") {
|
||||
let { deletedCount } = await Challenge.deleteOne({ roomID: challengeID });
|
||||
return res.json({ success: true });
|
||||
} else if (challengeResponse === "decline") {
|
||||
let { deletedCount } = await Challenge.deleteOne({ roomID: challengeID });
|
||||
return res.json({ success: true });
|
||||
} else {
|
||||
res.json({ success: false, error: { message: "Invalid query parameter" } });
|
||||
}
|
||||
})
|
||||
);
|
||||
// get user details
|
||||
router.get("/:userid", async (req, res, next) => {
|
||||
try {
|
||||
let userId = req.params.userid;
|
||||
const user = await User.findById(userId);
|
||||
let { id, username, email, fname, lname, country, location } = user;
|
||||
let friends = await user.getFriends();
|
||||
let games = await user.getGames();
|
||||
return res.status(200).json({ id, username, email, friends, fname, lname, country, location, games });
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// get friends of the user
|
||||
router.get("/:userid/friends", async (req, res, next) => {
|
||||
try {
|
||||
const user = await User.findById(req.params.userid);
|
||||
const friends = await user.getFriends();
|
||||
return res.json({ friends });
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// get current challenges of the user
|
||||
router.get("/:userid/challenges", checkAuth, async (req, res, next) => {
|
||||
try {
|
||||
let { userId } = req;
|
||||
const user = await user.findById(userId);
|
||||
let challenges = await Challenge.find({ challenged: user.username });
|
||||
if (!challenges) challenges = [];
|
||||
console.log("Challenges to", user.username, challenges);
|
||||
res.json({ challenges: challenges });
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO
|
||||
// get history of games played
|
||||
@@ -183,10 +234,10 @@ router.get(
|
||||
"/:userid/games",
|
||||
checkAuth,
|
||||
catchAsync(async (req, res, next) => {
|
||||
const userData = await User.findOne();
|
||||
let gamesData = await userData.getGames();
|
||||
const user = await User.findOne();
|
||||
let gamesData = await user.getGames();
|
||||
if (!gamesData) gamesData = [];
|
||||
return res.status(200).json({ success: true, data: gamesData });
|
||||
return res.status(200).json({ data: gamesData });
|
||||
})
|
||||
);
|
||||
|
||||
@@ -195,7 +246,7 @@ router.get(
|
||||
router.post("/:userid/game", checkAuth, async (req, res, next) => {
|
||||
const gameData = req.body;
|
||||
const gameDoc = await Game.create(gameData);
|
||||
return res.json({ success: true, data: gameDoc });
|
||||
return res.json({ data: gameDoc });
|
||||
});
|
||||
|
||||
// TODO
|
||||
@@ -207,9 +258,9 @@ router.get(
|
||||
const { gameid } = req.params;
|
||||
const gameData = await Game.findById(gameid);
|
||||
if (gameData) {
|
||||
return res.status(200).json({ success: true, data: gameData });
|
||||
return res.status(200).json({ data: gameData });
|
||||
} else {
|
||||
return res.status(404).json({ success: false, error: { message: "Game not found" } });
|
||||
return res.status(404).json({ error: { message: "Game not found" } });
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@@ -6,7 +6,6 @@ const { Game } = require("./models/game");
|
||||
const {
|
||||
CHESS_MOVE,
|
||||
CHESS_OPPONENT_MOVE,
|
||||
CONNECTION,
|
||||
JOIN_ROOM,
|
||||
JOIN_ROOM_ERROR,
|
||||
JOIN_ROOM_SUCCESS,
|
||||
|
||||
@@ -52,14 +52,15 @@ function checkAuthMiddleware(req, res, next) {
|
||||
}
|
||||
let authToken = req.cookies["auth-token"];
|
||||
if (!authToken) {
|
||||
return res.status(401).json({ userMessage: "Not authenticated", devMessage: "Auth token not found" });
|
||||
return res.status(401).json({ message: "Not authenticated", description: "Auth token not found" });
|
||||
}
|
||||
try {
|
||||
const validatedToken = validateJSONToken(authToken);
|
||||
req.userid = validatedToken;
|
||||
req.userId = validatedToken.id;
|
||||
req.isAuthenticated = true;
|
||||
} catch (error) {
|
||||
console.log("NOT AUTH. TOKEN INVALID.");
|
||||
return res.status(401).json({ userMessage: "Not authenticated", devMessage: "Invalid auth token" });
|
||||
return res.status(401).json({ message: "Not authenticated", description: "Invalid auth token" });
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.prettierrc.js
|
||||
.eslintrc.js
|
||||
env.d.ts
|
||||
+36
-14
@@ -1,15 +1,37 @@
|
||||
module.exports = {
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react/jsx-runtime',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
|
||||
settings: { react: { version: '18.2' } },
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': 'warn',
|
||||
},
|
||||
}
|
||||
extends: [
|
||||
// By extending from a plugin config, we can get recommended rules without having to add them manually.
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:jsx-a11y/recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
// This disables the formatting rules in ESLint that Prettier is going to be responsible for handling.
|
||||
// Make sure it's always the last config, so it gets the chance to override other configs.
|
||||
'eslint-config-prettier',
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
// Tells eslint-plugin-react to automatically detect the version of React to use.
|
||||
version: 'detect',
|
||||
},
|
||||
// Tells eslint how to resolve imports
|
||||
'import/resolver': {
|
||||
node: {
|
||||
paths: ['src'],
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
// Add your own rules here to override ones from the extended configs.
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"react/jsx-uses-react": "off",
|
||||
"no-console": "off",
|
||||
},
|
||||
"env":{
|
||||
"browser":true,
|
||||
"node":true
|
||||
}
|
||||
};
|
||||
|
||||
Generated
+1169
-510
File diff suppressed because it is too large
Load Diff
@@ -17,8 +17,16 @@
|
||||
"@mantine/hooks": "^6.0.14",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@tabler/icons-react": "^2.23.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.2.0",
|
||||
"@typescript-eslint/parser": "^6.2.0",
|
||||
"chess.js": "^1.0.0-beta.6",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-react": "^7.33.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
"prettier": "^3.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.45.2",
|
||||
@@ -30,8 +38,6 @@
|
||||
"@types/react": "^18.0.37",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.3.4",
|
||||
"vite": "^4.3.9"
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import './App.css'
|
||||
import { createBrowserRouter, redirect, RouterProvider } from 'react-router-dom'
|
||||
import Home from './pages/Home'
|
||||
import MainLayout from './layout/MainLayout'
|
||||
import Settings from './pages/Settings/Settings'
|
||||
import Profile from './pages/Settings/Profile'
|
||||
import Friends from './pages/Settings/Friends'
|
||||
import Password from './pages/Settings/Password'
|
||||
import Themes from './pages/Settings/Themes'
|
||||
@@ -11,12 +9,11 @@ import PlayLayout from './pages/Play/Layout'
|
||||
import PlayFriend from './pages/Play/PlayFriend'
|
||||
import Play from './pages/Play/Play'
|
||||
import AuthenticationPage, { loginAction, signupAction } from './pages/Authentication/Authentication'
|
||||
import { getAuthToken, getUserData } from '../utils/auth'
|
||||
import { logoutAction } from './components/Logout'
|
||||
import { getAuthToken, getUserData } from './utils/auth'
|
||||
import ChallengeFriend, { playFriendAction } from './pages/Play/ChallengeFriend'
|
||||
import ChessGame from './pages/Chess/ChessGame'
|
||||
import ChessGameContextProvider from './context/chess-game-context'
|
||||
import { action as profileAction } from './pages/Settings/Profile'
|
||||
import Profile, { action as profileAction } from './pages/Settings/Profile'
|
||||
|
||||
const router = createBrowserRouter([{
|
||||
path: '/',
|
||||
@@ -58,7 +55,7 @@ const router = createBrowserRouter([{
|
||||
}, {
|
||||
path: '/signup', element: <AuthenticationPage isLogin={false} />, action: signupAction, loader: () => { if (getAuthToken()) return redirect('/signup'); else return null; }
|
||||
}, {
|
||||
path: '/logout', loader: () => { getAuthToken() || redirect('/home') }, action: logoutAction
|
||||
path: '/logout', loader: () => { getAuthToken() || redirect('/home') }
|
||||
}]);
|
||||
|
||||
function App() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useContext, useState } from 'react'
|
||||
import React, { useContext } from 'react'
|
||||
import Piece from './Piece';
|
||||
import { socket } from '../socket';
|
||||
import { Box, Flex, Modal } from '@mantine/core';
|
||||
import { Box, Flex } from '@mantine/core';
|
||||
import { useDroppable } from '@dnd-kit/core'
|
||||
import { ChessGameContext } from '../context/chess-game-context';
|
||||
import { SOCKET_EVENTS } from '../constants';
|
||||
@@ -9,7 +9,7 @@ const { CHESS_MOVE } = SOCKET_EVENTS
|
||||
|
||||
const Cell = ({ cell }) => {
|
||||
let roomID = localStorage.getItem('roomID');
|
||||
let { square, type, color } = cell;
|
||||
let { square, type } = cell;
|
||||
const { getSquareColor, isSquareMarked, handleSquareClick } = useContext(ChessGameContext)
|
||||
const { isOver, setNodeRef } = useDroppable({ id: square });
|
||||
let squareColor = getSquareColor(square);
|
||||
@@ -24,11 +24,16 @@ const Cell = ({ cell }) => {
|
||||
});
|
||||
}
|
||||
|
||||
let content = marked && !type ? <Mark /> : <Piece cell={cell} />;
|
||||
let content = null;
|
||||
if (marked) {
|
||||
content = <Mark />
|
||||
} else if (type) {
|
||||
content = <Piece cell={cell} />
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex ref={setNodeRef} style={{ aspectRatio: '1/1', position: 'relative' }} sx={theme => {
|
||||
let color = theme.colors.lime
|
||||
<Flex ref={setNodeRef} style={{ aspectRatio: '1/1' }} sx={theme => {
|
||||
let color = theme.colors.lime;
|
||||
return { backgroundColor: squareColor === 'b' ? color[8] : color[1], filter: 'saturate(0.5)' }
|
||||
}} onClick={handleClick} bg={squareColor === 'w' ? "white" : "gray"} >
|
||||
{
|
||||
|
||||
@@ -1,88 +1,35 @@
|
||||
import { Button, Group, Stack, Text, Title } from '@mantine/core';
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { getAuthToken, getUserData } from '../../utils/auth'
|
||||
|
||||
const Challenges = () => {
|
||||
const navigate = useNavigate();
|
||||
const [challenges, setChallenges] = useState([]);
|
||||
const { id: userid } = getUserData();
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
console.log(challenges)
|
||||
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
let response = null;
|
||||
|
||||
if (error) return;
|
||||
const fetchData = async () => {
|
||||
let url = `${import.meta.env.VITE_BACKEND_HOST}/api/user/${userid}/challenges`;
|
||||
let url = `${import.meta.env.VITE_BACKEND_HOST}/api/user/challenges`;
|
||||
try {
|
||||
response = await fetch(url, {
|
||||
signal: abortController.signal, headers: {
|
||||
'Authorization': `Bearer ${getAuthToken()}`
|
||||
}
|
||||
})
|
||||
const response = await fetch(url, {
|
||||
credentials: 'include'
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
setChallenges(data.challenges);
|
||||
if (response.ok) {
|
||||
setChallenges(data);
|
||||
} else {
|
||||
throw data.error;
|
||||
setError('Cannot')
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.message === 'The user aborted a request.');
|
||||
else {
|
||||
console.log('Error fetching data');
|
||||
throw error;
|
||||
}
|
||||
console.log(error);
|
||||
setError("Something went wrong")
|
||||
}
|
||||
}
|
||||
|
||||
fetchData();
|
||||
|
||||
return () => {
|
||||
if (!response) {
|
||||
abortController.abort();
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const acceptChallengeHandler = ({ challenger, roomID, color, timeLimit }) => {
|
||||
async function handler() {
|
||||
const res = await deleteChallenge(roomID, 'accept');
|
||||
if (res?.success) {
|
||||
localStorage.setItem('myColor', color === 'b' ? 'w' : 'b');
|
||||
localStorage.setItem('roomID', roomID);
|
||||
localStorage.setItem('opponent', challenger);
|
||||
localStorage.setItem('timeLimit', timeLimit);
|
||||
navigate(`/game/friend/${roomID}`);
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
const declineChallengeHandler = ({ challenger, roomID, color, timeLimit }) => {
|
||||
async function handler() {
|
||||
const res = await deleteChallenge(roomID, 'decline');
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
const deleteChallenge = async (challengeID, response) => {
|
||||
try {
|
||||
let url = `${import.meta.env.VITE_BACKEND_HOST}/api/user/${userid}/challenges/${challengeID}?response=${response}`
|
||||
console.log(url)
|
||||
let res = await fetch(url, {
|
||||
method: 'DELETE', headers: {
|
||||
Authorization: `Bearer ${getAuthToken()}`,
|
||||
}
|
||||
})
|
||||
const resData = await res.json();
|
||||
return resData;
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
setError(err)
|
||||
}
|
||||
}
|
||||
}, [error])
|
||||
|
||||
if (!challenges || challenges.length === 0) {
|
||||
return (
|
||||
@@ -93,19 +40,65 @@ const Challenges = () => {
|
||||
)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<>
|
||||
<Title mt="20px" mb="10px" order={3}>Challenges</Title>
|
||||
<Text>{error}</Text><Text onClick={() => setError(null)} fw={800} sx={{ cursor: 'pointer' }}>Retry</Text>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Title mt="20px" mb="10px" order={3}>Challenges</Title>
|
||||
<Stack>
|
||||
{
|
||||
challenges.map(({ challenger, roomID, color, timeLimit }) => {
|
||||
challenges.map(({ id, challenger, roomID, color, timeLimit }, index) => {
|
||||
console.log(challenger, roomID, color, timeLimit);
|
||||
return (
|
||||
<Group position='apart'>
|
||||
<Group position='apart' key={id}>
|
||||
<Text>Challenge by {challenger}</Text>
|
||||
<Group position='center'>
|
||||
<Button color='lime' onClick={acceptChallengeHandler({ challenger, roomID, color, timeLimit })}>Accept</Button>
|
||||
<Button color='gray' onClick={declineChallengeHandler({ challenger, roomID, color, timeLimit })}>Decline</Button>
|
||||
<Button color='lime' onClick={async () => {
|
||||
try {
|
||||
let url = `${import.meta.env.VITE_BACKEND_HOST}/api/user/challenges/${id}`
|
||||
const response = await fetch(url, { method: 'DELETE', credentials: 'include' });
|
||||
console.log(id, challenger);
|
||||
const resData = await response.json();
|
||||
if (response.ok) {
|
||||
localStorage.setItem('myColor', color === 'b' ? 'w' : 'b');
|
||||
localStorage.setItem('roomID', roomID);
|
||||
localStorage.setItem('opponent', challenger);
|
||||
localStorage.setItem('timeLimit', timeLimit);
|
||||
navigate(`/game/friend/${roomID}`);
|
||||
} else {
|
||||
console.log(resData)
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Something went wrong");
|
||||
console.log(err);
|
||||
}
|
||||
}}>Accept</Button>
|
||||
<Button color='gray' onClick={async () => {
|
||||
try {
|
||||
let url = `${import.meta.env.VITE_BACKEND_HOST}/api/user/challenges/${id}`
|
||||
const response = await fetch(url, { method: 'DELETE', credentials: 'include' });
|
||||
console.log(id, challenger);
|
||||
if (response.ok) {
|
||||
challenges.splice(index, 1);
|
||||
setChallenges(challenges);
|
||||
} else {
|
||||
const resData = await response.json();
|
||||
console.log(resData)
|
||||
}
|
||||
} catch (err) {
|
||||
setError("Something went wrong");
|
||||
console.log(err);
|
||||
}
|
||||
}}>Decline</Button>
|
||||
</Group>
|
||||
</Group>
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ const FriendsList = () => {
|
||||
No friends
|
||||
</Text>
|
||||
:
|
||||
friends.map((friend, index) => <NavLink key={index} component={Link} to={`/play/friend/${friend.username}`} p='5px' icon={<Avatar size='sm' color='blue' children={friend.username[0].toUpperCase()} />} label={<Text fw={700}>{friend.username}</Text>} />)
|
||||
friends.map((friend, index) => <NavLink key={index} component={Link} to={`/play/friend/${friend.username}`} p='5px' icon={<Avatar size='sm' color='blue' >{friend.username[0].toUpperCase()}</Avatar>} label={<Text fw={700}>{friend.username}</Text>} />)
|
||||
}
|
||||
</Flex>
|
||||
)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useContext } from 'react'
|
||||
import { ChessGameContext } from '../context/chess-game-context'
|
||||
import { Button, Flex, Group, ScrollArea, Text, Tooltip, createStyles } from '@mantine/core';
|
||||
import { Button, Flex, ScrollArea, Tooltip, createStyles } from '@mantine/core';
|
||||
import { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'
|
||||
|
||||
const useStyles = createStyles(theme => {
|
||||
const useStyles = createStyles(() => {
|
||||
return {
|
||||
movebtn: {
|
||||
fontSize: '14px',
|
||||
@@ -26,7 +26,7 @@ const useStyles = createStyles(theme => {
|
||||
|
||||
const GameHistory = () => {
|
||||
let { classes } = useStyles();
|
||||
const { gameHistory, jumpTo, currentIndex, goBack, goAhead } = useContext(ChessGameContext)
|
||||
const { gameHistory, jumpTo, goBack, goAhead } = useContext(ChessGameContext)
|
||||
|
||||
let gameHistoryJSX = [];
|
||||
for (let i = 0; i < gameHistory.length;) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Button, Flex, Modal, Text, Title } from '@mantine/core'
|
||||
import { Form, redirect, useNavigate } from 'react-router-dom'
|
||||
import { redirect, useNavigate } from 'react-router-dom'
|
||||
import { useDisclosure } from '@mantine/hooks'
|
||||
|
||||
const Logout = () => {
|
||||
@@ -27,7 +27,7 @@ const Logout = () => {
|
||||
localStorage.removeItem('loggedIn');
|
||||
return navigate('/login');
|
||||
} else {
|
||||
return setErrorMsg(resData.userMessage || "Something went wrong")
|
||||
return setErrorMsg(resData.message || "Something went wrong")
|
||||
}
|
||||
} catch (err) {
|
||||
setIsLoading(false)
|
||||
@@ -54,11 +54,4 @@ const Logout = () => {
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const logoutAction = ({ request }) => {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('user');
|
||||
return redirect('/login');
|
||||
}
|
||||
|
||||
export default Logout
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Group, NavLink, Text, ThemeIcon, UnstyledButton } from '@mantine/core'
|
||||
import { NavLink, Text, ThemeIcon } from '@mantine/core'
|
||||
import { GearIcon, HomeIcon, PlayIcon } from '@radix-ui/react-icons'
|
||||
import React, { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
@@ -31,7 +31,7 @@ const NavbarLink = ({ label, icon, to, index, active, setActive }) => {
|
||||
component={Link}
|
||||
to={to}
|
||||
icon={
|
||||
<ThemeIcon variant="filled" color={active===index?'gray':'lime'}>
|
||||
<ThemeIcon variant="filled" color={active === index ? 'gray' : 'lime'}>
|
||||
{icon}
|
||||
</ThemeIcon>
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ const useStyles = createStyles((theme) => ({
|
||||
boxShadow: 'none',
|
||||
borderColor: 'transparent'
|
||||
}
|
||||
}))
|
||||
}));
|
||||
|
||||
const Piece = ({ cell }) => {
|
||||
const { classes } = useStyles();
|
||||
@@ -50,7 +50,7 @@ const Piece = ({ cell }) => {
|
||||
const style = transform ? {
|
||||
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
|
||||
cursor: isDragging ? 'grabbing' : 'pointer',
|
||||
zIndex: isDragging ? 100 : 20,
|
||||
zIndex: isDragging ? 1000 : 10,
|
||||
aspectRatio: '1',
|
||||
touchAction: 'none',
|
||||
borderRadius: '10px',
|
||||
@@ -66,15 +66,15 @@ const Piece = ({ cell }) => {
|
||||
|
||||
if (logo) {
|
||||
return (
|
||||
<div style={{ position: 'relative', zIndex: 100 }}>
|
||||
<div style={{ position: 'relative' }}>
|
||||
<div style={{ position: 'absolute', borderRadius: '50%', boxSizing: 'border-box', borderWidth: '8px', width: '100%', height: '100%', borderStyle: 'solid', borderColor }}>
|
||||
</div>
|
||||
<Image classNames={{ root: classes['chess-piece'] }} ref={setNodeRef} style={style} sx={{ cursor: 'pointer' }} {...listeners} {...attributes} src={`/src/assets/images/pieces/${logo}.png`} />
|
||||
<Image classNames={{ root: classes['chess-piece'] }} ref={setNodeRef} style={style} sx={{ cursor: 'pointer' }} {...listeners} {...attributes} src={`/src/assets/images/${logo}.png`} />
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div style={{ width: '100%' }}></div>
|
||||
<div style={{ width: '100%', zIndex: 100 }}></div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { createContext, useReducer, useRef, useState } from 'react'
|
||||
import { ChessModified, chessInit } from '../../utils/chess';
|
||||
import { ChessModified, chessInit } from '../utils/chess';
|
||||
import { DISPATCH_EVENTS, SOCKET_EVENTS } from '../constants';
|
||||
import { socket } from '../socket';
|
||||
const { CAPTURE_PIECE, MOVE_PIECE, SELECT_PIECE, JUMP_TO, SET_GAME_HISTORY, END_GAME } = DISPATCH_EVENTS
|
||||
const { GAME_END, CHESS_MOVE, CHESS_OPPONENT_MOVE } = SOCKET_EVENTS;
|
||||
const { GAME_END, CHESS_MOVE } = SOCKET_EVENTS;
|
||||
export const ChessGameContext = createContext();
|
||||
// myColor: null, chess: null, chessBoard: null, moveHints: null, selected: null, dispatch: null, handleOpponentMove: null, handleSquareClick: null, getSquareColor: null, isSquareMarked: null, selectPiece: null, handleDrop: null
|
||||
|
||||
@@ -171,7 +171,7 @@ const ChessGameContextProvider = ({ children }) => {
|
||||
}
|
||||
}
|
||||
|
||||
function selectPiece({ square, type, color: pieceColor }) {
|
||||
function selectPiece({ square, color: pieceColor }) {
|
||||
if (pieceColor === myColor && myColor === chess.turn()) {
|
||||
dispatch({ type: SELECT_PIECE, val: square });
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import React, { createContext, useEffect, useState } from 'react'
|
||||
import Cookie from 'js-cookie'
|
||||
export const UserDataContext = createContext();
|
||||
|
||||
export const UserDataContext = createContext();
|
||||
|
||||
const UserDataContextProvider = ({ children }) => {
|
||||
// TODO: use more secure mechanism insted of localstorage
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(JSON.parse(localStorage.getItem('loggedIn')));
|
||||
const [user, setUser] = useState(null);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
console.log(user)
|
||||
|
||||
async function fetchUserDetails() {
|
||||
try {
|
||||
@@ -22,8 +20,7 @@ const UserDataContextProvider = ({ children }) => {
|
||||
if (response.ok) {
|
||||
setUser(resData);
|
||||
} else {
|
||||
console.log(resData.devMessage);
|
||||
setErrorMessage(resData.userMessage);
|
||||
setErrorMessage(resData.message);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -36,7 +33,7 @@ const UserDataContextProvider = ({ children }) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<UserDataContext.Provider value={{ user, friends: user?.friends , games: user?.games, errorMessage, isLoggedIn, setIsLoggedIn }}>
|
||||
<UserDataContext.Provider value={{ user, friends: user?.friends, games: user?.games, errorMessage, isLoggedIn, setIsLoggedIn }}>
|
||||
{children}
|
||||
</UserDataContext.Provider>
|
||||
)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const useCountDown = (timeLimit,isTimerOn) => {
|
||||
const useCountDown = (timeLimit, isTimerOn) => {
|
||||
const [timeLeft, setTimeLeft] = useState(timeLimit * 60 * 1000);
|
||||
|
||||
useEffect(() => {
|
||||
if(!isTimerOn) {
|
||||
if (!isTimerOn) {
|
||||
return;
|
||||
}
|
||||
if (timeLeft > 0) {
|
||||
|
||||
@@ -73,7 +73,7 @@ const LoginForm = () => {
|
||||
setIsLoggedIn(true);
|
||||
return navigate('/');
|
||||
} else {
|
||||
setErrorMsg(resData.userMessage || "Something went wrong");
|
||||
setErrorMsg(resData.message || "Something went wrong");
|
||||
}
|
||||
} catch (err) {
|
||||
setIsLoading(false);
|
||||
@@ -123,8 +123,8 @@ const SignupForm = () => {
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
console.log(resData);
|
||||
console.log(resData.devMessage);
|
||||
setErrorMsg(resData.userMessage);
|
||||
console.log(resData.description);
|
||||
setErrorMsg(resData.message);
|
||||
resData?.error?.username && setError('username', { message: resData.error.username });
|
||||
resData?.error?.email && setError('email', { message: resData.error.email });
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { Avatar, Button, Flex, Group, Image, Loader, MediaQuery, Modal, NavLink, Text, Title } from '@mantine/core'
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import ChessBoard from '../Chess/ChessBoard'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { socket } from '../../socket'
|
||||
import { getUserData } from '../../../utils/auth'
|
||||
import { getUserData } from '../../utils/auth'
|
||||
import { ChessGameContext } from '../../context/chess-game-context'
|
||||
import GameHistory from '../../components/GameHistory'
|
||||
import Timer from './Timer'
|
||||
import MainLoader from '../../components/MainLoader'
|
||||
import { useDisclosure } from '@mantine/hooks'
|
||||
import { SOCKET_EVENTS } from '../../constants'
|
||||
const { CONNECT, DISCONNECT, CHESS_OPPONENT_MOVE, USER_RESIGNED, CONNECTION, JOIN_ROOM, JOIN_ROOM_ERROR, JOIN_ROOM_SUCCESS, ROOM_FULL, USER_JOINED_ROOM } = SOCKET_EVENTS;
|
||||
const { CONNECT, DISCONNECT, CHESS_OPPONENT_MOVE, USER_RESIGNED, JOIN_ROOM, JOIN_ROOM_ERROR, JOIN_ROOM_SUCCESS, ROOM_FULL, USER_JOINED_ROOM } = SOCKET_EVENTS;
|
||||
|
||||
const ChessGame = () => {
|
||||
const { setGameHistory, isTimerOn, setIsTimerOn, hasGameEnded, gameEndedReason, endGame } = useContext(ChessGameContext);
|
||||
const { setGameHistory, hasGameEnded, gameEndedReason, endGame } = useContext(ChessGameContext);
|
||||
const [gameEndedModalOpen, modalFunctions] = useDisclosure(true);
|
||||
|
||||
const user = getUserData();
|
||||
@@ -67,7 +67,7 @@ const ChessGame = () => {
|
||||
console.log('Socket disconnected due to', reason);
|
||||
});
|
||||
|
||||
socket.on(CHESS_OPPONENT_MOVE, (data) => {
|
||||
socket.on(CHESS_OPPONENT_MOVE, () => {
|
||||
// console.log(data);
|
||||
// setIsTimerOn(true);
|
||||
})
|
||||
@@ -76,9 +76,9 @@ const ChessGame = () => {
|
||||
setIsWaiting(false);
|
||||
});
|
||||
|
||||
socket.on(USER_RESIGNED, (roomID, username) => {
|
||||
socket.on(USER_RESIGNED, () => {
|
||||
endGame('RESIGN');
|
||||
})
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.offAny();
|
||||
@@ -87,7 +87,7 @@ const ChessGame = () => {
|
||||
}, []);
|
||||
|
||||
if (!hasJoinedRoom) return (
|
||||
<Loader variant='bars' />
|
||||
<MainLoader />
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -104,7 +104,9 @@ const ChessGame = () => {
|
||||
style={{ width: "500px" }}
|
||||
p="2px"
|
||||
label={isWaiting ? "Waiting for opponent..." : opponent}
|
||||
icon={<Avatar radius="3px" children={opponent[0].toUpperCase()} />}
|
||||
icon={<Avatar radius="3px" >
|
||||
{opponent[0].toUpperCase}
|
||||
</Avatar>}
|
||||
description={"description"}
|
||||
/>
|
||||
{/* <Timer on={!isTimerOn} /> */}
|
||||
@@ -128,7 +130,9 @@ const ChessGame = () => {
|
||||
style={{ width: "500px" }}
|
||||
p="2px"
|
||||
label={username}
|
||||
icon={<Avatar radius="3px" children={username[0].toUpperCase()} />}
|
||||
icon={<Avatar radius="3px" >
|
||||
{username[0].toUpperCase()}
|
||||
</Avatar>}
|
||||
description={"description"}
|
||||
/>
|
||||
{/* <Timer on={isTimerOn} /> */}
|
||||
@@ -140,7 +144,7 @@ const ChessGame = () => {
|
||||
height: '100%',
|
||||
textAlign: 'center',
|
||||
borderRadius: '10px',
|
||||
backgroundColor:'#272623'
|
||||
backgroundColor: '#272623'
|
||||
}} bg='gray' justify='start' py='md' align='center' direction='column' h="600px">
|
||||
<Title my='20px'>Game Data</Title>
|
||||
<Flex direction='column' w='100%'>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Box } from '@mantine/core';
|
||||
import { ChessGameContext } from '../../context/chess-game-context';
|
||||
|
||||
const Timer = ({ on }) => {
|
||||
const { isTimerOn } = useContext(ChessGameContext)
|
||||
// const { isTimerOn } = useContext(ChessGameContext)
|
||||
const timeLimit = localStorage.getItem('timeLimit');
|
||||
const [seconds, minutes] = useCountDown(timeLimit, on);
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Avatar, Button, Card, Flex, Image, Select, Text, TextInput, Title } from '@mantine/core'
|
||||
import { Avatar, Button, Card, Flex, Select, Text, Title } from '@mantine/core'
|
||||
import React from 'react'
|
||||
import { Form, redirect, useParams } from 'react-router-dom'
|
||||
import { getAuthToken, getUserData } from '../../../utils/auth'
|
||||
import { getUserData } from '../../utils/auth'
|
||||
|
||||
const ChallengeFriend = () => {
|
||||
const params = useParams();
|
||||
@@ -9,12 +9,12 @@ const ChallengeFriend = () => {
|
||||
|
||||
return (
|
||||
<Card
|
||||
maw={450} sx={{
|
||||
width: '100%',
|
||||
height: '600px',
|
||||
textAlign: 'center',
|
||||
backgroundColor:'#262523'
|
||||
}}
|
||||
maw={450} sx={{
|
||||
width: '100%',
|
||||
height: '600px',
|
||||
textAlign: 'center',
|
||||
backgroundColor: '#262523'
|
||||
}}
|
||||
>
|
||||
<Form action={`/play/friend/${friend_username}`} method='POST'>
|
||||
<Flex align="center" direction="column" justify="center" gap="xs" my="lg">
|
||||
@@ -42,20 +42,19 @@ export const playFriendAction = async ({ request, params }) => {
|
||||
let timeLimit = formData.get('timeLimit');
|
||||
let username = getUserData().username;
|
||||
let challenged = params.friend_username;
|
||||
console.log(color, timeLimit, username, challenged);
|
||||
|
||||
let roomIDURL = `${import.meta.env.VITE_BACKEND_HOST}/api/room/create`;
|
||||
let roomIDURL = `${import.meta.env.VITE_BACKEND_HOST}/api/room`;
|
||||
let reqBody = { challenger: username, challenged, timeLimit, color }
|
||||
|
||||
try {
|
||||
console.log(reqBody);
|
||||
const response = await fetch(roomIDURL, {
|
||||
method: 'POST', body: JSON.stringify(reqBody), headers: {
|
||||
'Authorization': `Bearer ${getAuthToken()}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
},
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
console.log(response.status);
|
||||
const resJSON = await response.json();
|
||||
const { roomID } = resJSON;
|
||||
console.log('Room ID:', roomID);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Avatar, Box, Card, Divider, Flex, Image, MediaQuery, NavLink, Text, Title } from '@mantine/core'
|
||||
import { Avatar, Flex, Image, MediaQuery, NavLink } from '@mantine/core'
|
||||
import React from 'react'
|
||||
import { Link, Outlet } from 'react-router-dom'
|
||||
import { getUserData } from '../../../utils/auth';
|
||||
import { Outlet } from 'react-router-dom'
|
||||
import { getUserData } from '../../utils/auth';
|
||||
|
||||
const Layout = () => {
|
||||
const user = getUserData();
|
||||
|
||||
@@ -1,48 +1,30 @@
|
||||
import React, { useState } from 'react'
|
||||
import { Button, Card, CopyButton, Flex, Group, Image, Modal, NativeSelect, NavLink, Select, Text, TextInput, Title } from '@mantine/core'
|
||||
import React from 'react'
|
||||
import { Button, Card, Flex, Image, Modal, NativeSelect, Text, TextInput, Title } from '@mantine/core'
|
||||
import { useDisclosure } from '@mantine/hooks'
|
||||
import { IconSearch, IconUserCircle } from '@tabler/icons-react'
|
||||
import { IconSearch } from '@tabler/icons-react'
|
||||
import FriendsList from '../../components/FriendsList'
|
||||
import { Form } from 'react-router-dom'
|
||||
import Challenges from '../../components/Challenges'
|
||||
|
||||
const createChallengeLink = (color) => {
|
||||
let challengeLink = Math.floor(Math.random() * 100_000_000).toString();
|
||||
if (color === 'RANDOM') {
|
||||
challengeLink = challengeLink.concat(Math.random() < 0.5 ? 'W' : 'B');
|
||||
} else {
|
||||
challengeLink = challengeLink.concat(color);
|
||||
}
|
||||
return challengeLink;
|
||||
}
|
||||
|
||||
const PlayFriend = () => {
|
||||
const [opened, { open, close }] = useDisclosure(false);
|
||||
const [joinChallengeModalState, modalFunctions] = useDisclosure(false);
|
||||
return (
|
||||
<>
|
||||
<Modal zIndex={10} opened={opened} onClose={close} title={<Text mx="auto" size="xl">Create Challenge Link</Text>} centered>
|
||||
<Text>Start a game with anyone</Text>
|
||||
<div>
|
||||
<NativeSelect onChange={(evt) => setColor(evt.target.value)} my="20px" label={<Text mx="auto" order={3}>I play as</Text>} placeholder='choose your color' data={[
|
||||
<NativeSelect my="20px" label={<Text mx="auto" order={3}>I play as</Text>} placeholder='choose your color' data={[
|
||||
{ value: 'W', label: 'White' },
|
||||
{ value: 'B', label: 'Black' },
|
||||
{ value: 'RANDOM', label: 'Random' }
|
||||
]} />
|
||||
</div>
|
||||
{/* TODO: update createChallengeLink function */}
|
||||
{/* <CopyButton>
|
||||
{
|
||||
({ copied, copy }) => <Button disabled onClick={copy} color={copied ? 'gray' : 'lime'}> {copied ? 'Copied' : 'Copy Link'} </Button>
|
||||
}
|
||||
</CopyButton> */}
|
||||
</Modal>
|
||||
<Card
|
||||
maw={450} sx={{
|
||||
width: '100%',
|
||||
height: '600px',
|
||||
textAlign: 'center',
|
||||
backgroundColor:'#262523'
|
||||
backgroundColor: '#262523'
|
||||
}}
|
||||
>
|
||||
<Flex align="center" justify="center" gap="xs" my="lg">
|
||||
@@ -61,11 +43,11 @@ const PlayFriend = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const friends = [
|
||||
{ avatar: <IconUserCircle />, username: "friend", rating: 100 },
|
||||
{ avatar: <IconUserCircle />, username: "friend", rating: 100 },
|
||||
{ avatar: <IconUserCircle />, username: "friend", rating: 100 },
|
||||
{ avatar: <IconUserCircle />, username: "friend", rating: 100 },
|
||||
]
|
||||
// const friends = [
|
||||
// { avatar: <IconUserCircle />, username: "friend", rating: 100 },
|
||||
// { avatar: <IconUserCircle />, username: "friend", rating: 100 },
|
||||
// { avatar: <IconUserCircle />, username: "friend", rating: 100 },
|
||||
// { avatar: <IconUserCircle />, username: "friend", rating: 100 },
|
||||
// ]
|
||||
|
||||
export default PlayFriend
|
||||
@@ -1,20 +1,16 @@
|
||||
import React from 'react'
|
||||
import { Button, Card, Flex, List, Stack, TextInput, Title } from '@mantine/core'
|
||||
import { Button, Card, Flex, TextInput, Title } from '@mantine/core'
|
||||
import { IconSearch } from '@tabler/icons-react'
|
||||
import { useForm } from '@mantine/form'
|
||||
import { getAuthToken, getUserData } from '../../../utils/auth'
|
||||
import FriendsList from '../../components/FriendsList'
|
||||
|
||||
const Friends = () => {
|
||||
let { id: userid } = getUserData();
|
||||
const form = useForm({ initialValues: { username: '' }, })
|
||||
|
||||
const addFriend = async () => {
|
||||
const response = await fetch(`${import.meta.env.VITE_BACKEND_HOST}/api/user/${userid}/friends/${form.values.username}`, {
|
||||
const response = await fetch(`${import.meta.env.VITE_BACKEND_HOST}/api/user/friends/${form.values.username}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${getAuthToken()}`
|
||||
}
|
||||
credentials: 'include'
|
||||
});
|
||||
const resData = await response.json();
|
||||
if (resData.success === false) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useContext } from 'react'
|
||||
import { Avatar, Button, Flex, Grid, Group, Loader, Stack, Text, TextInput, Title } from '@mantine/core'
|
||||
import { getAuthToken, getUserData } from '../../../utils/auth'
|
||||
import { Avatar, Button, Flex, Grid, Group, Stack, Text, TextInput, Title } from '@mantine/core'
|
||||
import { getUserData } from '../../utils/auth'
|
||||
import { UserDataContext } from '../../context/user-data-context'
|
||||
import { useForm } from '@mantine/form'
|
||||
import { Form } from 'react-router-dom'
|
||||
@@ -83,9 +83,9 @@ export const action = async ({ request }) => {
|
||||
body: JSON.stringify(reqBody),
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
Authorization: `Bearer ${getAuthToken()}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
},
|
||||
credentials: 'include'
|
||||
})
|
||||
const resData = await response.json();
|
||||
console.log(resData)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { Box, Flex, NavLink, Title } from '@mantine/core'
|
||||
import { ColorWheelIcon, GearIcon, GlobeIcon, LockOpen1Icon, PersonIcon } from '@radix-ui/react-icons'
|
||||
import React, { useState } from 'react'
|
||||
import React from 'react'
|
||||
import { Link, Outlet } from 'react-router-dom';
|
||||
|
||||
const Settings = () => {
|
||||
const [active, setActive] = useState(null);
|
||||
return (
|
||||
<Box ml='45px'>
|
||||
<Flex align="center" my="lg">
|
||||
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "_chess_",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
Reference in New Issue
Block a user