From d76bb948f0f4d548090790723e72d7f2bf486e6e Mon Sep 17 00:00:00 2001 From: mkalidindi Date: Wed, 27 Dec 2023 11:19:01 -0600 Subject: [PATCH] added required changes --- src/features/photos/create/index.js | 7 ++++-- src/features/photos/list/index.js | 8 +++++-- src/features/photos/photos.slice.js | 17 +++++++++++++- src/features/search/search-bar/index.js | 4 +++- src/features/suggestion/index.js | 9 ++++--- src/features/suggestion/suggestion.slice.js | 26 +++++++++++++++++++-- 6 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/features/photos/create/index.js b/src/features/photos/create/index.js index d988b0a..b0f6311 100644 --- a/src/features/photos/create/index.js +++ b/src/features/photos/create/index.js @@ -1,5 +1,6 @@ import { useState } from 'react'; - +import { useDispatch } from 'react-redux'; +import { addPhoto } from '../photos.slice'; // Task 2: Import the `useDispatch()` method from the appropriate package // Task 3: Import the `addPhoto()` action creator from the photos slice @@ -8,6 +9,7 @@ import './create.css'; export default function CreatePhoto() { const [formData, setFormData] = useState({ imageUrl: '', caption: '' }); // Task 4: Store a reference to the Redux store's dispatch method in a variable called `dispatch` + const dispatch = useDispatch(); function handleChange({ target: { name, value } }) { setFormData({ @@ -19,6 +21,7 @@ export default function CreatePhoto() { function handleSubmit(event) { event.preventDefault(); // Task 5: Dispatch the `addPhoto()` action creator, passing in the form data + dispatch(addPhoto({imageUrl:formData.imageUrl, caption:formData.caption})); setFormData({ imageUrl: '', caption: '' }); } @@ -50,4 +53,4 @@ export default function CreatePhoto() { ); -} +} \ No newline at end of file diff --git a/src/features/photos/list/index.js b/src/features/photos/list/index.js index 3ed9ea5..54cc3d8 100644 --- a/src/features/photos/list/index.js +++ b/src/features/photos/list/index.js @@ -1,18 +1,22 @@ import { useSelector, useDispatch } from 'react-redux'; import { // Task 7: Import the `removePhoto()` action creator from the photos slice + removePhoto, selectAllPhotos, // Task 13: Import the `selectFilteredPhotos()` selector from the photos slice + selectFilteredPhotos, } from '../photos.slice'; import './list.css'; export default function PhotosList() { // Task 14: Call `useSelector()` below with `selectFilteredPhotos` instead of `selectAllPhotos` - const photos = useSelector(selectAllPhotos); + const photos = useSelector(selectFilteredPhotos); // Task 8: Store a reference to the Redux store's dispatch method in a variable called `dispatch` + const dispatch = useDispatch(); function handleDeleteButtonClick(id) { // Task 9: Dispatch the `removePhoto()` action creator, passing in the id + dispatch(removePhoto(id)); } const photosListItems = photos.map(({ id, caption, imageUrl }) => ( @@ -34,4 +38,4 @@ export default function PhotosList() { ) : (

