Show text if in trusted group someone rejoined queue

This commit is contained in:
Kalle
2026-09-20 10:42:28 +03:00
parent 52a6f7fd11
commit 442d5845a2
21 changed files with 112 additions and 11 deletions

View File

@@ -58,9 +58,11 @@ export function MatchmadeRejoinSection({
export function TrustedRejoinSection({
viewerGroup,
hasJoinedNewGroup,
someGroupMemberHasJoinedNewGroup,
}: {
viewerGroup: NonNullable<SendouQMatchLoaderData["match"]["groupAlpha"]>;
hasJoinedNewGroup: boolean;
someGroupMemberHasJoinedNewGroup: boolean;
}) {
const { t } = useTranslation(["q"]);
const lookAgain = useActionSubmit(matchSchema);
@@ -77,6 +79,15 @@ export function TrustedRejoinSection({
);
}
// the whole group has to be free for it, so offering it here could only fail
if (someGroupMemberHasJoinedNewGroup) {
return (
<RejoinQueueSection
explanation={t("q:match.rematch.memberJoinedNewGroup")}
/>
);
}
return (
<div className="stack md items-center">
<SendouButton
@@ -96,14 +107,18 @@ export function TrustedRejoinSection({
function DeclinedSection() {
const { t } = useTranslation(["q"]);
return <RejoinQueueSection explanation={t("q:match.rematch.declined")} />;
}
function RejoinQueueSection({ explanation }: { explanation: string }) {
const { t } = useTranslation(["q"]);
const rejoinQueue = useActionSubmit(frontPageSchema, {
action: SENDOUQ_PAGE,
});
return (
<div className="stack md items-center">
<p className="text-lighter text-sm text-center">
{t("q:match.rematch.declined")}
</p>
<p className="text-lighter text-sm text-center">{explanation}</p>
<SendouButton
variant="minimal"
className="text-sm font-bold"

View File

@@ -286,6 +286,9 @@ function RequeueTab({
<TrustedRejoinSection
viewerGroup={viewerGroup}
hasJoinedNewGroup={data.hasJoinedNewGroup}
someGroupMemberHasJoinedNewGroup={
data.someGroupMemberHasJoinedNewGroup
}
/>
) : null}
{isOnReporterTeam ? <hr className={styles.divider} /> : null}

View File

@@ -1,7 +1,9 @@
import { beforeEach, describe, expect, test } from "vitest";
import * as SQGroupFactory from "~/db/seed/factories/SQGroupFactory";
import * as SQMatchFactory from "~/db/seed/factories/SQMatchFactory";
import * as UserFactory from "~/db/seed/factories/UserFactory";
import { db } from "~/db/sql";
import { refreshSendouQInstance } from "~/features/sendouq/core/SendouQ.server";
import type { SerializeFrom } from "~/utils/remix";
import { wrappedLoader } from "~/utils/Test";
import { loader } from "./q.match.$id.server";
@@ -21,11 +23,14 @@ describe("q match loader", () => {
await users.create(10);
});
const createMatch = () =>
SQMatchFactory.create({
alphaUserIds: alphaUserIds(),
bravoUserIds: bravoUserIds(),
});
const createMatch = (options: { isConcluded?: boolean } = {}) =>
SQMatchFactory.create(
{
alphaUserIds: alphaUserIds(),
bravoUserIds: bravoUserIds(),
},
options,
);
const groupChatRoomId = async (groupId: number) =>
(
@@ -93,4 +98,50 @@ describe("q match loader", () => {
expect(data.chatRooms).toEqual([]);
});
describe("requeueing with the same group", () => {
const queueElsewhere = async (userId: number) => {
await SQGroupFactory.create({ memberUserIds: [userId] });
await refreshSendouQInstance();
};
test("offers the requeue while every member is free of other groups", async () => {
const match = await createMatch({ isConcluded: true });
await refreshSendouQInstance();
const data = await loadAs(alphaUserIds()[0], match.id);
expect(data.hasJoinedNewGroup).toBe(false);
expect(data.someGroupMemberHasJoinedNewGroup).toBe(false);
});
test("points the member who queued elsewhere to their new group", async () => {
const match = await createMatch({ isConcluded: true });
await queueElsewhere(alphaUserIds()[1]);
const data = await loadAs(alphaUserIds()[1], match.id);
expect(data.hasJoinedNewGroup).toBe(true);
});
test("blocks the requeue for the rest of the group too", async () => {
const match = await createMatch({ isConcluded: true });
await queueElsewhere(alphaUserIds()[1]);
const data = await loadAs(alphaUserIds()[0], match.id);
expect(data.hasJoinedNewGroup).toBe(false);
expect(data.someGroupMemberHasJoinedNewGroup).toBe(true);
});
test("leaves the other group's requeue alone", async () => {
const match = await createMatch({ isConcluded: true });
await queueElsewhere(alphaUserIds()[1]);
const data = await loadAs(bravoUserIds()[0], match.id);
expect(data.hasJoinedNewGroup).toBe(false);
expect(data.someGroupMemberHasJoinedNewGroup).toBe(false);
});
});
});

View File

@@ -46,12 +46,23 @@ export const loader = async ({ params }: LoaderFunctionArgs) => {
const match = SendouQ.mapMatch(matchUnmapped, user);
const currentGroup = user ? SendouQ.findOwnGroup(user.id) : undefined;
const viewerGroup = user
? [matchUnmapped.groupAlpha, matchUnmapped.groupBravo].find((group) =>
group.members.some((member) => member.id === user.id),
)
: undefined;
const joinedNewGroup = (userId: number) => {
const currentGroup = SendouQ.findOwnGroup(userId);
return Boolean(currentGroup && currentGroup.matchId !== matchId);
};
return {
// e.g. the group already requeued, so the viewer has nothing left to requeue with
hasJoinedNewGroup: Boolean(
currentGroup && currentGroup.matchId !== matchId,
hasJoinedNewGroup: Boolean(user && joinedNewGroup(user.id)),
// requeueing with the same group needs every member of it free of other groups
someGroupMemberHasJoinedNewGroup: Boolean(
viewerGroup?.members.some((member) => joinedNewGroup(member.id)),
),
...(await UserCardRepository.findAllByUserIds({
userIds: matchUsers,

View File

@@ -0,0 +1,5 @@
---
navItem: sendouq
type: bug
---
"Look again with same group" is no longer offered when someone from your group has already joined another group. Instead you are told so and can rejoin the queue right away

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "No, I'm done",
"match.rematch.vote.noConfirm": "Vote no? You can't change your vote afterwards.",
"match.rematch.declined": "You are not continuing with this group",
"match.rematch.memberJoinedNewGroup": "A member of your group already joined another group",
"match.rematch.fizzled": "Nobody wanted to continue",
"match.rematch.rejoinQueue": "Rejoin queue",
"match.rematch.backToQueue": "Back to queue",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "No, he terminado",
"match.rematch.vote.noConfirm": "¿Votar no? No podrás cambiar tu voto después.",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "Nadie quiso continuar",
"match.rematch.rejoinQueue": "Volver a la cola",
"match.rematch.backToQueue": "Volver a la cola",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "No, he terminado",
"match.rematch.vote.noConfirm": "¿Votar no? No podrás cambiar tu voto después.",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "Nadie quiso continuar",
"match.rematch.rejoinQueue": "Volver a la cola",
"match.rematch.backToQueue": "Volver a la cola",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "",
"match.rematch.vote.noConfirm": "",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "",
"match.rematch.rejoinQueue": "",
"match.rematch.backToQueue": "",

View File

@@ -165,6 +165,7 @@
"match.rematch.vote.no": "不,到此为止",
"match.rematch.vote.noConfirm": "确认投反对票吗?投票后将无法更改。",
"match.rematch.declined": "",
"match.rematch.memberJoinedNewGroup": "",
"match.rematch.fizzled": "无人想要继续排队",
"match.rematch.rejoinQueue": "重新加入队列",
"match.rematch.backToQueue": "返回队列",