diff --git a/.env b/.env
new file mode 100644
index 000000000..859e9be42
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+REACT_APP_YOUTUBE_API_KEY=AIzaSyCJDk0qSH8AeWBxdSnIFdjw9kOiblAiHI4
diff --git a/package.json b/package.json
index 4addda755..794e9f40e 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
"@testing-library/user-event": "^12.1.3",
"react": "^16.13.1",
"react-dom": "^16.13.1",
+ "react-player": "^2.9.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3",
diff --git a/src/components/App/App.component.jsx b/src/components/App/App.component.jsx
index 1739c0058..794ee8575 100644
--- a/src/components/App/App.component.jsx
+++ b/src/components/App/App.component.jsx
@@ -1,7 +1,11 @@
import React, { useState } from 'react';
import { ThemeProvider, createGlobalStyle } from 'styled-components';
import HomePage from '../../pages/Home';
+import HeaderSection from '../../pages/Header/Header.page';
+import DataProvider from '../../states/provider';
import Button from '../Button';
+import useFetchData from '../../states/useFetchData';
+import VideoPage from '../../pages/Video/Video.page';
const lightTheme = {
bg: '#fff',
@@ -21,20 +25,32 @@ const GlobalStyles = createGlobalStyle`body{
function App() {
const [mode, setMode] = useState('light');
-
+ const [videoDetails, setVideoDetails] = useState();
+ const { setSearch, response } = useFetchData();
return (
-
-
-
-
-
-
-
+
+
+
+
+
+
+ {videoDetails ? (
+
+ ) : (
+
+ )}
+
+
+
);
}
diff --git a/src/components/App/App.component.test.jsx b/src/components/App/App.component.test.jsx
index c4fc3d59e..3f4d45262 100644
--- a/src/components/App/App.component.test.jsx
+++ b/src/components/App/App.component.test.jsx
@@ -1,5 +1,12 @@
import React from 'react';
-import { render, screen, queryByAttribute } from '@testing-library/react';
+import {
+ render,
+ screen,
+ queryByAttribute,
+ cleanup,
+ fireEvent,
+} from '@testing-library/react';
+
import App from '.';
describe('App Component tests', () => {
diff --git a/src/components/Emoji/Emoji.jsx b/src/components/Emoji/Emoji.jsx
index 6737b0288..38151a5ff 100644
--- a/src/components/Emoji/Emoji.jsx
+++ b/src/components/Emoji/Emoji.jsx
@@ -4,8 +4,8 @@ const Emoji = (props) => (
{props.symbol}
diff --git a/src/pages/Card/Card.page.jsx b/src/pages/Card/Card.page.jsx
index 0b6a8b4bd..aae6581d8 100644
--- a/src/pages/Card/Card.page.jsx
+++ b/src/pages/Card/Card.page.jsx
@@ -3,6 +3,7 @@ import styled from 'styled-components';
const Container = styled.div`
width: 22%;
+ height: 20em;
border-style: solid;
margin: 1em;
border-radius: 1em;
@@ -10,20 +11,29 @@ const Container = styled.div`
justify-content: space-between;
float: left;
background-color: #d47b7b;
- word-wrap: break-word;
+ text-overflow: ellipsis;
+ overflow: hidden;
`;
-function Card({ title, description, image, width, height }) {
+function Card({ videoId, title, description, image, width, height, selectVideo }) {
return (
-
-
-
- {title}
-
- {description}
-
-
-
+ {
+ const val = {
+ videoId,
+ title,
+ description,
+ };
+
+ selectVideo(val);
+ }}
+ >
+
+ {title}
+
+ {description}
+
+
);
}
diff --git a/src/pages/Card/Card.page.test.jsx b/src/pages/Card/Card.page.test.jsx
index bb83ec966..eab9a567d 100644
--- a/src/pages/Card/Card.page.test.jsx
+++ b/src/pages/Card/Card.page.test.jsx
@@ -39,7 +39,7 @@ describe('Card Component tests', () => {
height="90"
/>
);
- expect(screen.getByText('testTitle').tagName).toBe('H2');
+ expect(screen.getByText('testTitle').tagName).toBe('H3');
});
it('Card Description type', () => {
diff --git a/src/pages/Header/Header.page.jsx b/src/pages/Header/Header.page.jsx
index dd0a3fb65..a93ea5f01 100644
--- a/src/pages/Header/Header.page.jsx
+++ b/src/pages/Header/Header.page.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState } from 'react';
import styled from 'styled-components';
import Emoji from '../../components/Emoji';
import Button from '../../components/Button';
@@ -15,16 +15,50 @@ const CurrentDiv = styled.div`
background-color: #2183d3;
`;
-function HeaderSection() {
+function HeaderSection({ globalSetSearch, videoDetails }) {
+ const [search, setSearch] = useState(undefined);
+
+ function dispatchEvent() {
+ if (!search) {
+ alert('please enter a valid search term');
+ } else {
+ globalSetSearch(search);
+ videoDetails(undefined);
+ }
+ }
+
+ function eventHandler(event) {
+ if (event.charCode === 13) {
+ dispatchEvent('onEnter');
+ }
+ }
+
+ function onSearchClick() {
+ dispatchEvent('onClick');
+ }
+
return (
-
);
diff --git a/src/pages/Home/Home.page.jsx b/src/pages/Home/Home.page.jsx
index 94129754c..d5a98b80f 100644
--- a/src/pages/Home/Home.page.jsx
+++ b/src/pages/Home/Home.page.jsx
@@ -1,22 +1,27 @@
import React from 'react';
-import HeaderSection from '../Header/Header.page';
import Card from '../Card/Card.page';
-import mockedData from '../../data/mockItems.json';
+import { useData } from '../../states/provider';
+
+function HomePage({ selectVideo }) {
+ const { data } = useData();
+ const elements = data.data;
-function HomePage() {
return (
-
- {mockedData.items.map((item) => (
-
- ))}
+ {elements &&
+ elements.items &&
+ elements.items.map((item) => (
+
+ ))}
);
}
diff --git a/src/pages/Home/Home.page.test.jsx b/src/pages/Home/Home.page.test.jsx
index 149a4ea9d..1c5420178 100644
--- a/src/pages/Home/Home.page.test.jsx
+++ b/src/pages/Home/Home.page.test.jsx
@@ -1,31 +1,26 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import HomePage from '.';
+import DataProvider from '../../states/provider';
+import mockedData from '../../data/mockItems.json';
describe('Home Component tests', () => {
- it('Header Section Contains search button defined', () => {
- render();
- expect(screen.getByText('🔍')).toBeDefined();
- });
-
- it('Header Section Contains search button defined', () => {
- render();
- expect(screen.getByText('☰')).toBeDefined();
- });
-
- it('Header Section Contains search input defined', () => {
- render();
- expect(screen.getByPlaceholderText('Search the site...')).toBeDefined();
- });
-
it('Card Section Contain title', () => {
- render();
+ render(
+
+
+
+ );
expect(
screen.getByText('Video Tour | Welcome to Wizeline Guadalajara').tagName
- ).toBe('H2');
+ ).toBe('H3');
});
it('Card Section Contain Description', () => {
- render();
+ render(
+
+
+
+ );
expect(
screen.getByText(
'Follow Hector Padilla, Wizeline Director of Engineering, for a lively tour of our office. In 2018, Wizeline opened its stunning new office in Guadalajara, Jalisco, ...'
@@ -33,20 +28,32 @@ describe('Home Component tests', () => {
).toBe('P');
});
it('Card Section Contain image', () => {
- render();
+ render(
+
+
+
+ );
expect(
screen.getByAltText('Video Tour | Welcome to Wizeline Guadalajara').tagName
).toBe('IMG');
});
it('Card Section image size width', () => {
- render();
+ render(
+
+
+
+ );
const image = screen.getByAltText('Video Tour | Welcome to Wizeline Guadalajara');
expect(image.width).toEqual(120);
});
it('Card Section image size height', () => {
- render();
+ render(
+
+
+
+ );
const image = screen.getByAltText('Video Tour | Welcome to Wizeline Guadalajara');
expect(image.height).toEqual(90);
});
diff --git a/src/pages/Video/Video.page.jsx b/src/pages/Video/Video.page.jsx
new file mode 100644
index 000000000..1504dbf4c
--- /dev/null
+++ b/src/pages/Video/Video.page.jsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import ReactPlayer from 'react-player';
+import styled from 'styled-components';
+import useFetchData from '../../states/useFetchData';
+import Card from '../Card/Card.page';
+
+const Video = styled.div`
+ border-style: solid;
+ margin: 1em;
+ height: 50%;
+ padding: 1em;
+ border-radius: 1em;
+ display: block;
+ justify-content: space-between;
+ background-color: #d47b7b;
+ word-wrap: break-word;
+ transition: 0.5s;
+`;
+
+const RelatedVideos = styled.div`
+ margin: 1em;
+ height: 20%;
+ padding: 1em;
+ border-radius: 1em;
+ background-color: #d47b7b;
+ display: inline-block;
+`;
+
+function VideoPage({ video, selectVideo }) {
+ const { videoId, title, description } = video;
+ const { response } = useFetchData(videoId);
+
+ console.log('relatedVideos', response);
+
+ return (
+
+
+
+
+ Related Videos
+
+
+ {response &&
+ response.items &&
+ response.items.map((item) => (
+
+ ))}
+
+
+ );
+}
+
+export default VideoPage;
diff --git a/src/pages/Video/index.js b/src/pages/Video/index.js
new file mode 100644
index 000000000..146c86bb6
--- /dev/null
+++ b/src/pages/Video/index.js
@@ -0,0 +1 @@
+export { default } from './Video.page';
diff --git a/src/states/provider.jsx b/src/states/provider.jsx
new file mode 100644
index 000000000..8c9a6429a
--- /dev/null
+++ b/src/states/provider.jsx
@@ -0,0 +1,30 @@
+import React, { createContext, useContext } from 'react';
+
+const initState = {
+ data: [],
+ history: [],
+};
+
+const DataContext = createContext({
+ data: [],
+ history: [],
+});
+
+function useData() {
+ const context = useContext(DataContext);
+ if (!context) {
+ throw new Error(`Can't use "useData" without an DataProvider!`);
+ }
+ return context;
+}
+
+function DataProvider({ response, children }) {
+ initState.data = response;
+ const [data] = [initState];
+
+ return {children};
+}
+
+export { useData };
+
+export default DataProvider;
diff --git a/src/states/useFetchData.jsx b/src/states/useFetchData.jsx
new file mode 100644
index 000000000..d3b71a920
--- /dev/null
+++ b/src/states/useFetchData.jsx
@@ -0,0 +1,27 @@
+import { useEffect, useState } from 'react';
+
+const SEARCH_URL = 'https://www.googleapis.com/youtube/v3/search';
+
+export default function useFetchData(videoId) {
+ const [response, setResponse] = useState([]);
+ const [search, setSearch] = useState('wizeline');
+ const relatedVideosUrl = videoId ? `&relatedToVideoId=${videoId}` : '';
+ const maxResults = `&maxResults=${videoId ? '8' : '40'}`;
+ const url = `${SEARCH_URL}?part=snippet${maxResults}&q=${search}&key=${process.env.REACT_APP_YOUTUBE_API_KEY}&type=video${relatedVideosUrl}`;
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const responseData = await fetch(url);
+ const jsonResponse = await responseData.json();
+ setResponse(jsonResponse);
+ } catch (e) {
+ console.error(e);
+ }
+ };
+
+ fetchData();
+ }, [url]);
+
+ return { setSearch, response };
+}