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);