From 26f25a18018ee19dd0f24c2f6f9386a89601dfe8 Mon Sep 17 00:00:00 2001 From: Blessing Makaraba Date: Sun, 26 Sep 2021 19:47:55 +0100 Subject: [PATCH] ft(user): Implement error view for user experience --- README.md | 53 ++++++++------------ netlify.toml | 9 ++++ src/UI/atoms/Title/Title.tsx | 2 +- src/UI/pages/Contributors/Contributors.tsx | 47 ++++++++++------- src/UI/pages/Home/Home.tsx | 30 ++++++++--- src/UI/templates/Card/Card.styles.ts | 2 - src/UI/templates/Card/Card.tsx | 2 +- src/UI/templates/NotFound/NotFound.styles.ts | 13 +++++ src/UI/templates/NotFound/NotFound.tsx | 13 +++++ src/assets/not found.svg | 51 +++++++++++++++++++ src/context/dataProvider.tsx | 2 +- src/hooks/{request.ts => useRequest.ts} | 8 +-- src/index.styles.ts | 4 +- 13 files changed, 168 insertions(+), 68 deletions(-) create mode 100644 netlify.toml create mode 100644 src/UI/templates/NotFound/NotFound.styles.ts create mode 100644 src/UI/templates/NotFound/NotFound.tsx create mode 100644 src/assets/not found.svg rename src/hooks/{request.ts => useRequest.ts} (90%) diff --git a/README.md b/README.md index 892d2b8..cf72ece 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,37 @@ -# Description +# GitHub-Users -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). +GitHub Users is a React Web Application that enables customers to search for repositories and view details of contributors respectively. It is powered by [GITHUB-REST-API](https://docs.github.com/en/free-pro-team@latest/rest). -## Available Scripts +[Web-Application-Published-Link](https://github-users-blessing.netlify.app) -In the project directory, you can run: +#### Features -### `yarn start` +#### Required Features -Runs the app in the development mode.\ -Open [http://localhost:3000](http://localhost:3000) to view it in the browser. +- Search for repositories. +- View Contributors details in a repository. -The page will reload if you make edits.\ -You will also see any lint errors in the console. +#### User Features -### `yarn test` +- Search for repositories. +- View Contributors details in a repository. -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. +#### Tools -### `yarn build` +##### Dev Tools -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. +- React +- TypeScript -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! +### Getting Started -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. +#### Installations -### `yarn eject` +- Install Node js -**Note: this is a one-way operation. Once you `eject`, you can’t go back!** +#### Running the web app -If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. - -You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). +- Clone this repo +- Open terminal +- Run `yarn install` +- Run `yarn start` diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..21fb2b6 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,9 @@ +[build] + command = "yarn build --prod" + publish = "build" + base = "/" + +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 \ No newline at end of file diff --git a/src/UI/atoms/Title/Title.tsx b/src/UI/atoms/Title/Title.tsx index fa5cfee..24a8ce9 100644 --- a/src/UI/atoms/Title/Title.tsx +++ b/src/UI/atoms/Title/Title.tsx @@ -1,6 +1,6 @@ import { StyledTitle } from "./Title.styles"; -const Title: React.FC<{ children: string }> = ({ children }) => ( +const Title: React.FC<{ children: any }> = ({ children }) => ( {children} ); diff --git a/src/UI/pages/Contributors/Contributors.tsx b/src/UI/pages/Contributors/Contributors.tsx index c6bba2c..426e17c 100644 --- a/src/UI/pages/Contributors/Contributors.tsx +++ b/src/UI/pages/Contributors/Contributors.tsx @@ -1,40 +1,53 @@ import useDataContext from "hooks/useDataContext"; -import { Item, ItemII } from "interfaces/dataItem"; +import { ItemII } from "interfaces/dataItem"; import React, { useEffect } from "react"; import Title from "UI/atoms/Title/Title"; import { CardII } from "UI/templates/Card/Card"; import { CardDisplayWrapper } from "../Home/Home.styles"; +import Skeleton from "react-skeleton-loading"; +import NotFound from "UI/templates/NotFound/NotFound"; + const Contributors: React.FC<{}> = (props: any) => { - const { data, error, loading, makeRequest } = useDataContext(); + let { data, error, loading, makeRequest } = useDataContext(); - let datum = data.find( - (data: any) => data.owner?.id === +props.match.params.id - ); + const repositoryFullName = props.location.pathname.slice(14); useEffect(() => { - if (datum) { + if (repositoryFullName) { makeRequest( - `https://api.github.com/repos/${datum.full_name}/contributors`, + `https://api.github.com/repos/${repositoryFullName}/contributors`, "contributors" ); } - }, [makeRequest, datum]); + }, [makeRequest, repositoryFullName]); - console.log({ data }); + const attributedData = loading ? Array(6).fill(null) : data; - const attributedData = loading ? Array(20).fill(null) : data; + const cardDisplay = + Array.isArray(attributedData) && + attributedData.length > 0 && + attributedData.map((item: ItemII, index: number) => ( + + )); - const cardDisplay = attributedData.map((item: ItemII, index: number) => ( - - )); + const renderCondition = attributedData.length > 0; return ( <> - - {datum ? `${datum.full_name} Contributors` : "Retrieving Contributors"} - - {cardDisplay} + {repositoryFullName ? ( + {`${repositoryFullName} Contributors`} + ) : ( + + )} + + {renderCondition ? ( + {cardDisplay} + ) : ( + + )} ); }; diff --git a/src/UI/pages/Home/Home.tsx b/src/UI/pages/Home/Home.tsx index 6bc63b4..8c3a453 100644 --- a/src/UI/pages/Home/Home.tsx +++ b/src/UI/pages/Home/Home.tsx @@ -7,6 +7,7 @@ import Title from "UI/atoms/Title/Title"; import Search from "UI/molecules/Search/Search"; import Card from "UI/templates/Card/Card"; import { CardDisplayWrapper } from "./Home.styles"; +import NotFound from "UI/templates/NotFound/NotFound"; const Home: React.FC<{}> = () => { const [searchValue, setSearchValue] = useState(""); @@ -40,9 +41,14 @@ const Home: React.FC<{}> = () => { const attributedData = loading ? Array(30).fill(null) : data; - const cardDisplay = attributedData.map((item: Item, index: number) => ( - - )); + const cardDisplay = + Array.isArray(attributedData) && + attributedData.length > 0 && + attributedData.map((item: Item, index: number) => ( + + )); + + const renderCondition = attributedData.length > 0; return ( <> @@ -53,10 +59,20 @@ const Home: React.FC<{}> = () => { loading={loading} /> - - {justMounted.current ? "Popular Repositories" : "Searched Repositories"} - - {cardDisplay} + {renderCondition ? ( + <> + + {justMounted.current + ? "Popular Repositories" + : "Searched Repositories"} + + {cardDisplay}{" "} + + ) : ( + + )} ); }; diff --git a/src/UI/templates/Card/Card.styles.ts b/src/UI/templates/Card/Card.styles.ts index 5d0ea48..5cc2c7a 100644 --- a/src/UI/templates/Card/Card.styles.ts +++ b/src/UI/templates/Card/Card.styles.ts @@ -3,8 +3,6 @@ import { Link } from "react-router-dom"; export const StyledCard = styled.div` background-color: white; - - border: 1px solid #272b36; padding: 3rem 3rem; flex-basis: 80%; margin-top: 2rem; diff --git a/src/UI/templates/Card/Card.tsx b/src/UI/templates/Card/Card.tsx index f884a22..cb68e18 100644 --- a/src/UI/templates/Card/Card.tsx +++ b/src/UI/templates/Card/Card.tsx @@ -50,7 +50,7 @@ const Card: React.FC<{ datum: Item; state: boolean }> = ({ datum, state }) => ( )} {!state ? ( - + View Contributors ) : ( diff --git a/src/UI/templates/NotFound/NotFound.styles.ts b/src/UI/templates/NotFound/NotFound.styles.ts new file mode 100644 index 0000000..3f36ef5 --- /dev/null +++ b/src/UI/templates/NotFound/NotFound.styles.ts @@ -0,0 +1,13 @@ +import styled from "styled-components"; + +export const NotFoundImageContainer = styled.div` + display: flex; + align-items: center; + flex-direction: column; + padding: 0.5rem; + margin-top: 15rem; +`; + +export const NotFoundImage = styled.img` + max-width: 100%; +`; diff --git a/src/UI/templates/NotFound/NotFound.tsx b/src/UI/templates/NotFound/NotFound.tsx new file mode 100644 index 0000000..f3989af --- /dev/null +++ b/src/UI/templates/NotFound/NotFound.tsx @@ -0,0 +1,13 @@ +import { NotFoundImage, NotFoundImageContainer } from "./NotFound.styles"; +import notFoundImage from "assets/not found.svg"; + +const NotFound: React.FC<{ message: string }> = ({ message }) => { + return ( + +

