feat: add public user profiles

- Add GET /api/users/:username endpoint for public profiles
- Create PublicProfilePage component with user stats and info
- Add getUserByUsername function to API service
- Add /:username route to App.jsx
- Display user info: name, location, stats, WSDC ID, social links
- Only show public data (no email or sensitive information)
- Accessible only to authenticated users

Users can now view public profiles of other users by visiting
/<username>. The profile displays stats, location, WSDC ID, and
social media links.
This commit is contained in:
Radosław Gierwiało
2025-11-13 21:03:37 +01:00
parent 144b13a0cf
commit 897d6e61b3
4 changed files with 294 additions and 1 deletions

View File

@@ -81,4 +81,71 @@ router.patch('/me', authenticate, updateProfileValidation, updateProfile);
// PATCH /api/users/me/password - Change password
router.patch('/me/password', authenticate, changePasswordValidation, changePassword);
// GET /api/users/:username - Get public user profile by username
router.get('/:username', authenticate, async (req, res, next) => {
try {
const { username } = req.params;
const user = await prisma.user.findUnique({
where: { username },
select: {
id: true,
username: true,
firstName: true,
lastName: true,
wsdcId: true,
youtubeUrl: true,
instagramUrl: true,
facebookUrl: true,
tiktokUrl: true,
country: true,
city: true,
avatar: true,
createdAt: true,
_count: {
select: {
matchesAsUser1: true,
matchesAsUser2: true,
ratingsReceived: true,
},
},
},
});
if (!user) {
return res.status(404).json({
success: false,
error: 'User not found',
});
}
// Calculate total matches
const totalMatches = user._count.matchesAsUser1 + user._count.matchesAsUser2;
// Calculate average rating
const ratings = await prisma.rating.findMany({
where: { ratedId: user.id },
select: { score: true },
});
const averageRating = ratings.length > 0
? ratings.reduce((sum, r) => sum + r.score, 0) / ratings.length
: 0;
res.json({
success: true,
data: {
...user,
stats: {
matchesCount: totalMatches,
ratingsCount: user._count.ratingsReceived,
rating: averageRating.toFixed(1),
},
},
});
} catch (error) {
next(error);
}
});
module.exports = router;