Skip to content

Update front end api calls#58

Merged
ValentinMalassigne merged 7 commits into
mainfrom
update-front-end-api-calls
Nov 30, 2025
Merged

Update front end api calls#58
ValentinMalassigne merged 7 commits into
mainfrom
update-front-end-api-calls

Conversation

@ValentinMalassigne
Copy link
Copy Markdown
Collaborator

No description provided.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the frontend API layer to centralize API calls through a consistent axios-based client architecture. The changes introduce type-safe API functions, React Query hooks, and update components to use the new architecture, while also removing Next.js API route proxies in favor of direct backend communication.

Key Changes:

  • Introduced centralized API client layer with proper TypeScript types for all endpoints (auth, profile, browsing, userProfile)
  • Migrated components to use React Query hooks for data fetching and mutations
  • Removed Next.js API route proxies (/api/auth/login, /api/auth/signup, /api/auth/logout, /api/auth/me) in favor of direct backend calls
  • Updated nginx configuration to properly handle cookies for authentication

Reviewed changes

Copilot reviewed 38 out of 38 changed files in this pull request and generated 23 comments.

Show a summary per file
File Description
nginx/nginx.conf Added cookie handling directives for authentication
nextjs/matcha/src/types/myProfile.ts New type definition for user's own profile data
nextjs/matcha/src/types/api/*.ts New API request/response type definitions
nextjs/matcha/src/lib/axios.ts Created axios instance with credentials support
nextjs/matcha/src/lib/api/*.ts Implemented centralized API client functions
nextjs/matcha/src/hooks/*.ts Created React Query hooks for API integration
nextjs/matcha/src/components/**/*.tsx Updated components to use new hooks
nextjs/matcha/src/middleware.ts Uncommented authentication redirect logic
nextjs/matcha/src/app/api/auth/*/route.ts Removed Next.js API proxies (deleted files)
nextjs/matcha/src/app/(logged)/**/*.tsx Refactored pages to use new API layer
fastify/assets/srcs/services/UserService.ts Enhanced profile picture deletion and added firstName/lastName to profile response
fastify/assets/srcs/routes/private/user/me/profile.ts Updated validation rules and added new fields
fastify/assets/srcs/routes/private/index.ts Modified static file serving configuration
fastify/assets/srcs/plugins/checkImageConformity.ts Disabled aspect ratio validation (commented out)
fastify/assets/srcs/controllers/auth/signup.ts Added security flags to JWT cookie

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

