diff --git a/app/components/EventsList.module.css b/app/components/EventsList.module.css
new file mode 100644
index 000000000..237139854
--- /dev/null
+++ b/app/components/EventsList.module.css
@@ -0,0 +1,8 @@
+.dayHeader {
+ padding: var(--s-2) var(--s-2) var(--s-1);
+ font-size: var(--font-2xs);
+ font-weight: var(--weight-bold);
+ color: var(--color-text-high);
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+}
diff --git a/app/components/EventsList.tsx b/app/components/EventsList.tsx
new file mode 100644
index 000000000..1e455ce22
--- /dev/null
+++ b/app/components/EventsList.tsx
@@ -0,0 +1,101 @@
+import { isToday, isTomorrow } from "date-fns";
+import { useTranslation } from "react-i18next";
+import type { SidebarEvent } from "~/features/sidebar/core/sidebar.server";
+import styles from "./EventsList.module.css";
+import { ListLink } from "./SideNav";
+
+export function EventsList({
+ events,
+ onClick,
+}: {
+ events: SidebarEvent[];
+ onClick?: () => void;
+}) {
+ const { t, i18n } = useTranslation(["front"]);
+
+ if (events.length === 0) {
+ return (
+
+ {t("front:sideNav.noEvents")}
+
+ );
+ }
+
+ const getDayKey = (timestamp: number) => {
+ const date = new Date(timestamp * 1000);
+ return date.toDateString();
+ };
+
+ const formatDayHeader = (date: Date) => {
+ if (isToday(date)) {
+ const rtf = new Intl.RelativeTimeFormat(i18n.language, {
+ numeric: "auto",
+ });
+ const str = rtf.format(0, "day");
+ return str.charAt(0).toUpperCase() + str.slice(1);
+ }
+ if (isTomorrow(date)) {
+ const rtf = new Intl.RelativeTimeFormat(i18n.language, {
+ numeric: "auto",
+ });
+ const str = rtf.format(1, "day");
+ return str.charAt(0).toUpperCase() + str.slice(1);
+ }
+ return date.toLocaleDateString(i18n.language, {
+ weekday: "long",
+ month: "short",
+ day: "numeric",
+ });
+ };
+
+ const formatTime = (date: Date) => {
+ return date.toLocaleTimeString(i18n.language, {
+ hour: "numeric",
+ minute: "2-digit",
+ });
+ };
+
+ const groupedEvents = events.reduce>(
+ (acc, event) => {
+ const key = getDayKey(event.startTime);
+ if (!acc[key]) {
+ acc[key] = [];
+ }
+ acc[key].push(event);
+ return acc;
+ },
+ {},
+ );
+
+ const dayKeys = Object.keys(groupedEvents);
+
+ return (
+ <>
+ {dayKeys.map((dayKey) => {
+ const dayEvents = groupedEvents[dayKey];
+ const firstDate = new Date(dayEvents[0].startTime * 1000);
+
+ return (
+
+
{formatDayHeader(firstDate)}
+ {dayEvents.map((event) => (
+
+ {event.scrimStatus === "booked"
+ ? t("front:sideNav.scrimVs", { opponent: event.name })
+ : event.scrimStatus === "looking"
+ ? t("front:sideNav.lookingForScrim")
+ : event.name}
+
+ ))}
+
+ );
+ })}
+ >
+ );
+}
diff --git a/app/components/MobileNav.module.css b/app/components/MobileNav.module.css
index 6efb2c533..60d9e3b8c 100644
--- a/app/components/MobileNav.module.css
+++ b/app/components/MobileNav.module.css
@@ -299,24 +299,24 @@
}
.panelSectionLink {
- display: block;
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ width: fit-content;
+ margin: var(--s-4) auto;
font-size: var(--font-2xs);
color: var(--color-text-high);
text-decoration: none;
- padding: var(--s-3) var(--s-2);
- text-align: center;
+ padding: var(--s-1) var(--s-3);
+ background-color: var(--color-bg-higher);
+ border-radius: var(--radius-field);
+
+ & svg {
+ stroke-width: 3;
+ }
}
.panelSectionLink:hover {
color: var(--color-text);
- text-decoration: underline;
-}
-
-.dayHeader {
- padding: var(--s-2) var(--s-2) var(--s-1);
- font-size: var(--font-2xs);
- font-weight: var(--weight-bold);
- color: var(--color-text-high);
- text-transform: uppercase;
- letter-spacing: 0.05em;
+ background-color: var(--color-bg-high);
}
diff --git a/app/components/MobileNav.tsx b/app/components/MobileNav.tsx
index edf34e7cd..370a951b5 100644
--- a/app/components/MobileNav.tsx
+++ b/app/components/MobileNav.tsx
@@ -1,7 +1,7 @@
import clsx from "clsx";
-import { isToday, isTomorrow } from "date-fns";
import {
Calendar,
+ ChevronRight,
LogIn,
Menu,
Settings,
@@ -18,12 +18,14 @@ import { useUser } from "~/features/auth/core/user";
import { FriendMenu } from "~/features/friends/components/FriendMenu";
import type { RootLoaderData } from "~/root";
import {
+ EVENTS_PAGE,
FRIENDS_PAGE,
navIconUrl,
SETTINGS_PAGE,
userPage,
} from "~/utils/urls";
import { Avatar } from "./Avatar";
+import { EventsList } from "./EventsList";
import { SendouButton } from "./elements/Button";
import { Image } from "./Image";
import { LogInButtonContainer } from "./layout/LogInButtonContainer";
@@ -34,7 +36,6 @@ import {
import { navItems } from "./layout/nav-items";
import styles from "./MobileNav.module.css";
import { NotificationDot } from "./NotificationDot";
-import { ListLink } from "./SideNav";
import { StreamListItems } from "./StreamListItems";
type SidebarData = RootLoaderData["sidebar"] | undefined;
@@ -302,6 +303,7 @@ function FriendsPanel({
onClick={onClose}
>
{t("common:actions.viewAll")}
+
);
@@ -314,91 +316,19 @@ function TourneysPanel({
events: NonNullable["events"];
onClose: () => void;
}) {
- const { t, i18n } = useTranslation(["front"]);
-
- const formatDayHeader = (date: Date) => {
- if (isToday(date)) {
- const rtf = new Intl.RelativeTimeFormat(i18n.language, {
- numeric: "auto",
- });
- const str = rtf.format(0, "day");
- return str.charAt(0).toUpperCase() + str.slice(1);
- }
- if (isTomorrow(date)) {
- const rtf = new Intl.RelativeTimeFormat(i18n.language, {
- numeric: "auto",
- });
- const str = rtf.format(1, "day");
- return str.charAt(0).toUpperCase() + str.slice(1);
- }
- return date.toLocaleDateString(i18n.language, {
- weekday: "long",
- month: "short",
- day: "numeric",
- });
- };
-
- const formatTime = (date: Date) => {
- return date.toLocaleTimeString(i18n.language, {
- hour: "numeric",
- minute: "2-digit",
- });
- };
-
- const getDayKey = (timestamp: number) => {
- const date = new Date(timestamp * 1000);
- return date.toDateString();
- };
-
- const groupedEvents = events.reduce>(
- (acc, event) => {
- const key = getDayKey(event.startTime);
- if (!acc[key]) {
- acc[key] = [];
- }
- acc[key].push(event);
- return acc;
- },
- {},
- );
-
- const dayKeys = Object.keys(groupedEvents);
+ const { t } = useTranslation(["front", "common"]);
return (
- {events.length > 0 ? (
- dayKeys.map((dayKey) => {
- const dayEvents = groupedEvents[dayKey];
- const firstDate = new Date(dayEvents[0].startTime * 1000);
-
- return (
-
-
- {formatDayHeader(firstDate)}
-
- {dayEvents.map((event) => (
-
- {event.scrimStatus === "booked"
- ? t("front:sideNav.scrimVs", { opponent: event.name })
- : event.scrimStatus === "looking"
- ? t("front:sideNav.lookingForScrim")
- : event.name}
-
- ))}
-
- );
- })
- ) : (
-
- {t("front:sideNav.noEvents")}
-
- )}
+
+
+ {t("common:actions.viewAll")}
+
+
);
}
diff --git a/app/components/layout/NotificationPopover.module.css b/app/components/layout/NotificationPopover.module.css
index 28693565f..7a5bb8c4b 100644
--- a/app/components/layout/NotificationPopover.module.css
+++ b/app/components/layout/NotificationPopover.module.css
@@ -44,3 +44,32 @@
.divider {
border-color: var(--color-border);
}
+
+.viewAllLink {
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ width: fit-content;
+ margin: var(--s-2) auto;
+ font-size: var(--font-2xs);
+ color: var(--color-text-high);
+ text-decoration: none;
+ padding: var(--s-1) var(--s-3);
+ background-color: var(--color-bg-higher);
+ border-radius: var(--radius-field);
+
+ & svg {
+ stroke-width: 3;
+ }
+}
+
+@media screen and (max-width: 599px) {
+ .viewAllLink {
+ margin-top: var(--s-4);
+ }
+}
+
+.viewAllLink:hover {
+ color: var(--color-text);
+ background-color: var(--color-bg-high);
+}
diff --git a/app/components/layout/NotificationPopover.tsx b/app/components/layout/NotificationPopover.tsx
index f2468e51a..2d365f9b8 100644
--- a/app/components/layout/NotificationPopover.tsx
+++ b/app/components/layout/NotificationPopover.tsx
@@ -1,7 +1,7 @@
-import { Bell, RefreshCcw } from "lucide-react";
+import { Bell, ChevronRight, RefreshCcw } from "lucide-react";
import * as React from "react";
import { useTranslation } from "react-i18next";
-import { useMatches, useRevalidator } from "react-router";
+import { Link, useMatches, useRevalidator } from "react-router";
import {
NotificationItem,
NotificationItemDivider,
@@ -11,7 +11,7 @@ import { NOTIFICATIONS } from "~/features/notifications/notifications-contants";
import type { RootLoaderData } from "~/root";
import { NOTIFICATIONS_URL } from "~/utils/urls";
import { useMarkNotificationsAsSeen } from "../../features/notifications/notifications-hooks";
-import { LinkButton, SendouButton } from "../elements/Button";
+import { SendouButton } from "../elements/Button";
import styles from "./NotificationPopover.module.css";
@@ -95,15 +95,15 @@ function NotificationsFooter({ onClose }: { onClose?: () => void }) {
return (
-
- {t("common:notifications.seeAll")}
-
+ {t("common:actions.viewAll")}
+
+
);
}
diff --git a/app/components/layout/index.tsx b/app/components/layout/index.tsx
index f6a015968..cd949b7fe 100644
--- a/app/components/layout/index.tsx
+++ b/app/components/layout/index.tsx
@@ -25,7 +25,12 @@ import { useUser } from "~/features/auth/core/user";
import { FriendMenu } from "~/features/friends/components/FriendMenu";
import type { RootLoaderData } from "~/root";
import type { Breadcrumb, SendouRouteHandle } from "~/utils/remix.server";
-import { FRIENDS_PAGE, SETTINGS_PAGE, userPage } from "~/utils/urls";
+import {
+ EVENTS_PAGE,
+ FRIENDS_PAGE,
+ SETTINGS_PAGE,
+ userPage,
+} from "~/utils/urls";
import { Avatar } from "../Avatar";
import { SendouButton } from "../elements/Button";
import { SendouPopover } from "../elements/Popover";
@@ -210,7 +215,17 @@ export function Layout({
const sideNavChildren = (
<>
- }>
+ }
+ action={
+ user ? (
+
+ {t("common:actions.viewAll")}
+
+
+ ) : null
+ }
+ >
{t("front:sideNav.myCalendar")}
{events.length > 0 ? (
diff --git a/app/features/calendar/loaders/events.server.ts b/app/features/calendar/loaders/events.server.ts
new file mode 100644
index 000000000..a201e6108
--- /dev/null
+++ b/app/features/calendar/loaders/events.server.ts
@@ -0,0 +1,32 @@
+import { requireUser } from "~/features/auth/core/user.server";
+import * as ShowcaseTournaments from "~/features/front-page/core/ShowcaseTournaments.server";
+import * as ScrimPostRepository from "~/features/scrims/ScrimPostRepository.server";
+import {
+ scrimToSidebarEvent,
+ tournamentToSidebarEvent,
+} from "~/features/sidebar/core/sidebar.server";
+
+export type EventsLoaderData = typeof loader;
+
+export const loader = async () => {
+ const user = requireUser();
+
+ const [tournamentsData, scrimsData] = await Promise.all([
+ ShowcaseTournaments.frontPageTournamentsByUserId(user.id),
+ ScrimPostRepository.findUserScrims(user.id),
+ ]);
+
+ const registered = tournamentsData.participatingFor
+ .map(tournamentToSidebarEvent)
+ .sort((a, b) => a.startTime - b.startTime);
+
+ const hosting = tournamentsData.organizingFor
+ .map(tournamentToSidebarEvent)
+ .sort((a, b) => a.startTime - b.startTime);
+
+ const scrims = scrimsData
+ .map(scrimToSidebarEvent)
+ .sort((a, b) => a.startTime - b.startTime);
+
+ return { registered, hosting, scrims };
+};
diff --git a/app/features/calendar/routes/events.module.css b/app/features/calendar/routes/events.module.css
new file mode 100644
index 000000000..44bb705a9
--- /dev/null
+++ b/app/features/calendar/routes/events.module.css
@@ -0,0 +1,22 @@
+.eventsListHeader {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ gap: var(--s-2);
+ margin-block-end: var(--s-2);
+}
+
+.filterRadio {
+ padding: var(--s-1) var(--s-2);
+ border-radius: var(--radius-field);
+ cursor: pointer;
+ color: var(--color-text-high);
+ font-weight: var(--weight-semi);
+ font-size: var(--font-3xs);
+}
+
+.filterRadioSelected {
+ background-color: var(--color-bg-higher);
+ color: var(--color-text);
+}
diff --git a/app/features/calendar/routes/events.tsx b/app/features/calendar/routes/events.tsx
new file mode 100644
index 000000000..b8a801022
--- /dev/null
+++ b/app/features/calendar/routes/events.tsx
@@ -0,0 +1,83 @@
+import clsx from "clsx";
+import { useState } from "react";
+import { Radio, RadioGroup } from "react-aria-components";
+import { useTranslation } from "react-i18next";
+import { Link, useLoaderData } from "react-router";
+import { EventsList } from "~/components/EventsList";
+import { Main } from "~/components/Main";
+import type { SendouRouteHandle } from "~/utils/remix.server";
+import { CALENDAR_PAGE } from "~/utils/urls";
+import type { EventsLoaderData } from "../loaders/events.server";
+import styles from "./events.module.css";
+
+export { loader } from "../loaders/events.server";
+
+export const handle: SendouRouteHandle = {
+ i18n: ["calendar"],
+};
+
+type ViewFilter = "registered" | "hosting" | "scrims";
+
+export default function EventsPage() {
+ const { t } = useTranslation(["calendar"]);
+ const data = useLoaderData();
+ const [filter, setFilter] = useState("registered");
+
+ const viewLabels: Record = {
+ registered: t("calendar:events.view.registered"),
+ hosting: t("calendar:events.view.hosting"),
+ scrims: t("calendar:events.view.scrims"),
+ };
+
+ const shownEvents =
+ filter === "registered"
+ ? data.registered
+ : filter === "hosting"
+ ? data.hosting
+ : data.scrims;
+
+ const hasNoEventsAtAll =
+ data.registered.length === 0 &&
+ data.hosting.length === 0 &&
+ data.scrims.length === 0;
+
+ return (
+
+
+
{t("calendar:events.title")}
+ {hasNoEventsAtAll ? null : (
+ setFilter(v as ViewFilter)}
+ orientation="horizontal"
+ className="stack horizontal xs"
+ >
+ {(["registered", "hosting", "scrims"] as const).map((value) => (
+
+ {({ isSelected }) => (
+
+ {viewLabels[value]}
+
+ )}
+
+ ))}
+
+ )}
+
+ {hasNoEventsAtAll ? (
+
+ {t("calendar:events.emptyAll")}{" "}
+ {t("calendar:events.findOnCalendar")}
+
+ ) : shownEvents.length === 0 ? (
+ {t("calendar:events.empty")}
+ ) : (
+
+ )}
+
+ );
+}
diff --git a/app/features/sidebar/core/sidebar.server.ts b/app/features/sidebar/core/sidebar.server.ts
index 5076909a1..0192e1da5 100644
--- a/app/features/sidebar/core/sidebar.server.ts
+++ b/app/features/sidebar/core/sidebar.server.ts
@@ -12,6 +12,7 @@ import * as FriendRepository from "~/features/friends/FriendRepository.server";
import { resolveFriendActivity } from "~/features/friends/friends-utils.server";
import * as ShowcaseTournaments from "~/features/front-page/core/ShowcaseTournaments.server";
import * as LiveStreamRepository from "~/features/live-streams/LiveStreamRepository.server";
+import type { SidebarScrim } from "~/features/scrims/ScrimPostRepository.server";
import * as ScrimPostRepository from "~/features/scrims/ScrimPostRepository.server";
import { getSendouQSidebarStreams } from "~/features/sendouq-streams/core/streams.server";
import type { TournamentTierNumber } from "~/features/tournament/core/tiering";
@@ -81,27 +82,9 @@ export async function resolveSidebarData(userId: number | null) {
seenTournamentIds.add(t.id);
return true;
})
- .map((t) => ({
- id: t.id,
- name: t.name,
- url: t.url,
- logoUrl: t.logoUrl,
- startTime: t.startTime,
- type: "tournament" as const,
- }));
+ .map(tournamentToSidebarEvent);
- const scrimsIconUrl = `${navIconUrl("scrims")}.png`;
- const scrimEvents: SidebarEvent[] = scrimsData.map((s) => ({
- id: s.id,
- name: s.opponentName ?? "Scrim",
- url: s.isAccepted
- ? href("/scrims/:id", { id: String(s.id) })
- : href("/scrims"),
- logoUrl: s.opponentAvatarUrl ?? scrimsIconUrl,
- startTime: s.at,
- type: "scrim" as const,
- scrimStatus: s.isAccepted ? ("booked" as const) : ("looking" as const),
- }));
+ const scrimEvents: SidebarEvent[] = scrimsData.map(scrimToSidebarEvent);
const personalEvents = [...tournamentEvents, ...scrimEvents].sort(
(a, b) => a.startTime - b.startTime,
@@ -347,3 +330,32 @@ function rowToSidebarFriend(
tournamentId: row.tournamentId,
};
}
+
+export function tournamentToSidebarEvent(
+ t: ShowcaseCalendarEvent,
+): SidebarEvent {
+ return {
+ id: t.id,
+ name: t.name,
+ url: t.url,
+ logoUrl: t.logoUrl,
+ startTime: t.startTime,
+ type: "tournament" as const,
+ };
+}
+
+const SCRIMS_ICON_URL = `${navIconUrl("scrims")}.png`;
+
+export function scrimToSidebarEvent(s: SidebarScrim): SidebarEvent {
+ return {
+ id: s.id,
+ name: s.opponentName ?? "Scrim",
+ url: s.isAccepted
+ ? href("/scrims/:id", { id: String(s.id) })
+ : href("/scrims"),
+ logoUrl: s.opponentAvatarUrl ?? SCRIMS_ICON_URL,
+ startTime: s.at,
+ type: "scrim" as const,
+ scrimStatus: s.isAccepted ? ("booked" as const) : ("looking" as const),
+ };
+}
diff --git a/app/routes.ts b/app/routes.ts
index 13eadc395..344e559c9 100644
--- a/app/routes.ts
+++ b/app/routes.ts
@@ -44,6 +44,8 @@ export default [
route("/friends", "features/friends/routes/friends.tsx"),
+ route("/events", "features/calendar/routes/events.tsx"),
+
route("/suspended", "features/ban/routes/suspended.tsx"),
route("/u", "features/user-search/routes/u.tsx"),
diff --git a/app/utils/urls.ts b/app/utils/urls.ts
index f4e451fc7..ebde668c7 100644
--- a/app/utils/urls.ts
+++ b/app/utils/urls.ts
@@ -120,6 +120,7 @@ export const SENDOUQ_STREAMS_PAGE = "/q/streams";
export const TIERS_PAGE = "/tiers";
export const SUSPENDED_PAGE = "/suspended";
export const LFG_PAGE = "/lfg";
+export const EVENTS_PAGE = "/events";
export const FRIENDS_PAGE = "/friends";
export const SETTINGS_PAGE = "/settings";
export const LUTI_PAGE = "/luti";
diff --git a/locales/da/calendar.json b/locales/da/calendar.json
index a7baefcb6..4ee77f0a3 100644
--- a/locales/da/calendar.json
+++ b/locales/da/calendar.json
@@ -79,5 +79,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/de/calendar.json b/locales/de/calendar.json
index 00f8f418c..5cee7f59f 100644
--- a/locales/de/calendar.json
+++ b/locales/de/calendar.json
@@ -79,5 +79,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/en/calendar.json b/locales/en/calendar.json
index d6a15d3dd..79add1679 100644
--- a/locales/en/calendar.json
+++ b/locales/en/calendar.json
@@ -79,5 +79,12 @@
"filter.applyAndDefault": "Apply & make default",
"forms.draft": "Draft",
"forms.draftInfo": "Draft tournaments are hidden and only visible to organizers. The tournament must be opened (by disabling this toggle) before any bracket can be started.",
- "forms.draftBracketStartBlocked": "Tournament is in draft mode. Edit the tournament and disable the draft toggle before starting the bracket."
+ "forms.draftBracketStartBlocked": "Tournament is in draft mode. Edit the tournament and disable the draft toggle before starting the bracket.",
+ "events.title": "My Events",
+ "events.view.registered": "Registered",
+ "events.view.hosting": "Hosting",
+ "events.view.scrims": "Scrims",
+ "events.empty": "No events in this category",
+ "events.emptyAll": "You have no upcoming events.",
+ "events.findOnCalendar": "Find an event to join on the calendar!"
}
diff --git a/locales/es-ES/calendar.json b/locales/es-ES/calendar.json
index b005cae62..5d090bcac 100644
--- a/locales/es-ES/calendar.json
+++ b/locales/es-ES/calendar.json
@@ -81,5 +81,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/es-US/calendar.json b/locales/es-US/calendar.json
index b005cae62..5d090bcac 100644
--- a/locales/es-US/calendar.json
+++ b/locales/es-US/calendar.json
@@ -81,5 +81,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/fr-CA/calendar.json b/locales/fr-CA/calendar.json
index 4f84120c7..dc078ffb7 100644
--- a/locales/fr-CA/calendar.json
+++ b/locales/fr-CA/calendar.json
@@ -81,5 +81,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/fr-EU/calendar.json b/locales/fr-EU/calendar.json
index 4f84120c7..dc078ffb7 100644
--- a/locales/fr-EU/calendar.json
+++ b/locales/fr-EU/calendar.json
@@ -81,5 +81,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/he/calendar.json b/locales/he/calendar.json
index 2a16dd62e..f99a4eed0 100644
--- a/locales/he/calendar.json
+++ b/locales/he/calendar.json
@@ -81,5 +81,12 @@
"filter.applyAndDefault": "החל והפוך לברירת מחדל",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/it/calendar.json b/locales/it/calendar.json
index 3dbf60a04..f6b586379 100644
--- a/locales/it/calendar.json
+++ b/locales/it/calendar.json
@@ -81,5 +81,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/ja/calendar.json b/locales/ja/calendar.json
index a654dd3cf..ee4f47556 100644
--- a/locales/ja/calendar.json
+++ b/locales/ja/calendar.json
@@ -75,5 +75,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/ko/calendar.json b/locales/ko/calendar.json
index f6c4d3aea..4949c5605 100644
--- a/locales/ko/calendar.json
+++ b/locales/ko/calendar.json
@@ -75,5 +75,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/nl/calendar.json b/locales/nl/calendar.json
index 4d196d1c6..d93969574 100644
--- a/locales/nl/calendar.json
+++ b/locales/nl/calendar.json
@@ -79,5 +79,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/pl/calendar.json b/locales/pl/calendar.json
index 40c933639..3783cab0c 100644
--- a/locales/pl/calendar.json
+++ b/locales/pl/calendar.json
@@ -83,5 +83,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/pt-BR/calendar.json b/locales/pt-BR/calendar.json
index cfefc88a9..39d841705 100644
--- a/locales/pt-BR/calendar.json
+++ b/locales/pt-BR/calendar.json
@@ -81,5 +81,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/ru/calendar.json b/locales/ru/calendar.json
index b882eae0f..be936a053 100644
--- a/locales/ru/calendar.json
+++ b/locales/ru/calendar.json
@@ -83,5 +83,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}
diff --git a/locales/zh/calendar.json b/locales/zh/calendar.json
index 639d367cf..1b8170d23 100644
--- a/locales/zh/calendar.json
+++ b/locales/zh/calendar.json
@@ -75,5 +75,12 @@
"filter.applyAndDefault": "",
"forms.draft": "",
"forms.draftInfo": "",
- "forms.draftBracketStartBlocked": ""
+ "forms.draftBracketStartBlocked": "",
+ "events.title": "",
+ "events.view.registered": "",
+ "events.view.hosting": "",
+ "events.view.scrims": "",
+ "events.empty": "",
+ "events.emptyAll": "",
+ "events.findOnCalendar": ""
}