{message}

+ +
+ ); +}; + +export default NotFound; diff --git a/src/assets/not found.svg b/src/assets/not found.svg new file mode 100644 index 0000000..22d3a34 --- /dev/null +++ b/src/assets/not found.svg @@ -0,0 +1,51 @@ + + + Group 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/context/dataProvider.tsx b/src/context/dataProvider.tsx index 88b9636..17ca011 100644 --- a/src/context/dataProvider.tsx +++ b/src/context/dataProvider.tsx @@ -1,4 +1,4 @@ -import useRequest from "hooks/request"; +import useRequest from "hooks/useRequest"; import DataContext from "./dataContext"; diff --git a/src/hooks/request.ts b/src/hooks/useRequest.ts similarity index 90% rename from src/hooks/request.ts rename to src/hooks/useRequest.ts index 6cdec50..81b6909 100644 --- a/src/hooks/request.ts +++ b/src/hooks/useRequest.ts @@ -1,4 +1,4 @@ -import { objectLiteral } from "interfaces/dataItem"; +import { Item, ItemII } from "interfaces/dataItem"; import { useCallback, useReducer } from "react"; const initialState = { @@ -10,7 +10,7 @@ const initialState = { type reducerState = { error: string; loading: boolean; - data: Array; + data: Array | Array; }; type actionType = { @@ -44,8 +44,6 @@ function useRequest() { try { const response = await (await fetch(url)).json(); - console.log({ response }); - if (type === "contributors") { dispatch({ type: "data", payload: response }); } else { @@ -53,8 +51,6 @@ function useRequest() { } } catch (err: any) { dispatch({ type: "error", error: err.message }); - - console.log({ err }); } }, [dispatch] diff --git a/src/index.styles.ts b/src/index.styles.ts index aa47a2c..f8aa9e0 100644 --- a/src/index.styles.ts +++ b/src/index.styles.ts @@ -9,10 +9,10 @@ export const GlobalStyle = createGlobalStyle` html { box-sizing: border-box; - font-size: 62.5%; + font-size: 70%; @media screen and (min-width: 900px) { - font-size: 80%; + font-size: 90%; } }