try {
fs.unlinkSync(picturePath);
} catch (err) {
console.error(`Failed to delete file ${picturePath}:`, err);
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error handling only logs the error but doesn't throw or report it. When file deletion fails, the database will still be updated to remove the picture reference, leading to inconsistent state. Consider either:

  1. Throwing the error to roll back the database transaction
  2. Implementing a cleanup job to handle orphaned files
  3. At minimum, logging with more context (user ID, picture index) for debugging
Suggested change
console.error(`Failed to delete file ${picturePath}:`, err);
console.error(`Failed to delete file ${picturePath} for user ID ${user.id}, picture index ${pictureIndex}:`, err);
throw new InternalServerError(`Failed to delete profile picture file for user ID ${user.id}, picture index ${pictureIndex}`);

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +32
const domain = window.location.hostname;
const cookieOptions = `path=/; domain=${domain}; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax`;
document.cookie = `jwt=; ${cookieOptions}`;
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logout implementation only clears the JWT cookie on the client side. This is insufficient for proper logout:

  1. The backend should have a logout endpoint to invalidate the token server-side
  2. Client-side cookie deletion can be bypassed or fail
  3. The httpOnly flag (if set on the cookie) would prevent JavaScript from deleting it

Consider implementing a proper backend logout endpoint and calling it via axios.

Suggested change
const domain = window.location.hostname;
const cookieOptions = `path=/; domain=${domain}; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax`;
document.cookie = `jwt=; ${cookieOptions}`;
await axios.post('/api/auth/logout');

Copilot uses AI. Check for mistakes.
bio: string;
tags: string[];
bornAt: string;
gender: 'male' | 'female';
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type inconsistency: The gender field in CompleteProfileRequest and UpdateProfileRequest is typed as 'men' | 'women', but in MyProfile type it's 'male' | 'female'. This mismatch can lead to runtime errors. Consider standardizing the gender values across the application or documenting the transformation logic.

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +18
gender: string;
orientation: string;
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type inconsistency: In UserProfileResponse, the gender and orientation fields are typed as generic string, but they should have specific union types like 'male' | 'female' for gender and 'heterosexual' | 'homosexual' | 'bisexual' for orientation to match the rest of the API and provide better type safety.

Copilot uses AI. Check for mistakes.
firstName: { type: 'string' },
lastName: { type: 'string' },
email: { type: 'string', format: 'email' },
bio: { type: 'string', minLength: 50, maxLength: 100 },
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing validation: The bio length validation changed from minLength: 2 to minLength: 50, but there's no corresponding error message or user guidance. Users who previously had bios shorter than 50 characters will now fail validation. Consider:

  1. Adding a migration to handle existing short bios
  2. Providing clear error messages about the new minimum length
  3. Ensuring the frontend validation matches this requirement
Suggested change
bio: { type: 'string', minLength: 50, maxLength: 100 },
bio: {
type: 'string',
minLength: 50,
maxLength: 100,
description: 'Your bio must be between 50 and 100 characters.',
errorMessage: {
minLength: 'Bio must be at least 50 characters long.',
maxLength: 'Bio must be at most 100 characters long.'
}
},

Copilot uses AI. Check for mistakes.
const { data: availableInterests = [] } = useAvailableInterests();

// hooks for like/pass
const { likeUser, isLiking } = useLikeUser();
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable isLiking.

Suggested change
const { likeUser, isLiking } = useLikeUser();
const { likeUser } = useLikeUser();

Copilot uses AI. Check for mistakes.

// hooks for like/pass
const { likeUser, isLiking } = useLikeUser();
const { passUser, isPassing } = usePassUser();
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable isPassing.

Suggested change
const { passUser, isPassing } = usePassUser();
const { passUser } = usePassUser();

Copilot uses AI. Check for mistakes.
const searchParams = useSearchParams();
const userId = searchParams.get("id");
const { selectedMatchUserId, closeMatchModal } = useBrowsing();
const { selectedMatchUserId, closeMatchModal } = useBrowsingContext(); // still available if later reused for match modal logic
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable selectedMatchUserId.

Suggested change
const { selectedMatchUserId, closeMatchModal } = useBrowsingContext(); // still available if later reused for match modal logic
const { closeMatchModal } = useBrowsingContext(); // still available if later reused for match modal logic

Copilot uses AI. Check for mistakes.
const searchParams = useSearchParams();
const userId = searchParams.get("id");
const { selectedMatchUserId, closeMatchModal } = useBrowsing();
const { selectedMatchUserId, closeMatchModal } = useBrowsingContext(); // still available if later reused for match modal logic
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable closeMatchModal.

Suggested change
const { selectedMatchUserId, closeMatchModal } = useBrowsingContext(); // still available if later reused for match modal logic
const { selectedMatchUserId } = useBrowsingContext(); // still available if later reused for match modal logic

Copilot uses AI. Check for mistakes.
const [passwordError, setPasswordError] = useState("");
const router = useRouter();

const { signup, isPending, error: signupError } = useSignup();
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable signupError.

Suggested change
const { signup, isPending, error: signupError } = useSignup();
const { signup, isPending } = useSignup();

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings November 30, 2025 15:35
@ValentinMalassigne ValentinMalassigne merged commit 4b13514 into main Nov 30, 2025
4 of 5 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 46 out of 47 changed files in this pull request and generated 16 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +126 to 136
// Update location with default values (Paris)
try {
await profileApi.updateProfile({
location: {
latitude: 48.8566,
longitude: 2.3522
}
});
} catch (error) {
console.error('Error submitting onboarding:', error);
throw error;
console.error("Failed to update default location:", error);
}
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Hardcoded default location (Paris coordinates: 48.8566, 2.3522) is silently set after profile completion. If the location update fails, the error is only logged to console. Consider either making this location explicit to the user, optional, or handling the failure more gracefully (e.g., showing a notification).

Copilot uses AI. Check for mistakes.
Comment on lines +204 to +218
console.log("BrowsingService.browseUsers called with filters:", filters, "and sort:", sort);
const user = await this.fastify.userService.getMe(userId);
const lat = filters?.location?.latitude ?? user.location?.latitude;
const lng = filters?.location?.longitude ?? user.location?.longitude;
if (filters?.tags && filters.tags.length === 0) {
console.log("Deleting empty tags filter");
delete filters.tags;
}
const bornAt = user.bornAt;
const fameRate = user.fameRate;
const tags = user.tags;

console.log("filterTags:", filters?.tags);
console.log("userTags:", tags);

Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove console.log statements from production code. These debug statements should be removed or replaced with proper logging (lines 204, 209, 216-217).

Suggested change
console.log("BrowsingService.browseUsers called with filters:", filters, "and sort:", sort);
const user = await this.fastify.userService.getMe(userId);
const lat = filters?.location?.latitude ?? user.location?.latitude;
const lng = filters?.location?.longitude ?? user.location?.longitude;
if (filters?.tags && filters.tags.length === 0) {
console.log("Deleting empty tags filter");
delete filters.tags;
}
const bornAt = user.bornAt;
const fameRate = user.fameRate;
const tags = user.tags;
console.log("filterTags:", filters?.tags);
console.log("userTags:", tags);
this.fastify.log.debug({ filters, sort }, "BrowsingService.browseUsers called");
const user = await this.fastify.userService.getMe(userId);
const lat = filters?.location?.latitude ?? user.location?.latitude;
const lng = filters?.location?.longitude ?? user.location?.longitude;
if (filters?.tags && filters.tags.length === 0) {
this.fastify.log.debug("Deleting empty tags filter");
delete filters.tags;
}
const bornAt = user.bornAt;
const fameRate = user.fameRate;
const tags = user.tags;
this.fastify.log.debug({ filterTags: filters?.tags, userTags: tags }, "BrowsingService.browseUsers tags info");

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +36
// const ratio = (currentSize.width / currentSize.height).toPrecision(3);
const expectedRatio = (ratiox / ratioy).toPrecision(3);
if (currentSize.width > maxWidth || currentSize.width < minWidth || ratio != expectedRatio)
if (currentSize.width > maxWidth || currentSize.width < minWidth
// || ratio != expectedRatio
)
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aspect ratio check has been commented out, allowing images with any aspect ratio to be uploaded. This defeats the purpose of the checkImageConformity validation. If the ratio check is too strict, consider loosening the tolerance instead of removing it entirely:

const tolerance = 0.1; // 10% tolerance
if (Math.abs(parseFloat(ratio) - parseFloat(expectedRatio)) > tolerance) {
  throw new Error('Wrong file dimensions');
}

Copilot uses AI. Check for mistakes.
Comment on lines +81 to +87
// const noFilterresult = await this.fastify.pg.query(
// `
// SELECT u.id, u.username, u.first_name, u.gender, u.profile_pictures, u.profile_picture_index, u.born_at, u.tags, u.fame_rate FROM users u;
// `,
// );
// console.log(`BrowsingService: Retrieved ${noFilterresult.rowCount} users without filters.`);
// console.log("firstRow:", noFilterresult.rows[0]);
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name noFilterresult in the commented code contains a typo - should be noFilterResult. While this is commented out, if it's ever uncommented it would be inconsistent with naming conventions.

Suggested change
// const noFilterresult = await this.fastify.pg.query(
// `
// SELECT u.id, u.username, u.first_name, u.gender, u.profile_pictures, u.profile_picture_index, u.born_at, u.tags, u.fame_rate FROM users u;
// `,
// );
// console.log(`BrowsingService: Retrieved ${noFilterresult.rowCount} users without filters.`);
// console.log("firstRow:", noFilterresult.rows[0]);
// const noFilterResult = await this.fastify.pg.query(
// `
// SELECT u.id, u.username, u.first_name, u.gender, u.profile_pictures, u.profile_picture_index, u.born_at, u.tags, u.fame_rate FROM users u;
// `,
// );
// console.log(`BrowsingService: Retrieved ${noFilterResult.rowCount} users without filters.`);
// console.log("firstRow:", noFilterResult.rows[0]);

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +78
const lat = userProfile?.location?.latitude || 48.8566;
const lng = userProfile?.location?.longitude || 2.3522;
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Hardcoded default coordinates (Paris: 48.8566, 2.3522) are used as fallback. Consider making these configurable through environment variables or application settings, or prompting the user for their location instead of silently defaulting to Paris.

Copilot uses AI. Check for mistakes.
sortBy = 'default',
} = params;

