Skip to content

Commit

Permalink
auth
Browse files Browse the repository at this point in the history
  • Loading branch information
IrynaSlavinska committed Jan 5, 2024
1 parent e2be8f4 commit accb903
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 36 deletions.
1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="modal-root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
Expand Down
10 changes: 10 additions & 0 deletions src/components/App.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { lazy } from 'react';
import { Routes, Route } from 'react-router-dom';

import { useEffect } from 'react';
import { useDispatch } from 'react-redux';

import Layout from './Layout/Layout';
import ContactsPage from 'pages/ContactsPage/ContactsPage';
import RegisterPage from 'pages/RegisterPage/RegisterPage';
import NotFound from 'pages/NotFound/NotFound';

import operations from '../redux/auth/authOperations';

const HomePage = lazy(() => import('pages/HomePage/HomePage'));
const LoginPage = lazy(() => import('pages/LoginPage/LoginPage'));

const App = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(operations.refreshUser());
}, [dispatch]);

return (
<Routes>
<Route path="/" element={<Layout />}>
Expand Down
56 changes: 53 additions & 3 deletions src/components/ContactForm/ContactForm.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Notiflix from 'notiflix';

import { selectContacts } from '../../redux/selectors';
import { addContactAction } from '../../redux/contacts/contactsOperations';

import {
Form,
Label,
Expand All @@ -10,16 +17,59 @@ import {
} from './ContactForm.styled';

export const ContactForm = () => {
const [name, setName] = useState('');
const [number, setNumber] = useState('');
const contacts = useSelector(selectContacts);
const dispatch = useDispatch();

const handleSubmit = e => {
e.preventDefault();
const isExist = contacts.some(contact => contact.name === name);
if (isExist) {
Notiflix.Notify.warning(`${name} is already in your phonebook`);
return;
}
dispatch(addContactAction({ name, number }));
setName('');
setNumber('');
};

const handleChange = e => {
const { name, value } = e.target;
switch (name) {
case 'name':
setName(value);
break;
case 'number':
setNumber(value);
break;
default:
break;
}
};

return (
<Form>
<Form onSubmit={handleSubmit}>
<Label>
Name
<Input type="text" name="name" required placeholder="Enter name" />
<Input
type="text"
name="name"
required
placeholder="Enter name"
onChange={handleChange}
/>
</Label>

<Label>
Number
<Input type="tel" name="number" required placeholder="Enter number" />
<Input
type="tel"
name="number"
required
placeholder="Enter number"
onChange={handleChange}
/>
</Label>

{/* <Group>Group</Group>
Expand Down
8 changes: 3 additions & 5 deletions src/components/ContactsList/ContactsList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export const ContactsList = () => {

const getFilteredContacts = () => {
if (filter.filter === '') return;

const normilezedFilter = filter.toLowerCase().trim();
const visibleContacts = contacts.filter(contact =>
contact.name.toLowerCase().includes(normilezedFilter)
Expand All @@ -53,9 +52,8 @@ export const ContactsList = () => {

return (
<>
{isLoading ? (
<HourglassLoader />
) : (
{error && <p>Something went wrong!. Try again later</p>}
{visibleContacts.length > 0 && (
<List>
{visibleContacts.map(({ id, name, number }) => (
<Item key={id}>
Expand All @@ -80,7 +78,7 @@ export const ContactsList = () => {
))}
</List>
)}
{error && <p>Something went wrong!. Try again later</p>}
{isLoading && <HourglassLoader />}
</>
);
};
32 changes: 30 additions & 2 deletions src/components/ContactsList/ContactsList.styled.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
import styled from '@emotion/styled';

export const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
`;

export const ContactsHeader = styled.div`
background-color: #7ad9f7;
padding: 12px 80px;
border-radius: 8px;
display: flex;
justify-content: space-between;
margin-bottom: 20px;
gap: 50px;
`;
export const MyContacts = styled.p`
font-size: 20px;
color: #000000;
padding: 8px 16px;
border-radius: 8px;
background-color: #e9af3d;
`;

export const AddButton = styled.button`
padding: 8px 16px;
border-radius: 8px;
background-color: #e9af3d;
`;

export const List = styled.ul`
background-color: #7ad9f7;
padding: 32px;
Expand All @@ -20,8 +50,6 @@ export const Item = styled.li`
background-color: #e9af3d;
`;

export const Container = styled.div``;

export const ContactData = styled.p`
font-size: 20px;
color: #000000;
Expand Down
29 changes: 29 additions & 0 deletions src/components/Filter/Filter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useDispatch, useSelector } from 'react-redux';

import { selectFilterValue } from '../../redux/selectors';
import { setSearchFilterAction } from '../../redux/filter/filterSlice';
import { FilterContainer, Label, Input } from './Filter.styled';

export const Filter = () => {
const { filter } = useSelector(selectFilterValue);
const dispatch = useDispatch();

const filterChange = e => {
dispatch(setSearchFilterAction(e.target.value));
};

return (
<FilterContainer>
<Label>
Find contact
<Input
type="text"
name="search"
placeholder="Search..."
value={filter}
onChange={filterChange}
/>
</Label>
</FilterContainer>
);
};
31 changes: 31 additions & 0 deletions src/components/Filter/Filter.styled.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import styled from '@emotion/styled';

export const FilterContainer = styled.div`
width: 400px;
background-color: #7ad9f7;
padding: 12px;
border-radius: 8px;
`;

export const Label = styled.label`
color: #000000;
font-size: 20px;
display: flex;
align-items: center;
gap: 20px;
`;

export const Input = styled.input`
font-size: 18px;
padding: 4px;
margin-top: 4px;
border-radius: 4px;
border: 2px solid transparent;
outline: transparent;
&: focus {
border-color: #e9af3d;
}
&: hover {
border-color: #e9af3d;
}
`;
26 changes: 22 additions & 4 deletions src/pages/ContactsPage/ContactsPage.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
// import { ContactForm } from 'components/ContactForm/ContactForm';
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { Container } from 'components/ContactsList/ContactsList.styled';
import { ContactForm } from 'components/ContactForm/ContactForm';
import { Filter } from 'components/Filter/Filter';
import { ContactsList } from 'components/ContactsList/ContactsList';
import { HourglassLoader } from 'components/Loader/Loader';

import { getAllContactsAction } from '../../redux/contacts/contactsOperations';
import { selectIsLoading } from '../../redux/selectors';

const ContactsPage = () => {
const dispatch = useDispatch();
const isLoading = useSelector(selectIsLoading);

useEffect(() => {
dispatch(getAllContactsAction());
}, [dispatch]);

return (
<>
{/* <ContactForm /> */}
<Container>
{isLoading && <HourglassLoader />}
<ContactForm />
<Filter />
<ContactsList />
</>
</Container>
);
};

Expand Down
8 changes: 1 addition & 7 deletions src/pages/HomePage/HomePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,11 @@ import { useSelector } from 'react-redux';
import authSelectors from '../../redux/auth/authSelectors';

import { Title } from './HomePage.styled';
import { HourglassLoader } from 'components/Loader/Loader';

const HomePage = () => {
const name = useSelector(authSelectors.selectUserName);

return (
<>
<Title>Hello {name}</Title>
<HourglassLoader />
</>
);
return <Title>Hello {name}</Title>;
};

export default HomePage;
17 changes: 17 additions & 0 deletions src/redux/auth/authOperations.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,26 @@ const logOut = createAsyncThunk('auth/logout', async (_, thunkApi) => {
}
});

const refreshUser = createAsyncThunk('auht/refresh', async (_, thunkApi) => {
const state = thunkApi.getState();
const persistedToken = state.auth.token;

if (persistedToken === 0) return;

token.set(persistedToken);

try {
const { data } = await axios.get('/users/current');
return data;
} catch (error) {
return thunkApi.rejectWithValue(error.message);
}
});

const operations = {
register,
logIn,
logOut,
refreshUser,
};
export default operations;
4 changes: 4 additions & 0 deletions src/redux/auth/authSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const authSlice = createSlice({
state.user = { name: null, email: null };
state.token = null;
state.isLoggedIn = false;
})
.addCase(operations.refreshUser.fulfilled, (state, action) => {
state.user = action.payload;
state.isLoggedIn = true;
});
},
});
Expand Down
23 changes: 8 additions & 15 deletions src/redux/contacts/contactsOperations.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,40 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
import Notiflix from 'notiflix';

