Scope my events hosting list to author and explicit organizers, organization events on the my events page

This commit is contained in:
Kalle
2026-06-16 11:30:19 +03:00
parent 40ac14eb68
commit c141591269
23 changed files with 59 additions and 42 deletions

View File

@@ -7,14 +7,16 @@ import styles from "./SubNav.module.css";
export function SubNav({
children,
secondary,
className,
}: {
children: React.ReactNode;
secondary?: boolean;
className?: string;
}) {
return (
<div>
<nav
className={clsx(styles.container, {
className={clsx(styles.container, className, {
[styles.secondary]: secondary,
})}
>

View File

@@ -42,6 +42,8 @@ export interface CalendarEvent extends CommonEvent {
export interface ShowcaseCalendarEvent extends CommonEvent {
type: "showcase";
startTime: number;
/** Id of the organization the event belongs to, if any */
organizationId: number | null;
/** Tournament is hidden from the public (test tournament) */
hidden: boolean;
isFinalized: boolean;

View File

@@ -6,16 +6,25 @@ import {
tournamentToSidebarEvent,
} from "~/features/sidebar/core/sidebar.server";
import * as SavedCalendarEventRepository from "~/features/tournament/SavedCalendarEventRepository.server";
import * as TournamentOrganizationRepository from "~/features/tournament-organization/TournamentOrganizationRepository.server";
export type EventsLoaderData = typeof loader;
export const loader = async () => {
const user = requireUser();
const [tournamentsData, scrimsData, savedTournaments] = await Promise.all([
const [
tournamentsData,
scrimsData,
savedTournaments,
upcomingTournaments,
userOrganizations,
] = await Promise.all([
ShowcaseTournaments.categorizedTournamentsByUserId(user.id),
ScrimPostRepository.findUserScrims(user.id),
SavedCalendarEventRepository.upcoming(user.id),
ShowcaseTournaments.upcomingTournaments(),
TournamentOrganizationRepository.findByUserId(user.id),
]);
const registered = tournamentsData.participatingFor
@@ -34,5 +43,16 @@ export const loader = async () => {
.map(tournamentToSidebarEvent)
.sort((a, b) => a.startTime - b.startTime);
return { registered, hosting, scrims, saved };
const userOrganizationIds = new Set(userOrganizations.map((org) => org.id));
const organization = upcomingTournaments
.filter(
(tournament) =>
!tournament.hidden &&
tournament.organizationId !== null &&
userOrganizationIds.has(tournament.organizationId),
)
.map(tournamentToSidebarEvent)
.sort((a, b) => a.startTime - b.startTime);
return { registered, hosting, scrims, saved, organization };
};

View File

@@ -6,3 +6,7 @@
gap: var(--s-2);
margin-block-end: var(--s-2);
}
.subNav {
justify-content: start;
}

View File

@@ -14,7 +14,13 @@ export const handle: SendouRouteHandle = {
i18n: ["calendar"],
};
const VIEW_FILTERS = ["registered", "hosting", "scrims", "saved"] as const;
const VIEW_FILTERS = [
"registered",
"hosting",
"scrims",
"saved",
"organization",
] as const;
type ViewFilter = (typeof VIEW_FILTERS)[number];
export default function EventsPage() {
@@ -33,29 +39,19 @@ export default function EventsPage() {
hosting: `${t("calendar:events.view.hosting")} (${data.hosting.length})`,
scrims: `${t("calendar:events.view.scrims")} (${data.scrims.length})`,
saved: `${t("calendar:events.view.saved")} (${data.saved.length})`,
organization: `${t("calendar:events.view.organization")} (${data.organization.length})`,
};
const shownEvents =
filter === "registered"
? data.registered
: filter === "hosting"
? data.hosting
: filter === "saved"
? data.saved
: data.scrims;
const shownEvents = data[filter];
const hasNoEventsAtAll =
data.registered.length === 0 &&
data.hosting.length === 0 &&
data.scrims.length === 0 &&
data.saved.length === 0;
const hasNoEventsAtAll = VIEW_FILTERS.every((key) => data[key].length === 0);
return (
<Main halfWidth>
<div className={styles.eventsListHeader}>
<h2 className="text-lg mx-2">{t("calendar:events.title")}</h2>
{hasNoEventsAtAll ? null : (
<SubNav secondary>
<SubNav secondary className={styles.subNav}>
{VIEW_FILTERS.map((value) => (
<SubNavLink
key={value}

View File

@@ -275,10 +275,6 @@ async function tournamentsToParticipationInfoMap(
addToMap(userId, tournament.id, "organizer");
}
for (const { userId } of tournament.organizationMembers) {
addToMap(userId, tournament.id, "organizer");
}
addToMap(tournament.authorId, tournament.id, "organizer");
}
@@ -304,6 +300,7 @@ function mapTournamentFromDB(
url: tournamentPage(tournament.id),
id: tournament.id,
authorId: tournament.authorId,
organizationId: tournament.organizationId,
name: tournament.name,
startTime: tournament.startTime,
teamsCount: tournament.teamsCount,

View File

@@ -465,25 +465,6 @@ export function relatedUsersByTournamentIds(tournamentIds: number[]) {
.whereRef("TournamentStaff.tournamentId", "=", "Tournament.id")
.where("TournamentStaff.role", "=", "ORGANIZER"),
).as("staff"),
jsonArrayFrom(
eb
.selectFrom("TournamentOrganization")
.innerJoin(
"TournamentOrganizationMember",
"TournamentOrganization.id",
"TournamentOrganizationMember.organizationId",
)
.select(["TournamentOrganizationMember.userId"])
.whereRef(
"TournamentOrganization.id",
"=",
"CalendarEvent.organizationId",
)
.where("TournamentOrganizationMember.role", "in", [
"ADMIN",
"ORGANIZER",
]),
).as("organizationMembers"),
jsonArrayFrom(
eb
.selectFrom("TournamentTeam")
@@ -499,7 +480,6 @@ export function relatedUsersByTournamentIds(tournamentIds: number[]) {
.where("Tournament.id", "in", tournamentIds)
.$narrowType<{
staff: NotNull;
organizationMembers: NotNull;
teamMembers: NotNull;
}>()
.execute();

View File

@@ -85,6 +85,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -85,6 +85,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -85,6 +85,7 @@
"events.view.hosting": "Hosting",
"events.view.scrims": "Scrims",
"events.view.saved": "Saved",
"events.view.organization": "Organization",
"events.empty": "No events in this category",
"events.emptyAll": "You have no upcoming events.",
"events.findOnCalendar": "Find an event to join on the calendar!"

View File

@@ -87,6 +87,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -87,6 +87,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -87,6 +87,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -87,6 +87,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -87,6 +87,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -87,6 +87,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -81,6 +81,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -81,6 +81,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -85,6 +85,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -89,6 +89,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -87,6 +87,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -89,6 +89,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""

View File

@@ -81,6 +81,7 @@
"events.view.hosting": "",
"events.view.scrims": "",
"events.view.saved": "",
"events.view.organization": "",
"events.empty": "",
"events.emptyAll": "",
"events.findOnCalendar": ""