tournament page ready

This commit is contained in:
Sendou
2020-05-02 03:46:36 +03:00
parent a878be2d85
commit 2b3124ca18
11 changed files with 240 additions and 143 deletions

View File

@@ -1,115 +1,92 @@
import React, { useState, useEffect, useRef } from "react"
import jstz from "jstz"
import React, { useContext } from "react"
import { useQuery } from "@apollo/react-hooks"
import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverArrow,
PopoverCloseButton,
PopoverBody,
Box,
Link,
Icon,
} from "@chakra-ui/core"
UPCOMING_EVENTS,
UpcomingEventsData,
} from "../../graphql/queries/upcomingEvents"
import { RouteComponentProps } from "@reach/router"
import { useContext } from "react"
import MyThemeContext from "../../themeContext"
import PageHeader from "../common/PageHeader"
import { Helmet } from "react-helmet-async"
import Button from "../elements/Button"
import Loading from "../common/Loading"
import Error from "../common/Error"
import { getWeek, ordinal_suffix_of } from "../../utils/helperFunctions"
import SubHeader from "../common/SubHeader"
import { Box, Badge, Flex } from "@chakra-ui/core"
import { months, days } from "../../utils/lists"
import MyThemeContext from "../../themeContext"
import TournamentInfo from "./TournamentInfo"
const CalendarPage: React.FC<RouteComponentProps> = () => {
const { darkerBgColor, themeColorWithShade, grayWithShade } = useContext(
MyThemeContext
)
const [showCode, setShowCode] = useState(false)
const calenderDiv = useRef<HTMLDivElement | null>(null)
const badgeColor: { [key: string]: string } = {
Friday: "purple",
Saturday: "green",
Sunday: "blue",
} as const
const iFrameHTML = `<iframe title="calendar" src="https://calendar.google.com/calendar/embed?height=600&amp;wkst=2&amp;bgcolor=%23ffffff&amp;src=NDNnYnJlamkxbnQyZTY1dWJuZzdvYWkxZGtAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ&amp;color=%23E67C73&amp;showTitle=0&amp;showNav=1&amp;showDate=1&amp;showPrint=0&amp;showCalendars=0&amp;ctz=${jstz
.determine()
.name()}" style=border-width: 0 width=${"90%"} height="1000" frameBorder="0" scrolling="no"></iframe>`
const CalendarPage: React.FC<RouteComponentProps> = ({}) => {
const { darkerBgColor, grayWithShade } = useContext(MyThemeContext)
const { data, error, loading } = useQuery<UpcomingEventsData>(UPCOMING_EVENTS)
//This is a weird solution but I couldn't get it working just setting the iframe src from a variable
useEffect(() => {
if (!calenderDiv?.current) return
calenderDiv.current.innerHTML = iFrameHTML
}, [iFrameHTML])
if (loading) return <Loading />
if (error) return <Error errorMessage={error.message} />
const events = data!.upcomingEvents
let lastPrintedWeek: number | null = null
let lastPrintedDay: number | null = null
let lastPrintedMonth: number | null = null
const thisWeekNumber = getWeek(new Date())
return (
<>
<Helmet>
<title>Competitive Calendar | sendou.ink</title>
</Helmet>
<PageHeader title="Competitive Calendar" />
<Popover placement="top-start">
<PopoverTrigger>
<Box mt="1em">
<Button outlined onClick={() => setShowCode(!showCode)}>
Show emoji code
</Button>
</Box>
</PopoverTrigger>
<PopoverContent zIndex={4} background={darkerBgColor} width="280px">
<PopoverArrow />
<PopoverCloseButton />
<PopoverBody>
<h4>
<span role="img" aria-label="money bag emoji">
💰
</span>{" "}
- Has prizes
<br />
<span role="img" aria-label="masks emoji">
🎭
</span>{" "}
- Unconventional ruleset
<br />
<span role="img" aria-label="lock emoji">
🔒
</span>{" "}
- Limited registration
<br />
<span role="img" aria-label="handshake emoji">
🤝
</span>{" "}
- Local event
<br />
<span role="img" aria-label="dice emoji">
🎲
</span>{" "}
- Solo registration available
<br />
<span role="img" aria-label="eyes emoji">
👀
</span>{" "}
- No open registration
</h4>
</PopoverBody>
</PopoverContent>
</Popover>
<Box mt="2em" ref={calenderDiv} />
<Box mt="2em" color={grayWithShade}>
If an event is missing you can contact{" "}
<Link
href="https://twitter.com/Kbot_273"
color={themeColorWithShade}
isExternal
>
Kbot <Icon name="external-link" mx="2px" />
</Link>{" "}
about it.
<br />
You can add the calendar to your personal Google Calendar by pressing
the plus button above. If you are using other kind of calendar program
you can try{" "}
<Link
href="https://calendar.google.com/calendar/ical/43gbreji1nt2e65ubng7oai1dk%40group.calendar.google.com/public/basic.ics"
color={themeColorWithShade}
isExternal
>
this link <Icon name="external-link" mx="2px" />
</Link>{" "}
instead.
{events.map((event) => {
const time = new Date(parseInt(event.date))
const weekNumber = getWeek(time)
const thisDay = time.getDate()
const thisDayOfTheWeek = days[time.getDay()]
const thisMonth = time.getMonth()
const printWeekHeader = weekNumber !== lastPrintedWeek
const printDayHeader =
thisDay !== lastPrintedDay || thisMonth !== lastPrintedMonth
if (printWeekHeader) {
lastPrintedWeek = weekNumber
}
if (printDayHeader) {
lastPrintedDay = thisDay
lastPrintedMonth = thisMonth
}
const colorForBadge = badgeColor[thisDayOfTheWeek] ?? "red"
return (
<React.Fragment key={event.discord_invite_url}>
{printWeekHeader && (
<Box my="2em">
<SubHeader>
Week {weekNumber}{" "}
{thisWeekNumber === weekNumber && <>(This week)</>}
</SubHeader>
</Box>
)}
{printDayHeader && (
<Flex
bg={darkerBgColor}
borderRadius="5px"
p="0.5em"
my="1.5em"
alignItems="center"
>
{months[thisMonth + 1]} {thisDay}
{ordinal_suffix_of(thisDay)}
<Badge ml="1em" variantColor={colorForBadge}>
{thisDayOfTheWeek}
</Badge>
</Flex>
)}
<TournamentInfo tournament={event} date={time} />
</React.Fragment>
)
})}
<Box color={grayWithShade} mt="2em">
All events listed in your local time: {new Date().toTimeString()}
</Box>
</>
)

View File

@@ -0,0 +1,73 @@
import React, { useState, useContext } from "react"
import { CompetitiveFeedEvent } from "../../graphql/queries/upcomingEvents"
import Markdown from "../elements/Markdown"
import { Heading, Box, Flex, Link as ChakraLink } from "@chakra-ui/core"
import Button from "../elements/Button"
import { FiInfo, FiClock } from "react-icons/fi"
import { FaDiscord } from "react-icons/fa"
import MyThemeContext from "../../themeContext"
import UserAvatar from "../common/UserAvatar"
import { Link } from "@reach/router"
interface TournamentInfoProps {
tournament: CompetitiveFeedEvent
date: Date
}
const TournamentInfo: React.FC<TournamentInfoProps> = ({
tournament,
date,
}) => {
const { themeColorWithShade, grayWithShade } = useContext(MyThemeContext)
const [expanded, setExpanded] = useState(false)
const poster = tournament.poster_discord_user
return (
<Box>
<Heading fontFamily="'Rubik', sans-serif" size="lg">
{tournament.name}
</Heading>
<Flex alignItems="center" color={grayWithShade}>
<Box as={FiClock} mr="0.5em" color={themeColorWithShade} />
{date.toLocaleString()}
</Flex>
<Flex alignItems="center" color={grayWithShade} my="0.5em">
{poster.twitter_name && (
<Box mr="0.5em">
<UserAvatar
twitterName={poster.twitter_name}
name={poster.username}
size="sm"
/>
</Box>
)}{" "}
<Link to={`/u/${poster.discord_id}`}>
<Box>
{poster.username}#{poster.discriminator}
</Box>
</Link>
</Flex>
<Flex flexWrap="wrap" my="1em">
<Box mr="1em" mb="1em">
<a href={tournament.discord_invite_url}>
<Button outlined icon={FaDiscord} width="150px">
Join Discord
</Button>
</a>
</Box>
<Button
outlined={expanded}
onClick={() => setExpanded(!expanded)}
icon={FiInfo}
width="150px"
>
{expanded ? "Hide info" : "Show info"}
</Button>
</Flex>
{expanded && <Markdown value={tournament.description} />}
</Box>
)
}
export default TournamentInfo

View File

@@ -19,7 +19,7 @@
content: "";
position: absolute;
top: 50%;
border-bottom: 4px solid;
border-bottom: 2px solid;
border-color: var(--sub-header-border);
width: 592px; /* half of limiter */
margin: 0 20px;

View File

@@ -3,7 +3,7 @@ import "./SubHeader.css"
import MyThemeContext from "../../themeContext"
interface SubHeaderProps {
children: string[] | string
children: React.ReactNode
}
const SubHeader: React.FC<SubHeaderProps> = ({ children }) => {

View File

@@ -9,6 +9,7 @@ interface ButtonProps {
onClick?: () => void
size?: "xs" | "sm" | "lg" | "md"
icon?: IconType
width?: string
outlined?: boolean
disabled?: boolean
loading?: boolean
@@ -21,6 +22,7 @@ const Button: React.FC<ButtonProps> = ({
size,
disabled,
loading,
width,
outlined = false,
}) => {
const { themeColor } = useContext(MyThemeContext)
@@ -33,6 +35,7 @@ const Button: React.FC<ButtonProps> = ({
size={size}
isDisabled={disabled}
isLoading={loading}
width={width ?? undefined}
>
{children}
</ChakraButton>

View File

@@ -16,13 +16,7 @@ const HomePage: React.FC<RouteComponentProps> = () => {
<title>sendou.ink | Competitive Splatoon Hub</title>
</Helmet>
<Flex flexDirection="column" alignItems="center">
<Image
className="rgb"
src={posterGirl[colorMode]}
w="400px"
h="auto"
title="Picture by borzoic (@borzoic_ on Twitter)"
/>
<Image className="rgb" src={posterGirl[colorMode]} w="400px" h="auto" />
<Heading
letterSpacing="1px"
fontFamily="'Rubik', sans-serif"

View File

@@ -12,7 +12,7 @@ const About: React.FC<RouteComponentProps> = () => {
<title>About | sendou.ink</title>
</Helmet>
<div style={{ marginTop: "1em" }}>
<Heading size="lg" mb="0.5em">
<Heading size="lg" mb="0.5em" fontFamily="'Rubik', sans-serif">
Help
</Heading>
If you need help using the site don't hesitate to ask on our Discord.
@@ -29,20 +29,55 @@ const About: React.FC<RouteComponentProps> = () => {
<Heading size="lg">Thanks to</Heading>
<ul style={{ marginLeft: "1.2em", marginTop: "0.5em" }}>
<li>
<a href="https://twitter.com/LeanYoshi">Lean</a> (provided the Top
500 X Rank data)
<Link
isExternal
color={themeColorWithShade}
href="https://twitter.com/LeanYoshi"
>
Lean
</Link>{" "}
(provided the Top 500 X Rank data)
</li>
<li>
<a href="https://twitter.com/zorg_z0rg_z0r8">zorg</a> (provided
background pictures for the map planner)
<Link
isExternal
color={themeColorWithShade}
href="https://twitter.com/zorg_z0rg_z0r8"
>
zorg
</Link>{" "}
(provided background pictures for the map planner)
</li>
<li>
<a href="https://twitter.com/ganbawoomy">ganbawoomy</a> (provided
the data for tournament browser)
<Link
isExternal
color={themeColorWithShade}
href="https://twitter.com/ganbawoomy"
>
ganbawoomy
</Link>{" "}
(provided the data for tournament browser)
</li>
<li>
<a href="https://twitter.com/noaim_brn">NoAimbUrn</a> (gave plenty
of useful feedback)
<Link
isExternal
color={themeColorWithShade}
href="https://twitter.com/noaim_brn"
>
NoAimbUrn
</Link>{" "}
(gave plenty of useful feedback)
</li>
<li>
<Link
isExternal
color={themeColorWithShade}
href="https://twitter.com/borzoic_"
>
borzoic
</Link>{" "}
(art for the site like the inkling on the front page as well as
footer pictures)
</li>
</ul>
</div>

View File

@@ -27,8 +27,8 @@ import {
FiLogOut,
FiUser,
FiPlus,
FiShoppingCart,
FiLogIn,
FiHeart,
} from "react-icons/fi"
import { RiTShirt2Line } from "react-icons/ri"
import Logo from "./Logo"
@@ -148,11 +148,7 @@ export const SideNavContent: React.FC<SideNavProps> = ({ showLogo = true }) => {
<NavItem to="calendar" icon={FiCalendar} title="Calendar" />
<NavItem to="builds" icon={RiTShirt2Line} title="Builds" />
<NavItem to="u" icon={FiUsers} title="User Search" />
<NavItem
to="freeagents"
icon={FiShoppingCart}
title="Free Agents"
/>
<NavItem to="freeagents" icon={FiHeart} title="Free Agents" />
<NavItem
to="tournaments"
icon={FiAward}

View File

@@ -1,24 +1,25 @@
import { gql, DocumentNode } from "apollo-boost"
import { User } from "../../types"
export interface UpcomingEventsData {
upcomingEvents: {
name: string
date: string
description: string
message_url: string
discord_invite_url: string
picture_url?: string
poster_discord_user: {
username: string
discriminator: string
twitter_name?: string
discord_id: string
}
}[]
export interface CompetitiveFeedEvent {
name: string
date: string
description: string
message_url: string
discord_invite_url: string
picture_url?: string
poster_discord_user: {
username: string
discriminator: string
twitter_name?: string
discord_id: string
}
}
export const SEARCH_FOR_USER: DocumentNode = gql`
export interface UpcomingEventsData {
upcomingEvents: CompetitiveFeedEvent[]
}
export const UPCOMING_EVENTS: DocumentNode = gql`
{
upcomingEvents {
name

View File

@@ -36,3 +36,11 @@ export const removeFalsy = (obj: { [key: string]: any }) => {
})
return newObj
}
// https://stackoverflow.com/a/31810991
export const getWeek = (date: Date) => {
const onejan = new Date(date.getFullYear(), 0, 1)
const today = new Date(date.getFullYear(), date.getMonth(), date.getDate())
const dayOfYear = (today.getTime() - onejan.getTime() + 86400000) / 86400000
return Math.ceil(dayOfYear / 7)
}

View File

@@ -1586,6 +1586,16 @@ export const months = [
"December",
] as const
export const days = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
] as const
export const weapons = [
"Sploosh-o-matic",
"Neo Sploosh-o-matic",