feat: extract tournament details to context provider

This commit is contained in:
MTG2000
2022-09-09 20:37:14 +03:00
parent 329ecf3b60
commit e1a2e46276
9 changed files with 122 additions and 102 deletions

View File

@@ -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'>

View File

@@ -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
}

View File

@@ -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 (

View File

@@ -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>
)
}

View File

@@ -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);

View File

@@ -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>
</>
)
}

View File

@@ -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">

View File

@@ -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)
}

View File

@@ -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>
)
}