generated from goitacademy/react-homework-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
49 changed files
with
4,579 additions
and
1,437 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
import { useEffect, lazy, Suspense} from 'react'; | ||
import { Navigate, Route, Routes } from 'react-router-dom'; | ||
import {PrivateRoute} from 'routes/PrivatRoutes'; | ||
import {PublicRoute} from 'routes/PublicRoutes'; | ||
import { authOperations, authSelectors } from 'redux/auth'; | ||
import {Loader} from 'components/Loader/Loader'; | ||
import {AppBar} from 'components/AppBar/AppBar'; | ||
import { ToastContainer } from 'react-toastify'; | ||
|
||
const PageHome = lazy(() => import('pages/PageHome')); | ||
const PageRegistration = lazy(() => import('pages/PageRegistration')); | ||
const PageLogin = lazy(() => import('pages/PageLogin')); | ||
const PageContacts = lazy(() => import('pages/PageContacts')); | ||
|
||
export const App = () => { | ||
const dispatch = useDispatch(); | ||
const isFetchingCurrentUser = useSelector(authSelectors.getIsFetchingCurrent); | ||
|
||
useEffect(() => { | ||
dispatch(authOperations.fetchCurrentUser()); | ||
}, [dispatch]); | ||
|
||
return ( | ||
<> | ||
{!isFetchingCurrentUser && ( | ||
<> | ||
<AppBar /> | ||
<Suspense fallback={<Loader />}> | ||
<Routes> | ||
<Route | ||
path="/" | ||
exact | ||
element={ | ||
<PublicRoute> | ||
<PageHome /> | ||
</PublicRoute> | ||
} | ||
/> | ||
<Route | ||
path="register" | ||
element={ | ||
<PublicRoute redirectTo="/contacts" restricted> | ||
<PageRegistration /> | ||
</PublicRoute> | ||
} | ||
/> | ||
<Route | ||
path="login" | ||
element={ | ||
<PublicRoute redirectTo="/contacts" restricted> | ||
< PageLogin /> | ||
</PublicRoute> | ||
} | ||
/> | ||
<Route | ||
path="contacts" | ||
element={ | ||
<PrivateRoute> | ||
<PageContacts /> | ||
</PrivateRoute> | ||
} | ||
/> | ||
<Route path="*" element={<Navigate to="/" />} /> | ||
</Routes> | ||
</Suspense> | ||
<ToastContainer autoClose={3700} position="top-center" /> | ||
</> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { useSelector } from 'react-redux'; | ||
import { authSelectors } from 'redux/auth/'; | ||
import { AuthForm } from 'components/AuthForm/AuthForm'; | ||
import { Navigation } from 'components/Navigation/Navigation'; | ||
import { UserMenu } from 'components/UserMenu/UserMenu'; | ||
|
||
import { Header, Box } from './AppBar.styled'; | ||
|
||
export function AppBar() { | ||
const isLoggedIn = useSelector(authSelectors.getIsLoggedIn); | ||
|
||
return ( | ||
<Header> | ||
<Box> | ||
<Navigation /> | ||
{isLoggedIn ? <UserMenu /> : <AuthForm />} | ||
</Box> | ||
</Header> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import styled from '@emotion/styled'; | ||
|
||
export const Header = styled.section` | ||
min-width: 440px; | ||
background-color: lightblue; | ||
width: 80%; | ||
margin: 12px auto; | ||
padding: 2em; | ||
border-radius: 10px; | ||
box-shadow: 0 0 0 1px rgb(194, 192, 184) inset, | ||
0 5px 0 -3px rgb(194, 192, 184); | ||
`; | ||
|
||
export const Box = styled.div` | ||
display: flex; | ||
justify-content: space-between; | ||
max-width: auto | ||
margin: 0 auto; | ||
border-bottom: 3px solid; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { Link } from './AuthForm.styled'; | ||
|
||
export function AuthForm() { | ||
return ( | ||
<nav> | ||
<Link to="/register" exact> | ||
Sign up | ||
</Link> | ||
<Link to="/login" exact> | ||
Log in | ||
</Link> | ||
</nav> | ||
); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import styled from '@emotion/styled' | ||
import { NavLink } from "react-router-dom"; | ||
|
||
export const Link = styled(NavLink)` | ||
text-decoration: none; | ||
padding: 12px; | ||
font-weight: 800; | ||
color: var(--primaryTextColor); | ||
&:not(:last-child){ | ||
margin-right: 12px; | ||
} | ||
transition: all 0.5s ease; | ||
text-shadow: 2px 2px 4px blue; | ||
&.active { | ||
color: var(--secondaryTextColor); | ||
} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { useState } from 'react'; | ||
import { Form, Label, Input, Button } from './ContactForm.styled'; | ||
import toast, { Toaster } from 'react-hot-toast'; | ||
import { nanoid } from 'nanoid'; | ||
import { | ||
useFetchContactsQuery, | ||
useCreateContactMutation, | ||
} from 'redux/contacts/contactsApi'; | ||
import { Loader } from 'components/Loader/Loader'; | ||
|
||
export function ContactForm() { | ||
const [name, setName] = useState(''); | ||
const [number, setNumber] = useState(''); | ||
const { data: contacts, isLoading } = useFetchContactsQuery(); | ||
const [createContact] = useCreateContactMutation(); | ||
|
||
const handleChange = e => { | ||
const { name, value } = e.currentTarget; | ||
|
||
switch (name) { | ||
case 'name': | ||
setName(value); | ||
break; | ||
case 'number': | ||
setNumber(value); | ||
break; | ||
default: | ||
return; | ||
} | ||
}; | ||
|
||
const addContact = data => { | ||
const contactName = contacts.map(contact => contact.name.toLowerCase()); | ||
const isAdding = contactName.includes(data.name.toLowerCase()); | ||
|
||
if (!isAdding) { | ||
createContact(data); | ||
reset(); | ||
toast.success(`😃 Contact, ${name} successfully added`); | ||
} else { | ||
toast.error(`😏${data.name} is already in contacts.`); | ||
} | ||
}; | ||
|
||
const handleSubmit = e => { | ||
e.preventDefault(); | ||
|
||
const newContact = { | ||
id: nanoid(), | ||
name, | ||
number, | ||
}; | ||
|
||
addContact(newContact); | ||
}; | ||
|
||
const reset = () => { | ||
setName(''); | ||
setNumber(''); | ||
}; | ||
|
||
return ( | ||
<Form onSubmit={handleSubmit} autoComplete="off"> | ||
<Label> | ||
Name | ||
<Input | ||
type="text" | ||
id="name_input" | ||
name="name" | ||
value={name} | ||
onChange={handleChange} | ||
placeholder="Enter your name..." | ||
pattern="^[a-zA-Zа-яА-Я]+(([' -][a-zA-Zа-яА-Я ])?[a-zA-Zа-яА-Я]*)*$" | ||
title="Name may contain only letters, apostrophe, dash and spaces. For example Adrian, Jacob Mercer, Charles de Batz de Castelmore d'Artagnan" | ||
required | ||
/> | ||
</Label> | ||
|
||
<Label> | ||
Number | ||
<Input | ||
type="tel" | ||
id="name_input" | ||
name="number" | ||
value={number} | ||
onChange={handleChange} | ||
placeholder="Enter your number..." | ||
pattern="\+?\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}" | ||
title="Phone number must be digits and can contain spaces, dashes, parentheses and can start with +" | ||
required | ||
/> | ||
<Button type="submit">Add contact</Button> | ||
</Label> | ||
|
||
<Toaster /> | ||
{isLoading && <Loader />} | ||
</Form> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import styled from '@emotion/styled'; | ||
|
||
export const Form = styled.form` | ||
margin-top: 10px; | ||
margin-bottom: 20px; | ||
border-radius: 10px; | ||
padding: 10px; | ||
box-shadow: var(--boxShadow); | ||
`; | ||
|
||
export const Label = styled.label` | ||
display: flex; | ||
flex-direction: column; | ||
margin-bottom: 20px; | ||
font-weight: 500; | ||
font-size: 20px; | ||
align-items: center; | ||
`; | ||
|
||
export const Input = styled.input` | ||
display: block; | ||
margin-left: auto; | ||
margin-right: auto; | ||
margin-top: 2px; | ||
padding: 10px; | ||
width: 60%; | ||
border: 2px solid blue; | ||
border-radius: 20px; | ||
cursor: pointer; | ||
font-size: 15px; | ||
box-shadow: 17px 17px 84px 18px rgba(21, 15, 15, 0.2) inset; | ||
&::placeholder { | ||
color: #ffffff; | ||
font-style: italic; | ||
} | ||
&:focus { | ||
background-color: #f9f1f1; | ||
/* outline-color: var(--accentColor); */ | ||
box-shadow: rgba(50, 50, 93, 0.25) 0px 30px 60px -12px inset, | ||
rgba(0, 0, 0, 0.3) 0px 18px 36px -18px inset; | ||
border: 2px solid rgb(22, 2, 2); | ||
} | ||
&: nth-last-child(2) { | ||
margin-bottom: 35px; | ||
} | ||
`; | ||
|
||
export const Button = styled.button` | ||
width: 100px; | ||
height: 100%; | ||
padding: 5px; | ||
border-radius: 20px; | ||
color: #ffffff; | ||
cursor: pointer; | ||
font-size: 15px; | ||
box-shadow: 17px 17px 84px 18px rgba(21, 15, 15, 0.2) inset; | ||
border: 2px solid blue; | ||
background-color: lightblue; | ||
&:hover, | ||
&:focus { | ||
background: rgba(73, 155, 234, 1); | ||
} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { Item, Button } from './ContactItem.styled' | ||
import { RotatingLines } from 'react-loader-spinner'; | ||
import { useDeleteContactMutation } from 'redux/contacts/contactsApi'; | ||
|
||
function ContactItem({ id, name, number}) {const [deleteContact, { isLoading: isDeleting }] = useDeleteContactMutation(); | ||
|
||
return ( | ||
<Item key={id}> | ||
<p> | ||
{name}: {number} {' '} | ||
</p> | ||
<Button type="button" onClick={() => deleteContact(id)} | ||
disabled={isDeleting}> | ||
{isDeleting && <RotatingLines width="10" />} Delete | ||
</Button> | ||
</Item> | ||
); | ||
}; | ||
|
||
export default ContactItem; |
Oops, something went wrong.