From 97ccb9097e64433cfebced834b648b3ceeb35a21 Mon Sep 17 00:00:00 2001 From: IrynaSlavinska <133566139+IrynaSlavinska@users.noreply.github.com> Date: Wed, 3 Jan 2024 16:05:42 +0200 Subject: [PATCH] redux --- package-lock.json | 15 ++++++++++++ package.json | 1 + src/components/AppBar/AppBar.jsx | 22 +++++++++++++++++ src/components/AppBar/AppBar.styled.jsx | 28 ++++++++++++++++++++++ src/components/ContactForm/ContactForm.jsx | 4 ++-- src/components/Layout/Layout.jsx | 28 +++------------------- src/components/Layout/Layout.styled.jsx | 27 --------------------- src/hooks/useAuth.js | 18 ++++++++++++++ src/index.js | 19 ++++++++------- src/redux/contactsSlice.js | 18 ++++++++++++++ src/redux/filterSlice.js | 17 +++++++++++++ src/redux/reducer.js | 17 +++++++++++++ src/redux/selectors.js | 2 ++ src/redux/store.js | 22 +++++++++++++++++ 14 files changed, 176 insertions(+), 62 deletions(-) create mode 100644 src/components/AppBar/AppBar.jsx create mode 100644 src/components/AppBar/AppBar.styled.jsx create mode 100644 src/hooks/useAuth.js create mode 100644 src/redux/contactsSlice.js create mode 100644 src/redux/filterSlice.js create mode 100644 src/redux/reducer.js create mode 100644 src/redux/selectors.js create mode 100644 src/redux/store.js diff --git a/package-lock.json b/package-lock.json index 083f221..e377adf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "react-redux": "^9.0.4", "react-router-dom": "^6.21.1", "react-scripts": "5.0.1", + "redux-persist": "^6.0.0", "web-vitals": "^2.1.3" } }, @@ -12087,6 +12088,14 @@ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" }, + "node_modules/redux-persist": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz", + "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==", + "peerDependencies": { + "redux": ">4.0.0" + } + }, "node_modules/redux-thunk": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", @@ -23319,6 +23328,12 @@ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" }, + "redux-persist": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz", + "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==", + "requires": {} + }, "redux-thunk": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", diff --git a/package.json b/package.json index c86b6c4..c3140f2 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react-redux": "^9.0.4", "react-router-dom": "^6.21.1", "react-scripts": "5.0.1", + "redux-persist": "^6.0.0", "web-vitals": "^2.1.3" }, "scripts": { diff --git a/src/components/AppBar/AppBar.jsx b/src/components/AppBar/AppBar.jsx new file mode 100644 index 0000000..e15ec0b --- /dev/null +++ b/src/components/AppBar/AppBar.jsx @@ -0,0 +1,22 @@ +import { Header, Navigation, NavItem, StyledLink } from './AppBar.styled'; + +export const AppBar = () => { + return ( +
+ + + Home + + + Register + + + Log In + + + Contacts + + +
+ ); +}; diff --git a/src/components/AppBar/AppBar.styled.jsx b/src/components/AppBar/AppBar.styled.jsx new file mode 100644 index 0000000..044081c --- /dev/null +++ b/src/components/AppBar/AppBar.styled.jsx @@ -0,0 +1,28 @@ +import styled from '@emotion/styled'; +import { NavLink } from 'react-router-dom'; + +export const Header = styled.header` + margin-bottom: 20px; +`; + +export const Navigation = styled.ul` + display: flex; + gap: 50px; +`; + +export const NavItem = styled.li``; + +export const StyledLink = styled(NavLink)` + font-size: 20px; + color: #000000; + background-color: #78a1bb; + padding: 8px; + border-radius: 4px; + + &.active { + color: #000000; + background-color: #e9af3d; + padding: 8px; + border-radius: 4px; + } +`; diff --git a/src/components/ContactForm/ContactForm.jsx b/src/components/ContactForm/ContactForm.jsx index 843ab60..bfb7f99 100644 --- a/src/components/ContactForm/ContactForm.jsx +++ b/src/components/ContactForm/ContactForm.jsx @@ -22,7 +22,7 @@ export const ContactForm = () => { - Group + {/* Group Family @@ -43,7 +43,7 @@ export const ContactForm = () => { Others - + */} Add contact diff --git a/src/components/Layout/Layout.jsx b/src/components/Layout/Layout.jsx index 7f09ada..933400d 100644 --- a/src/components/Layout/Layout.jsx +++ b/src/components/Layout/Layout.jsx @@ -1,34 +1,12 @@ import { Outlet } from 'react-router-dom'; import { Suspense } from 'react'; -import { - Container, - Header, - Navigation, - NavItem, - StyledLink, - Main, -} from './Layout.styled'; +import { AppBar } from 'components/AppBar/AppBar'; +import { Container, Main } from './Layout.styled'; const Layout = () => { return ( -
- - - Home - - - Register - - - Log In - - - Contacts - - -
- +
diff --git a/src/components/Layout/Layout.styled.jsx b/src/components/Layout/Layout.styled.jsx index 1acafe4..582d818 100644 --- a/src/components/Layout/Layout.styled.jsx +++ b/src/components/Layout/Layout.styled.jsx @@ -1,5 +1,4 @@ import styled from '@emotion/styled'; -import { NavLink } from 'react-router-dom'; export const Container = styled.div` width: 1400px; @@ -7,32 +6,6 @@ export const Container = styled.div` padding: 10px; `; -export const Header = styled.header` - margin-bottom: 20px; -`; - -export const Navigation = styled.ul` - display: flex; - gap: 50px; -`; - -export const NavItem = styled.li``; - -export const StyledLink = styled(NavLink)` - font-size: 20px; - color: #000000; - background-color: #78a1bb; - padding: 8px; - border-radius: 4px; - - &.active { - color: #000000; - background-color: #e9af3d; - padding: 8px; - border-radius: 4px; - } -`; - export const Main = styled.main` background-image: url(https://images.pexels.com/photos/949587/pexels-photo-949587.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1); background-repeat: no-repeat; diff --git a/src/hooks/useAuth.js b/src/hooks/useAuth.js new file mode 100644 index 0000000..1d717c8 --- /dev/null +++ b/src/hooks/useAuth.js @@ -0,0 +1,18 @@ +import { useSelector } from 'react-redux'; +import { + selectUser, + selectIsLoggedIn, + selectIsRefreshing, +} from '../redux/auth/selectors'; + +export const useAuth = () => { + const isLoggedIn = useSelector(selectIsLoggedIn); + const isRefreshing = useSelector(selectIsRefreshing); + const user = useSelector(selectUser); + + return { + isLoggedIn, + isRefreshing, + user, + }; +}; diff --git a/src/index.js b/src/index.js index 06923b9..4b453dc 100644 --- a/src/index.js +++ b/src/index.js @@ -1,18 +1,21 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from 'components/App'; -import './index.css'; import { BrowserRouter } from 'react-router-dom'; -// import { Provider } from 'react-redux'; -// import { store } from './redux/store'; +import { PersistGate } from 'redux-persist/integration/react'; +import { Provider } from 'react-redux'; +import { store, persistor } from './redux/store'; +import './index.css'; ReactDOM.createRoot(document.getElementById('root')).render( - {/* */} - - - - {/* */} + + + + + + + ); diff --git a/src/redux/contactsSlice.js b/src/redux/contactsSlice.js new file mode 100644 index 0000000..4641e0b --- /dev/null +++ b/src/redux/contactsSlice.js @@ -0,0 +1,18 @@ +import { createSlice } from '@reduxjs/toolkit'; + +const contactsSlice = createSlice({ + name: 'contacts', + initialState: { contacts: [] }, + reducers: { + deleteContactAction: (state, action) => { + state.contacts = state.contacts.filter(el => el.id !== action.payload); + }, + addContactAction: (state, action) => { + state.contacts = [...state.contacts, action.payload]; + }, + }, +}); + +export const { addContactAction, deleteContactAction } = contactsSlice.actions; + +export const contactsReducer = contactsSlice.reducer; diff --git a/src/redux/filterSlice.js b/src/redux/filterSlice.js new file mode 100644 index 0000000..8f83bb7 --- /dev/null +++ b/src/redux/filterSlice.js @@ -0,0 +1,17 @@ +import { createSlice } from '@reduxjs/toolkit'; + +const filterSlice = createSlice({ + name: 'filter', + initialState: { + filter: '', + }, + reducers: { + setSearchFilterAction(state, action) { + return { ...state, filter: `${action.payload}` }; + }, + }, +}); + +export const { setSearchFilterAction } = filterSlice.actions; + +export const filterReducer = filterSlice.reducer; diff --git a/src/redux/reducer.js b/src/redux/reducer.js new file mode 100644 index 0000000..6dc1d2d --- /dev/null +++ b/src/redux/reducer.js @@ -0,0 +1,17 @@ +import { persistReducer } from 'redux-persist'; +import storage from 'redux-persist/lib/storage'; + +import { contactsReducer } from './contactsSlice'; +import { filterReducer } from './filterSlice'; + +const persistConfig = { + key: 'root', + storage, +}; + +const persistedReducer = persistReducer(persistConfig, contactsReducer); + +export const reducer = { + contacts: persistedReducer, + filter: filterReducer, +}; diff --git a/src/redux/selectors.js b/src/redux/selectors.js new file mode 100644 index 0000000..fa352db --- /dev/null +++ b/src/redux/selectors.js @@ -0,0 +1,2 @@ +export const getContacts = state => state.contacts.contacts; +export const getFilterValue = state => state.filter.filter; diff --git a/src/redux/store.js b/src/redux/store.js new file mode 100644 index 0000000..2111fda --- /dev/null +++ b/src/redux/store.js @@ -0,0 +1,22 @@ +import { configureStore } from '@reduxjs/toolkit'; +import { reducer } from './reducer'; +import { + persistStore, + FLUSH, + REHYDRATE, + PAUSE, + PERSIST, + PURGE, + REGISTER, +} from 'redux-persist'; + +export const store = configureStore({ + reducer, + middleware: getDefaultMiddleware => + getDefaultMiddleware({ + serializableCheck: { + ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], + }, + }), +}); +export const persistor = persistStore(store);