From 9e6c98e7bc84ea452b6bf042c7fb6f6ace6cca06 Mon Sep 17 00:00:00 2001 From: christopher-lamkin Date: Sat, 20 May 2017 13:20:56 -0700 Subject: [PATCH 1/8] initial setup, create searchBar component --- package.json | 3 ++- src/components/app.js | 9 -------- src/components/search_bar.js | 8 +++++++ .../index.js => components/video_detail.js} | 0 src/components/video_list.js | 0 src/components/video_list_item.js | 0 src/index.js | 22 ++++++++++--------- src/reducers/index.js | 7 ------ 8 files changed, 22 insertions(+), 27 deletions(-) delete mode 100644 src/components/app.js create mode 100644 src/components/search_bar.js rename src/{actions/index.js => components/video_detail.js} (100%) create mode 100644 src/components/video_list.js create mode 100644 src/components/video_list_item.js delete mode 100644 src/reducers/index.js diff --git a/package.json b/package.json index 102a759b94..86774ccdcc 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "react-dom": "^0.14.3", "react-redux": "4.3.0", "react-router": "^2.0.1", - "redux": "^3.0.4" + "redux": "^3.0.4", + "youtube-api-search": "0.0.5" } } diff --git a/src/components/app.js b/src/components/app.js deleted file mode 100644 index 58614b02cf..0000000000 --- a/src/components/app.js +++ /dev/null @@ -1,9 +0,0 @@ -import React, { Component } from 'react'; - -export default class App extends Component { - render() { - return ( -
React simple starter
- ); - } -} diff --git a/src/components/search_bar.js b/src/components/search_bar.js new file mode 100644 index 0000000000..2553df3aa9 --- /dev/null +++ b/src/components/search_bar.js @@ -0,0 +1,8 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +const SearchBar = () => { + return ; +}; + +export default SearchBar; diff --git a/src/actions/index.js b/src/components/video_detail.js similarity index 100% rename from src/actions/index.js rename to src/components/video_detail.js diff --git a/src/components/video_list.js b/src/components/video_list.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/components/video_list_item.js b/src/components/video_list_item.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/index.js b/src/index.js index 69d577acd1..e1c1731cce 100644 --- a/src/index.js +++ b/src/index.js @@ -1,15 +1,17 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { Provider } from 'react-redux'; -import { createStore, applyMiddleware } from 'redux'; +import SearchBar from './components/search_bar'; -import App from './components/app'; -import reducers from './reducers'; +const API_KEY = 'AIzaSyAGMgh7QKPSGbjOV-JEVug4TCtyET_Vfuo'; -const createStoreWithMiddleware = applyMiddleware()(createStore); +const App = () => { + return ( +
+ +
+ ); +}; -ReactDOM.render( - - - - , document.querySelector('.container')); +// Attach this component's generated html and put it on the page (DOM) + +ReactDOM.render(, document.querySelector('.container')); diff --git a/src/reducers/index.js b/src/reducers/index.js deleted file mode 100644 index d12506f382..0000000000 --- a/src/reducers/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import { combineReducers } from 'redux'; - -const rootReducer = combineReducers({ - state: (state = {}) => state -}); - -export default rootReducer; From 59b549a1dfea586cbbe6f57f699938a67a1e50d7 Mon Sep 17 00:00:00 2001 From: christopher-lamkin Date: Sat, 20 May 2017 13:26:07 -0700 Subject: [PATCH 2/8] convert SearchBar from functional to class-based component --- src/components/search_bar.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/search_bar.js b/src/components/search_bar.js index 2553df3aa9..c9469c0271 100644 --- a/src/components/search_bar.js +++ b/src/components/search_bar.js @@ -1,8 +1,10 @@ -import React from 'react'; +import React, { Component } from 'react'; import ReactDOM from 'react-dom'; -const SearchBar = () => { - return ; -}; +class SearchBar extends Component { + render() { + return ; + } +} export default SearchBar; From e9a5041b57569e10e609ae27033ad54d53993273 Mon Sep 17 00:00:00 2001 From: christopher-lamkin Date: Sat, 20 May 2017 13:35:23 -0700 Subject: [PATCH 3/8] add event handler for input change --- src/components/search_bar.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/search_bar.js b/src/components/search_bar.js index c9469c0271..8f4466ea71 100644 --- a/src/components/search_bar.js +++ b/src/components/search_bar.js @@ -3,7 +3,11 @@ import ReactDOM from 'react-dom'; class SearchBar extends Component { render() { - return ; + return console.log(event.target.value)}/>; + } + + onInputChange(event) { + console.log(event.target.value); } } From 5db565639aaf591cf0191a8b88f87c1ead1a9dee Mon Sep 17 00:00:00 2001 From: christopher-lamkin Date: Sat, 20 May 2017 13:45:42 -0700 Subject: [PATCH 4/8] initialize state with a term property, set state to update term on input change --- src/components/search_bar.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/search_bar.js b/src/components/search_bar.js index 8f4466ea71..f2c67b4fc3 100644 --- a/src/components/search_bar.js +++ b/src/components/search_bar.js @@ -2,12 +2,18 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class SearchBar extends Component { - render() { - return console.log(event.target.value)}/>; + constructor(props) { + super(props); + + this.state = { term: ''} } - onInputChange(event) { - console.log(event.target.value); + render() { + return ( +
+ this.setState({ term: event.target.value })} />; +
+ ); } } From 3aa16f2a18c5b83de97c3d506bef3023fedb1798 Mon Sep 17 00:00:00 2001 From: christopher-lamkin Date: Sun, 21 May 2017 10:32:48 -0700 Subject: [PATCH 5/8] convert App to class-based component, fetch data from youtube API --- src/components/search_bar.js | 4 +++- src/index.js | 28 +++++++++++++++++++--------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/components/search_bar.js b/src/components/search_bar.js index f2c67b4fc3..756f9ad9ca 100644 --- a/src/components/search_bar.js +++ b/src/components/search_bar.js @@ -11,7 +11,9 @@ class SearchBar extends Component { render() { return (
- this.setState({ term: event.target.value })} />; + this.setState({ term: event.target.value })} />;
); } diff --git a/src/index.js b/src/index.js index e1c1731cce..e4abeaf105 100644 --- a/src/index.js +++ b/src/index.js @@ -1,17 +1,27 @@ -import React from 'react'; +import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import SearchBar from './components/search_bar'; +import YTSearch from 'youtube-api-search'; const API_KEY = 'AIzaSyAGMgh7QKPSGbjOV-JEVug4TCtyET_Vfuo'; -const App = () => { - return ( -
- -
- ); -}; +class App extends Component { + constructor(props){ + super(props); -// Attach this component's generated html and put it on the page (DOM) + this.state = { videos: [] }; + + YTSearch({key: API_KEY, term: 'surfboards'}, (videos) => { + this.setState({ videos }); + }); + } + render(){ + return ( +
+ +
+ ); + } +} ReactDOM.render(, document.querySelector('.container')); From 0f21114cfce255aa437701401c0da2157d24138a Mon Sep 17 00:00:00 2001 From: christopher-lamkin Date: Sun, 21 May 2017 12:26:29 -0700 Subject: [PATCH 6/8] creaet VideoList and VideoListItem components --- src/components/video_list.js | 16 ++++++++++++++++ src/components/video_list_item.js | 7 +++++++ src/index.js | 2 ++ 3 files changed, 25 insertions(+) diff --git a/src/components/video_list.js b/src/components/video_list.js index e69de29bb2..d39a6e8316 100644 --- a/src/components/video_list.js +++ b/src/components/video_list.js @@ -0,0 +1,16 @@ +import React from 'react'; +import VideoListItem from './video_list_item'; + +const VideoList = (props) => { + const videoItems = props.videos.map((video) => { + return + }); + + return ( +
    + {videoItems} +
+ ); +} + +export default VideoList; diff --git a/src/components/video_list_item.js b/src/components/video_list_item.js index e69de29bb2..da7e88ace5 100644 --- a/src/components/video_list_item.js +++ b/src/components/video_list_item.js @@ -0,0 +1,7 @@ +import React from 'react'; + +const VideoListItem = (props) => { + return
  • Video
  • +}; + +export default VideoListItem; diff --git a/src/index.js b/src/index.js index e4abeaf105..a01f44c8cf 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import SearchBar from './components/search_bar'; +import VideoList from './components/video_list'; import YTSearch from 'youtube-api-search'; const API_KEY = 'AIzaSyAGMgh7QKPSGbjOV-JEVug4TCtyET_Vfuo'; @@ -19,6 +20,7 @@ class App extends Component { return (
    +
    ); } From a86df780a1481b1a512be5ed3cd61935643c09be Mon Sep 17 00:00:00 2001 From: christopher-lamkin Date: Sun, 21 May 2017 13:25:09 -0700 Subject: [PATCH 7/8] add styling, refactor API call, searchBar input now updates search term state --- src/components/search_bar.js | 12 ++++++++---- src/components/video_detail.js | 23 +++++++++++++++++++++++ src/components/video_list.js | 7 ++++++- src/components/video_list_item.js | 19 ++++++++++++++++--- src/index.js | 23 ++++++++++++++++++----- style/style.css | 27 +++++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 13 deletions(-) diff --git a/src/components/search_bar.js b/src/components/search_bar.js index 756f9ad9ca..b98eb57d57 100644 --- a/src/components/search_bar.js +++ b/src/components/search_bar.js @@ -1,22 +1,26 @@ import React, { Component } from 'react'; -import ReactDOM from 'react-dom'; class SearchBar extends Component { constructor(props) { super(props); - this.state = { term: ''} + this.state = { term: ''}; } render() { return ( -
    +
    this.setState({ term: event.target.value })} />; + onChange={event => this.onInputChange(event.target.value)} />
    ); } + + onInputChange(term) { + this.setState({term}); + this.props.onSearchTermChange(term); + } } export default SearchBar; diff --git a/src/components/video_detail.js b/src/components/video_detail.js index e69de29bb2..5d62f04541 100644 --- a/src/components/video_detail.js +++ b/src/components/video_detail.js @@ -0,0 +1,23 @@ +import React from 'react'; + +const VideoDetail = ({video}) => { + if (!video){ + return
    Loading...
    + } + + const videoId = video.id.videoId; + const url = `https://www.youtube.com/embed/${videoId}`; + return ( +
    +
    + +
    +
    +
    {video.snippet.title}
    +
    {video.snippet.description}
    +
    +
    + ); +} + +export default VideoDetail; diff --git a/src/components/video_list.js b/src/components/video_list.js index d39a6e8316..46b0ce8d7c 100644 --- a/src/components/video_list.js +++ b/src/components/video_list.js @@ -3,7 +3,12 @@ import VideoListItem from './video_list_item'; const VideoList = (props) => { const videoItems = props.videos.map((video) => { - return + return ( + + ); }); return ( diff --git a/src/components/video_list_item.js b/src/components/video_list_item.js index da7e88ace5..3bc971a749 100644 --- a/src/components/video_list_item.js +++ b/src/components/video_list_item.js @@ -1,7 +1,20 @@ import React from 'react'; -const VideoListItem = (props) => { - return
  • Video
  • -}; +const VideoListItem = ({video, onVideoSelect}) => { + const imageUrl = video.snippet.thumbnails.default.url; + + return ( +
  • onVideoSelect(video)} className="list-group-item"> +
    +
    + +
    +
    +
    {video.snippet.title}
    +
    +
    +
  • + ); +} export default VideoListItem; diff --git a/src/index.js b/src/index.js index a01f44c8cf..40ea3b9eed 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import SearchBar from './components/search_bar'; import VideoList from './components/video_list'; +import VideoDetail from './components/video_detail'; import YTSearch from 'youtube-api-search'; const API_KEY = 'AIzaSyAGMgh7QKPSGbjOV-JEVug4TCtyET_Vfuo'; @@ -10,17 +11,29 @@ class App extends Component { constructor(props){ super(props); - this.state = { videos: [] }; + this.state = { + videos: [], + selectedVideo: null + }; - YTSearch({key: API_KEY, term: 'surfboards'}, (videos) => { - this.setState({ videos }); + this.videoSearch('surfboards'); + } + videoSearch(term){ + YTSearch({key: API_KEY, term: term}, (videos) => { + this.setState({ + videos: videos, + selectedVideo: videos[0] + }); }); } render(){ return (
    - - + this.videoSearch(term)} /> + + this.setState({selectedVideo}) } + videos = {this.state.videos} />
    ); } diff --git a/style/style.css b/style/style.css index e69de29bb2..098b349949 100644 --- a/style/style.css +++ b/style/style.css @@ -0,0 +1,27 @@ +.search-bar { + margin: 20px; + text-align: center; +} + +.search-bar input{ + width: 75%; +} + +.video-item img { + max-width: 64px; +} + +.video-detail .details { + margin-top: 10px; + padding: 10px; + border: 1px solid #ddd; + border-radius: 4px; +} + +.list-group-item { + cursor: pointer; +} + +.list-group-item:hover { + background-color: #eee; +} From 1d7236dfcae2663e562c4b222047d458aba7edb5 Mon Sep 17 00:00:00 2001 From: christopher-lamkin Date: Sun, 21 May 2017 21:19:15 -0700 Subject: [PATCH 8/8] use lodash to add debounce to onSearchTermChange call --- src/components/search_bar.js | 10 +++++----- src/index.js | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/search_bar.js b/src/components/search_bar.js index b98eb57d57..57d94c97b1 100644 --- a/src/components/search_bar.js +++ b/src/components/search_bar.js @@ -7,6 +7,11 @@ class SearchBar extends Component { this.state = { term: ''}; } + onInputChange(term) { + this.setState({term}); + this.props.onSearchTermChange(term); + } + render() { return (
    @@ -16,11 +21,6 @@ class SearchBar extends Component {
    ); } - - onInputChange(term) { - this.setState({term}); - this.props.onSearchTermChange(term); - } } export default SearchBar; diff --git a/src/index.js b/src/index.js index 40ea3b9eed..65d0d2530e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,4 @@ +import _ from 'lodash'; import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import SearchBar from './components/search_bar'; @@ -27,9 +28,10 @@ class App extends Component { }); } render(){ + const videoSearch = _.debounce((term) => {this.videoSearch(term)}, 300); return (
    - this.videoSearch(term)} /> + this.setState({selectedVideo}) }