Skip to content

Commit a473c2e

Browse files
committedApr 13, 2020
feat: series & films on the dashboard
1 parent 622a730 commit a473c2e

File tree

23 files changed

+337
-181
lines changed

23 files changed

+337
-181
lines changed
 
70.2 KB
Loading
Loading
Loading
55 KB
Loading
Loading

‎src/components/card/card.js

+27-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { Container, Group, Item, Cta } from './styles/Card';
2+
import { Container, Group, Title, SubTitle, Text, Meta, Entities, Item, Image } from './styles/Card';
33

44
export function Card({ children, ...restProps }) {
55
return <Container {...restProps}>{children}</Container>;
@@ -9,16 +9,36 @@ Card.Group = function CardGroup({ children, ...restProps }) {
99
return <Group {...restProps}>{children}</Group>;
1010
};
1111

12+
Card.Title = function CardTitle({ children, ...restProps }) {
13+
return <Title {...restProps}>{children}</Title>;
14+
};
15+
16+
Card.Title = function CardTitle({ children, ...restProps }) {
17+
return <Title {...restProps}>{children}</Title>;
18+
};
19+
20+
Card.SubTitle = function CardSubTitle({ children, ...restProps }) {
21+
return <SubTitle {...restProps}>{children}</SubTitle>;
22+
};
23+
24+
Card.Text = function CardText({ children, ...restProps }) {
25+
return <Text {...restProps}>{children}</Text>;
26+
};
27+
28+
Card.Entities = function CardEntities({ children, ...restProps }) {
29+
return <Entities {...restProps}>{children}</Entities>;
30+
};
31+
32+
Card.Meta = function CardMeta({ children, ...restProps }) {
33+
return <Meta {...restProps}>{children}</Meta>;
34+
};
35+
1236
Card.Item = function CardItem({ children, ...restProps }) {
1337
return <Item {...restProps}>{children}</Item>;
1438
};
1539

16-
Card.Cta = function CardCta({ backgroundSrc, children, ...restProps }) {
17-
return (
18-
<Cta backgroundSrc={backgroundSrc} {...restProps}>
19-
{children}
20-
</Cta>
21-
);
40+
Card.Image = function CardImage({ src, ...restProps }) {
41+
return <Image src={src} {...restProps} />;
2242
};
2343

2444
// loading state on cards (placeholder)

‎src/components/card/styles/Card.js

+75-13
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,93 @@ import styled from 'styled-components';
22

33
export const Container = styled.div`
44
display: flex;
5-
border-bottom: 8px solid #222;
6-
padding: 50px 5%;
7-
color: white;
8-
`;
5+
flex-direction: column;
6+
margin: 0 3.5rem;
7+
margin-bottom: 50px;
98
10-
export const Item = styled.div`
11-
display: flex;
12-
margin-right: 5px;
9+
&:first-of-type {
10+
margin-top: 50px;
11+
}
1312
1413
&:last-of-type {
15-
margin-right: 0;
14+
margin-bottom: 0;
1615
}
1716
`;
1817

1918
export const Group = styled.div`
19+
display: flex;
20+
flex-direction: column;
21+
`;
22+
23+
export const Title = styled.p`
24+
font-size: 1.5rem;
25+
color: #e5e5e5;
26+
font-weight: bold;
27+
margin-top: 0;
28+
`;
29+
30+
export const SubTitle = styled.p`
31+
font-size: 12px;
32+
color: #fff;
33+
font-weight: bold;
34+
margin-top: 0;
35+
margin-bottom: 0;
36+
user-select: none;
37+
display: none;
38+
`;
39+
40+
export const Text = styled.p`
41+
margin-top: 5px;
42+
font-size: 10px;
43+
color: #fff;
44+
margin-bottom: 0;
45+
user-select: none;
46+
display: none;
47+
line-height: normal;
48+
`;
49+
50+
export const Entities = styled.div`
2051
display: flex;
2152
flex-direction: row;
2253
`;
2354

24-
export const Cta = styled.button`
25-
cursor: pointer;
55+
export const Meta = styled.div`
56+
display: none;
57+
position: absolute;
58+
bottom: 0;
59+
padding: 10px;
60+
background-color: #0000008f;
61+
`;
62+
63+
export const Image = styled.img`
2664
border: 0;
27-
background: url(${(props) => props.backgroundSrc});
28-
width: 305px;
29-
height: 172px;
65+
background: url(${(props) => props.src});
66+
width: 100%;
67+
max-width: 305px;
68+
height: auto;
3069
padding: 0;
3170
margin: 0;
3271
`;
72+
73+
export const Item = styled.div`
74+
display: flex;
75+
flex-direction: column;
76+
margin-right: 5px;
77+
position: relative;
78+
cursor: pointer;
79+
transition: transform 0.2s;
80+
81+
&:hover {
82+
transform: scale(1.3);
83+
z-index: 99;
84+
}
85+
86+
&:hover ${Meta}, &:hover ${Text}, &:hover ${SubTitle} {
87+
display: block;
88+
z-index: 100;
89+
}
90+
91+
&:last-of-type {
92+
margin-right: 0;
93+
}
94+
`;

‎src/components/header/Header.js

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
import React, { useContext, createContext } from 'react';
1+
import React from 'react';
22
import { Link as ReachRouterLink } from 'react-router-dom';
3-
import { Container, Background, Link, Logo } from './styles/Header';
3+
import { Container, Group, Background, Link, ButtonLink, Logo } from './styles/Header';
44

5-
export const LinkContext = createContext();
6-
7-
export function Header({ bg = true, to, children, ...restProps }) {
8-
return (
9-
<LinkContext.Provider value={{ to }}>
10-
{bg ? <Background {...restProps}>{children}</Background> : children}
11-
</LinkContext.Provider>
12-
);
5+
export function Header({ bg = true, children, ...restProps }) {
6+
return bg ? <Background {...restProps}>{children}</Background> : children;
137
}
148

159
Header.Frame = function HeaderFrame({ children, ...restProps }) {
1610
return <Container {...restProps}>{children}</Container>;
1711
};
1812

13+
Header.Group = function HeaderGroup({ children, ...restProps }) {
14+
return <Group {...restProps}>{children}</Group>;
15+
};
16+
1917
Header.Logo = function HeaderLogo({ to, ...restProps }) {
2018
return (
2119
<ReachRouterLink to={to}>
@@ -24,12 +22,14 @@ Header.Logo = function HeaderLogo({ to, ...restProps }) {
2422
);
2523
};
2624

27-
Header.Link = function HeaderButton({ children, ...restProps }) {
28-
const { to } = useContext(LinkContext);
25+
Header.Text = function HeaderText({ children, ...restProps }) {
26+
return <Link {...restProps}>{children}</Link>;
27+
};
2928

30-
return (
31-
<Link to={to} {...restProps}>
32-
{children}
33-
</Link>
34-
);
29+
Header.Link = function HeaderLink({ children, ...restProps }) {
30+
return <Link {...restProps}>{children}</Link>;
31+
};
32+
33+
Header.ButtonLink = function HeaderButtonLink({ children, ...restProps }) {
34+
return <ButtonLink {...restProps}>{children}</ButtonLink>;
3535
};

‎src/components/header/styles/Header.js

+24-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const Background = styled.div`
77
background: url(../images/misc/home-bg.jpg) top left / cover no-repeat;
88
`;
99

10-
export const Container = styled.section`
10+
export const Container = styled.div`
1111
display: flex;
1212
margin: 0 3.5rem;
1313
height: 4rem;
@@ -16,7 +16,28 @@ export const Container = styled.section`
1616
align-items: center;
1717
`;
1818

19-
export const Link = styled(ReachRouterLink)`
19+
export const Link = styled.p`
20+
color: #fff;
21+
text-decoration: none;
22+
margin-right: 30px;
23+
font-weight: ${(props) => (props.active === 'true' ? '700' : 'normal')};
24+
cursor: pointer;
25+
26+
&:hover {
27+
font-weight: bold;
28+
}
29+
30+
&:last-of-type {
31+
margin-right: 0;
32+
}
33+
`;
34+
35+
export const Group = styled.div`
36+
display: flex;
37+
align-items: center;
38+
`;
39+
40+
export const ButtonLink = styled(ReachRouterLink)`
2041
display: block;
2142
background-color: #e50914;
2243
width: 84px;
@@ -38,6 +59,7 @@ export const Link = styled(ReachRouterLink)`
3859
export const Logo = styled.img`
3960
height: 32px;
4061
width: 108px;
62+
margin-right: 40px;
4163
4264
@media (min-width: 1449px) {
4365
height: 45px;

‎src/components/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,5 @@ import { SignInForm } from './signinform';
77
import { Profiles } from './profiles';
88
import { Footer } from './footer';
99
import { Header } from './header';
10-
import { Slider } from './slider';
1110

12-
export { Accordion, Card, Jumbotron, Feature, OptForm, SignInForm, Profiles, Footer, Header, Slider };
11+
export { Accordion, Card, Jumbotron, Feature, OptForm, SignInForm, Profiles, Footer, Header };

‎src/components/profiles/styles/Profiles.js

+21-19
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,24 @@ export const List = styled.ul`
2424
flex-direction: row;
2525
`;
2626

27+
export const Name = styled.p`
28+
color: #808080;
29+
text-overflow: ellipsis;
30+
font-size: 1rem;
31+
32+
&:hover {
33+
font-weight: bold;
34+
color: #e5e5e5;
35+
}
36+
`;
37+
38+
export const Picture = styled.img`
39+
width: 100%;
40+
max-width: 150px;
41+
height: auto;
42+
border: 3px solid black;
43+
`;
44+
2745
export const Item = styled.li`
2846
max-height: 200px;
2947
max-width: 200px;
@@ -32,32 +50,16 @@ export const Item = styled.li`
3250
margin-right: 30px;
3351
cursor: pointer;
3452
35-
&:hover > img {
53+
&:hover > ${Picture} {
3654
border: 3px solid white;
3755
}
3856
39-
&:hover > p {
57+
&:hover ${Name} {
58+
font-weight: bold;
4059
color: white;
4160
}
4261
4362
&:last-of-type {
4463
margin-right: 0;
4564
}
4665
`;
47-
48-
export const Picture = styled.img`
49-
width: 100%;
50-
max-width: 150px;
51-
height: auto;
52-
border: 3px solid black;
53-
`;
54-
55-
export const Name = styled.p`
56-
color: #808080;
57-
text-overflow: ellipsis;
58-
font-size: 1rem;
59-
60-
&:hover {
61-
color: #e5e5e5;
62-
}
63-
`;

‎src/components/slider/index.js

-13
This file was deleted.

‎src/components/slider/slider.js

-3
This file was deleted.

‎src/components/slider/styles/Slider.js

-19
This file was deleted.

‎src/containers/browse.js

+37-63
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,46 @@
11
import React from 'react';
2-
import { useSeries } from '../hooks/useSeries';
3-
import { Card, Slider } from '../components';
4-
5-
export function BrowseContainer() {
6-
const { series } = useSeries();
7-
8-
const documentaries = series.filter((item) => item.genre === 'documentaries');
9-
const comedies = series.filter((item) => item.genre === 'comedies');
10-
const children = series.filter((item) => item.genre === 'children');
11-
const crime = series.filter((item) => item.genre === 'crime');
12-
const feelGood = series.filter((item) => item.genre === 'feel-good');
2+
import { Card, Header } from '../components';
3+
import * as ROUTES from '../constants/routes';
4+
import { FooterContainer } from './footer';
5+
import logo from '../logo.svg';
136

7+
export function BrowseContainer({ selection, setSelection, slides }) {
148
return (
159
<>
16-
<Slider>
17-
<Slider.Title>Documentaries</Slider.Title>
18-
<Card.Group>
19-
{documentaries?.map((item) => (
20-
<Card.Item key={item.docId}>
21-
<Card.Cta backgroundSrc={`/images/series/${item.genre}/${item.slug}/small.jpg`} />
22-
</Card.Item>
23-
))}
24-
</Card.Group>
25-
</Slider>
26-
27-
<Slider>
28-
<Slider.Title>Comedies</Slider.Title>
29-
<Card.Group>
30-
{comedies?.map((item) => (
31-
<Card.Item key={item.docId}>
32-
<Card.Cta backgroundSrc={`/images/series/${item.genre}/${item.slug}/small.jpg`} />
33-
</Card.Item>
34-
))}
35-
</Card.Group>
36-
</Slider>
37-
38-
<Slider>
39-
<Slider.Title>Children</Slider.Title>
40-
<Card.Group>
41-
{children?.map((item) => (
42-
<Card.Item key={item.docId}>
43-
<Card.Cta backgroundSrc={`/images/series/${item.genre}/${item.slug}/small.jpg`} />
44-
</Card.Item>
45-
))}
46-
</Card.Group>
47-
</Slider>
10+
<Header bg={false}>
11+
<Header.Frame>
12+
<Header.Group>
13+
<Header.Logo to={ROUTES.HOME} src={logo} alt="Netflix" />
14+
<Header.Link active={selection === 'series' ? 'true' : 'false'} onClick={() => setSelection('series')}>
15+
Series
16+
</Header.Link>
17+
<Header.Link active={selection === 'films' ? 'true' : 'false'} onClick={() => setSelection('films')}>
18+
Films
19+
</Header.Link>
20+
</Header.Group>
21+
</Header.Frame>
22+
</Header>
4823

49-
<Slider>
50-
<Slider.Title>Crime</Slider.Title>
51-
<Card.Group>
52-
{crime?.map((item) => (
53-
<Card.Item key={item.docId}>
54-
<Card.Cta backgroundSrc={`/images/series/${item.genre}/${item.slug}/small.jpg`} />
55-
</Card.Item>
56-
))}
57-
</Card.Group>
58-
</Slider>
24+
<Card.Group>
25+
{slides.map((slideItem) => (
26+
<Card key={`${slideItem.title}-${slideItem.genre}`}>
27+
<Card.Title>{slideItem.title}</Card.Title>
28+
<Card.Entities>
29+
{slideItem.data?.map((item) => (
30+
<Card.Item key={item.docId}>
31+
<Card.Image src={`/images/${selection}/${item.genre}/${item.slug}/small.jpg`} />
32+
<Card.Meta>
33+
<Card.SubTitle>{item.title}</Card.SubTitle>
34+
<Card.Text>{item.description}</Card.Text>
35+
</Card.Meta>
36+
</Card.Item>
37+
))}
38+
</Card.Entities>
39+
</Card>
40+
))}
41+
</Card.Group>
5942

60-
<Slider>
61-
<Slider.Title>Feel Good</Slider.Title>
62-
<Card.Group>
63-
{feelGood?.map((item) => (
64-
<Card.Item key={item.docId}>
65-
<Card.Cta backgroundSrc={`/images/series/${item.genre}/${item.slug}/small.jpg`} />
66-
</Card.Item>
67-
))}
68-
</Card.Group>
69-
</Slider>
43+
<FooterContainer />
7044
</>
7145
);
7246
}

‎src/containers/header.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export function HeaderContainer({ children }) {
88
<Header>
99
<Header.Frame>
1010
<Header.Logo to={ROUTES.HOME} src={logo} alt="Netflix" />
11-
<Header.Link to={ROUTES.SIGN_IN}>Sign In</Header.Link>
11+
<Header.ButtonLink to={ROUTES.SIGN_IN}>Sign In</Header.ButtonLink>
1212
</Header.Frame>
1313
{children}
1414
</Header>

‎src/hooks/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
import { useAuthListener } from './useAuthListener';
2+
import { useSeries } from './useSeries';
3+
import { useFilms } from './useFilms';
24

3-
export { useAuthListener };
5+
export { useAuthListener, useSeries, useFilms };

‎src/hooks/useFilms.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { useEffect, useState, useContext } from 'react';
2+
import { FirebaseContext } from '../context';
3+
4+
export const useFilms = () => {
5+
const [films, setFilms] = useState([]);
6+
const { firebase } = useContext(FirebaseContext);
7+
8+
useEffect(() => {
9+
firebase
10+
.firestore()
11+
.collection('films')
12+
.get()
13+
.then((snapshot) => {
14+
const allFilms = snapshot.docs.map((filmsObj) => ({
15+
...filmsObj.data(),
16+
docId: filmsObj.id,
17+
}));
18+
19+
setFilms(allFilms);
20+
})
21+
.catch((error) => {
22+
console.log(error.message);
23+
});
24+
}, []);
25+
26+
return { films };
27+
};

‎src/pages/browse.js

+8-13
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
import React, { useState } from 'react';
2-
import { BrowseContainer, FooterContainer, SelectProfileContainer } from '../containers';
3-
import * as ROUTES from '../constants/routes';
4-
import logo from '../logo.svg';
5-
import { Header } from '../components';
2+
import { BrowseContainer, SelectProfileContainer } from '../containers';
3+
import { useFilms, useSeries } from '../hooks';
4+
import { selectionMap } from '../utils';
65

76
export function Browse() {
7+
const { series } = useSeries();
8+
const { films } = useFilms();
89
const [profileId, setProfileId] = useState(null);
10+
const [selection, setSelection] = useState('series');
11+
const slideData = selectionMap({ series, films });
912

1013
return profileId ? (
11-
<>
12-
<Header bg={false}>
13-
<Header.Frame>
14-
<Header.Logo to={ROUTES.HOME} src={logo} alt="Netflix" />
15-
</Header.Frame>
16-
</Header>
17-
<BrowseContainer />
18-
<FooterContainer />
19-
</>
14+
<BrowseContainer selection={selection} setSelection={setSelection} slides={slideData[selection]} />
2015
) : (
2116
<SelectProfileContainer setProfileId={setProfileId} />
2217
);

‎src/seed.js

+77-8
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ export function seedDatabase(firebase) {
1010
/* eslint-enable */
1111
}
1212

13+
/* Series
14+
============================================ */
1315
// Documentaries
14-
for (let index = 0; index <= 10; index += 1) {
16+
for (let index = 0; index < 5; index += 1) {
1517
firebase.firestore().collection('series').add({
1618
id: getUUID(),
1719
title: 'Tiger King',
@@ -23,7 +25,7 @@ export function seedDatabase(firebase) {
2325
}
2426

2527
// Comedies
26-
for (let index = 0; index <= 10; index += 1) {
28+
for (let index = 0; index < 5; index += 1) {
2729
firebase.firestore().collection('series').add({
2830
id: getUUID(),
2931
title: 'The Office',
@@ -36,20 +38,20 @@ export function seedDatabase(firebase) {
3638
}
3739

3840
// Children
39-
for (let index = 0; index <= 10; index += 1) {
41+
for (let index = 0; index < 5; index += 1) {
4042
firebase.firestore().collection('series').add({
4143
id: getUUID(),
42-
title: 'Hotel Transylvania',
44+
title: 'Peppa Pig',
4345
description:
44-
'Dracula, who owns a high-end resort for monsters, attempts to keep his daughter from falling in love with Jonathan, a human.',
46+
'Peppa, an outgoing preschool pig, participates in many energetic activities. She learns something new every day and has a lot of fun with her family and friends.',
4547
genre: 'children',
4648
maturity: '0',
47-
slug: 'hotel-transylvania',
49+
slug: 'peppa-pig',
4850
});
4951
}
5052

5153
// Crime
52-
for (let index = 0; index <= 10; index += 1) {
54+
for (let index = 0; index < 5; index += 1) {
5355
firebase.firestore().collection('series').add({
5456
id: getUUID(),
5557
title: 'Making a Murderer',
@@ -62,7 +64,7 @@ export function seedDatabase(firebase) {
6264
}
6365

6466
// Feel-good
65-
for (let index = 0; index <= 10; index += 1) {
67+
for (let index = 0; index < 5; index += 1) {
6668
firebase.firestore().collection('series').add({
6769
id: getUUID(),
6870
title: 'Good Will Hunting',
@@ -73,4 +75,71 @@ export function seedDatabase(firebase) {
7375
slug: 'good-will-hunting',
7476
});
7577
}
78+
79+
/* Films
80+
============================================ */
81+
// Drama
82+
for (let index = 0; index < 5; index += 1) {
83+
firebase.firestore().collection('films').add({
84+
id: getUUID(),
85+
title: 'The Prestige',
86+
description:
87+
'Two friends and fellow magicians become bitter enemies after a sudden tragedy. As they devote themselves to this rivalry, they make sacrifices that bring them fame but with terrible consequences.',
88+
genre: 'drama',
89+
maturity: '15',
90+
slug: 'the-prestige',
91+
});
92+
}
93+
94+
// Suspense
95+
for (let index = 0; index < 5; index += 1) {
96+
firebase.firestore().collection('films').add({
97+
id: getUUID(),
98+
title: 'Shutter Island',
99+
description:
100+
'Teddy Daniels and Chuck Aule, two US marshals, are sent to an asylum on a remote island in order to investigate the disappearance of a patient, where Teddy uncovers a shocking truth about the place.',
101+
genre: 'suspense',
102+
maturity: '15',
103+
slug: 'shutter-island',
104+
});
105+
}
106+
107+
// Children
108+
for (let index = 0; index < 5; index += 1) {
109+
firebase.firestore().collection('films').add({
110+
id: getUUID(),
111+
title: 'Hotel Transylvania',
112+
description:
113+
'Dracula, who owns a high-end resort for monsters, attempts to keep his daughter from falling in love with Jonathan, a human.',
114+
genre: 'children',
115+
maturity: '0',
116+
slug: 'hotel-transylvania',
117+
});
118+
}
119+
120+
// Thriller
121+
for (let index = 0; index < 5; index += 1) {
122+
firebase.firestore().collection('films').add({
123+
id: getUUID(),
124+
title: 'Joker',
125+
description:
126+
'Forever alone in a crowd, failed comedian Arthur Fleck seeks connection as he walks the streets of Gotham City.',
127+
genre: 'thriller',
128+
maturity: '15',
129+
slug: 'joker',
130+
});
131+
}
132+
133+
// Romance
134+
for (let index = 0; index < 5; index += 1) {
135+
firebase.firestore().collection('films').add({
136+
id: getUUID(),
137+
title: 'A Star Is Born',
138+
description:
139+
'After falling in love with struggling artist Ally, Jackson, a musician, coaxes her to follow her dreams, while he battles with alcoholism and his personal demons.',
140+
genre: 'romance',
141+
maturity: '15',
142+
slug: 'a-star-is-born',
143+
});
144+
}
76145
}

‎src/utils/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { selectionMap } from './selectionMap';
2+
3+
export { selectionMap };

‎src/utils/selectionMap.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const selectionMap = ({ series, films }) => ({
2+
series: [
3+
{ title: 'Documentaries', data: series.filter((item) => item.genre === 'documentaries') },
4+
{ title: 'Comedies', data: series.filter((item) => item.genre === 'comedies') },
5+
{ title: 'Children', data: series.filter((item) => item.genre === 'children') },
6+
{ title: 'Crime', data: series.filter((item) => item.genre === 'crime') },
7+
{ title: 'Feel Good', data: series.filter((item) => item.genre === 'feel-good') },
8+
],
9+
films: [
10+
{ title: 'Drama', data: films.filter((item) => item.genre === 'drama') },
11+
{ title: 'Thriller', data: films.filter((item) => item.genre === 'thriller') },
12+
{ title: 'Children', data: films.filter((item) => item.genre === 'children') },
13+
{ title: 'Suspense', data: films.filter((item) => item.genre === 'suspense') },
14+
{ title: 'Romance', data: films.filter((item) => item.genre === 'romance') },
15+
],
16+
});

0 commit comments

Comments
 (0)
Please sign in to comment.