axios.defaults.baseURL = 'https://658c671c859b3491d3f606a0.mockapi.io';
axios.defaults.baseURL = 'https://connections-api.herokuapp.com';

export const getAllContactsAction = createAsyncThunk(
'contacts/getAllContacts',

async (_, thunkApi) => {
async (_, thunkAPI) => {
try {
const response = await axios.get('/contacts');
return response.data;
} catch (error) {
Notiflix.Notify.info('Something went wrong! Try again');
return thunkApi.rejectWithValue(error.message);
return thunkAPI.rejectWithValue(error.message);
}
}
);

export const addContactAction = createAsyncThunk(
'contacts/addContactPost',

async (info, thunkApi) => {
async (body, thunkAPI) => {
try {
const response = await axios.post('/contacts', info);
const response = await axios.post('/contacts', body);
return response.data;
} catch (error) {
Notiflix.Notify.info('Something went wrong! Try again later');
return thunkApi.rejectWithValue(error.message);
return thunkAPI.rejectWithValue(error.message);
}
}
);

export const deleteContactAction = createAsyncThunk(
'contacts/deleteContact',

async (contactId, thunkApi) => {
async (contactId, thunkAPI) => {
try {
const response = await axios.delete(`/contacts/${contactId}`);
return response.data;
} catch (error) {
Notiflix.Notify.info('Something went wrong! Try again later');
return thunkApi.rejectWithValue(error.message);
return thunkAPI.rejectWithValue(error.message);
}
}
);

0 comments on commit accb903

Please sign in to comment.