diff --git a/.gitignore b/.gitignore index 43324af733..40333b4e7a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ npm-debug.log # IntelliJ *.iml -/.idea \ No newline at end of file +/.idea + +notes.js diff --git a/package.json b/package.json index a0fed88b12..3cc732e0da 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "react-dom": "^0.14.3", "react-redux": "^4.0.0", "react-router": "^2.0.1", - "redux": "^3.0.4" + "redux": "^3.0.4", + "youtube-api-search": "0.0.5" } } diff --git a/src/actions/index.js b/src/actions/index.js deleted file mode 100644 index e69de29bb2..0000000000 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..96f12c8f6a --- /dev/null +++ b/src/components/search_bar.js @@ -0,0 +1,41 @@ +// need to import react into all components that have jsx + +import React, { Component } from 'react'; + +// // functional component +// const SearchBar = () => { +// return +// }; + +// class component +// this is how we define methods on a class +// when we create a class component we must always create a render method and have some jsx, or else there will be an error +// declare event handler and pass it to the input element +class SearchBar extends Component { +// this is how we initialize state in a class based component + constructor(props) { + super(props); + +// create a new obj and assign it to this.state +// as user types in input, update this.state to be value of what is in the input field + this.state = { term: ''} + } + +// use this.setState to inform react that state is changing + render() { + return ( +
+ 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 new file mode 100644 index 0000000000..a93e0fc56b --- /dev/null +++ b/src/components/video_detail.js @@ -0,0 +1,25 @@ +import React from 'react'; + +const VideoDetail = ({video}) => { + // react tries to load immediately, so need this if statement to guard against trying to get the id off of an object that is undefined + 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 new file mode 100644 index 0000000000..406dc0222a --- /dev/null +++ b/src/components/video_list.js @@ -0,0 +1,23 @@ +import React from 'react'; +import VideoListItem from './video_list_item'; + +// key = {video.etag} provides a unique key for each element in the list +const VideoList = (props) => { + const videoItems = props.videos.map((video) => { + return ( + + ); + }) + + + return ( + + ) +} + +export default VideoList; diff --git a/src/components/video_list_item.js b/src/components/video_list_item.js new file mode 100644 index 0000000000..c3cac2426a --- /dev/null +++ b/src/components/video_list_item.js @@ -0,0 +1,26 @@ +import React from 'react'; + +// const VideoListItem = ({video, onVideoSelect}) => { +// const video = props.video; +// const onVideoSelect = props.onVideoSelect; +// OR, use ES6: + +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 69d577acd1..5f5255be87 100644 --- a/src/index.js +++ b/src/index.js @@ -1,15 +1,48 @@ -import React from 'react'; +import React, {Component} from 'react'; import ReactDOM from 'react-dom'; -import { Provider } from 'react-redux'; -import { createStore, applyMiddleware } from 'redux'; +import YTSearch from 'youtube-api-search'; +import SearchBar from './components/search_bar'; +import VideoList from './components/video_list'; +import VideoDetail from './components/video_detail'; +const API_KEY = 'AIzaSyC_XvStCGm1z1suSkSnjeTkciTWMJQFjMc'; -import App from './components/app'; -import reducers from './reducers'; -const createStoreWithMiddleware = applyMiddleware()(createStore); +// Create a new component. This component should produce some HTML +// constructor will run on page load because we make a new instance of App, which will immediately kick off a searchwith the term surfboards, then the callback function will be called with the list of videos +class App extends Component { + constructor(props) { + super(props); -ReactDOM.render( - - - - , document.querySelector('.container')); + this.state = { + videos: [], + selectedVideo: null + } + 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}/> +
    + ); + } +} + +// Take this component's generated HTML and put it in the DOM +// first arg is instance of App function, and second arg is where to place the rendered HTML + +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; diff --git a/style/style.css b/style/style.css index e69de29bb2..3439e978f0 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; +}