Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f2d8b67
added bookings
XxcuriousxX Nov 2, 2025
d55e990
Merge remote-tracking branch 'origin' into bookings
XxcuriousxX Nov 7, 2025
c11d0db
chore: navbar file
sitarass Nov 7, 2025
9bd98d7
fix: useIntersectionObserver
sitarass Nov 7, 2025
515cd48
added getRoutes (as driver || as passenger) func
XxcuriousxX Nov 7, 2025
fcc194f
chore: remove redundant file & missing await statements
sitarass Nov 8, 2025
b8a9053
refactor --> Routes to Ride fe & be
XxcuriousxX Nov 8, 2025
a4f8bf8
chore: naming updates
sitarass Nov 9, 2025
205b411
getRideById impl
XxcuriousxX Nov 9, 2025
f6b089a
chore: clean-up & define types
sitarass Nov 9, 2025
f47a0a7
chore: comment fix
sitarass Nov 9, 2025
63cdae5
Update back-end/src/controllers/booking.controller.ts
Sitaras Nov 9, 2025
887888f
Update back-end/src/controllers/booking.controller.ts
Sitaras Nov 9, 2025
1dda699
feat: book seat fe
sitarass Nov 9, 2025
a9434d4
chore: pagination types
sitarass Nov 9, 2025
a0d55d5
Update back-end/src/controllers/user.controller.ts
Sitaras Nov 9, 2025
c20006d
chore: upgrade next.js to 16.0.1
sitarass Nov 10, 2025
60a60dc
chore: update wrtch and improve refresh token handling
sitarass Nov 10, 2025
bf0bce9
chore: migration zod v3 to v4
sitarass Nov 16, 2025
b182ab0
feat: pagination at user getRides
sitarass Nov 16, 2025
161bc89
feat: driver's data
sitarass Nov 16, 2025
b7dc38c
feat: me/user-rides fe api
sitarass Nov 16, 2025
20a1f05
refactor: corrections
sitarass Nov 16, 2025
77e7bfd
Update back-end/src/controllers/user.controller.ts
Sitaras Nov 17, 2025
3d4e54e
chore: linters on commit
sitarass Nov 22, 2025
68da195
chore: husky install
sitarass Nov 22, 2025
3144b65
chore: lint configuration
sitarass Nov 22, 2025
66d77a1
chore: lint fe
sitarass Nov 22, 2025
e67250d
chore: lint fe
sitarass Nov 22, 2025
e7536b4
Logout (#9)
dabouledidia Nov 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions back-end/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 28 additions & 31 deletions back-end/src/controllers/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@ export class AuthController {
lastName,
dateOfBirth,
} = req.body;

if (password !== verifyPassword) {
res.error("Passwords do not match");
return;
}

const existingUser = await User.findOne({
$or: [{ email }, { phoneNumber }],
});

if (existingUser) {
res.error("User already exists");
return;
}

const user = new User({
email,
password,
Expand All @@ -52,50 +52,47 @@ export class AuthController {
email,
phoneNumber,
});

user.profile = profile._id as any;

await Promise.all([user.save(), profile.save()]);

res.success(req.body, "User registered successfully");
} catch (error) {
console.error("Registration error:", error);
res.error("An error occurred", 500);
}
}

static async login(
req: Request<{}, {}, IUserLogin>,
res: Response
): Promise<void> {
static async login(req: Request<{}, {}, IUserLogin>, res: Response) {
try {
const { email, password } = req.body;

const user = await User.findOne({ email });

if (!user) {
res.error("INVALID_CREDENTIALS");
return;
}

const isValidPassword = await user.comparePassword(password);

if (!isValidPassword) {
res.error("INVALID_CREDENTIALS");
return;
}

const tokenPayload = {
userId: user._id as string,
roles: user.roles,
};

const accessToken = tokenUtils.generateAccessToken(tokenPayload);
const refreshToken = tokenUtils.generateRefreshToken(tokenPayload);

user.refreshTokens.push({ token: refreshToken, createdAt: new Date() });
await user.save();

res.success(
{
tokens: {
Expand All @@ -113,53 +110,53 @@ export class AuthController {
static async refreshToken(
req: Request<{}, {}, IRefreshTokenPayload>,
res: Response
): Promise<void> {
) {
try {
const { refreshToken } = req.body;

const user = await User.findOne({
"refreshTokens.token": refreshToken,
});

if (!user) {
res.error("Unauthorized", 401);
return;
}

try {
const decoded = verifyRefreshToken(refreshToken);

if (
typeof decoded === "string" ||
(user._id as string).toString() !== decoded.userId
) {
res.error("Unauthorized", 401);
return;
}

user.refreshTokens = user.refreshTokens.filter((token) => {
const tokenAge = Date.now() - token.createdAt.getTime();
return tokenAge < 7 * 24 * 60 * 60 * 1000; // 7 days
});

const tokenPayload = {
userId: user._id as string,
roles: user.roles,
};

const newAccessToken = tokenUtils.generateAccessToken(tokenPayload);
const newRefreshToken = tokenUtils.generateRefreshToken(tokenPayload);

user.refreshTokens = user.refreshTokens.filter(
(token) => token.token !== refreshToken
);
user.refreshTokens.push({
token: newRefreshToken,
createdAt: new Date(),
});

await user.save();

res.success(
{
accessToken: newAccessToken,
Expand All @@ -175,4 +172,4 @@ export class AuthController {
res.error("An error occurred", 500);
}
}
}
}
76 changes: 76 additions & 0 deletions back-end/src/controllers/booking.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Response } from "express";
import { Booking } from "../models/booking.model";
import { Ride } from "../models/ride.model";
import { Types } from "mongoose";
import { AuthRequest } from "../middleware/auth.middleware";
import { isUserInRide } from "../utils/rideUtils";
import { StatusCodes } from "http-status-codes";
import { ICreateBookingPayload } from "@/schemas/bookingSchema";

export class BookingController {
static async createBooking(
req: AuthRequest<{}, {}, ICreateBookingPayload>,
res: Response
) {
try {
const { rideId } = req.body;
const passengerId = req.user?.userId;

if (!Types.ObjectId.isValid(rideId)) {
return res.error("Invalid Ride ID", StatusCodes.BAD_REQUEST);
}

const rideDoc = await Ride.findById(rideId);
if (!rideDoc) {
return res.error("Ride not found", StatusCodes.NOT_FOUND);
}

if (!rideDoc.isBookable()) {
return res.error(
"Ride is not available for booking.",
StatusCodes.BAD_REQUEST
);
}

if (rideDoc.driver.toString() === passengerId) {
return res.error(
"Driver cannot book their own rideId.",
StatusCodes.BAD_REQUEST
);
}

if (await isUserInRide(passengerId!, rideId)) {
return res.error(
"User already in rideId or pending booking.",
StatusCodes.BAD_REQUEST
);
}

rideDoc.passengers.push({
user: new Types.ObjectId(passengerId),
seatsBooked: 1,
status: "pending",
});
await rideDoc.save();

const booking = await Booking.create({
passenger: passengerId,
driver: rideDoc.driver,
rideId,
status: "pending",
});

return res.success(
booking,
"Booking created successfully.",
StatusCodes.CREATED
);
} catch (error) {
return res.error(
"Server Error",
StatusCodes.INTERNAL_SERVER_ERROR,
error
);
}
}
}
Loading
Loading