From 8269288cb2722dd0e1fb104ece6b493f2d5b08bd Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Fri, 12 Aug 2022 22:52:55 +0300 Subject: [PATCH] Banner on calendar page to notify about reporting --- TODO.md | 2 +- app/components/Alert.tsx | 16 ++++++++++++++++ app/db/models/calendar.server.ts | 33 ++++++++++++++++++++++++++++++++ app/routes/calendar/index.tsx | 30 +++++++++++++++++++++++++++-- app/styles/calendar.css | 4 ++++ app/styles/common.css | 23 ++++++++++++++++++++++ app/styles/vars.css | 4 ++++ 7 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 app/components/Alert.tsx diff --git a/TODO.md b/TODO.md index 80cc591d3..ebcce550e 100644 --- a/TODO.md +++ b/TODO.md @@ -17,7 +17,7 @@ Calendar - [x] Add winners page - [ ] E2E test add winners page - [x] Winners on the event info page -- [ ] There should be a banner on the list page if you have past tournaments to report +- [x] There should be a banner on the list page if you have past tournaments to report - [x] On the user page tab showing past results - [ ] Translations diff --git a/app/components/Alert.tsx b/app/components/Alert.tsx new file mode 100644 index 000000000..4d0af01c2 --- /dev/null +++ b/app/components/Alert.tsx @@ -0,0 +1,16 @@ +import type * as React from "react"; +import { AlertIcon } from "./icons/Alert"; + +export function Alert({ + children, + textClassName, +}: { + children: React.ReactNode; + textClassName?: string; +}) { + return ( +
+
{children}
+
+ ); +} diff --git a/app/db/models/calendar.server.ts b/app/db/models/calendar.server.ts index 549ee56e0..0bca230d6 100644 --- a/app/db/models/calendar.server.ts +++ b/app/db/models/calendar.server.ts @@ -502,3 +502,36 @@ export function findBadgesById(eventId: CalendarEvent["id"]) { Pick >; } + +const eventsToReportStm = sql.prepare(` + select + "CalendarEvent"."id", + "CalendarEvent"."name", + (select max("startTime") + from "CalendarEventDate" + where "eventId" = "CalendarEvent"."id") as "startTime" + from "CalendarEvent" + where + "CalendarEvent"."authorId" = $authorId + and + "startTime" > $lowerLimitTime + and + "startTime" < $upperLimitTime + and + "CalendarEvent"."participantCount" is null +`); + +export function eventsToReport(authorId?: CalendarEvent["authorId"]) { + if (!authorId) return []; + + const oneMonthAgo = new Date(); + oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1); + + return ( + eventsToReportStm.all({ + authorId, + upperLimitTime: dateToDatabaseTimestamp(new Date()), + lowerLimitTime: dateToDatabaseTimestamp(oneMonthAgo), + }) as Array> + ).map((row) => ({ id: row.id, name: row.name })); +} diff --git a/app/routes/calendar/index.tsx b/app/routes/calendar/index.tsx index 7e7d74017..6f6b498a0 100644 --- a/app/routes/calendar/index.tsx +++ b/app/routes/calendar/index.tsx @@ -8,10 +8,11 @@ import React from "react"; import { Flipped, Flipper } from "react-flip-toolkit"; import { useTranslation } from "react-i18next"; import { z } from "zod"; +import { Alert } from "~/components/Alert"; import { LinkButton } from "~/components/Button"; import { db } from "~/db"; import { useIsMounted } from "~/hooks/useIsMounted"; -import { useUser } from "~/modules/auth"; +import { getUser, useUser } from "~/modules/auth"; import { i18next } from "~/modules/i18n"; import styles from "~/styles/calendar.css"; import { joinListToNaturalString } from "~/utils/arrays"; @@ -22,7 +23,7 @@ import { } from "~/utils/dates"; import { discordFullName, makeTitle } from "~/utils/strings"; import type { Unpacked } from "~/utils/types"; -import { resolveBaseUrl } from "~/utils/urls"; +import { calendarReportWinnersPage, resolveBaseUrl } from "~/utils/urls"; import { actualNumber } from "~/utils/zod"; import { Tags } from "./components/Tags"; @@ -55,6 +56,7 @@ const loaderSearchParamsSchema = z.object({ }); export const loader = async ({ request }: LoaderArgs) => { + const user = await getUser(request); const t = await i18next.getFixedT(request); const url = new URL(request.url); const parsedParams = loaderSearchParamsSchema.safeParse({ @@ -87,6 +89,7 @@ export const loader = async ({ request }: LoaderArgs) => { }), weeks: closeByWeeks({ week: displayedWeek, year: displayedYear }), events: fetchEventsOfWeek({ week: displayedWeek, year: displayedYear }), + eventsToReport: db.calendarEvents.eventsToReport(user?.id), title: makeTitle([`Week ${displayedWeek}`, t("pages.calendar")]), }); }; @@ -143,6 +146,7 @@ export default function CalendarPage() { return (
+
{user && ( @@ -287,6 +291,28 @@ function getEventsCountPerWeek( return result; } +function EventsToReport() { + const data = useLoaderData(); + + if (data.eventsToReport.length === 0) return null; + + return ( + + You can report results for{" "} + {data.eventsToReport.map((event, i) => ( + + {event.name} + {i === data.eventsToReport.length - 1 + ? "" + : i === data.eventsToReport.length - 2 + ? " and " + : ", "} + + ))} + + ); +} + function EventsList({ events, }: { diff --git a/app/styles/calendar.css b/app/styles/calendar.css index 32e31042b..25950e962 100644 --- a/app/styles/calendar.css +++ b/app/styles/calendar.css @@ -85,6 +85,10 @@ line-height: 0.8; } +.calendar__events-to-report { + line-height: 1.25rem; +} + .calendar__events-container { background-color: var(--bg-lighter); } diff --git a/app/styles/common.css b/app/styles/common.css index 4559b8eba..cb994d86d 100644 --- a/app/styles/common.css +++ b/app/styles/common.css @@ -480,12 +480,35 @@ dialog::backdrop { background-color: var(--theme-transparent); } +.alert { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + background-color: var(--theme-info-transparent); + border-radius: var(--rounded); + color: var(--text); + font-size: var(--fonts-sm); + font-weight: var(--semi-bold); + gap: var(--s-2); + line-height: 0.75; + margin-inline: auto; + padding-block: var(--s-1-5); + padding-inline-end: var(--s-4); + padding-inline-start: var(--s-3); +} + .avatar { background-color: var(--bg-lighter); background-image: url("/svg/background-pattern.svg"); border-radius: 50%; } +.alert > svg { + height: 1.75rem; + fill: var(--theme-info); +} + .form-errors { font-size: var(--fonts-sm); } diff --git a/app/styles/vars.css b/app/styles/vars.css index 33eb19668..5689b9f8b 100644 --- a/app/styles/vars.css +++ b/app/styles/vars.css @@ -18,6 +18,8 @@ --theme-warning: #c9c900; --theme-success: #00a514; --theme-success-transparent: #00a51452; + --theme-info: #1fb0d0; + --theme-info-transparent: #1fb0d052; --theme: hsl(255deg 64% 63%); --theme-vibrant: hsl(255deg 100% 81%); --theme-transparent: hsl(255deg 66.7% 75% / 40%); @@ -90,6 +92,8 @@ --theme-warning: #f5f587; --theme-success: #a3ffae; --theme-success-transparent: #a3ffae52; + --theme-info: #87cddc; + --theme-info-transparent: #87cddc52; --theme: hsl(255deg 66.7% 75%); --theme-vibrant: hsl(255deg 78% 65%); --theme-transparent: hsl(255deg 66.7% 75% / 40%);