From e1be5bfcaab5334555bb32403cf5063a41b61c96 Mon Sep 17 00:00:00 2001 From: Alex Mireles Date: Wed, 12 Dec 2018 16:57:36 -0800 Subject: [PATCH] Alex Mireles patch - thank you --- reactjs/components/Gallery/index.js | 32 +++++++++++++++ reactjs/components/HtmlHead/index.js | 1 + reactjs/package-lock.json | 58 ++++++++++++++++++++++++++++ reactjs/package.json | 4 ++ reactjs/pages/_app.js | 2 + reactjs/pages/index.js | 52 +++++++++++++++++++++---- reactjs/pages/pageTwo.js | 53 +++++++++++++++++++++++++ reactjs/store/actions/giphy.js | 23 +++++++++++ reactjs/store/reducers/giphy.js | 20 ++++++++++ reactjs/store/reducers/index.js | 2 + reactjs/store/sagas/giphy.js | 33 ++++++++++++++++ reactjs/store/sagas/index.js | 2 + 12 files changed, 275 insertions(+), 7 deletions(-) create mode 100644 reactjs/components/Gallery/index.js create mode 100644 reactjs/pages/pageTwo.js create mode 100644 reactjs/store/actions/giphy.js create mode 100644 reactjs/store/reducers/giphy.js create mode 100644 reactjs/store/sagas/giphy.js diff --git a/reactjs/components/Gallery/index.js b/reactjs/components/Gallery/index.js new file mode 100644 index 0000000..ab13a9d --- /dev/null +++ b/reactjs/components/Gallery/index.js @@ -0,0 +1,32 @@ +import PropTypes from 'prop-types'; + +function Gallery(props) { + const content = props.giphyData.map((img) => +
+
+
+ {img.title}/ +
+
{img.title}
+
+
+ +
+
+); +return ( +
+
+
+
{content}
+
+
+
+ ) +} + +Gallery.propTypes = { + content: PropTypes.array +} + +export default Gallery; diff --git a/reactjs/components/HtmlHead/index.js b/reactjs/components/HtmlHead/index.js index 3e9d76b..4f8c980 100644 --- a/reactjs/components/HtmlHead/index.js +++ b/reactjs/components/HtmlHead/index.js @@ -25,6 +25,7 @@ SystemSeed Technical Assessment + {stylesheets} ); diff --git a/reactjs/package-lock.json b/reactjs/package-lock.json index fb33b39..57c3f78 100644 --- a/reactjs/package-lock.json +++ b/reactjs/package-lock.json @@ -1369,6 +1369,15 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "axios": { + "version": "0.18.0", + "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "1.1.6" + } + }, "axobject-query": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", @@ -1582,6 +1591,11 @@ "type-is": "1.6.16" } }, + "bootstrap": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.3.tgz", + "integrity": "sha512-rDFIzgXcof0jDyjNosjv4Sno77X4KuPeFxG2XZZv1/Kc8DRVGVADdoQyyOVDwPqL36DDmtCQbrpMCqvpPLJQ0w==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3303,6 +3317,24 @@ "readable-stream": "2.3.6" } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -4615,6 +4647,22 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "isomorphic-unfetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.0.0.tgz", + "integrity": "sha512-V0tmJSYfkKokZ5mgl0cmfQMTb7MLHsBMngTkbLY0eXvKqiVRRoZP04Ly+KhKrJfKtzC9E6Pp15Jo+bwh7Vi2XQ==", + "requires": { + "node-fetch": "2.3.0", + "unfetch": "4.0.1" + }, + "dependencies": { + "unfetch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.0.1.tgz", + "integrity": "sha512-HzDM9NgldcRvHVDb/O9vKoUszVij30Yw5ePjOZJig8nF/YisG7QN/9CBXZ8dsHLouXMeLZ82r+Jod9M2wFkEbQ==" + } + } + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -5381,6 +5429,11 @@ "lower-case": "1.1.4" } }, + "node-fetch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", + "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" + }, "node-gyp": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", @@ -6139,6 +6192,11 @@ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, + "random-words": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/random-words/-/random-words-1.1.0.tgz", + "integrity": "sha512-GyV8PlSmQE08S/RSCjG9Uh0uQaUC7iRpA18PWk9OSnvNCzKQ+B2NxqqN/cYBej4t7dfBWxh10KFBYSiNcg1jlg==" + }, "randombytes": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", diff --git a/reactjs/package.json b/reactjs/package.json index 3397b0f..9ed0517 100644 --- a/reactjs/package.json +++ b/reactjs/package.json @@ -3,8 +3,11 @@ "version": "1.1.0", "license": "MIT", "dependencies": { + "axios": "^0.18.0", + "bootstrap": "^4.1.3", "compression": "^1.7.3", "express": "^4.16.3", + "isomorphic-unfetch": "^3.0.0", "next": "^7.0.2", "next-redux-saga": "^3.0.0-beta.1", "next-redux-wrapper": "^2.0.0", @@ -12,6 +15,7 @@ "node-sass-glob-importer": "^5.2.0", "nprogress": "^0.2.0", "prop-types": "^15.6.2", + "random-words": "^1.1.0", "raw-loader": "^0.5.1", "react": "^16.4.1", "react-dom": "^16.4.1", diff --git a/reactjs/pages/_app.js b/reactjs/pages/_app.js index ab82d09..2e16664 100644 --- a/reactjs/pages/_app.js +++ b/reactjs/pages/_app.js @@ -6,6 +6,8 @@ import withReduxSaga from 'next-redux-saga'; import HtmlHead from '../components/HtmlHead'; import configureStore from '../store/store'; import '../components/PageProgressBar'; // Beautiful page transition indicator. +import '../node_modules/bootstrap/dist/css/bootstrap.min.css'; + class Application extends App { static async getInitialProps({ Component, ctx }) { diff --git a/reactjs/pages/index.js b/reactjs/pages/index.js index c6b3226..5a106ec 100644 --- a/reactjs/pages/index.js +++ b/reactjs/pages/index.js @@ -1,16 +1,54 @@ import React from 'react'; -import HelloFriend from '../components/HelloFriend'; +import Link from 'next/link'; +import {connect} from 'react-redux'; +import PropTypes from 'prop-types'; + +import Gallery from '../components/Gallery'; class Page extends React.Component { - static async getInitialProps() { - return { - name: 'value', - }; + + componentDidMount() { + this.props.dispatch({type: 'API_CALL_REQUEST'}); + this.interval = setInterval(() => { + this.props.dispatch({type: 'API_CALL_REQUEST'}); + }, 5000); + } + + componentWillUnmount() { + clearInterval(this.interval) } render() { - return ; + const giphys = this.props.imageData; + return ( +
+
+
+

