mirror of
https://github.com/UiO-Gaming/name-100-uio-gamers.git
synced 2026-11-05 13:56:53 +01:00
fix duplicate displayname/nickname matching issue
the matching logic now handles cases where there are multiple people with the same nickname or global name
This commit is contained in:
4 files changed
+68
-25
No files matched your search
@@ -81,7 +81,7 @@ function memberMatchesInput(member: DiscordGuildMember, normalizedInput: string)
|
||||
return username === normalizedInput || globalName === normalizedInput || nickname === normalizedInput;
|
||||
}
|
||||
|
||||
export async function findDiscordMember(input: string): Promise<Match> {
|
||||
export async function findDiscordMember(input: string, guessedIds: string[] = []): Promise<Match> {
|
||||
const payingMemberRoleId = process.env.DISCORD_REQUIRED_ROLE_ID;
|
||||
|
||||
if (!payingMemberRoleId) {
|
||||
@@ -96,31 +96,25 @@ export async function findDiscordMember(input: string): Promise<Match> {
|
||||
|
||||
try {
|
||||
const members = await getDiscordMembers();
|
||||
const payingMembers = members.filter((member) => member.roles.includes(payingMemberRoleId));
|
||||
const normalizedInput = normalizeInput(input);
|
||||
|
||||
// First check if any member matches the input (regardless of role)
|
||||
const anyMatchingMember = members.find((member) => memberMatchesInput(member, normalizedInput));
|
||||
const allMatchingMembers = members.filter((member) => memberMatchesInput(member, normalizedInput));
|
||||
|
||||
// If member exists but doesn't have the paying member role
|
||||
if (anyMatchingMember && !anyMatchingMember.roles.includes(payingMemberRoleId)) {
|
||||
return {
|
||||
input,
|
||||
name: getDisplayName(anyMatchingMember),
|
||||
description: undefined,
|
||||
translationKey: "notPayingMember",
|
||||
correct: false,
|
||||
};
|
||||
if (allMatchingMembers.length === 0) {
|
||||
return { input, name: undefined, description: undefined, correct: false };
|
||||
}
|
||||
|
||||
// Find matching member among paying members
|
||||
const matchingMember = payingMembers.find((member) => memberMatchesInput(member, normalizedInput));
|
||||
const payingMembers = allMatchingMembers.filter((member) => member.roles.includes(payingMemberRoleId));
|
||||
const nonPayingMembers = allMatchingMembers.filter((member) => !member.roles.includes(payingMemberRoleId));
|
||||
|
||||
if (matchingMember) {
|
||||
const displayName = getDisplayName(matchingMember);
|
||||
const username = matchingMember.user.username;
|
||||
const unguessedPayingMember = payingMembers.find((member) => !guessedIds.includes(member.user.id));
|
||||
|
||||
if (unguessedPayingMember) {
|
||||
const displayName = getDisplayName(unguessedPayingMember);
|
||||
const username = unguessedPayingMember.user.username;
|
||||
|
||||
return {
|
||||
id: unguessedPayingMember.user.id,
|
||||
input,
|
||||
name: displayName,
|
||||
description: displayName === username ? undefined : username,
|
||||
@@ -128,6 +122,49 @@ export async function findDiscordMember(input: string): Promise<Match> {
|
||||
};
|
||||
}
|
||||
|
||||
const unguessedNonPayingMember = nonPayingMembers.find((member) => !guessedIds.includes(member.user.id));
|
||||
|
||||
if (unguessedNonPayingMember) {
|
||||
return {
|
||||
id: unguessedNonPayingMember.user.id,
|
||||
input,
|
||||
name: getDisplayName(unguessedNonPayingMember),
|
||||
description: undefined,
|
||||
translationKey: "notPayingMember",
|
||||
correct: false,
|
||||
};
|
||||
}
|
||||
|
||||
// If we are here, all matching members (paying or not) have been guessed.
|
||||
// Return the first paying member match to signal a duplicate to the client.
|
||||
if (payingMembers.length > 0) {
|
||||
const firstPayingMatch = payingMembers[0];
|
||||
const displayName = getDisplayName(firstPayingMatch);
|
||||
const username = firstPayingMatch.user.username;
|
||||
|
||||
return {
|
||||
id: firstPayingMatch.user.id,
|
||||
input,
|
||||
name: displayName,
|
||||
description: displayName === username ? undefined : username,
|
||||
correct: true, // It is a correct member, but already guessed.
|
||||
};
|
||||
}
|
||||
|
||||
// If no paying members matched, return the first non-paying member.
|
||||
if (nonPayingMembers.length > 0) {
|
||||
const firstNonPayingMatch = nonPayingMembers[0];
|
||||
return {
|
||||
id: firstNonPayingMatch.user.id,
|
||||
input,
|
||||
name: getDisplayName(firstNonPayingMatch),
|
||||
description: undefined,
|
||||
translationKey: "notPayingMember",
|
||||
correct: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Should not be reached if allMatchingMembers.length > 0
|
||||
return {
|
||||
input,
|
||||
name: undefined,
|
||||
|
||||
@@ -9,7 +9,7 @@ export async function POST(request: Request) {
|
||||
if (!session) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
}
|
||||
const { input } = await request.json();
|
||||
const match: Match = await findDiscordMember(input);
|
||||
const { input, guessedIds } = await request.json();
|
||||
const match: Match = await findDiscordMember(input, guessedIds);
|
||||
return NextResponse.json(match);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ export default function HomeClient({ session }: { session: Session }) {
|
||||
e.preventDefault();
|
||||
const trimmedInput = input.trim();
|
||||
if (!trimmedInput) return;
|
||||
if (matches.some((m) => m.input.toLowerCase() === trimmedInput.toLowerCase())) {
|
||||
if (matches.some((m) => m.input.toLowerCase() === trimmedInput.toLowerCase() && !m.name)) {
|
||||
setRepeatMessage(t.alreadySubmitted);
|
||||
return;
|
||||
}
|
||||
@@ -81,19 +81,24 @@ export default function HomeClient({ session }: { session: Session }) {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const guessedIds = matches.filter((m) => m.correct && m.id).map((m) => m.id!);
|
||||
|
||||
const res = await fetch("/api/guess", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ input: trimmedInput }),
|
||||
body: JSON.stringify({ input: trimmedInput, guessedIds }),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
if (data.name && matches.some((m) => m.name && m.name.toLowerCase() === data.name.toLowerCase())) {
|
||||
const data = (await res.json()) as Match;
|
||||
|
||||
if (data.id && matches.some((m) => m.id && m.id === data.id)) {
|
||||
setRepeatMessage(t.alreadySubmitted);
|
||||
setInput("");
|
||||
return;
|
||||
}
|
||||
setMatches((prev) => [...prev, { input: trimmedInput, ...data }]);
|
||||
setMatches((prev) => [...prev, data]);
|
||||
|
||||
if (data.correct && !timerStarted) {
|
||||
startTimer();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export interface Match {
|
||||
id?: string;
|
||||
input: string;
|
||||
name: string | undefined;
|
||||
description: string | undefined;
|
||||
|
||||
Reference in new issue
Block a user