mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-24 15:08:44 -05:00
Add sorting to badges owned widget
This commit is contained in:
parent
e8c5ab6c07
commit
0936e70e73
|
|
@ -2,6 +2,7 @@ import type { ExpressionBuilder, NotNull } from "kysely";
|
|||
import { jsonArrayFrom, jsonObjectFrom } from "kysely/helpers/sqlite";
|
||||
import { db } from "~/db/sql";
|
||||
import type { DB } from "~/db/tables";
|
||||
import { sortBadgesByFavorites } from "~/features/user-page/core/badge-sorting.server";
|
||||
import invariant from "~/utils/invariant";
|
||||
import { COMMON_USER_FIELDS } from "~/utils/kysely.server";
|
||||
import { SPLATOON_3_XP_BADGE_VALUES } from "./badges-constants";
|
||||
|
|
@ -110,20 +111,35 @@ export function findManagedByUserId(userId: number) {
|
|||
.execute();
|
||||
}
|
||||
|
||||
export function findByOwnerUserId(userId: number) {
|
||||
return db
|
||||
export async function findByOwnerUserId(userId: number) {
|
||||
const rows = await db
|
||||
.selectFrom("BadgeOwner")
|
||||
.innerJoin("Badge", "Badge.id", "BadgeOwner.badgeId")
|
||||
.innerJoin("User", "User.id", "BadgeOwner.userId")
|
||||
.select(({ fn }) => [
|
||||
fn.count<number>("BadgeOwner.badgeId").as("count"),
|
||||
"Badge.id",
|
||||
"Badge.displayName",
|
||||
"Badge.code",
|
||||
"Badge.hue",
|
||||
"User.favoriteBadgeIds",
|
||||
"User.patronTier",
|
||||
])
|
||||
.where("BadgeOwner.userId", "=", userId)
|
||||
.groupBy(["BadgeOwner.badgeId", "BadgeOwner.userId"])
|
||||
.execute();
|
||||
|
||||
if (rows.length === 0) return [];
|
||||
|
||||
const { favoriteBadgeIds, patronTier } = rows[0];
|
||||
|
||||
return sortBadgesByFavorites({
|
||||
favoriteBadgeIds,
|
||||
badges: rows.map(
|
||||
({ favoriteBadgeIds: _, patronTier: __, ...badge }) => badge,
|
||||
),
|
||||
patronTier,
|
||||
}).badges;
|
||||
}
|
||||
|
||||
export function findByAuthorUserId(userId: number) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { logger } from "~/utils/logger";
|
|||
import { safeNumberParse } from "~/utils/number";
|
||||
import { bskyUrl, twitchUrl, youtubeUrl } from "~/utils/urls";
|
||||
import type { ChatUser } from "../chat/chat-types";
|
||||
import { sortBadgesByFavorites } from "./core/badge-sorting.server";
|
||||
import { findWidgetById } from "./core/widgets/portfolio";
|
||||
import { WIDGET_LOADERS } from "./core/widgets/portfolio-loaders.server";
|
||||
import type { LoadedWidget } from "./core/widgets/types";
|
||||
|
|
@ -242,27 +243,12 @@ export async function findProfileByIdentifier(
|
|||
return null;
|
||||
}
|
||||
|
||||
const favoriteBadgeIds = favoriteBadgesOwnedAndSupporterStatusAdjusted(row);
|
||||
|
||||
return {
|
||||
...row,
|
||||
team: row.teams.find((t) => t.isMainTeam),
|
||||
secondaryTeams: row.teams.filter((t) => !t.isMainTeam),
|
||||
teams: undefined,
|
||||
favoriteBadgeIds,
|
||||
badges: row.badges.sort((a, b) => {
|
||||
const aIdx = favoriteBadgeIds?.indexOf(a.id) ?? -1;
|
||||
const bIdx = favoriteBadgeIds?.indexOf(b.id) ?? -1;
|
||||
|
||||
if (aIdx !== bIdx) {
|
||||
if (aIdx === -1) return 1;
|
||||
if (bIdx === -1) return -1;
|
||||
|
||||
return aIdx - bIdx;
|
||||
}
|
||||
|
||||
return b.id - a.id;
|
||||
}),
|
||||
...sortBadgesByFavorites(row),
|
||||
discordUniqueName:
|
||||
forceShowDiscordUniqueName || row.showDiscordUniqueName
|
||||
? row.discordUniqueName
|
||||
|
|
@ -366,33 +352,6 @@ export async function widgetsByUserId(
|
|||
return loadedWidgets.filter((w) => w !== null);
|
||||
}
|
||||
|
||||
function favoriteBadgesOwnedAndSupporterStatusAdjusted(row: {
|
||||
favoriteBadgeIds: number[] | null;
|
||||
badges: Array<{
|
||||
id: number;
|
||||
}>;
|
||||
patronTier: number | null;
|
||||
}) {
|
||||
// filter out favorite badges no longer owner of
|
||||
let favoriteBadgeIds =
|
||||
row.favoriteBadgeIds?.filter((badgeId) =>
|
||||
row.badges.some((badge) => badge.id === badgeId),
|
||||
) ?? null;
|
||||
|
||||
if (favoriteBadgeIds?.length === 0) {
|
||||
favoriteBadgeIds = null;
|
||||
}
|
||||
|
||||
// non-supporters can only have one favorite badge, handle losing supporter status
|
||||
favoriteBadgeIds = isSupporter(row)
|
||||
? favoriteBadgeIds
|
||||
: favoriteBadgeIds
|
||||
? [favoriteBadgeIds[0]]
|
||||
: null;
|
||||
|
||||
return favoriteBadgeIds;
|
||||
}
|
||||
|
||||
export function findByCustomUrl(customUrl: string) {
|
||||
return db
|
||||
.selectFrom("User")
|
||||
|
|
|
|||
63
app/features/user-page/core/badge-sorting.server.test.ts
Normal file
63
app/features/user-page/core/badge-sorting.server.test.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { sortBadgesByFavorites } from "./badge-sorting.server";
|
||||
|
||||
const badge = (id: number) => ({
|
||||
id,
|
||||
displayName: `Badge ${id}`,
|
||||
code: `b${id}`,
|
||||
});
|
||||
|
||||
describe("sortBadgesByFavorites", () => {
|
||||
it("returns badges sorted by descending id when no favorites", () => {
|
||||
const result = sortBadgesByFavorites({
|
||||
favoriteBadgeIds: null,
|
||||
badges: [badge(1), badge(3), badge(2)],
|
||||
patronTier: null,
|
||||
});
|
||||
|
||||
expect(result.badges.map((b) => b.id)).toEqual([3, 2, 1]);
|
||||
expect(result.favoriteBadgeIds).toBeNull();
|
||||
});
|
||||
|
||||
it("places favorites first in order for supporters", () => {
|
||||
const result = sortBadgesByFavorites({
|
||||
favoriteBadgeIds: [2, 1],
|
||||
badges: [badge(1), badge(2), badge(3)],
|
||||
patronTier: 2,
|
||||
});
|
||||
|
||||
expect(result.badges.map((b) => b.id)).toEqual([2, 1, 3]);
|
||||
expect(result.favoriteBadgeIds).toEqual([2, 1]);
|
||||
});
|
||||
|
||||
it("limits non-supporters to one favorite", () => {
|
||||
const result = sortBadgesByFavorites({
|
||||
favoriteBadgeIds: [2, 3],
|
||||
badges: [badge(1), badge(2), badge(3)],
|
||||
patronTier: null,
|
||||
});
|
||||
|
||||
expect(result.favoriteBadgeIds).toEqual([2]);
|
||||
expect(result.badges[0].id).toBe(2);
|
||||
});
|
||||
|
||||
it("filters out unowned favorite badge ids", () => {
|
||||
const result = sortBadgesByFavorites({
|
||||
favoriteBadgeIds: [99, 1],
|
||||
badges: [badge(1), badge(2)],
|
||||
patronTier: 2,
|
||||
});
|
||||
|
||||
expect(result.favoriteBadgeIds).toEqual([1]);
|
||||
});
|
||||
|
||||
it("returns null favoriteBadgeIds when all favorites are unowned", () => {
|
||||
const result = sortBadgesByFavorites({
|
||||
favoriteBadgeIds: [99],
|
||||
badges: [badge(1), badge(2)],
|
||||
patronTier: 2,
|
||||
});
|
||||
|
||||
expect(result.favoriteBadgeIds).toBeNull();
|
||||
});
|
||||
});
|
||||
49
app/features/user-page/core/badge-sorting.server.ts
Normal file
49
app/features/user-page/core/badge-sorting.server.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { isSupporter } from "~/modules/permissions/utils";
|
||||
|
||||
interface SortBadgesByFavoritesArgs<T extends { id: number }[]> {
|
||||
favoriteBadgeIds: number[] | null;
|
||||
badges: T;
|
||||
patronTier: number | null;
|
||||
}
|
||||
|
||||
export function sortBadgesByFavorites<T extends { id: number }[]>({
|
||||
favoriteBadgeIds,
|
||||
badges,
|
||||
patronTier,
|
||||
}: SortBadgesByFavoritesArgs<T>): {
|
||||
badges: T;
|
||||
favoriteBadgeIds: number[] | null;
|
||||
} {
|
||||
// filter out favorite badges no longer owner of
|
||||
let filteredFavoriteIds =
|
||||
favoriteBadgeIds?.filter((badgeId) =>
|
||||
badges.some((badge) => badge.id === badgeId),
|
||||
) ?? null;
|
||||
|
||||
if (filteredFavoriteIds?.length === 0) {
|
||||
filteredFavoriteIds = null;
|
||||
}
|
||||
|
||||
filteredFavoriteIds = isSupporter({ patronTier })
|
||||
? filteredFavoriteIds
|
||||
: filteredFavoriteIds
|
||||
? [filteredFavoriteIds[0]]
|
||||
: null;
|
||||
|
||||
// non-supporters can only have one favorite badge, handle losing supporter status
|
||||
const sortedBadges = badges.toSorted((a, b) => {
|
||||
const aIdx = filteredFavoriteIds?.indexOf(a.id) ?? -1;
|
||||
const bIdx = filteredFavoriteIds?.indexOf(b.id) ?? -1;
|
||||
|
||||
if (aIdx !== bIdx) {
|
||||
if (aIdx === -1) return 1;
|
||||
if (bIdx === -1) return -1;
|
||||
|
||||
return aIdx - bIdx;
|
||||
}
|
||||
|
||||
return b.id - a.id;
|
||||
}) as T;
|
||||
|
||||
return { badges: sortedBadges, favoriteBadgeIds: filteredFavoriteIds };
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user