const interests = params.interests ? params.interests.length > 0 ? params.interests : userProfile?.tags ?? [] : userProfile?.tags ?? [];
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Complex ternary operator logic for tags is difficult to read and maintain. Consider extracting this into a separate variable or function for better clarity:

const interests = params.interests?.length > 0 
  ? params.interests 
  : (userProfile?.tags ?? []);

Copilot uses AI. Check for mistakes.
</Typography>
<Typography variant="caption" color="secondary">
{biography.length} / 500
{biography.trim().length} / 500
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing minimum length validation for bio field. The backend requires a minimum of 50 characters (see fastify/assets/srcs/routes/private/user/me/profile.ts line 14), but this TextField doesn't enforce or display that requirement. Users may submit invalid data.

Copilot uses AI. Check for mistakes.
username: string;
password: string;
bornAt: string;
orientation: 'men' | 'women' | 'bisexual';
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The orientation field in SignupRequest is defined as 'men' | 'women' | 'bisexual' which appears incorrect. This should likely be 'heterosexual' | 'homosexual' | 'bisexual' to match the orientation enum used elsewhere in the codebase (see profile.ts and browsing.ts).

Copilot uses AI. Check for mistakes.
Comment on lines +108 to +124
// Step 3: Complete profile with onboarding data
const profileData = {
firstName: data.firstName,
lastName: data.lastName,
bio: data.biography,
tags: data.interests,
gender: genderMap[data.gender] || data.gender,
gender: (genderMap[data.gender] || data.gender) as 'men' | 'women',
orientation: data.interestedInGenders.length === 2
? 'bisexual'
? 'bisexual' as const
: data.interestedInGenders.map(g => genderMap[g] || g).includes(genderMap[data.gender] || data.gender)
? 'homosexual'
: 'heterosexual',
? 'homosexual' as const
: 'heterosexual' as const,
bornAt: new Date(data.birthday).toISOString(),
}; const response = await fetch('/api/private/user/me/profile', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(profileData),
});

};

if (!response.ok) {
const error = await response.json();
console.error('Failed to submit onboarding:', error);
throw new Error(error.message || 'Failed to submit onboarding');
}
const response = await profileApi.completeProfile(profileData);
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing validation for minimum tag count before calling completeProfile. According to the backend code (UserService.ts line 225), at least 3 interests are required, but the frontend only validates this in the onboarding page flow. If completeProfile is called directly with fewer than 3 tags, it will fail. Consider adding validation here or in the API layer.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,141 @@
import axios from '@/lib/axios';
import { generateMockProfilesWithMetadata } from '@/mocks/browsing_mocks';
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import generateMockProfilesWithMetadata.

Copilot uses AI. Check for mistakes.
@ValentinMalassigne ValentinMalassigne deleted the update-front-end-api-calls branch December 18, 2025 05:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants