From 5ee31452ba2b077077ab6043e436755fddde8c33 Mon Sep 17 00:00:00 2001 From: kovacspe Date: Thu, 16 Nov 2023 01:14:07 +0100 Subject: [PATCH] Add banner info (#214) * Add banner info * Move PageTitleContainer into PageLayout * Move CompetitionPage into own component * Add style to

in Markdown component * Move BannerContainer into PayeLayout * fix after review --------- Co-authored-by: matushl --- .../CompetitionPage/CompetitionPage.tsx | 107 +++++++++++++++ src/components/CompetitionPage/RulesPage.tsx | 17 +++ .../CompetitionPage}/competition.module.scss | 1 - .../competition.module.scss.d.ts | 0 src/components/PageLayout/Banner/Banner.tsx | 8 +- src/components/PageLayout/PageLayout.tsx | 49 ++++--- src/components/PageLayout/TopGrid/TopGrid.tsx | 11 +- src/components/Problems/Problems.tsx | 18 ++- src/components/StaticSites/Markdown.tsx | 3 +- src/components/StaticSites/Texts.module.scss | 4 + .../StaticSites/Texts.module.scss.d.ts | 1 + src/components/StaticSites/Texts.tsx | 1 + src/pages/_app.tsx | 5 +- src/pages/strom/akcie/[[...params]].tsx | 129 +++--------------- src/utils/BannerContainer.tsx | 9 ++ src/utils/PageTitleContainer.tsx | 4 +- 16 files changed, 212 insertions(+), 155 deletions(-) create mode 100644 src/components/CompetitionPage/CompetitionPage.tsx create mode 100644 src/components/CompetitionPage/RulesPage.tsx rename src/{pages/strom/akcie => components/CompetitionPage}/competition.module.scss (98%) rename src/{pages/strom/akcie => components/CompetitionPage}/competition.module.scss.d.ts (100%) create mode 100644 src/utils/BannerContainer.tsx diff --git a/src/components/CompetitionPage/CompetitionPage.tsx b/src/components/CompetitionPage/CompetitionPage.tsx new file mode 100644 index 00000000..f3915ea8 --- /dev/null +++ b/src/components/CompetitionPage/CompetitionPage.tsx @@ -0,0 +1,107 @@ +import {useRouter} from 'next/router' +import {FC, Fragment} from 'react' + +import {Link} from '@/components/Clickable/Clickable' +import {Competition, Event} from '@/types/api/competition' +import {BannerContainer} from '@/utils/BannerContainer' +import {formatDate} from '@/utils/formatDate' + +import styles from './competition.module.scss' + +type OurCompetition = Omit & {history_events: Event[]} + +type CompetitionPageProps = { + competition: OurCompetition +} + +export const CompetitionPage: FC = ({ + competition: {name, who_can_participate, description, upcoming_or_current_event, competition_type, history_events}, +}) => { + const {setBannerText} = BannerContainer.useContainer() + + const startDate = upcoming_or_current_event ? formatDate(upcoming_or_current_event.start) : null + const endDate = upcoming_or_current_event ? formatDate(upcoming_or_current_event.end) : null + setBannerText(startDate ? `${name} sa bude konať ${startDate}` : '') + + const router = useRouter() + const rulesLink = `${router.asPath}/pravidla` + + return ( + <> +

+ {who_can_participate &&

Pre koho? {who_can_participate}

} +

{description}

+
+
+ {upcoming_or_current_event ? ( +
+

+ Nadchádzajúci ročník: +

+ {startDate &&

Odkedy? {startDate}

} + {endDate &&

Dokedy? {endDate}

} + {upcoming_or_current_event.publication_set.length > 0 && ( +

+ Pozvánka +

+ )} + {upcoming_or_current_event.registration_link && ( +
+

+ Registrácia prebieha do: + {upcoming_or_current_event.registration_link.end} + Registračný formulár +

+ +

{upcoming_or_current_event.registration_link.additional_info}

+
+ )} +
+ ) : ( +

+ Nadchádzajúci ročník: Pripravujeme +

+ )} +
+ +
+
+
+ Pravidlá +
+
+
+ +
+

Archív:

+
+ {/* TODO: asi zjednotit styly, neriesit with/without publications */} + {competition_type?.name === 'Tábor' ? ( +
+ {history_events.map((event) => ( + +
+ {name + ' '} {event.school_year} +
+
+ ))} +
+ ) : ( +
+ {history_events.map((event) => ( + +
+ {name} {event.school_year} +
+ {event.publication_set.map((publication) => ( + + {publication.name} + + ))} +
+ ))} +
+ )} + + ) +} diff --git a/src/components/CompetitionPage/RulesPage.tsx b/src/components/CompetitionPage/RulesPage.tsx new file mode 100644 index 00000000..441f20fd --- /dev/null +++ b/src/components/CompetitionPage/RulesPage.tsx @@ -0,0 +1,17 @@ +import {FC} from 'react' + +import {Markdown} from '@/components/StaticSites/Markdown' +import {Competition} from '@/types/api/generated/competition' +import {BannerContainer} from '@/utils/BannerContainer' +import {formatDate} from '@/utils/formatDate' + +type RulesPageProps = Pick + +export const RulesPage: FC = ({name, rules, upcoming_or_current_event}) => { + const {setBannerText} = BannerContainer.useContainer() + + const startDate = formatDate(upcoming_or_current_event?.start) + setBannerText(upcoming_or_current_event ? `${name} sa bude konať ${startDate}` : '') + + return +} diff --git a/src/pages/strom/akcie/competition.module.scss b/src/components/CompetitionPage/competition.module.scss similarity index 98% rename from src/pages/strom/akcie/competition.module.scss rename to src/components/CompetitionPage/competition.module.scss index fdf921d4..7911683a 100644 --- a/src/pages/strom/akcie/competition.module.scss +++ b/src/components/CompetitionPage/competition.module.scss @@ -1,7 +1,6 @@ .mainText{ >p{ padding: 20px; - width: 1000px; } } diff --git a/src/pages/strom/akcie/competition.module.scss.d.ts b/src/components/CompetitionPage/competition.module.scss.d.ts similarity index 100% rename from src/pages/strom/akcie/competition.module.scss.d.ts rename to src/components/CompetitionPage/competition.module.scss.d.ts diff --git a/src/components/PageLayout/Banner/Banner.tsx b/src/components/PageLayout/Banner/Banner.tsx index 453bce9c..a9dc9182 100644 --- a/src/components/PageLayout/Banner/Banner.tsx +++ b/src/components/PageLayout/Banner/Banner.tsx @@ -1,16 +1,16 @@ import {FC} from 'react' import {Marquee} from '@/components/Marquee/Marquee' +import {BannerContainer} from '@/utils/BannerContainer' import styles from './Banner.module.scss' export const Banner: FC = () => { - const text = - 'Matboj sa uskutoční 15. októbra 2021 - Matboj sa uskutoční 15. októbra 2021 - Matboj sa uskutoční 15. októbra 2021' + const {bannerText} = BannerContainer.useContainer() return (
- -
{text}
+ +
{bannerText}
) diff --git a/src/components/PageLayout/PageLayout.tsx b/src/components/PageLayout/PageLayout.tsx index 4296df2d..2991dfcf 100644 --- a/src/components/PageLayout/PageLayout.tsx +++ b/src/components/PageLayout/PageLayout.tsx @@ -1,6 +1,7 @@ import clsx from 'clsx' -import {FC, ReactNode, useEffect} from 'react' +import {FC, ReactNode} from 'react' +import {BannerContainer} from '@/utils/BannerContainer' import {PageTitleContainer} from '@/utils/PageTitleContainer' import {Banner} from './Banner/Banner' @@ -19,31 +20,29 @@ type PageLayoutProps = { // pre pouzitie len na seminarovych strankach a podstrankach - `/matik(/*)` // ked budeme potrebovat top-level stranky ako `/ina-stranka`, budeme musiet upravit, ako sa pracuje s `useSeminarInfo` export const PageLayout: FC = ({contentWidth = 2, title = '', children}) => { - const {pageTitle, setPageTitle} = PageTitleContainer.useContainer() - - useEffect(() => { - if (title !== '') setPageTitle(title) - }, [contentWidth, title, setPageTitle]) - return ( -
- - - -
- -
- {children} + + +
+ + + +
+ +
+ {children} +
+
+
-
-
-
+ + ) } diff --git a/src/components/PageLayout/TopGrid/TopGrid.tsx b/src/components/PageLayout/TopGrid/TopGrid.tsx index 120be81f..3248af4b 100644 --- a/src/components/PageLayout/TopGrid/TopGrid.tsx +++ b/src/components/PageLayout/TopGrid/TopGrid.tsx @@ -4,20 +4,19 @@ import {useRouter} from 'next/router' import {FC} from 'react' import {SemesterPicker} from '@/components/SemesterPicker/SemesterPicker' +import {PageTitleContainer} from '@/utils/PageTitleContainer' import {useSeminarInfo} from '@/utils/useSeminarInfo' import styles from './TopGrid.module.scss' -type TopGridProps = { - title: string -} - -export const TopGrid: FC = ({title}) => { +export const TopGrid: FC = () => { const {seminar} = useSeminarInfo() // z napr. `/matik/zadania(/*)` vytiahne `zadania` const page = useRouter().pathname.split('/')[2] + const {pageTitle} = PageTitleContainer.useContainer() + return (
@@ -31,7 +30,7 @@ export const TopGrid: FC = ({title}) => { Strom
-
{title}
+
{pageTitle}
{(page === 'zadania' || page === 'vysledky') && (
diff --git a/src/components/Problems/Problems.tsx b/src/components/Problems/Problems.tsx index b1a4ac57..63217a37 100644 --- a/src/components/Problems/Problems.tsx +++ b/src/components/Problems/Problems.tsx @@ -1,13 +1,15 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' import axios from 'axios' import {useRouter} from 'next/router' -import {FC, useState} from 'react' +import {FC, useEffect, useState} from 'react' import {useInterval} from 'usehooks-ts' import {Button, Link} from '@/components/Clickable/Clickable' import {SeriesWithProblems} from '@/types/api/competition' import {Profile} from '@/types/api/personal' import {AuthContainer} from '@/utils/AuthContainer' +import {BannerContainer} from '@/utils/BannerContainer' +import {formatDate} from '@/utils/formatDate' import {useDataFromURL} from '@/utils/useDataFromURL' import {useHasPermissions} from '@/utils/useHasPermissions' @@ -29,6 +31,7 @@ export const Problems: FC = () => { const router = useRouter() const {isAuthed} = AuthContainer.useContainer() + const {setBannerText} = BannerContainer.useContainer() const {data} = useQuery({ queryKey: ['personal', 'profiles', 'myprofile'], @@ -78,6 +81,19 @@ export const Problems: FC = () => { const invalidateSeriesQuery = () => queryClient.invalidateQueries({queryKey: ['competition', 'series', id.seriesId]}) + useEffect(() => { + if (seriesData === undefined) { + setBannerText('') + } else { + const deadline = formatDate(seriesData.data.deadline) + if (seriesData?.data.can_submit) { + setBannerText(`Termín série: ${deadline}`) + } else { + setBannerText(`Séria je uzavretá.`) + } + } + }, [seriesData, setBannerText]) + const {mutate: registerToSemester} = useMutation({ mutationFn: (id: number) => axios.post(`/api/competition/event/${id}/register`), onSuccess: () => { diff --git a/src/components/StaticSites/Markdown.tsx b/src/components/StaticSites/Markdown.tsx index 0559526d..bff84801 100644 --- a/src/components/StaticSites/Markdown.tsx +++ b/src/components/StaticSites/Markdown.tsx @@ -6,7 +6,7 @@ import rehypeKatex from 'rehype-katex' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' -import {MarkdownLink, Table, Td, Th} from './Texts' +import {MarkdownLink, P, Table, Td, Th} from './Texts' type MarkdownProps = { content: string @@ -21,6 +21,7 @@ export const Markdown: FC = ({content}) => ( td: Td, a: MarkdownLink, table: Table, + p: P, }} > {content} diff --git a/src/components/StaticSites/Texts.module.scss b/src/components/StaticSites/Texts.module.scss index a07deceb..2e6417d0 100644 --- a/src/components/StaticSites/Texts.module.scss +++ b/src/components/StaticSites/Texts.module.scss @@ -12,4 +12,8 @@ font-weight: bold; font-style: italic; text-transform: uppercase; +} + +.p { + margin: 1rem 0; } \ No newline at end of file diff --git a/src/components/StaticSites/Texts.module.scss.d.ts b/src/components/StaticSites/Texts.module.scss.d.ts index 6aa1d36f..aff0cd78 100644 --- a/src/components/StaticSites/Texts.module.scss.d.ts +++ b/src/components/StaticSites/Texts.module.scss.d.ts @@ -1,4 +1,5 @@ export type Styles = { + p: string table: string td: string th: string diff --git a/src/components/StaticSites/Texts.tsx b/src/components/StaticSites/Texts.tsx index ac1fc5d9..4c176612 100644 --- a/src/components/StaticSites/Texts.tsx +++ b/src/components/StaticSites/Texts.tsx @@ -13,3 +13,4 @@ export const MarkdownLink: FC = ({children, href}) => = ({children}) => {children} export const Td: FC = ({children}) => {children} export const Table: FC = ({children}) => {children}
+export const P: FC = ({children}) =>

{children}

diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index cb3c5dfe..f5be7762 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -11,7 +11,6 @@ import {CookiesProvider} from 'react-cookie' import {theme} from '@/theme' import {AuthContainer} from '@/utils/AuthContainer' -import {PageTitleContainer} from '@/utils/PageTitleContainer' const ReactQueryDevtools = dynamic( () => import('@tanstack/react-query-devtools').then(({ReactQueryDevtools}) => ReactQueryDevtools), @@ -84,9 +83,7 @@ const MyApp: FC = ({Component, pageProps}) => { - - - + diff --git a/src/pages/strom/akcie/[[...params]].tsx b/src/pages/strom/akcie/[[...params]].tsx index 9b95393e..492d3857 100644 --- a/src/pages/strom/akcie/[[...params]].tsx +++ b/src/pages/strom/akcie/[[...params]].tsx @@ -1,18 +1,12 @@ import axios from 'axios' import {GetServerSideProps, NextPage} from 'next' -import {useRouter} from 'next/router' -import {FC, Fragment} from 'react' -import {Link} from '@/components/Clickable/Clickable' +import {CompetitionPage} from '@/components/CompetitionPage/CompetitionPage' +import {RulesPage} from '@/components/CompetitionPage/RulesPage' import {PageLayout} from '@/components/PageLayout/PageLayout' -import {Markdown} from '@/components/StaticSites/Markdown' -import {Competition, Event} from '@/types/api/generated/competition' -import {formatDate} from '@/utils/formatDate' +import {Competition, Event} from '@/types/api/competition' import {Seminar} from '@/utils/useSeminarInfo' -import styles from './competition.module.scss' - -// skusime to opravit v API - `history_events` je nespravne vygenerovane ako `any` type OurCompetition = Omit & {history_events: Event[]} type CompetitionPageProps = { @@ -20,102 +14,21 @@ type CompetitionPageProps = { is_rules: boolean } -const StaticPage: NextPage = ({ - competition: { - name, - rules, - who_can_participate, - description, - upcoming_or_current_event, - competition_type, - history_events, - }, - is_rules, -}) => ( - - {is_rules ? ( -
{rules && }
- ) : ( - <> -
- {who_can_participate &&

Pre koho? {who_can_participate}

} -

{description}

-
-
- {upcoming_or_current_event ? ( -
-

- Nadchádzajúci ročník: -

- {upcoming_or_current_event.start &&

Odkedy? {formatDate(upcoming_or_current_event.start)}

} - {upcoming_or_current_event.end &&

Dokedy? {formatDate(upcoming_or_current_event.end)}

} - {upcoming_or_current_event.publication_set.length > 0 && ( - // TODO: vyplut vsetky publikacie -

- Pozvánka -

- )} - {upcoming_or_current_event.registration_link && ( -
-

- Registrácia prebieha do: - {formatDate(upcoming_or_current_event.registration_link.end)} - Registračný formulár -

- -

{upcoming_or_current_event.registration_link.additional_info}

-
- )} -
- ) : ( -

- Nadchádzajúci ročník: Pripravujeme -

- )} -
- -
-
-
- -
-
-
- -
-

Archív:

-
- {/* TODO: asi zjednotit styly, neriesit with/without publications */} - {competition_type.name === 'Tábor' ? ( -
- {history_events.map((event) => ( - -
- {name + ' '} {event.school_year} -
-
- ))} -
- ) : ( -
- {history_events.map((event) => ( - -
- {name} {event.school_year} -
- {event.publication_set.map((publication) => ( - - {publication.name} - - ))} -
- ))} -
- )} - - )} -
-) +const StaticPage: NextPage = ({competition, is_rules}) => { + return ( + + {is_rules ? ( + + ) : ( + + )} + + ) +} export default StaticPage @@ -153,9 +66,3 @@ export const competitionBasedGetServerSideProps = } export const getServerSideProps = competitionBasedGetServerSideProps('strom') - -const RulesLink: FC = () => { - const router = useRouter() - const active = `${router.asPath}/pravidla` - return Pravidlá -} diff --git a/src/utils/BannerContainer.tsx b/src/utils/BannerContainer.tsx new file mode 100644 index 00000000..21562279 --- /dev/null +++ b/src/utils/BannerContainer.tsx @@ -0,0 +1,9 @@ +import {useState} from 'react' +import {createContainer} from 'unstated-next' + +const useBannerText = () => { + const [bannerText, setBannerText] = useState('') + return {bannerText, setBannerText} +} + +export const BannerContainer = createContainer(useBannerText) diff --git a/src/utils/PageTitleContainer.tsx b/src/utils/PageTitleContainer.tsx index 01c31d64..e20a2d42 100644 --- a/src/utils/PageTitleContainer.tsx +++ b/src/utils/PageTitleContainer.tsx @@ -1,8 +1,8 @@ import {useState} from 'react' import {createContainer} from 'unstated-next' -const usePageTitle = () => { - const [pageTitle, setPageTitle] = useState('') +const usePageTitle = (initial = '') => { + const [pageTitle, setPageTitle] = useState(initial) return {pageTitle, setPageTitle} }