UserCardRepository
app/features/user-card/UserCardRepository.server.ts- Tables
- LFGPostPlusTierPrivateUserNoteSplatoonPlayerUnvalidatedUserSubmittedImageUserUserFriendCodeUserSubmittedImageXRankPlacement
- Calls
- AdminRepositoryLeaderboardRepositorySkillRepositoryUserRepository
- Imports
- Seasons
- Used by
- 15 loaders1 action1 route1 script2 other
Functions & values
UserCardData for many users, keyed by user id. One batched query ({@link userCardDataJsonObject}) merged with the in-memory SEASON caches (userSkills, cachedFullUserLeaderboard); privateNote is scoped to the acting user. Spread the result into a route loader so UserCard can find it.
export async function findAllByUserIds({ userIds, include, includeHiddenStats = false, }: { userIds: Array<number>; /** Opt-in fields skipped from the query by default. */ include?: { friendCode?: boolean }; /** Keep hidden stats in `stats`; only the edit page opts in, so hidden values never reach a viewer. */ includeHiddenStats?: boolean; }): Promise<{ userCards: UserCardsById }>
Unit tests (15)
- returns an empty map when given no user ids
- keys cards by user id and builds the stats array from db fields
- surfaces
- ignores
- shows
- falls back to the other division when the picked one has no placements
- judges self-reported peak XP against the picked division's verified XP
- keeps
- persists edited card fields and surfaces hidden stats
- produces a URL banner when an uploaded banner image is set
Like {@link findAllByUserIds} but viewer-independent card data comes from a 30s in-memory cache (for revalidation bursts on the SendouQ looking page); privateNote and friendCode are overlaid fresh per call. The cache holds the in-flight query so concurrent misses share one query.
export async function findAllByUserIdsCached({ userIds, include, }: { userIds: Array<number>; /** Opt-in fields skipped from the query by default. */ include?: { friendCode?: boolean }; }): Promise<{ userCards: UserCardsById }>
Drops every cached card.
export function clearUserCardCache()
Raw card fields the edit form needs that are not part of {@link UserCardData}.
export async function findCardEditExtrasByUserId(userId: number)
Verified XP the card would show with xpDivision (see {@link verifiedXp}), so the edit form can judge a self-reported peak against it. null without X Rank placements.
export async function findVerifiedXpByUserId( userId: number, xpDivision: XRankPlacementRegion | null, )
Updates the acting user's own card and drops it from the cache.
export async function updateOwnCard(args: { shortBio: string | null; bannerPresetImg: string | null; bannerImgId: number | null; unverifiedPeakXP: PeakXP | null; /** `null` leaves the card showing their highest XP across both divisions. */ xpDivision: XRankPlacementRegion | null; hiddenCardStats: Array<HideableUserCardStat>; })