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/components/Select.jsx b/src/components/Select.jsx new file mode 100644 index 0000000..5c25d62 --- /dev/null +++ b/src/components/Select.jsx @@ -0,0 +1,37 @@ +import PropTypes from "prop-types"; +import classnames from "classnames"; + +function Select({ name, disabled, className, options, value }) { + return ( + + { + options.map((option) => ( + + {option} + + )) + } + + ); + } + +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/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..581506d 100644 --- a/src/global.css +++ b/src/global.css @@ -1,3 +1,23 @@ +.thumb { + width: 250px; + height: 250px; +} + +.small { + width: 500px; + height: 500px; +} + +.med { + width: 750px; + height: 750px; +} + +.full { + width: 1000px; + height: 1000px; +} + .m-all-1 { margin: var(--space-1); } diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 30f8287..5f9c312 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,17 +1,138 @@ -import { FullscreenWrapper, CustomLink } from "components"; +import { useState, useEffect } from "react"; +import { useSelector, useDispatch } from "react-redux"; + +import { FullscreenWrapper, CustomLink, Loader, Button, Input, Select } from "components"; +import { logout } from "redux/actions/authActions"; + +import { fetchDogs } from "redux/actions/dogActions"; +import { waitForDomChange } from "@testing-library/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); + const [photoLimit, setPhotoLimit] = useState(10); + const [ascending, setAscending] = useState(true); + const [selection, setSelection] = useState("thumb"); + + useEffect(function onMount(){ + if (username){ + dispatch(fetchDogs( + { + page: currentPage, + limit: photoLimit, + order: ascending ? "ASC" : "DESC" + } + )); + } + }, [currentPage, ascending, selection]); + + function handleValueChange(e, valueCb) { + const newValue = e.target.value; + valueCb(newValue); + } + + function handleCurrentPageDecrement() { + if (currentPage === 0) { + return; + } + + setCurrentPage(currentPage -1); + } + + function handleCurrentPageIncrement() { + setCurrentPage(currentPage +1); + } + + function handleOrderChange() { + setAscending(!ascending); + } + + function handleLogout() { + dispatch(logout()); + } + + function handleSelectChange(e, valueCb) { + console.log("selection changed") + const newValue = e.target.value; + valueCb(newValue); + } return ( Doggo List - {userName - ? `Welcome, ${userName}!` + {username + ? `Welcome, ${username}!` : "To see a list of doggos, please log in first."} - + {username ? ( + + + + + + handleValueChange(e, setPhotoLimit)} + /> + + handleSelectChange(e, setSelection)} + action="/" + > + thumb + small + med + full + + + + + + + ) : () + } + {username ? ((fetchingDogs) ? : ( + + { + dogsList.map((dog) => ( + + + + {dog.breeds[0] ? dog.breeds[0].name : "Doggo"} + + + )) + } + + )): null} ); } 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..833a8f8 --- /dev/null +++ b/src/redux/actions/dogActions.js @@ -0,0 +1,24 @@ +import { dog } from "constants/ActionTypes"; + +import { default as fetchDogsAPI } from "utils/fetchDogs"; + +export function fetchDogs({page = 0,limit = 10, order = "ASC"} = {}){ + return async (dispatch) => { + dispatch({ + type: dog.FETCH_DOG_PENDING, + }); + + const dogsList = await fetchDogsAPI({ + page, + limit, + order, + }); + + 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; diff --git a/src/utils/fetchDogs.js b/src/utils/fetchDogs.js index e56b345..85104fe 100644 --- a/src/utils/fetchDogs.js +++ b/src/utils/fetchDogs.js @@ -2,7 +2,7 @@ async function fetchDogs({ limit = 10, page = 0, order = "ASC", - size = "med", + size = "small", } = {}) { const response = await fetch( `https://api.thedogapi.com/v1/images/search?limit=${limit}&page=${page}&order=${order}&size=${size}`
- {userName - ? `Welcome, ${userName}!` + {username + ? `Welcome, ${username}!` : "To see a list of doggos, please log in first."}