mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-24 12:06:54 -05:00
Sort truster selects by team (#1893)
* Initial * Main team first * Sorting, deduplicating * To SQ * No "Others" if also no teams
This commit is contained in:
@@ -278,9 +278,10 @@ export function deletePrivateUserNote({
|
||||
}
|
||||
|
||||
export async function usersThatTrusted(userId: number) {
|
||||
const teamIds = await db
|
||||
const teams = await db
|
||||
.selectFrom("TeamMemberWithSecondary")
|
||||
.select("teamId")
|
||||
.innerJoin("Team", "Team.id", "TeamMemberWithSecondary.teamId")
|
||||
.select(["Team.id", "Team.name", "TeamMemberWithSecondary.isMainTeam"])
|
||||
.where("userId", "=", userId)
|
||||
.execute();
|
||||
|
||||
@@ -288,24 +289,47 @@ export async function usersThatTrusted(userId: number) {
|
||||
.selectFrom("TeamMemberWithSecondary")
|
||||
.innerJoin("User", "User.id", "TeamMemberWithSecondary.userId")
|
||||
.innerJoin("UserFriendCode", "UserFriendCode.userId", "User.id")
|
||||
.select([...COMMON_USER_FIELDS, "User.inGameName"])
|
||||
.select([
|
||||
...COMMON_USER_FIELDS,
|
||||
"User.inGameName",
|
||||
"TeamMemberWithSecondary.teamId",
|
||||
])
|
||||
.where(
|
||||
"TeamMemberWithSecondary.teamId",
|
||||
"in",
|
||||
teamIds.map((t) => t.teamId),
|
||||
teams.map((t) => t.id),
|
||||
)
|
||||
.union((eb) =>
|
||||
eb
|
||||
.selectFrom("TrustRelationship")
|
||||
.innerJoin("User", "User.id", "TrustRelationship.trustGiverUserId")
|
||||
.innerJoin("UserFriendCode", "UserFriendCode.userId", "User.id")
|
||||
.select([...COMMON_USER_FIELDS, "User.inGameName"])
|
||||
.select([
|
||||
...COMMON_USER_FIELDS,
|
||||
"User.inGameName",
|
||||
sql.raw<any>("null").as("teamId"),
|
||||
])
|
||||
.where("TrustRelationship.trustReceiverUserId", "=", userId),
|
||||
)
|
||||
.orderBy("User.username asc")
|
||||
.execute();
|
||||
|
||||
const rowsWithoutBanned = rows.filter((row) => !userIsBanned(row.id));
|
||||
|
||||
return rowsWithoutBanned;
|
||||
const teamMemberIds = rowsWithoutBanned
|
||||
.filter((row) => row.teamId)
|
||||
.map((row) => row.id);
|
||||
|
||||
// we want user to show twice if member of two different teams
|
||||
// but we don't want a user from the team to show in teamless section
|
||||
const deduplicatedRows = rowsWithoutBanned.filter(
|
||||
(row) => row.teamId || !teamMemberIds.includes(row.id),
|
||||
);
|
||||
|
||||
// done here at not sql just because it was easier to do here ignoring case
|
||||
deduplicatedRows.sort((a, b) => a.username.localeCompare(b.username));
|
||||
|
||||
return {
|
||||
teams: teams.sort((a, b) => b.isMainTeam - a.isMainTeam),
|
||||
trusters: deduplicatedRows,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ function TrusterDropdown({
|
||||
groupMemberIds: number[];
|
||||
}) {
|
||||
const { t } = useTranslation(["q"]);
|
||||
const { trusters } = useTrusted();
|
||||
const { trusters, teams } = useTrusted();
|
||||
|
||||
if (!trusters || trusters.length === 0) {
|
||||
return (
|
||||
@@ -115,6 +115,16 @@ function TrusterDropdown({
|
||||
(truster) => !groupMemberIds.includes(truster.id),
|
||||
);
|
||||
|
||||
const othersOptions = trustersNotInGroup
|
||||
.filter((player) => !player.teamId)
|
||||
.map((player) => {
|
||||
return (
|
||||
<option key={player.id} value={player.id}>
|
||||
{player.username}
|
||||
</option>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<select
|
||||
name="id"
|
||||
@@ -124,14 +134,28 @@ function TrusterDropdown({
|
||||
}
|
||||
className="q__member-adder__input"
|
||||
>
|
||||
<option value="">{t("q:looking.groups.adder.selectUser")}</option>
|
||||
{trustersNotInGroup.map((player) => {
|
||||
{teams?.map((team) => {
|
||||
return (
|
||||
<option key={player.id} value={player.id}>
|
||||
{player.username}
|
||||
</option>
|
||||
<optgroup label={team.name} key={team.id}>
|
||||
{trustersNotInGroup
|
||||
.filter((player) => player.teamId === team.id)
|
||||
.map((player) => {
|
||||
return (
|
||||
<option key={player.id} value={player.id}>
|
||||
{player.username}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</optgroup>
|
||||
);
|
||||
})}
|
||||
{teams && teams.length > 0 ? (
|
||||
<optgroup label={t("q:looking.groups.adder.others")}>
|
||||
{othersOptions}
|
||||
</optgroup>
|
||||
) : (
|
||||
othersOptions
|
||||
)}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ export const action = async ({ request }: ActionFunctionArgs) => {
|
||||
}
|
||||
|
||||
validate(
|
||||
(await QRepository.usersThatTrusted(user.id)).some(
|
||||
(await QRepository.usersThatTrusted(user.id)).trusters.some(
|
||||
(trusterUser) => trusterUser.id === data.id,
|
||||
),
|
||||
"Not trusted",
|
||||
|
||||
@@ -200,7 +200,7 @@ export const action: ActionFunction = async ({ request, params }) => {
|
||||
);
|
||||
validate(ownTeam);
|
||||
validate(
|
||||
(await QRepository.usersThatTrusted(user.id)).some(
|
||||
(await QRepository.usersThatTrusted(user.id)).trusters.some(
|
||||
(trusterPlayer) => trusterPlayer.id === data.userId,
|
||||
),
|
||||
"No trust given from this user",
|
||||
|
||||
@@ -903,7 +903,7 @@ function FillRoster({
|
||||
(ownTeamCheckedIn && ownTeamMembers.length > tournament.minMembersPerTeam);
|
||||
|
||||
const playersAvailableToDirectlyAdd = (() => {
|
||||
return (data!.trusterPlayers ?? []).filter((user) => {
|
||||
return (data!.trusterPlayers?.trusters ?? []).filter((user) => {
|
||||
const isNotInTeam = tournament.ctx.teams.every((team) =>
|
||||
team.members.every((member) => member.userId !== user.id),
|
||||
);
|
||||
@@ -926,7 +926,10 @@ function FillRoster({
|
||||
<section className="tournament__section stack lg items-center">
|
||||
{playersAvailableToDirectlyAdd.length > 0 && canAddMembers ? (
|
||||
<>
|
||||
<DirectlyAddPlayerSelect players={playersAvailableToDirectlyAdd} />
|
||||
<DirectlyAddPlayerSelect
|
||||
players={playersAvailableToDirectlyAdd}
|
||||
teams={data!.trusterPlayers?.teams ?? []}
|
||||
/>
|
||||
<Divider className="text-uppercase">{t("common:or")}</Divider>
|
||||
</>
|
||||
) : null}
|
||||
@@ -1015,13 +1018,25 @@ function FillRoster({
|
||||
|
||||
function DirectlyAddPlayerSelect({
|
||||
players,
|
||||
teams,
|
||||
}: {
|
||||
players: { id: number; username: string }[];
|
||||
players: { id: number; username: string; teamId?: number }[];
|
||||
teams: { id: number; name: string }[];
|
||||
}) {
|
||||
const { t } = useTranslation(["tournament", "common"]);
|
||||
const fetcher = useFetcher();
|
||||
const id = React.useId();
|
||||
|
||||
const othersOptions = players
|
||||
.filter((player) => !player.teamId)
|
||||
.map((player) => {
|
||||
return (
|
||||
<option key={player.id} value={player.id}>
|
||||
{player.username}
|
||||
</option>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<fetcher.Form method="post" className="stack horizontal sm items-end">
|
||||
<div>
|
||||
@@ -1029,13 +1044,26 @@ function DirectlyAddPlayerSelect({
|
||||
{t("tournament:pre.roster.addTrusted.header")}
|
||||
</Label>
|
||||
<select id={id} name="userId">
|
||||
{players.map((player) => {
|
||||
{teams.map((team) => {
|
||||
return (
|
||||
<option key={player.id} value={player.id}>
|
||||
{player.username}
|
||||
</option>
|
||||
<optgroup label={team.name} key={team.id}>
|
||||
{players
|
||||
.filter((player) => player.teamId === team.id)
|
||||
.map((player) => {
|
||||
return (
|
||||
<option key={player.id} value={player.id}>
|
||||
{player.username}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</optgroup>
|
||||
);
|
||||
})}
|
||||
{teams && teams.length > 0 ? (
|
||||
<optgroup label="Others">{othersOptions}</optgroup>
|
||||
) : (
|
||||
othersOptions
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<SubmitButton
|
||||
|
||||
@@ -60,7 +60,8 @@ export function useTrusted() {
|
||||
);
|
||||
|
||||
return {
|
||||
trusters: data?.trusters,
|
||||
trusters: data?.trusters.trusters,
|
||||
teams: data?.trusters.teams,
|
||||
isLoading: !error && !data,
|
||||
isError: error,
|
||||
};
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
"looking.groups.actions.goBack": "Go back",
|
||||
"looking.groups.adder.quickAdd": "Quick add",
|
||||
"looking.groups.adder.error": "That user is already in a group",
|
||||
"looking.groups.adder.selectUser": "Select user",
|
||||
"looking.groups.adder.others": "Others",
|
||||
"looking.groups.adder.inviteLink": "Invite link",
|
||||
"looking.groups.editNote": "Edit note",
|
||||
"looking.groups.addNote": "Add note",
|
||||
|
||||
@@ -109,7 +109,6 @@
|
||||
"looking.groups.actions.goBack": "Regresar",
|
||||
"looking.groups.adder.quickAdd": "Añadir rapido",
|
||||
"looking.groups.adder.error": "Ese usuario ya está en un grupo",
|
||||
"looking.groups.adder.selectUser": "Elegir usuario",
|
||||
"looking.groups.adder.inviteLink": "Enlace de invitación",
|
||||
"looking.groups.editNote": "Editar nota",
|
||||
"looking.groups.addNote": "Añadir nota",
|
||||
|
||||
@@ -109,7 +109,6 @@
|
||||
"looking.groups.actions.goBack": "Regresar",
|
||||
"looking.groups.adder.quickAdd": "Añadir rápido",
|
||||
"looking.groups.adder.error": "Ese usuario ya está en un grupo",
|
||||
"looking.groups.adder.selectUser": "Elegir usuario",
|
||||
"looking.groups.adder.inviteLink": "Enlace de invitación",
|
||||
"looking.groups.editNote": "Editar nota",
|
||||
"looking.groups.addNote": "Añadir nota",
|
||||
|
||||
@@ -108,7 +108,6 @@
|
||||
"looking.groups.actions.goBack": "戻る",
|
||||
"looking.groups.adder.quickAdd": "クイック追加",
|
||||
"looking.groups.adder.error": "そのユーザーはグループに入っています",
|
||||
"looking.groups.adder.selectUser": "ユーザーを選択",
|
||||
"looking.groups.adder.inviteLink": "インバイトリンク",
|
||||
"looking.groups.editNote": "メモを編集する",
|
||||
"looking.groups.addNote": "メモを追加する",
|
||||
|
||||
@@ -107,7 +107,6 @@
|
||||
"looking.groups.actions.goBack": "Voltar",
|
||||
"looking.groups.adder.quickAdd": "Adicionar rapidamente (quick add)",
|
||||
"looking.groups.adder.error": "Esse usuário já está em um grupo",
|
||||
"looking.groups.adder.selectUser": "Selecionar usuário",
|
||||
"looking.groups.adder.inviteLink": "Link de convite",
|
||||
"looking.groups.editNote": "Editar nota",
|
||||
"looking.groups.addNote": "Adicionar nota",
|
||||
|
||||
@@ -94,7 +94,6 @@
|
||||
"looking.groups.actions.leaveQ": "Покинуть очередь",
|
||||
"looking.groups.actions.goBack": "Вернуться назад",
|
||||
"looking.groups.adder.quickAdd": "Быстро добавить",
|
||||
"looking.groups.adder.selectUser": "Выбрать пользователя",
|
||||
"looking.groups.adder.inviteLink": "Ссылка на приглашение",
|
||||
"looking.groups.editNote": "Изменить заметку",
|
||||
"looking.groups.addNote": "Добавить заметку",
|
||||
|
||||
@@ -108,7 +108,6 @@
|
||||
"looking.groups.actions.goBack": "返回",
|
||||
"looking.groups.adder.quickAdd": "快速添加",
|
||||
"looking.groups.adder.error": "该用户已加入其他小队",
|
||||
"looking.groups.adder.selectUser": "选择用户",
|
||||
"looking.groups.adder.inviteLink": "邀请链接",
|
||||
"looking.groups.editNote": "编辑笔记",
|
||||
"looking.groups.addNote": "添加笔记",
|
||||
|
||||
Reference in New Issue
Block a user