No doggies to display...

); -} +} \ No newline at end of file diff --git a/src/features/photos/photos.slice.js b/src/features/photos/photos.slice.js index 50985e8..e4399db 100644 --- a/src/features/photos/photos.slice.js +++ b/src/features/photos/photos.slice.js @@ -13,10 +13,19 @@ const options = { // Task 1: Create an `addPhoto()` case reducer that adds a photo to state.photos. // Task 1 Hint: You can use state.photos.unshift() // `unshift()` documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift + addPhoto: (state, action) => { + state.photos.unshift({ id: state.photos.length + 1, caption: action.payload.caption, imageUrl: action.payload.imageUrl }); + }, // Task 6: Create an `removePhoto()` case reducer that removes a photo from state.photos // Task 6 Hint: You can use state.photos.splice() // `splice()` documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice + removePhoto: (state, action) => { + state.photos.splice( + state.photos.findIndex((photo) => photo.id === action.payload), + 1 + ); + } }, }; @@ -29,4 +38,10 @@ export default photosSlice.reducer; export const selectAllPhotos = (state) => state.photos.photos; export const selectFilteredPhotos = (state) => { // Task 12: Complete `selectFilteredPhotos()` selector to return a filtered list of photos whose captions match the user's search term -}; + const photos = selectAllPhotos(state); + const searchTerm = selectSearchTerm(state); + + return photos.filter((photo) => + photo.caption.toLowerCase().includes(searchTerm.toLowerCase()) + ); +}; \ No newline at end of file diff --git a/src/features/search/search-bar/index.js b/src/features/search/search-bar/index.js index 0169c64..ff65655 100644 --- a/src/features/search/search-bar/index.js +++ b/src/features/search/search-bar/index.js @@ -5,9 +5,11 @@ import './search-bar.css'; export default function SearchBar() { const searchTerm = useSelector(selectSearchTerm); // Task 10: Store a reference to the Redux store's dispatch method in a variable called `dispatch` + const dispatch = useDispatch(); function handleChange({ target: { value } }) { // Task 11: Dispatch the `setSearchTerm()` action creator, passing in the value of the search input + dispatch(setSearchTerm(value)); } return ( @@ -23,4 +25,4 @@ export default function SearchBar() { /> ); -} +} \ No newline at end of file diff --git a/src/features/suggestion/index.js b/src/features/suggestion/index.js index e41c18c..c4987ac 100644 --- a/src/features/suggestion/index.js +++ b/src/features/suggestion/index.js @@ -5,12 +5,14 @@ import { selectError, selectLoading, // Task 18: Import the `selectSuggestion()` selector from the suggestion slice + selectSuggestion, } from './suggestion.slice'; import './suggestion.css'; export default function Suggestion() { // Task 19: Call useSelector() with the selectSuggestion() selector // The component needs to access the `imageUrl` and `caption` properties of the suggestion object. + const {imageUrl, caption} = useSelector(selectSuggestion); const loading = useSelector(selectLoading); const error = useSelector(selectError); const dispatch = useDispatch(); @@ -18,6 +20,7 @@ export default function Suggestion() { useEffect(() => { async function loadSuggestion() { // Task 20: Dispatch the fetchSuggestion() action creator + dispatch(fetchSuggestion()); } loadSuggestion(); }, [dispatch]); @@ -31,8 +34,8 @@ export default function Suggestion() { // Task 21: Enable the two JSX lines below needed to display the suggestion on the page render = ( <> - {/* {caption} -

{imageUrl}

*/} + {caption} +

{caption}

); } @@ -43,4 +46,4 @@ export default function Suggestion() { {render} ); -} +} \ No newline at end of file diff --git a/src/features/suggestion/suggestion.slice.js b/src/features/suggestion/suggestion.slice.js index 6db58f1..07acca7 100644 --- a/src/features/suggestion/suggestion.slice.js +++ b/src/features/suggestion/suggestion.slice.js @@ -1,7 +1,15 @@ import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; export const fetchSuggestion = - createAsyncThunk(/* Task 15: Complete the `createAsyncThunk()` function to load a suggestion from this URL: http://localhost:3004/api/suggestion */); + createAsyncThunk(/* Task 15: Complete the `createAsyncThunk()` function to load a suggestion from this URL: http://localhost:3004/api/suggestion */ + 'suggestion/fetchSuggestion', + async (arg, thunkAPI) => { + const reponse = await fetch('http://localhost:3004/api/suggestion'); + const { data } = await reponse.json(); + console.log(data); + return data; + } + ); const initialState = { suggestion: '', @@ -15,6 +23,19 @@ const options = { reducers: {}, extraReducers: { /* Task 16: Inside `extraReducers`, add reducers to handle all three promise lifecycle states - pending, fulfilled, and rejected - for the `fetchSuggestion()` call */ + [fetchSuggestion.pending]: (state) => { + state.loading = true; + state.error = false; + }, + [fetchSuggestion.fulfilled]: (state, { payload: { imageUrl, caption} }) => { + state.suggestion = { imageUrl, caption }; + state.loading = false; + state.error = false; + }, + [fetchSuggestion.rejected]: (state, action) => { + state.loading = false; + state.error = true; + }, }, }; @@ -23,6 +44,7 @@ const suggestionSlice = createSlice(options); export default suggestionSlice.reducer; // Task 17: Create a selector, called `selectSuggestion`, for the `suggestion` state variable and export it from the file +export const selectSuggestion = (state) => state.suggestion.suggestion; export const selectLoading = (state) => state.suggestion.loading; -export const selectError = (state) => state.suggestion.error; +export const selectError = (state) => state.suggestion.error; \ No newline at end of file