mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-28 22:31:22 -05:00
Sort in tournament LFG according to private note sentiment
This commit is contained in:
@@ -19,6 +19,7 @@ import { useUser } from "~/features/auth/core/user";
|
||||
import { useTopicRevalidation } from "~/features/chat/chat-hooks";
|
||||
import { useMarkSqLikesSeen } from "~/features/global-status/global-status-likes-seen";
|
||||
import type { UserCardData } from "~/features/user-card/user-card-types";
|
||||
import { privateNoteSentimentScore } from "~/features/user-card/user-card-utils";
|
||||
import { useDateTimeFormat } from "~/hooks/intl/useDateTimeFormat";
|
||||
import { useHydrated } from "~/hooks/useHydrated";
|
||||
import { useMainContentWidth } from "~/hooks/useMainContentWidth";
|
||||
@@ -478,18 +479,8 @@ function sortGroups<T extends { id: number; members?: { id: number }[] }>(
|
||||
suggestedGroupIds: Set<number>;
|
||||
},
|
||||
): T[] {
|
||||
const sentimentScore = (group: T) => {
|
||||
if (!group.members) return 0;
|
||||
|
||||
let score = 0;
|
||||
for (const member of group.members) {
|
||||
const sentiment = userCards.get(member.id)?.privateNote?.sentiment;
|
||||
if (sentiment === "NEGATIVE") return -1;
|
||||
if (sentiment === "POSITIVE") score = 1;
|
||||
}
|
||||
|
||||
return score;
|
||||
};
|
||||
const sentimentScore = (group: T) =>
|
||||
group.members ? privateNoteSentimentScore(group.members, userCards) : 0;
|
||||
|
||||
return groups.toSorted((a, b) => {
|
||||
const aIsSuggested = suggestedGroupIds.has(a.id);
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
UserCard,
|
||||
useUserCardData,
|
||||
} from "~/features/user-card/components/UserCard";
|
||||
import { privateNoteSentimentScore } from "~/features/user-card/user-card-utils";
|
||||
import { SendouForm } from "~/form/SendouForm";
|
||||
import { useHydrated } from "~/hooks/useHydrated";
|
||||
import { useMainContentWidth } from "~/hooks/useMainContentWidth";
|
||||
@@ -83,9 +84,13 @@ function GroupsView({
|
||||
data.ownGroup?.members.length ?? data.ownTeam?.members.length ?? 0;
|
||||
const availableSlots = tournament.maxMembersPerTeam - ownMemberCount;
|
||||
|
||||
const compatibleGroups = data.groups.filter(
|
||||
(group) => group.members.length <= availableSlots,
|
||||
);
|
||||
const compatibleGroups = data.groups
|
||||
.filter((group) => group.members.length <= availableSlots)
|
||||
.toSorted(
|
||||
(a, b) =>
|
||||
privateNoteSentimentScore(b.members, data.userCards) -
|
||||
privateNoteSentimentScore(a.members, data.userCards),
|
||||
);
|
||||
|
||||
const neutralGroups = compatibleGroups.filter(
|
||||
(group) =>
|
||||
|
||||
31
app/features/user-card/user-card-utils.test.ts
Normal file
31
app/features/user-card/user-card-utils.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import type { UserCardData } from "./user-card-types";
|
||||
import { privateNoteSentimentScore } from "./user-card-utils";
|
||||
|
||||
const cardWithSentiment = (sentiment: "POSITIVE" | "NEUTRAL" | "NEGATIVE") =>
|
||||
({
|
||||
privateNote: { text: "", sentiment, updatedAt: 0 },
|
||||
}) as unknown as UserCardData;
|
||||
|
||||
const userCards = new Map<number, UserCardData>([
|
||||
[1, cardWithSentiment("POSITIVE")],
|
||||
[2, cardWithSentiment("NEGATIVE")],
|
||||
[3, cardWithSentiment("NEUTRAL")],
|
||||
]);
|
||||
|
||||
describe("privateNoteSentimentScore", () => {
|
||||
test.each([
|
||||
{ why: "no notes", memberIds: [4, 5], expected: 0 },
|
||||
{ why: "neutral note", memberIds: [3], expected: 0 },
|
||||
{ why: "positive note", memberIds: [1, 4], expected: 1 },
|
||||
{ why: "negative note", memberIds: [2, 4], expected: -1 },
|
||||
{ why: "negative outweighs positive", memberIds: [1, 2], expected: -1 },
|
||||
])("$why", ({ memberIds, expected }) => {
|
||||
expect(
|
||||
privateNoteSentimentScore(
|
||||
memberIds.map((id) => ({ id })),
|
||||
userCards,
|
||||
),
|
||||
).toBe(expected);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import { USER_CARD } from "./user-card-constants";
|
||||
import type { UserCardData } from "./user-card-types";
|
||||
|
||||
/**
|
||||
* The claim must exceed the verified XP by no more than {@link USER_CARD.MAX_UNVERIFIED_XP_ABOVE_VERIFIED}.
|
||||
@@ -17,3 +18,21 @@ export function isValidUnverifiedXp({
|
||||
unverified <= verified + USER_CARD.MAX_UNVERIFIED_XP_ABOVE_VERIFIED
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scores a group by the viewer's private notes on its members: -1 if any member has a negative note,
|
||||
* 1 if any has a positive one (and none negative), otherwise 0. Sort descending to float liked groups up.
|
||||
*/
|
||||
export function privateNoteSentimentScore(
|
||||
members: { id: number }[],
|
||||
userCards: Map<number, UserCardData>,
|
||||
): number {
|
||||
let score = 0;
|
||||
for (const member of members) {
|
||||
const sentiment = userCards.get(member.id)?.privateNote?.sentiment;
|
||||
if (sentiment === "NEGATIVE") return -1;
|
||||
if (sentiment === "POSITIVE") score = 1;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
navItem: medal
|
||||
type: feature
|
||||
---
|
||||
Tournament LFG shows groups with players you have a positive private note on first and negative ones last, same as SendouQ
|
||||
Reference in New Issue
Block a user