diff --git a/package-lock.json b/package-lock.json index 1d06b58..ba8676d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6343,6 +6343,14 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "^16.7.0" + } + }, "hookrouter": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/hookrouter/-/hookrouter-1.2.3.tgz", @@ -11065,6 +11073,19 @@ } } }, + "react-redux": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.1.1.tgz", + "integrity": "sha512-QsW0vcmVVdNQzEkrgzh2W3Ksvr8cqpAv5FhEk7tNEft+5pp7rXxAudTz3VOPawRkLIepItpkEIyLcN/VVXzjTg==", + "requires": { + "@babel/runtime": "^7.5.5", + "hoist-non-react-statics": "^3.3.0", + "invariant": "^2.2.4", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.9.0" + } + }, "react-scripts": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.1.1.tgz", @@ -11253,6 +11274,20 @@ "minimatch": "3.0.4" } }, + "redux": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.4.tgz", + "integrity": "sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, + "redux-thunk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", + "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" + }, "reflect.ownkeys": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz", @@ -12698,6 +12733,11 @@ "util.promisify": "~1.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/package.json b/package.json index d471fd6..8dcc697 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,10 @@ "dependencies": { "react": "^16.9.0", "react-dom": "^16.9.0", + "react-redux": "^7.1.1", "react-scripts": "3.1.1", + "redux": "^4.0.4", + "redux-thunk": "^2.3.0", "styled-components": "^4.4.0" }, "scripts": { diff --git a/src/App.js b/src/App.js index e4b31fa..78aa955 100644 --- a/src/App.js +++ b/src/App.js @@ -10,12 +10,15 @@ import Login from './components/Login'; import Contact from './components/Contact'; import NoMatch from './components/NoMatch'; -import {useRoutes} from 'hookrouter'; +import { useRoutes } from 'hookrouter'; + +import { Provider } from 'react-redux'; +import store from './store'; const routes = { '/': () => , '/login': () => , - '/contact' : () => + '/contact': () => } const RouteResult = () => { @@ -36,30 +39,32 @@ const StyledNavBar = Styled.div` `; const App = () => ( - + - - - + + + - + - - - - - - - + + + + + + + - + - + - + + ); export default App; diff --git a/src/actions/actionTypes.js b/src/actions/actionTypes.js new file mode 100644 index 0000000..7ddc9c5 --- /dev/null +++ b/src/actions/actionTypes.js @@ -0,0 +1,3 @@ +export const Fetch_GETTING = 'Fetch_GETTING'; +export const Set_Data = 'Set_Data'; +export const Fetch_FAILURE = 'Fetch_FAILURE'; \ No newline at end of file diff --git a/src/actions/searchAction.js b/src/actions/searchAction.js new file mode 100644 index 0000000..0ab1511 --- /dev/null +++ b/src/actions/searchAction.js @@ -0,0 +1,45 @@ +import { Fetch_FAILURE, Set_Data, Fetch_GETTING } from './actionTypes'; +const api_key = "7elxdku9GGG5k8j0Xm8KWdANDgecHMV0"; +const full_url = + "https://app.ticketmaster.com/discovery/v2/events?apikey=" + + api_key + + "&locale=*"; + +export function Fetching(query) { + return async dispatch => { + dispatch(fetchStart()); + try { + const query_url = full_url + "&keyword=" + query; + const result = await fetch(query_url) + .then(function (response) { + return response.json(); + }) + dispatch(fetchingSuccess(result)); + } catch (err) { + dispatch(fetchingFailure()); + console.error(err); + } + + }; +}; + +function fetchStart() { + return { + type: Fetch_GETTING + }; +} + +function fetchingSuccess(result) { + return { + type: Set_Data, + result: result + }; +} + +function fetchingFailure(error) { + return { + type: Fetch_FAILURE, + error + }; +} + diff --git a/src/components/Ticketmaster.js b/src/components/Ticketmaster.js index db4df69..6b2dd4b 100644 --- a/src/components/Ticketmaster.js +++ b/src/components/Ticketmaster.js @@ -1,11 +1,14 @@ import React, { useState, useEffect } from "react"; import Styled from 'styled-components'; -const api_key = "7elxdku9GGG5k8j0Xm8KWdANDgecHMV0"; -const full_url = - "https://app.ticketmaster.com/discovery/v2/events?apikey=" + - api_key + - "&locale=*"; +import { useSelector, useDispatch } from 'react-redux'; +import { Fetching } from '../actions/searchAction' + +// const api_key = "7elxdku9GGG5k8j0Xm8KWdANDgecHMV0"; +// const full_url = +// "https://app.ticketmaster.com/discovery/v2/events?apikey=" + +// api_key + +// "&locale=*"; const SearchGroup = Styled.div` @@ -96,107 +99,102 @@ const ResultListMobile = Styled.ul` } `; -const Ticketmaster = function() { - const dummy = JSON.parse('{ "_embedded" : { "events": [] }}'); - - const [query, setQuery] = useState(""); - const [data, setData] = useState(dummy); - const [search, setSearch] = useState(""); - - useEffect(() => { - const fetchData = async () => { - const query_url = full_url + "&keyword=" + query; - const result = await fetch(query_url) - .then(function(response) { - return response.json(); - }) - .catch(function(error) { - console.log(error); - return dummy; - }); - - setData(result); - console.log(data); //debugging only - }; - - fetchData(); - }, [search]); - - function createDateLocation(dateString, locationString) - { - if (dateString && locationString) - { - return dateString + " @ " + locationString; +const Ticketmaster = function () { + const dispatch = useDispatch() + const searchResult = useSelector(state => state.searchResult) + // const dummy = JSON.parse('{ "_embedded" : { "events": [] }}'); + const [query, setQuery] = useState(""); + // const [data, setData] = useState(searchResult ? searchResult :dummy); + const [search, setSearch] = useState(""); + + useEffect(() => { + // const fetchData = async () => { + // const query_url = full_url + "&keyword=" + query; + // const result = await fetch(query_url) + // .then(function(response) { + // return response.json(); + // }) + // .catch(function(error) { + // console.log(error); + // return dummy; + // }); + + // setData(result); + // console.log(data); //debugging only + // }; + // fetchData(); + dispatch(Fetching(query)); + }, [search]); + + + function createDateLocation(dateString, locationString) { + if (dateString && locationString) { + return dateString + " @ " + locationString; + } + return "Unknown date"; } - return "Unknown date"; - } - - function createCityState(tmEventString) - { - var cityString = ""; - var stateString = ""; - try { - cityString = tmEventString._embedded.venues[0].city.name; - } catch (err) - { - cityString = ""; - } - - try { - stateString = tmEventString._embedded.venues[0].state.name; - } catch (err) - { - stateString = ""; - } - - if (cityString && stateString) - { - return cityString + "," + stateString - } - else if (cityString) - { - return cityString - } - return "Unknown location"; - } + function createCityState(tmEventString) { + var cityString = ""; + var stateString = ""; + + try { + cityString = tmEventString._embedded.venues[0].city.name; + } catch (err) { + cityString = ""; + } + + try { + stateString = tmEventString._embedded.venues[0].state.name; + } catch (err) { + stateString = ""; + } + + if (cityString && stateString) { + return cityString + "," + stateString + } + else if (cityString) { + return cityString + } + return "Unknown location"; + } - return ( - - - setQuery(event.target.value)} /> - - setSearch(query)}> - Search + return ( + + + setQuery(event.target.value)} /> + setSearch(query)}> + Search - - - - {data["_embedded"]["events"].map(tmevent => ( - - {tmevent.name} - {createDateLocation(tmevent.dates.start.localDate, tmevent._embedded.venues[0].name)} - {createCityState(tmevent)} - Buy Tickets - - ))} - - - - {data["_embedded"]["events"].map(tmevent => ( -
  • - {tmevent.name} -
  • - ))} -
    -
    - ); +
    + + + {searchResult["_embedded"]["events"].map(tmevent => ( + + {tmevent.name} + {createDateLocation(tmevent.dates.start.localDate, tmevent._embedded.venues[0].name)} + {createCityState(tmevent)} + Buy Tickets + + ))} + + + + {searchResult["_embedded"]["events"].map(tmevent => ( +
  • + {tmevent.name} +
  • + ))} +
    +
    + ); }; + export default Ticketmaster; diff --git a/src/reducers/SearchReducer.js b/src/reducers/SearchReducer.js new file mode 100644 index 0000000..c78b3a7 --- /dev/null +++ b/src/reducers/SearchReducer.js @@ -0,0 +1,35 @@ +import { Fetch_FAILURE, Set_Data, Fetch_GETTING } from '../actions/actionTypes'; + +const dummy = JSON.parse('{ "_embedded" : { "events": [] }}'); +const initialState = { + isGetting: false, + error: null, + searchResult: dummy +} + +export default (state = initialState, action = {}) => { + switch (action.type) { + case Fetch_GETTING: + return { + ...state, + isGetting: true, + error: null + }; + case Fetch_FAILURE: + return { + ...state, + isGetting: false, + error: action.error + }; + case Set_Data: + return { + ...state, + isGetting: false, + searchResult: action.result['_embedded'] ? action.result : dummy , + error: null + }; + default: + return state; + } +}; + diff --git a/src/store.js b/src/store.js new file mode 100644 index 0000000..479ad13 --- /dev/null +++ b/src/store.js @@ -0,0 +1,7 @@ +import { createStore, combineReducers, applyMiddleware } from 'redux'; +import thunk from "redux-thunk"; +import SearchReducer from "./reducers/SearchReducer"; + +const store = createStore(SearchReducer,applyMiddleware(thunk)); + +export default store;