Alex Mireles

+
+
+ +
+
+
+ + +
+
+ ); + } +} + +Page.propTypes = { + imageData: PropTypes.array +} + +function mapStateToProps(state) { + return { + imageData: state.giphy.images.data, } } -export default Page; +export default connect(mapStateToProps)(Page); diff --git a/reactjs/pages/pageTwo.js b/reactjs/pages/pageTwo.js new file mode 100644 index 0000000..d38fdc9 --- /dev/null +++ b/reactjs/pages/pageTwo.js @@ -0,0 +1,53 @@ +import React from 'react'; +import Link from 'next/link'; +import {connect} from 'react-redux'; +import PropTypes from 'prop-types'; + +import Gallery from '../components/Gallery'; + +class PageTwo extends React.Component { + + componentDidMount() { + this.props.dispatch({type: 'API_CALL_REQUEST'}); + this.interval = setInterval(() => { + this.props.dispatch({type: 'API_CALL_REQUEST'}); + }, 5000); + } + + componentWillUnmount() { + clearInterval(this.interval) + } + + render() { + const giphys = this.props.imageData; + return ( +
+
+
+

Alex Mireles

+
+
+ +
+
+
+ +
+
+ ); + } +} + +PageTwo.propTypes = { + imageData: PropTypes.array +} + +function mapStateToProps(state) { + return { + imageData: state.giphy.images.data, + } +} + +export default connect(mapStateToProps)(PageTwo); diff --git a/reactjs/store/actions/giphy.js b/reactjs/store/actions/giphy.js new file mode 100644 index 0000000..77a23b6 --- /dev/null +++ b/reactjs/store/actions/giphy.js @@ -0,0 +1,23 @@ +export const API_CALL_REQUEST = "API_CALL_REQUEST"; +export const API_CALL_SUCCESS = "API_CALL_SUCCESS"; +export const API_CALL_FAILURE = "API_CALL_FAILURE"; + +export function requestImages() { + return { + type: API_CALL_REQUEST + }; +} + +export function loadImages(images) { + return { + type: API_CALL_SUCCESS, + images + }; +} + +export function fetchImagesFail(error) { + return { + type: API_CALL_FAILURE, + error + }; +} diff --git a/reactjs/store/reducers/giphy.js b/reactjs/store/reducers/giphy.js new file mode 100644 index 0000000..a083b34 --- /dev/null +++ b/reactjs/store/reducers/giphy.js @@ -0,0 +1,20 @@ +import {API_CALL_REQUEST, API_CALL_SUCCESS, API_CALL_FAILURE, INCREMENT} from '../actions/giphy'; + +const defaultState = { + images: [], + isFetching: false, + error: false +} + +export default function images(state = {defaultState}, action) { + switch(action.type) { + case API_CALL_REQUEST: + return {...state, error: false, isFetching: true}; + case API_CALL_SUCCESS: + return {...state, error: false, images: action.images, isFetching: false} ; + case API_CALL_FAILURE: + return {...state, error: true, isFetching: false}; + default: + return state; + } +} diff --git a/reactjs/store/reducers/index.js b/reactjs/store/reducers/index.js index 72a8dcf..d3418fd 100644 --- a/reactjs/store/reducers/index.js +++ b/reactjs/store/reducers/index.js @@ -1,7 +1,9 @@ import { combineReducers } from 'redux'; // Put all your reducers here. import example from './example'; +import giphy from './giphy'; export default combineReducers({ example, + giphy, }); diff --git a/reactjs/store/sagas/giphy.js b/reactjs/store/sagas/giphy.js new file mode 100644 index 0000000..f71297a --- /dev/null +++ b/reactjs/store/sagas/giphy.js @@ -0,0 +1,33 @@ +import { all, takeLatest, call, put } from 'redux-saga/effects'; +import axios from 'axios'; + +import { API_CALL_REQUEST, API_CALL_SUCCESS, API_CALL_FAILURE, API_CALL_FETCHED } from '../actions/giphy'; + +function apiFetch() { + let randomWord = require('random-words'); + let API_ENDPOINT = `https://api.giphy.com/v1/gifs/search?api_key=h6q9hI50TiiUqR8F5D4aGBm2Gqiny0jG&q=${randomWord()}&limit=12`; + return axios({ + method: "get", + url: API_ENDPOINT + }); +} + +export function* fetchImages() { + try { + const res = yield call(apiFetch) + //const res = yield call(() => axios.get(API_ENDPOINT)) + const images = yield res.data + yield put({type: API_CALL_SUCCESS, images}) + + } catch (e) { + yield put({type: API_CALL_FAILURE, e}) + console.log('Error fetching giphy data') + } +} + +export default function* giphySaga() { + yield all([ + yield takeLatest(API_CALL_REQUEST, fetchImages), + yield call(fetchImages) + ]); +} diff --git a/reactjs/store/sagas/index.js b/reactjs/store/sagas/index.js index 6ff084d..13851b5 100644 --- a/reactjs/store/sagas/index.js +++ b/reactjs/store/sagas/index.js @@ -1,9 +1,11 @@ import { all } from 'redux-saga/effects'; // Put all your sagas here. import exampleSagas from './example'; +import giphySaga from './giphy'; export default function* rootSaga() { yield all([ ...exampleSagas(), + ...giphySaga(), ]); }