From 36fd61d3ac10b478c238d356f146e058af038704 Mon Sep 17 00:00:00 2001 From: sunda <> Date: Fri, 22 Oct 2021 15:44:28 +0200 Subject: [PATCH] started program guide list --- index.js | 13 +++++---- src/components/EpisodeCard/index.js | 43 ++++++++++++++++++++++++++++ src/components/EpisodeCard/styles.js | 39 +++++++++++++++++++++++++ src/components/Flex/index.js | 16 +++++++++++ src/components/Link/index.js | 4 +-- src/components/Text/index.js | 4 +-- src/data/strings.js | 2 ++ src/hooks/data.js | 14 ++++----- src/pages/Program/helpers.js | 35 ++++++++++++++++++++++ src/pages/Program/index.js | 42 +++++++++++++++++++++++++++ src/pages/Program/styles.js | 42 +++++++++++++++++++++++++++ src/pages/Series/index.js | 7 ++--- src/pages/SeriesPage/styles.js | 6 ++-- src/store/index.js | 2 +- 14 files changed, 243 insertions(+), 26 deletions(-) create mode 100644 src/components/EpisodeCard/index.js create mode 100644 src/components/EpisodeCard/styles.js create mode 100644 src/pages/Program/helpers.js create mode 100644 src/pages/Program/index.js create mode 100644 src/pages/Program/styles.js diff --git a/index.js b/index.js index 0d54d17..5f45bc8 100644 --- a/index.js +++ b/index.js @@ -5,35 +5,38 @@ import { BrowserRouter, Route, Switch } from 'react-router-dom' import Main from './app' import SeriesPage from './src/pages/SeriesPage' -import { useEventApi, useEventCalendar } from './src/hooks/data' +import { useEventApi } from './src/hooks/data' import { useTheme } from './src/store' import { useTimeout } from './src/hooks/timerHooks' import LoaderLayout from './src/pages/LoaderLayout' import FourOhFour from './src/pages/404' import Series from './src/pages/Series' +import Program from './src/pages/Program' const App = () => { const { theme } = useTheme((store) => store) - const { data: calData, calLoading } = useEventCalendar() - const { data: seriesDataArray, loading: eventsLoading } = useEventApi() + const { data, loading: eventsLoading } = useEventApi() const [minLoadTimePassed, setMinTimeUp] = useState(false) useTimeout(() => { setMinTimeUp(true) }, 1500) + // console.log({ episodes: data.episodes, series: data.series }) + + const seriesData = data.series ? Object.values(data.series) : [] - const seriesData = Object.values(seriesDataArray) return ( - {calLoading || eventsLoading || !minLoadTimePassed ? ( + {!seriesData.length || eventsLoading || !minLoadTimePassed ? ( ) : ( + {seriesData.length ? seriesData.map(series => ( diff --git a/src/components/EpisodeCard/index.js b/src/components/EpisodeCard/index.js new file mode 100644 index 0000000..51328cd --- /dev/null +++ b/src/components/EpisodeCard/index.js @@ -0,0 +1,43 @@ +import { h } from 'preact' +import { format } from 'date-fns' +import Link from '../Link' +import { H2, H3, Label } from '../Text' +import strings from '../../data/strings' +import { andList } from '../../helpers/string' +import { colours } from '../../assets/theme' +import { Img, Left, Right, Title, Row, Column, StyledButton as Button } from './styles' +import { useEventApi } from '../../hooks/data' + +const EpisodeCard = ({ image, title, seriesId, beginsOn, id, ...rest }) => { + const { data: { series: allSeries } } = useEventApi() + + const series = seriesId ? allSeries.filter(({ id }) => id === seriesId)[0] : {} + const hosts = series.hosts ? series.hosts.map(host => host.actor.name) : null + const startTime = format(new Date(beginsOn), 'ha') + + + return ( + + + + + {title} +
+ +

From: {`${series.title}: ${series.subtitle}`}

+ {hosts ? : null} +
+ +
+
+ + + +
+ ) +} + + +export default EpisodeCard diff --git a/src/components/EpisodeCard/styles.js b/src/components/EpisodeCard/styles.js new file mode 100644 index 0000000..fa1d461 --- /dev/null +++ b/src/components/EpisodeCard/styles.js @@ -0,0 +1,39 @@ +import styled from 'styled-components' +import { colours } from '../../assets/theme' +import { Label, H2 } from '../Text' +import { Row as FlexRow, Column as FlexColumn } from '../Flex' +import Button from '../Button' + +export const Row = styled(FlexRow)` + +` +export const Column = styled(FlexColumn)` + height: 100%; + max-width: 50%; +` + +export const Left = styled(FlexRow)` + +` + +export const Title = styled(H2)` + /* max-width: 50% */ +` + +export const Right = styled.div` + +` +export const StyledButton = styled(Button)` + width: max-content; + padding: 0.3em 2em; +` + +export const Img = styled.div` + background: url(${({ src }) => src}); + width: 380px; + height: 215px; + background-size: cover; + position: relative; + background-position: center; + margin-right: 1em; +` \ No newline at end of file diff --git a/src/components/Flex/index.js b/src/components/Flex/index.js index eadb460..0f352d7 100644 --- a/src/components/Flex/index.js +++ b/src/components/Flex/index.js @@ -1,3 +1,4 @@ +import { bool, number, oneOf } from 'prop-types' import styled from 'styled-components' export const Row = styled.div` @@ -5,6 +6,9 @@ export const Row = styled.div` flex-direction: ${props => (props.reverse ? 'row-reverse' : 'row')}; justify-content: ${props => props.justify || 'flex-start'}; align-items: ${props => props.align || 'flex-start'}; + ${props => props.flex ? ` + flex: ${props.flex}; + ` : ''} ` export const Column = styled.div` @@ -12,4 +16,16 @@ export const Column = styled.div` flex-direction: ${props => (props.reverse ? 'column-reverse' : 'column')}; justify-content: ${props => props.justify || 'flex-start'}; align-items: ${props => props.align || 'flex-start'}; + ${props => props.flex ? ` + flex: ${props.flex}; + ` : ''} ` +const propTypes = { + reverse: bool, + justify: oneOf(['flex-start', 'flex-end', 'center', 'space-around', 'space-between']), + align: oneOf(['flex-start', 'flex-end', 'center', 'stretch']), + flex: number +} + +Row.propTypes = propTypes +Column.propTypes = propTypes \ No newline at end of file diff --git a/src/components/Link/index.js b/src/components/Link/index.js index 51df15d..2b29f91 100644 --- a/src/components/Link/index.js +++ b/src/components/Link/index.js @@ -5,14 +5,14 @@ import { useRouteMatch } from 'react-router-dom' import { A } from '../Text' import { RRLink } from './styles' -const Link = ({ children, to, activeOnlyWhenExact = true, href, textProps: { colour, size } = {}, navLink, ...rest }) => { +const Link = ({ children, to, activeOnlyWhenExact = true, href, textProps: { colour, size, weight } = {}, navLink, ...rest }) => { const match = useRouteMatch({ path: to, exact: activeOnlyWhenExact }) return href ? {children} : ( - + {children} ) diff --git a/src/components/Text/index.js b/src/components/Text/index.js index a4fa6e3..a8c6484 100644 --- a/src/components/Text/index.js +++ b/src/components/Text/index.js @@ -91,10 +91,10 @@ export const H2 = ({ children, size, ...rest }) => ( ) -export const H3 = ({ children, size, ...rest }) => ( +export const H3 = ({ children, size, weight = '700', ...rest }) => ( { export const useEventApi = () => { - const [series, episodes, setSeries, setEpisodes] = useSeriesStore(store => [store.series, store.episodes, store.setSeries, store.setEpisodes]) - const [loading, setLoading] = useState(!!series.length) - + const [data, setData] = useSeriesStore(store => [store.series, store.setSeries]) + const [loading, setLoading] = useState(!!data.length) async function fetchData() { - if (!series.length) { + if (!data.length) { setLoading(true) const { data: responseData } = await axios.get( `${config.EVENTS_API_URL}/events` ) - setSeries(responseData) - // setEpisodes() - - // console.log({ episodes }) + setData(responseData) setLoading(false) } } @@ -124,5 +120,5 @@ export const useEventApi = () => { fetchData() }, []) - return { loading, data: series } + return { loading, data } } \ No newline at end of file diff --git a/src/pages/Program/helpers.js b/src/pages/Program/helpers.js new file mode 100644 index 0000000..53eef37 --- /dev/null +++ b/src/pages/Program/helpers.js @@ -0,0 +1,35 @@ +import { isBefore, format, isToday, isTomorrow } from 'date-fns' +import { capitaliseFirstLetter } from '../../helpers/string' +import strings from '../../data/strings' + +export const getScheduleFromData = data => data.filter(item => { + const { endsOn } = item + const today = format(new Date(), 'yyyy/M/d') + const broadcastEnd = new Date(endsOn) + return !isBefore(broadcastEnd, new Date(today)) +}) + .reduce((obj, item) => { + const newObject = obj + const { beginsOn } = item + const startDay = format(new Date(beginsOn), 'yyyy-MM-dd') + + if (newObject[startDay]) { + newObject[startDay] = [...newObject[startDay], item] + } else { + newObject[startDay] = [item] + } + + return newObject + }, {}) + + + +export const formatDay = (dateTime, lang = 'en') => { + let day = '' + const date = new Date(dateTime) + console.log({ date }) + if (isToday(date)) day = strings[lang].today + if (isTomorrow(date)) day = strings[lang].tomorrow + else day = format(date, 'cccc MMM d') + return capitaliseFirstLetter(day) +} diff --git a/src/pages/Program/index.js b/src/pages/Program/index.js new file mode 100644 index 0000000..c9bcbed --- /dev/null +++ b/src/pages/Program/index.js @@ -0,0 +1,42 @@ +/* eslint-disable react/prop-types */ +import { isWithinInterval } from 'date-fns' +import { h } from 'preact' +import { H1, H2 } from '../../components/Text' +import strings from '../../data/strings' +import { useEventApi } from '../../hooks/data' +import { Content, ScheduleList, Day } from './styles' + +import Page from '../../layouts/Page' +import { formatDay, getScheduleFromData } from './helpers' +import EpisodeCard from '../../components/EpisodeCard' +import { colours } from '../../assets/theme' + +const Program = () => { + const { data } = useEventApi() + + const episodes = getScheduleFromData(data.episodes) + console.log({ episodes }) + + return ( + + + + + {Object.keys(episodes || {}).sort((a, b) => new Date(a) - new Date(b)).map(day => ( + +

{formatDay(day)}

+ {episodes[day].map(episode => ( + + ))} + +
+ ))} +
+ {/*

Program

*/} + +
+
+ ) +} + +export default Program diff --git a/src/pages/Program/styles.js b/src/pages/Program/styles.js new file mode 100644 index 0000000..501ba62 --- /dev/null +++ b/src/pages/Program/styles.js @@ -0,0 +1,42 @@ +import styled from 'styled-components' +import { screenSizes } from '../../assets/theme' +import { Row } from '../../components/Flex' + +export const SeriesGrid = styled.div` + margin-left: 32px; +` +export const ScheduleList = styled.ul` + display: flex; + flex-direction: column; +` + +export const Day = styled.div` + margin: 0 0 6em 0; + + h1 { + margin-bottom: 0.5em; + } +` + +export const Content = styled.div` + width: 80vw; + max-width: ${screenSizes.lg}px; + margin: 0 auto; + padding: 64px 0; + overflow-y: scroll; + + + + ::-webkit-scrollbar { + display: none; + } + ` +/* ${mediaQuery.lessThan('lg')` + max-height: calc(100vh - 200px); + `} + + ${mediaQuery.lessThan('md')` + max-width: 600px; + padding: 8px 0; + margin: 0 32px; + `}; */ \ No newline at end of file diff --git a/src/pages/Series/index.js b/src/pages/Series/index.js index 6652472..8ef0cb8 100644 --- a/src/pages/Series/index.js +++ b/src/pages/Series/index.js @@ -11,12 +11,11 @@ import SeriesCard from '../../components/SeriesCard' import { colours } from '../../assets/theme' const Series = () => { - const { data: seriesDataArray } = useEventApi() + const { data } = useEventApi() const pastSeries = [] - const currentSeries = seriesDataArray.filter(series => { + const currentSeries = data.series ? data.series.filter(series => { // const seriesInTheLastMonth = series.episodes.past.filter(episode => { - // }) if (series.episodes.future.length) { return true @@ -24,7 +23,7 @@ const Series = () => { pastSeries.push(series) return false - }) + }) : [] return ( diff --git a/src/pages/SeriesPage/styles.js b/src/pages/SeriesPage/styles.js index 33820a3..50971b5 100644 --- a/src/pages/SeriesPage/styles.js +++ b/src/pages/SeriesPage/styles.js @@ -13,6 +13,7 @@ import CrossSvg from '../../components/Svg/Cross' import { H1, H2, Span, Label } from '../../components/Text' import Link from '../../components/Link' import Button from '../../components/Button' +import { slugify } from '../../helpers/string' export const TrailerContainer = styled.div` height: 22em; @@ -140,8 +141,6 @@ const renderTitles = titles => export const EpisodeCard = ({ title, image, - - description, beginsOn, hasPassed, @@ -149,6 +148,7 @@ export const EpisodeCard = ({ onClickButton, tzShort, theme, + id }) => { const startDate = new Date(beginsOn) const utcDate = zonedTimeToUtc(startDate, 'Europe/Berlin') @@ -156,7 +156,7 @@ export const EpisodeCard = ({ const { timeZone } = Intl.DateTimeFormat().resolvedOptions() const zonedDate = utcToZonedTime(utcDate, timeZone) return ( - + {`${hasPassed ? translations.en.streamDatePast : ''}`} diff --git a/src/store/index.js b/src/store/index.js index 679ab32..bba022a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2,7 +2,7 @@ import create from 'zustand' import { defaultTheme } from '../assets/theme' export const useSeriesStore = create((set, get) => ({ - series: [], + series: {}, episodes: [], setSeries: series => set({ series }), setEpisodes: () => {