diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..e69de29
diff --git a/package-lock.json b/package-lock.json
index 993b456..9a041da 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14878,6 +14878,11 @@
"requires-port": "^1.0.0"
}
},
+ "url-search-params-polyfill": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/url-search-params-polyfill/-/url-search-params-polyfill-8.1.1.tgz",
+ "integrity": "sha512-KmkCs6SjE6t4ihrfW9JelAPQIIIFbJweaaSLTh/4AO+c58JlDcb+GbdPt8yr5lRcFg4rPswRFRRhBGpWwh0K/Q=="
+ },
"use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
diff --git a/package.json b/package.json
index a154f9e..9602062 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"sass": "^1.32.11",
+ "url-search-params-polyfill": "^8.1.1",
"web-vitals": "^1.0.1"
},
"devDependencies": {
diff --git a/src/App.js b/src/App.js
index 3a49c0e..21f456a 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,9 +1,30 @@
import React from "react";
-
+import { Switch, Route } from "react-router-dom";
import Home from "./pages/Home";
+import Episode from "./pages/Episode";
+import Character from "./pages/Character";
+import Location from "./pages/Location";
function App() {
- return ;
+ return (
+
+ (
+
+ )} />
+
+ (
+
+ )} />
+
+ (
+
+ )} />
+
+ (
+
+ )} />
+
+ );
}
export default App;
diff --git a/src/api/index.js b/src/api/index.js
new file mode 100644
index 0000000..bb5e1a0
--- /dev/null
+++ b/src/api/index.js
@@ -0,0 +1,10 @@
+import axios from "axios";
+
+export async function makeRequest(url) {
+ try {
+ const response = await axios.get(url);
+ return [response , false];
+ } catch (error) {
+ return [null , error];
+ }
+}
\ No newline at end of file
diff --git a/src/components/CharacterCard/CharacterCard.js b/src/components/CharacterCard/CharacterCard.js
index 9e7e4ab..84e6a92 100644
--- a/src/components/CharacterCard/CharacterCard.js
+++ b/src/components/CharacterCard/CharacterCard.js
@@ -5,23 +5,40 @@ import "./CharacterCard.scss";
import * as routes from "../../constants/routes";
-function CharacterCard({ id, name, image, species, status, origin, location }) {
+function CharacterCard({ id, name, image, species, status, origin, location, showMoreDetails = false }) {
return (
-
+
{name}
+
Origin:
{origin.name}
+
|
-
{status}
+
Status: {status}
+
+ {showMoreDetails && (
+
+
Location:
+
+ {location.name}
+
+
+
|
+
Specie: {species}
+
+ )}
);
}
diff --git a/src/pages/Character/Character.js b/src/pages/Character/Character.js
new file mode 100644
index 0000000..c6498da
--- /dev/null
+++ b/src/pages/Character/Character.js
@@ -0,0 +1,129 @@
+import React, { Component } from "react";
+import { Link } from 'react-router-dom';
+import * as routes from "../../constants/routes";
+
+import Layout from "../../components/Layout";
+import EpisodeCard from "../../components/EpisodeCard";
+import { makeRequest } from '../../api';
+
+class Character extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ character: {
+ image: null,
+ name: null,
+ species: null,
+ status: null,
+ origin: null,
+ location: null
+ },
+ episodes: [],
+ hasError: false,
+ hasLoaded: false
+ }
+ }
+
+ async componentDidMount() {
+ // Get episode ID by regex, best would be by query param in URL
+ const path = window.location.pathname
+ const id = path.match(/(\d.*$)/)[0]
+
+ const [response, error] = await makeRequest(`https://rickandmortyapi.com/api/character/${id}`)
+
+ if (!error) {
+ const {data} = response
+ const promises = data.episode.map(url => makeRequest(url))
+
+ const characterLocation = await makeRequest(data.location.url)
+
+ const character = {
+ image: data.image,
+ name: data.name,
+ species: data.species,
+ status: data.status,
+ origin: data.origin,
+ location: characterLocation[0].data
+ }
+
+ Promise.all(promises)
+ .then(responses => (
+ this.setState({
+ character: character,
+ episodes: responses.map(res => res[0].data),
+ hasLoaded: true,
+ hasError: false
+ })
+ ))
+
+ } else {
+ this.setState({
+ hasLoaded: false,
+ hasError: true
+ })
+ }
+ }
+
+ render() {
+
+ const {character, episodes, hasError, hasLoaded} = this.state
+ return(
+
+
+
+ {!hasLoaded && (
Loading... )}
+ {hasError && (
API error )}
+
+ {!hasError && hasLoaded && (
+
+
+
+
{character.name}
+
+
+
Character
+
{character.species} | {character.status}
+
+
+
Origin
+
{character.origin.name}
+
+
+
Location
+
{character.location.name}
+
+
+
+ )}
+
+
+
+
+
+
+ {episodes.length > 0 && (
+
+
+ {episodes.map(episode => (
+
+
+
+ ))}
+
+
+ )}
+
+
+
+ )
+ }
+}
+
+export default Character
\ No newline at end of file
diff --git a/src/pages/Character/index.js b/src/pages/Character/index.js
new file mode 100644
index 0000000..4562dce
--- /dev/null
+++ b/src/pages/Character/index.js
@@ -0,0 +1 @@
+export { default } from "./Character";
\ No newline at end of file
diff --git a/src/pages/Episode/Episode.js b/src/pages/Episode/Episode.js
index 8255df5..af9a56a 100644
--- a/src/pages/Episode/Episode.js
+++ b/src/pages/Episode/Episode.js
@@ -1,26 +1,61 @@
import React, { Component } from "react";
+import { makeRequest } from '../../api'
import Layout from "../../components/Layout";
-// import CharacterCard from "../../components/CharacterCard";
+import CharacterCard from "../../components/CharacterCard";
class Episode extends Component {
constructor(props) {
super(props);
- this.state = {};
- // episode: null,
- // characters: [],
- // hasLoaded: false,
- // hasError: false,
- // errorMessage: null,
+ this.state = {
+ episode: null,
+ characters: [],
+ hasLoaded: false,
+ hasError: false,
+ errorMessage: null,
+ };
+ }
+
+ async componentDidMount() {
+ // Get episode ID by regex, best would be by query param in URL
+ const path = window.location.pathname
+ const id = path.match(/(\d.*$)/)[0]
+
+ const [response, error] = await makeRequest(`https://rickandmortyapi.com/api/episode/${id}`)
+
+ if (!error) {
+ const {data} = response
+ const promises = data.characters.map(url => makeRequest(url))
+ Promise.all(promises)
+ .then(responses => (
+ this.setState({
+ episode: data.episode,
+ characters: responses.map(res => res[0].data),
+ hasLoaded: true,
+ hasError: false
+ })
+ ))
+ } else {
+ this.setState({
+ hasLoaded: false,
+ hasError: true
+ })
+ }
}
render() {
+
+ const {characters, episode, hasLoaded, hasError, errorMessage} = this.state
+
return (
- {/* {characters.map((character) => (
+ {!hasLoaded && (
Loading... )}
+ {hasError && (API error )}
+
+ {characters.length > 0 && hasLoaded && characters.map((character) => (
- ))} */}
+ ))}
diff --git a/src/pages/Home/Home.js b/src/pages/Home/Home.js
index f86e93c..b18aef7 100644
--- a/src/pages/Home/Home.js
+++ b/src/pages/Home/Home.js
@@ -1,42 +1,70 @@
import React, { Component } from "react";
+import { Link } from "react-router-dom";
+import { makeRequest } from "../../api";
import Layout from "../../components/Layout";
-// import EpisodeCard from "../../components/EpisodeCard";
+import EpisodeCard from "../../components/EpisodeCard";
class Home extends Component {
constructor(props) {
super(props);
- this.state = {};
- // page: 1,
- // paginationInfo: null,
- // episodes: [],
- // hasLoaded: false,
- // hasError: false,
- // errorMessage: null,
+ this.state = {
+ episodes: [],
+ nextUrl: null,
+ prevUrl: null,
+ hasLoaded: false,
+ hasError: false
+ }
+
+ this.loadEpisodes = this.loadEpisodes.bind(this)
+ this.handlePagination = this.handlePagination.bind(this)
+ }
+
+ componentDidMount() {
+ this.loadEpisodes({})
}
- async componentDidMount() {
- // this.loadEpisodes();
+ handlePagination(event) {
+ const { nextUrl, prevUrl } = this.state
+ event.preventDefault()
+ event.target.getAttribute('data-pagination') === 'next' ?
+ this.loadEpisodes({url: nextUrl}) :
+ this.loadEpisodes({url: prevUrl})
}
- async loadEpisodes() {
- console.log(this);
+ async loadEpisodes({url = undefined}) {
+ // Get episodes
+ const { currentPage } = this.state
+ const apiUrl = url || `https://rickandmortyapi.com/api/episode?page=${currentPage}`
+
+ const [response, error] = await makeRequest(apiUrl)
+
+ if (!error) this.setState({
+ episodes: response.data.results,
+ hasLoaded: true,
+ hasError: false,
+ nextUrl: response.data.info.next,
+ prevUrl: response.data.info.prev,
+ })
+ if (error) this.setState({hasError: true, hasLoaded: false})
}
render() {
+ const {hasLoaded, hasError, episodes, nextUrl, prevUrl, currentPage} = this.state
+
return (
- {/* {hasLoaded && !hasError && (
+ {hasLoaded && !hasError && (
Episodes loaded!
- )} */}
+ )}
- {/* {episodes.map((episode) => (
+ {episodes.map((episode) => (
- ))} */}
+ ))}
+
+
+
+ {prevUrl && !hasError && (
+
+ Prev
+
+ )}
+ {nextUrl && !hasError && (
+
+ Next
+ )}
+
+
+
);
diff --git a/src/pages/Location/Location.js b/src/pages/Location/Location.js
new file mode 100644
index 0000000..b6f2986
--- /dev/null
+++ b/src/pages/Location/Location.js
@@ -0,0 +1,115 @@
+import React, { Component } from "react";
+
+import Layout from "../../components/Layout";
+import CharacterCard from "../../components/CharacterCard";
+import { makeRequest } from '../../api';
+
+class Location extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ id: null,
+ name: null,
+ type: null,
+ dimension: null,
+ characters: [],
+ hasLoaded: false,
+ hasError: false,
+ }
+ }
+
+ async componentDidMount() {
+ // Get episode ID by regex, best would be by query param in URL
+ const path = window.location.pathname
+ const id = path.match(/(\d.*$)/)[0]
+
+ const [response, error] = await makeRequest(`https://rickandmortyapi.com/api/location/${id}`)
+
+ if (!error) {
+ const {data} = response
+ const promises = data.residents.map(url => makeRequest(url))
+
+ Promise.all(promises)
+ .then(responses => (
+ this.setState({
+ id: data.id,
+ name: data.name,
+ type: data.type,
+ dimension: data.dimension,
+ characters: responses.map(res => res[0].data),
+ hasError: false,
+ hasLoaded: true
+ })
+ ))
+
+ } else {
+ this.setState({
+ hasLoaded: false,
+ hasError: true
+ })
+ }
+ }
+
+ render() {
+
+ const {id, name, type, dimension, characters, hasError, hasLoaded} = this.state
+ console.log(characters)
+ return(
+
+
+
+ {!hasLoaded && (
Loading... )}
+ {hasError && (
API error )}
+
+ {!hasError && hasLoaded && (
+
+
+
{name}
+
+
+
+
Dimension
+
{dimension}
+
+
+
+ )}
+
+
+
+
+
+
+ {characters.length > 0 && (
+
+
+ {characters.map(character => (
+
+
+
+ ))}
+
+
+ )}
+
+
+
+ )
+ }
+}
+
+export default Location
\ No newline at end of file
diff --git a/src/pages/Location/index.js b/src/pages/Location/index.js
new file mode 100644
index 0000000..e267389
--- /dev/null
+++ b/src/pages/Location/index.js
@@ -0,0 +1 @@
+export { default } from "./Location";
\ No newline at end of file