From c52f2fff83009dfe89ac93bebd1a169ada983126 Mon Sep 17 00:00:00 2001 From: bsfelizardo Date: Sun, 6 Feb 2022 14:02:08 +0800 Subject: [PATCH 1/7] Updates from react 3 --- src/components/FullscreenWrapper.module.scss | 2 +- src/constants/ActionTypes.js | 6 ++ src/global.css | 5 ++ src/pages/Home.jsx | 66 ++++++++++++++++++-- src/pages/Login.jsx | 5 ++ src/redux/actions/authActions.js | 14 ++--- src/redux/actions/dogActions.js | 23 +++++++ src/redux/reducers/authReducer.js | 4 ++ src/redux/reducers/dogReducer.js | 33 ++++++++++ src/redux/reducers/index.js | 2 + 10 files changed, 144 insertions(+), 16 deletions(-) create mode 100644 src/redux/actions/dogActions.js create mode 100644 src/redux/reducers/dogReducer.js diff --git a/src/components/FullscreenWrapper.module.scss b/src/components/FullscreenWrapper.module.scss index 066957a..0ffffdf 100644 --- a/src/components/FullscreenWrapper.module.scss +++ b/src/components/FullscreenWrapper.module.scss @@ -1,6 +1,6 @@ .wrapper { width: 100%; - height: 100vh; + height: 100%; padding: 70px 30px 0; color: var(--color-black); diff --git a/src/constants/ActionTypes.js b/src/constants/ActionTypes.js index 0eefe60..b7ace14 100644 --- a/src/constants/ActionTypes.js +++ b/src/constants/ActionTypes.js @@ -7,3 +7,9 @@ export const auth = keyMirror({ LOGOUT: null, }); + +export const dog = keyMirror({ + FETCH_DOG_PENDING: null, + FETCH_DOG_COMPLETED: null, + FETCH_DOG_FAILED: null, +}); \ No newline at end of file diff --git a/src/global.css b/src/global.css index efecfff..5264090 100644 --- a/src/global.css +++ b/src/global.css @@ -1,3 +1,8 @@ +.dog-img { + width: 250px; + height: 250px; +} + .m-all-1 { margin: var(--space-1); } diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 30f8287..c692c3b 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,17 +1,73 @@ -import { FullscreenWrapper, CustomLink } from "components"; +import { useEffect } from "react"; +import { useSelector, useDispatch } from "react-redux"; + +import { FullscreenWrapper, CustomLink, Loader, Button, Input } from "components"; + +import { fetchDogs } from "redux/actions/dogActions"; +import { useState } from "react"; function Home() { - const userName = null; + const username = useSelector(s => s.auth.username); + const fetchingDogs = useSelector(s => s.dog.fetchingDogs); + const dogsList = useSelector(s => s.dog.dogsList); + + const dispatch = useDispatch(); + + const [currentPage, setCurrentPage] = useState(0); + + useEffect(function onMount(){ + if (username){ + dispatch(fetchDogs({page: currentPage})); + } + }, [currentPage]); + + function handleCurrentPageDecrement() { + if (currentPage === 0) { + return; + } + + setCurrentPage(currentPage -1); + } + + function handleCurrentPageIncrement() { + setCurrentPage(currentPage +1); + } return (

Doggo List

- {userName - ? `Welcome, ${userName}!` + {username + ? `Welcome, ${username}!` : "To see a list of doggos, please log in first."}

- + {username ? ( +
+
+ ) : () + } + {fetchingDogs ? : ( +
+ { + dogsList.map((dog) => ( + + )) + } +
+ )}
); } diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index 1cf752d..a1f0066 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -28,6 +28,11 @@ function Login() { function handleFormSubmit(e) { e.preventDefault(); console.log(name, password); + if(!name || !password){ + alert("Name and Password required"); + }else{ + dispatch(login(name)); + } // dispatch(login()); } diff --git a/src/redux/actions/authActions.js b/src/redux/actions/authActions.js index ef33c2b..2f00d7f 100644 --- a/src/redux/actions/authActions.js +++ b/src/redux/actions/authActions.js @@ -1,6 +1,6 @@ import { auth } from "constants/ActionTypes"; -export function login() { +export function login(username) { return async (dispatch) => { dispatch({ type: auth.LOGIN_PENDING, @@ -8,19 +8,13 @@ export function login() { const hasError = false; setTimeout(() => { - if (hasError) { dispatch({ - type: auth.LOGIN_FAILED, + type: auth.LOGIN_COMPLETED, payload: { - errorMessage: "Something went wrong, please try again later.", + username, }, }); - } else { - dispatch({ - type: auth.LOGIN_COMPLETED, - }); - } - }, 3000); + }, 0); }; } diff --git a/src/redux/actions/dogActions.js b/src/redux/actions/dogActions.js new file mode 100644 index 0000000..55c3d09 --- /dev/null +++ b/src/redux/actions/dogActions.js @@ -0,0 +1,23 @@ +import { dog } from "constants/ActionTypes"; + +import { default as fetchDogsAPI } from "utils/fetchDogs"; + +export function fetchDogs({page = 0,limit = 10,} = {}){ + return async (dispatch) => { + dispatch({ + type: dog.FETCH_DOG_PENDING, + }); + + const dogsList = await fetchDogsAPI( + page, + limit, + ); + + dispatch({ + type: dog.FETCH_DOG_COMPLETED, + payload: { + dogsList, + }, + }) + }; +} \ No newline at end of file diff --git a/src/redux/reducers/authReducer.js b/src/redux/reducers/authReducer.js index 3935383..8e39b6c 100644 --- a/src/redux/reducers/authReducer.js +++ b/src/redux/reducers/authReducer.js @@ -5,6 +5,7 @@ const initialState = { loginError: null, // Wrong credentials / sorry you can't login today isLoggedIn: false, + username: null, }; /** @@ -22,10 +23,12 @@ export default function reducer(state = initialState, action = {}) { } case auth.LOGIN_COMPLETED: { + const { username } = action.payload; return { ...state, loginPending: false, isLoggedIn: true, + username, }; } @@ -42,6 +45,7 @@ export default function reducer(state = initialState, action = {}) { return { ...state, isLoggedIn: false, + username: null, }; } diff --git a/src/redux/reducers/dogReducer.js b/src/redux/reducers/dogReducer.js new file mode 100644 index 0000000..e870d16 --- /dev/null +++ b/src/redux/reducers/dogReducer.js @@ -0,0 +1,33 @@ +import { dog } from "constants/ActionTypes"; + +const initialState = { + fetchingDogs: false, + dogsList: [], +}; + +export default function reducer(state = initialState, action = {}) { + switch(action.type){ + case dog.FETCH_DOG_PENDING: { + return { + ...state, + fetchingDogs: true, + } + } + case dog.FETCH_DOG_COMPLETED: { + const { dogsList} = action.payload; + return { + ...state, + fetchingDogs: false, + dogsList, + } + } + case dog.FETCH_DOG_FAILED: { + return { + ...state, + fetchingDogs: false, + } + } + default: + return state + } +} \ No newline at end of file diff --git a/src/redux/reducers/index.js b/src/redux/reducers/index.js index a70e020..0e41afc 100644 --- a/src/redux/reducers/index.js +++ b/src/redux/reducers/index.js @@ -1,9 +1,11 @@ import { combineReducers } from "redux"; import auth from "redux/reducers/authReducer"; +import dog from "redux/reducers/dogReducer"; const rootReducer = combineReducers({ auth, + dog, }); export default rootReducer; From 4ba7bf91d715566c768277a91910d6d0d10a43e4 Mon Sep 17 00:00:00 2001 From: bsfelizardo Date: Sun, 6 Feb 2022 23:05:57 +0800 Subject: [PATCH 2/7] Add input field on home page to specify number of photos to display --- src/pages/Home.jsx | 17 ++++++++++++++++- src/redux/actions/dogActions.js | 4 ++-- src/utils/fetchDogs.js | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index c692c3b..8ba6219 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -14,13 +14,19 @@ function Home() { const dispatch = useDispatch(); const [currentPage, setCurrentPage] = useState(0); + const [photoLimit, setPhotoLimit] = useState(10); useEffect(function onMount(){ if (username){ - dispatch(fetchDogs({page: currentPage})); + dispatch(fetchDogs({page: currentPage, limit: photoLimit})); } }, [currentPage]); + function handleValueChange(e, valueCb) { + const newValue = e.target.value; + valueCb(newValue); + } + function handleCurrentPageDecrement() { if (currentPage === 0) { return; @@ -56,6 +62,15 @@ function Home() { disabled={fetchingDogs} onClick={handleCurrentPageIncrement} /> +
+ handleValueChange(e, setPhotoLimit)} + /> +
) : () } diff --git a/src/redux/actions/dogActions.js b/src/redux/actions/dogActions.js index 55c3d09..e6e86af 100644 --- a/src/redux/actions/dogActions.js +++ b/src/redux/actions/dogActions.js @@ -8,10 +8,10 @@ export function fetchDogs({page = 0,limit = 10,} = {}){ type: dog.FETCH_DOG_PENDING, }); - const dogsList = await fetchDogsAPI( + const dogsList = await fetchDogsAPI({ page, limit, - ); + }); dispatch({ type: dog.FETCH_DOG_COMPLETED, diff --git a/src/utils/fetchDogs.js b/src/utils/fetchDogs.js index e56b345..40fae17 100644 --- a/src/utils/fetchDogs.js +++ b/src/utils/fetchDogs.js @@ -4,6 +4,7 @@ async function fetchDogs({ order = "ASC", size = "med", } = {}) { + console.log(page); const response = await fetch( `https://api.thedogapi.com/v1/images/search?limit=${limit}&page=${page}&order=${order}&size=${size}` ); From fe39f0579d0a819f711f64750949202648668184 Mon Sep 17 00:00:00 2001 From: bsfelizardo Date: Mon, 7 Feb 2022 10:40:07 +0800 Subject: [PATCH 3/7] Add select input in home Initial commit: - src/components/Select.jsx: a select input component Update: - src/components/index.js: export Select component - src/page/Home.jsx: add select input --- src/components/Select.jsx | 36 ++++++++++++++++++++++++++++++++++++ src/components/index.js | 1 + src/pages/Home.jsx | 10 ++++++++-- src/utils/fetchDogs.js | 2 +- 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 src/components/Select.jsx diff --git a/src/components/Select.jsx b/src/components/Select.jsx new file mode 100644 index 0000000..fb74520 --- /dev/null +++ b/src/components/Select.jsx @@ -0,0 +1,36 @@ +import PropTypes from "prop-types"; +import classnames from "classnames"; + +function Select({ name, disabled, className, options }) { + return ( + + ); + } + +Select.propTypes = { + name: PropTypes.string.isRequired, + disabled: PropTypes.bool, + className: PropTypes.string, + options: PropTypes.array, +}; + +Select.defaultProps = { + name: "Select", + disabled: false, + className: null, + options: [], + }; + +export default Select; \ No newline at end of file diff --git a/src/components/index.js b/src/components/index.js index f82e569..99c94ac 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -3,3 +3,4 @@ export { default as CustomLink } from "components/CustomLink"; export { default as FullscreenWrapper } from "components/FullscreenWrapper"; export { default as Input } from "components/Input"; export { default as Loader } from "components/Loader"; +export { default as Select } from "components/Select"; diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 8ba6219..ae63407 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,7 +1,7 @@ import { useEffect } from "react"; import { useSelector, useDispatch } from "react-redux"; -import { FullscreenWrapper, CustomLink, Loader, Button, Input } from "components"; +import { FullscreenWrapper, CustomLink, Loader, Button, Input, Select } from "components"; import { fetchDogs } from "redux/actions/dogActions"; import { useState } from "react"; @@ -70,6 +70,12 @@ function Home() { className="m-bottom-2" onChange={(e) => handleValueChange(e, setPhotoLimit)} /> + handleValueChange(e, setPhotoLimit)} - /> - handleValueChange(e, setPhotoLimit)} + /> +