mirror of
https://github.com/aljazceru/landscape-template.git
synced 2026-01-27 18:24:25 +01:00
feat: extract tournament details to context provider
This commit is contained in:
@@ -1,18 +1,14 @@
|
||||
import { useState } from 'react'
|
||||
import { Tournament, TournamentEventTypeEnum } from 'src/graphql'
|
||||
import { TournamentEventTypeEnum } from 'src/graphql'
|
||||
import { useTournament } from '../TournamentDetailsPage/TournamentDetailsContext';
|
||||
import EventCard from './EventCard/EventCard';
|
||||
import EventsFilters from './EventsFilters/EventsFilters';
|
||||
|
||||
interface Props {
|
||||
data: Pick<Tournament,
|
||||
| 'events_count'
|
||||
| 'events'>
|
||||
}
|
||||
|
||||
export default function EventsPage({ data: { events, events_count } }: Props) {
|
||||
export default function EventsPage() {
|
||||
|
||||
const [searchFilter, setSearchFilter] = useState("")
|
||||
const [eventFilter, setEventFilter] = useState<TournamentEventTypeEnum | null>(null)
|
||||
const { tournamentDetails: { events, events_count } } = useTournament()
|
||||
|
||||
return (
|
||||
<div className='pb-42'>
|
||||
|
||||
@@ -10,6 +10,7 @@ import InfoCard from "src/Components/InfoCard/InfoCard";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useState } from "react";
|
||||
import { NotificationsService } from "src/services";
|
||||
import { useTournament } from "../../TournamentDetailsPage/TournamentDetailsContext";
|
||||
|
||||
type MakerType = GetMakersInTournamentQuery['getMakersInTournament']['makers'][number]
|
||||
|
||||
@@ -23,6 +24,9 @@ export default function MakerCard({ maker, isMe }: Props) {
|
||||
const dispatch = useAppDispatch();
|
||||
const [hackingStatus, setHackingStatus] = useState(maker.hacking_status)
|
||||
|
||||
const { tournamentDetails: { id: tournamentId } } = useTournament()
|
||||
|
||||
|
||||
const contactLinksAvailable = maker.user.github || maker.user.linkedin || maker.user.twitter;
|
||||
const [udpateInfo, updateInfoMutation] = useUpdateTournamentRegistrationMutation()
|
||||
|
||||
@@ -42,7 +46,7 @@ export default function MakerCard({ maker, isMe }: Props) {
|
||||
setHackingStatus(value);
|
||||
udpateInfo({
|
||||
variables: {
|
||||
tournamentId: 12,
|
||||
tournamentId,
|
||||
data: {
|
||||
hacking_status: value
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { Tournament, useMeTournamentQuery, User, } from 'src/graphql'
|
||||
import { useMeTournamentQuery, User, } from 'src/graphql'
|
||||
import { useTournament } from '../TournamentDetailsPage/TournamentDetailsContext';
|
||||
import MakerCard from './MakerCard/MakerCard';
|
||||
import MakerCardSkeleton from './MakerCard/MakerCard.Skeleton';
|
||||
import ParticipantsSection from './ParticipantsSection/ParticipantsSection';
|
||||
|
||||
interface Props {
|
||||
data: Pick<Tournament,
|
||||
| 'id'>
|
||||
}
|
||||
|
||||
|
||||
export default function MakersPage({ data: { id } }: Props) {
|
||||
export default function MakersPage() {
|
||||
|
||||
const { tournamentDetails: { id } } = useTournament()
|
||||
|
||||
const query = useMeTournamentQuery({
|
||||
variables: { id: id }
|
||||
variables: { id }
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,40 +2,33 @@ import DOMPurify from 'dompurify'
|
||||
import { marked } from 'marked'
|
||||
import Card from 'src/Components/Card/Card'
|
||||
import { Tournament } from 'src/graphql'
|
||||
import { useTournament } from '../TournamentDetailsPage/TournamentDetailsContext'
|
||||
import FAQsSection from './FAQsSection/FAQsSection'
|
||||
import JudgesSection from './JudgesSection/JudgesSection'
|
||||
import PrizesSection from './PrizesSection/PrizesSection'
|
||||
import RegisterCard from './RegisterCard/RegisterCard'
|
||||
|
||||
interface Props {
|
||||
data: Pick<Tournament,
|
||||
| "description"
|
||||
| "prizes"
|
||||
| "judges"
|
||||
| "start_date"
|
||||
| 'makers_count'
|
||||
| 'faqs'
|
||||
>
|
||||
avatars: string[]
|
||||
isRegistered: boolean;
|
||||
}
|
||||
|
||||
export default function OverviewPage({ data, avatars, isRegistered }: Props) {
|
||||
|
||||
export default function OverviewPage() {
|
||||
|
||||
const { tournamentDetails, makers, myParticipationInfo } = useTournament()
|
||||
|
||||
return (
|
||||
<Card onlyMd className='flex flex-col gap-42'>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-24 items-start">
|
||||
<div className='md:col-span-2'>
|
||||
<div
|
||||
className={`text-gray-600 mt-16 prose `}
|
||||
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(marked.parse(data.description)) }}
|
||||
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(marked.parse(tournamentDetails.description)) }}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<RegisterCard makers_count={data.makers_count} start_date={data.start_date} avatars={avatars} isRegistered={isRegistered} />
|
||||
<RegisterCard makers_count={tournamentDetails.makers_count} start_date={tournamentDetails.start_date} avatars={makers.map(m => m.user.avatar)} isRegistered={!!myParticipationInfo} />
|
||||
</div>
|
||||
<PrizesSection prizes={data.prizes} />
|
||||
<JudgesSection judges={data.judges} />
|
||||
<FAQsSection faqs={data.faqs} />
|
||||
<PrizesSection prizes={tournamentDetails.prizes} />
|
||||
<JudgesSection judges={tournamentDetails.judges} />
|
||||
<FAQsSection faqs={tournamentDetails.faqs} />
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { useDebouncedState } from '@react-hookz/web';
|
||||
import { useState } from 'react'
|
||||
import { FiSearch } from 'react-icons/fi';
|
||||
import { Tournament, useGetProjectsInTournamentQuery } from 'src/graphql'
|
||||
import { useGetProjectsInTournamentQuery } from 'src/graphql'
|
||||
import { useTournament } from '../TournamentDetailsPage/TournamentDetailsContext';
|
||||
import ProjectCard from './ProjectCard/ProjectCard';
|
||||
import ProjectCardSkeleton from './ProjectCard/ProjectCard.Skeleton';
|
||||
|
||||
interface Props {
|
||||
data: Pick<Tournament,
|
||||
| 'id'>
|
||||
}
|
||||
|
||||
export default function ProjectsPage({ data: { id } }: Props) {
|
||||
export default function ProjectsPage() {
|
||||
|
||||
|
||||
const { tournamentDetails: { id } } = useTournament()
|
||||
|
||||
const [searchFilter, setSearchFilter] = useState("");
|
||||
const [debouncedsearchFilter, setDebouncedSearchFilter] = useDebouncedState("", 500);
|
||||
|
||||
|
||||
@@ -1,36 +1,34 @@
|
||||
import dayjs from 'dayjs'
|
||||
import advancedFormat from 'dayjs/plugin/advancedFormat'
|
||||
import React from 'react'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { IoLocationOutline } from 'react-icons/io5'
|
||||
import { Tournament } from 'src/graphql'
|
||||
import Navigation from '../Navigation/Navigation'
|
||||
import { useTournament } from '../TournamentDetailsContext'
|
||||
dayjs.extend(advancedFormat)
|
||||
|
||||
interface Props {
|
||||
data: Pick<Tournament,
|
||||
| 'cover_image'
|
||||
| 'thumbnail_image'
|
||||
| 'title'
|
||||
| 'start_date'
|
||||
| 'end_date'
|
||||
| 'location'>
|
||||
}
|
||||
|
||||
export default function Header({ data }: Props) {
|
||||
|
||||
export default function Header() {
|
||||
const { tournamentDetails } = useTournament()
|
||||
return (
|
||||
<div className="w-full p-16 md:p-24 flex flex-col min-h-[240px] md:min-h-[280px] relative">
|
||||
<img src={data.cover_image} className='absolute inset-0 h-full w-full object-cover object-top' alt="" />
|
||||
<div className='absolute inset-0 h-full w-full bg-black bg-opacity-50 ' />
|
||||
<div className="content-container text-white flex flex-col md:flex-row gap-16 md:gap-32 relative" style={{ marginTop: 'auto' }}>
|
||||
<img src={data.thumbnail_image} className={'w-64 md:w-[128px] aspect-square rounded-16 md:rounded-24 border-2 border-gray-100'} alt="" />
|
||||
<div className='flex flex-col gap-4'>
|
||||
<p className="text-body6">TOURNAMENT 🏆</p>
|
||||
<p className="text-body1 md:text-h2 font-bold">{data.title}</p>
|
||||
<p className="text-body3"> {`${dayjs(data.start_date).format('Do')} - ${dayjs(data.end_date).format('Do MMMM, YYYY')}`}</p>
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{tournamentDetails.title} Tournament</title>
|
||||
</Helmet>
|
||||
<div className="w-full p-16 md:p-24 flex flex-col min-h-[240px] md:min-h-[280px] relative">
|
||||
<img src={tournamentDetails.cover_image} className='absolute inset-0 h-full w-full object-cover object-top' alt="" />
|
||||
<div className='absolute inset-0 h-full w-full bg-black bg-opacity-50 ' />
|
||||
<div className="content-container text-white flex flex-col md:flex-row gap-16 md:gap-32 relative" style={{ marginTop: 'auto' }}>
|
||||
<img src={tournamentDetails.thumbnail_image} className={'w-64 md:w-[128px] aspect-square rounded-16 md:rounded-24 border-2 border-gray-100'} alt="" />
|
||||
<div className='flex flex-col gap-4'>
|
||||
<p className="text-body6">TOURNAMENT 🏆</p>
|
||||
<p className="text-body1 md:text-h2 font-bold">{tournamentDetails.title}</p>
|
||||
<p className="text-body3"> {`${dayjs(tournamentDetails.start_date).format('Do')} - ${dayjs(tournamentDetails.end_date).format('Do MMMM, YYYY')}`}</p>
|
||||
|
||||
<p className='text-body5'><IoLocationOutline className="mr-8" /> {data.location}</p>
|
||||
<p className='text-body5'><IoLocationOutline className="mr-8" /> {tournamentDetails.location}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
import { useMemo } from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { Tournament } from 'src/graphql'
|
||||
import { useCarousel } from 'src/utils/hooks'
|
||||
import { useTournament } from '../TournamentDetailsContext'
|
||||
|
||||
interface Props {
|
||||
data: Pick<Tournament, 'events_count' | 'makers_count' | 'projects_count'>
|
||||
}
|
||||
|
||||
export default function Navigation({ data }: Props) {
|
||||
export default function Navigation() {
|
||||
|
||||
const { viewportRef, } = useCarousel({
|
||||
align: 'start', slidesToScroll: 2,
|
||||
containScroll: "trimSnaps",
|
||||
})
|
||||
|
||||
const { tournamentDetails } = useTournament()
|
||||
|
||||
const links = useMemo(() => [
|
||||
{
|
||||
text: "Overview",
|
||||
path: "overview",
|
||||
},
|
||||
{
|
||||
text: `Events (${data.events_count})`,
|
||||
text: `Events (${tournamentDetails.events_count})`,
|
||||
path: "events",
|
||||
},
|
||||
{
|
||||
text: `Makers (${data.makers_count})`,
|
||||
text: `Makers (${tournamentDetails.makers_count})`,
|
||||
path: "makers",
|
||||
},
|
||||
{
|
||||
@@ -42,7 +41,7 @@ export default function Navigation({ data }: Props) {
|
||||
// path: "resources",
|
||||
// isDisabled: true,
|
||||
// },
|
||||
], [data.events_count, data.makers_count])
|
||||
], [tournamentDetails.events_count, tournamentDetails.makers_count])
|
||||
|
||||
return (
|
||||
<div className="w-full bg-white py-16 border-b border-gray-200 sticky-top-element z-10">
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
|
||||
import React, { createContext, PropsWithChildren, useContext } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import LoadingPage from 'src/Components/LoadingPage/LoadingPage'
|
||||
import NotFoundPage from 'src/features/Shared/pages/NotFoundPage/NotFoundPage'
|
||||
import { GetTournamentByIdQuery, useGetTournamentByIdQuery } from 'src/graphql'
|
||||
|
||||
interface ITournamentDetails {
|
||||
makers: GetTournamentByIdQuery['getMakersInTournament']['makers']
|
||||
me: GetTournamentByIdQuery['me']
|
||||
tournamentDetails: GetTournamentByIdQuery['getTournamentById']
|
||||
myParticipationInfo: GetTournamentByIdQuery['tournamentParticipationInfo']
|
||||
}
|
||||
|
||||
const Ctx = createContext<ITournamentDetails>(null!)
|
||||
|
||||
|
||||
export default function TournamentDetailsContext({ children }: PropsWithChildren<{}>) {
|
||||
const { id } = useParams()
|
||||
|
||||
const tournaemntQuery = useGetTournamentByIdQuery({
|
||||
variables: {
|
||||
id: Number(id)!,
|
||||
},
|
||||
skip: !id
|
||||
})
|
||||
|
||||
|
||||
|
||||
if (tournaemntQuery.loading)
|
||||
return <LoadingPage />
|
||||
|
||||
if (!tournaemntQuery.data?.getTournamentById)
|
||||
return <NotFoundPage />
|
||||
|
||||
const { getMakersInTournament: makers, me, getTournamentById: tournamentDetails, tournamentParticipationInfo: myParticipationInfo } = tournaemntQuery.data
|
||||
|
||||
return (
|
||||
<Ctx.Provider value={{ makers: makers.makers, me, tournamentDetails, myParticipationInfo }}>{children}</Ctx.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useTournament = () => {
|
||||
return useContext(Ctx)
|
||||
}
|
||||
@@ -7,49 +7,35 @@ import Navigation from './Navigation/Navigation'
|
||||
import EventsPage from '../EventsPage/EventsPage'
|
||||
import MakersPage from '../MakersPage/MakersPage'
|
||||
import ProjectsPage from '../ProjectsPage/ProjectsPage'
|
||||
import { useGetTournamentByIdQuery, GetTournamentByIdQuery } from 'src/graphql'
|
||||
import LoadingPage from 'src/Components/LoadingPage/LoadingPage'
|
||||
import NotFoundPage from 'src/features/Shared/pages/NotFoundPage/NotFoundPage'
|
||||
import { GetTournamentByIdQuery } from 'src/graphql'
|
||||
import TournamentDetailsContext from './TournamentDetailsContext'
|
||||
|
||||
|
||||
|
||||
export type MeTournament = GetTournamentByIdQuery['me']
|
||||
|
||||
export default function TournamentDetailsPage() {
|
||||
|
||||
const { id } = useParams()
|
||||
|
||||
const tournaemntQuery = useGetTournamentByIdQuery({
|
||||
variables: {
|
||||
id: Number(id)!,
|
||||
},
|
||||
skip: !id
|
||||
})
|
||||
|
||||
if (tournaemntQuery.loading)
|
||||
return <LoadingPage />
|
||||
|
||||
if (!tournaemntQuery.data?.getTournamentById)
|
||||
return <NotFoundPage />
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
"--maxPageWidth": "910px"
|
||||
} as any}>
|
||||
<Helmet>
|
||||
<title>{tournaemntQuery.data.getTournamentById.title} Tournament</title>
|
||||
</Helmet>
|
||||
<Header data={tournaemntQuery.data.getTournamentById} />
|
||||
<Navigation data={tournaemntQuery.data.getTournamentById} />
|
||||
|
||||
<div className="content-container !mt-24">
|
||||
<Routes >
|
||||
<Route index element={<Navigate to='overview' />} />
|
||||
<Route path='overview' element={<OverviewPage data={tournaemntQuery.data.getTournamentById} avatars={tournaemntQuery.data.getMakersInTournament.makers.map(m => m.user.avatar)} isRegistered={!!tournaemntQuery.data.tournamentParticipationInfo} />} />
|
||||
<Route path='events' element={<EventsPage data={tournaemntQuery.data.getTournamentById} />} />
|
||||
<Route path='makers' element={<MakersPage data={tournaemntQuery.data.getTournamentById} />} />
|
||||
<Route path='projects' element={<ProjectsPage data={tournaemntQuery.data.getTournamentById} />} />
|
||||
</Routes>
|
||||
</div>
|
||||
<TournamentDetailsContext>
|
||||
<Header />
|
||||
<Navigation />
|
||||
|
||||
<div className="content-container !mt-24">
|
||||
<Routes >
|
||||
<Route index element={<Navigate to='overview' />} />
|
||||
<Route path='overview' element={<OverviewPage />} />
|
||||
<Route path='events' element={<EventsPage />} />
|
||||
<Route path='makers' element={<MakersPage />} />
|
||||
<Route path='projects' element={<ProjectsPage />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</TournamentDetailsContext>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user