Skip to main content

Favorite Users — Technical Reference

← Back to Favorite Users

Where this lives

Backend

Frontend

Technical implementation checklist

  • addToFavorites — wired in user-favorites.resolver.js; consumed by PublicProfilePage.tsx's favorite toggle
  • removeFromFavorites — wired; consumed by both FavoritesPage.tsx and PublicProfilePage.tsx
  • favoriteUsers — wired; consumed by FavoritesPage.tsx
  • isFavoriteUser — wired; consumed by PublicProfilePage.tsx to render the toggle's current state
  • reorderFavorites — wired in user-favorites.resolver.js; consumed by FavoritesPage.tsx's up/down row controls
  • getFavoritesStats — wired; consumed by FavoritesPage.tsx's stat header. Fixed this session: mutualFavorites/recentAdditions/mostFavoritedUser used to be hardcoded to 0/0/null; all three are now real aggregate queries (see Queries below)
  • Real persistence — favorites.manager.js delegates to user-favorite.access-service.js (create / destroy / getUserFavorites / getFavoritesCount / update), backed by the UserFavorite Sequelize model (migration 20250109000003-create-user-favorites-table.js). No mock scaffolding.

Queries

favoriteUsers returns the current user's full favorites list, with each entry's position (the sort order) and addedAt timestamp. Use limit and offset for paginated rendering.

isFavoriteUser is a lightweight boolean check — used by PublicProfilePage.tsx to render the "Add to favorites" / "Remove from favorites" toggle state in a profile's More options menu without fetching the full list.

getFavoritesStats declares fields for aggregate metrics (total, mutual, recent additions, most-favorited), and all of them are now real. Fixed this session: mutualFavorites/recentAdditions/mostFavoritedUser used to be hardcoded to 0/0/null. favorites.manager.js#getFavoritesStats now runs real queries against user_favorites: mutualFavorites counts reciprocal favoriting (users who have also favorited you back), recentAdditions counts favorites added in the last 7 days, and mostFavoritedUser is the one of your favorites with the highest total favorite count system-wide.

query FavoriteUsers($limit: Int, $offset: Int) {
favoriteUsers(limit: $limit, offset: $offset) {
total limit offset
favorites {
id position addedAt
user { id username profilePicture isVerified }
}
}
}

query IsFavorite($userId: ID!) {
isFavoriteUser(userId: $userId)
}

query FavoritesStats {
getFavoritesStats {
totalFavorites
mutualFavorites # users who have also favorited you
recentAdditions # added in the last 7 days
mostFavoritedUser { username profilePicture }
}
}

Mutations

addToFavorites adds a user to the favorites list and assigns them the next available position. The schema declares a nullable favorite: FavoriteUser field on the response. Fixed this session: the manager used to return a favoriteUser key, which doesn't exist on the schema at all (the field is named favorite), so it always resolved to null. It now returns a proper favorite: { id, user, addedAt, position } object matching FavoriteUser, so the mutation response can be used to insert the new entry without a re-fetch.

removeFromFavorites removes a user from the list. It does not recompact the remaining position values — gaps are left behind and simply don't affect ordering, since the list is always sorted by position ASC.

reorderFavorites accepts the complete ordered list of user IDs. The server replaces the existing order with the new sequence, updating position for every entry. To move one user, pass the full list with that user at the desired index.

mutation AddFavorite($userId: ID!) {
addToFavorites(userId: $userId) {
success message
favorite { id position addedAt user { username } }
}
}

mutation RemoveFavorite($userId: ID!) {
removeFromFavorites(userId: $userId) { success message }
}

# Pass the complete ordered list of user IDs to update all positions at once
mutation ReorderFavorites($userIds: [ID!]!) {
reorderFavorites(userIds: $userIds) { success message }
}

reorderFavorites accepts the complete ordered list of user IDs and updates position for each entry.