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.
added phonebook from previous homework
- Loading branch information
1 parent
e27f54e
commit 6b3f2d6
Showing
20 changed files
with
1,281 additions
and
77 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 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 |
---|---|---|
@@ -1,16 +1,39 @@ | ||
export const App = () => { | ||
import { ContactForm, ContactList, Filter } from 'components'; | ||
import { Loader } from 'components/Loader/Loader'; | ||
import { Error } from 'components/Error/Error'; | ||
import { useSelector } from 'react-redux'; | ||
// import { | ||
// selectContactsError, | ||
// selectContactsIsLoading, | ||
// selectContacts, | ||
// } from '../redux/contacts/contactsSelectors'; | ||
import { contactsSelectors } from 'redux/contacts'; | ||
const App = () => { | ||
const isLoading = useSelector(contactsSelectors.selectContactsIsLoading); | ||
const error = useSelector(contactsSelectors.selectContactsError); | ||
const phoneBook = useSelector(contactsSelectors.selectContacts); | ||
return ( | ||
<div | ||
style={{ | ||
height: '100vh', | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
fontSize: 40, | ||
color: '#010101' | ||
flexDirection: 'column', | ||
gap: '15px', | ||
margin: '0 auto', | ||
padding: '30px', | ||
}} | ||
> | ||
React homework template | ||
<h1 style={{ color: '#3645ab' }}>Phonebook</h1> | ||
<ContactForm /> | ||
<h2>Contacts</h2> | ||
{phoneBook.length === 0 && !error && !isLoading ? ( | ||
"You don't have any contacts yet" | ||
) : ( | ||
<Filter /> | ||
)} | ||
{error ? <Error /> : <ContactList />} | ||
{isLoading && <Loader />} | ||
</div> | ||
); | ||
}; | ||
|
||
export default App; |
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,80 @@ | ||
import React, { useState } from 'react'; | ||
import { nanoid } from 'nanoid'; | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
import { FormInput, Form, FormButton, FormLabel } from './ContactForm.styled'; | ||
// import { addContact } from 'redux/contacts/phoneBookSlice'; | ||
// import { selectContacts } from 'redux/contacts/contactsSelectors'; | ||
import { contactsSelectors, contactsSlices } from 'redux/contacts'; | ||
|
||
const ContactForm = () => { | ||
const [name, setName] = useState(''); | ||
const [number, setNumber] = useState(''); | ||
|
||
const dispatch = useDispatch(); | ||
const contacts = useSelector(contactsSelectors.selectContacts); | ||
|
||
const onSubmitAddContact = e => { | ||
e.preventDefault(); | ||
const data = { | ||
name, | ||
number: Number.parseFloat(number) || alert(`Number is not correct`), | ||
}; | ||
const newContact = { ...data, id: nanoid() }; | ||
|
||
const isExist = contacts.some( | ||
({ name }) => name.toLowerCase() === newContact.name.toLowerCase() | ||
); | ||
|
||
if (isExist) { | ||
alert(`Oops, contact '${newContact.name}' is already in contacts!`); | ||
return; | ||
} | ||
|
||
dispatch(contactsSlices.addContact(newContact)); | ||
setName(''); | ||
setNumber(''); | ||
}; | ||
|
||
const handleInputChange = e => { | ||
const { name, value } = e.currentTarget; | ||
switch (name) { | ||
case 'name': | ||
setName(value); | ||
break; | ||
case 'number': | ||
setNumber(value); | ||
break; | ||
|
||
default: | ||
break; | ||
} | ||
}; | ||
|
||
return ( | ||
<Form onSubmit={onSubmitAddContact}> | ||
<FormLabel htmlFor="name">Name</FormLabel> | ||
<FormInput | ||
type="text" | ||
name="name" | ||
onChange={handleInputChange} | ||
value={name} | ||
pattern="^[a-zA-Zа-яА-Я]+(([' \-][a-zA-Zа-яА-Я ])?[a-zA-Zа-яА-Я]*)*$" | ||
required | ||
/> | ||
|
||
<FormLabel htmlFor="number">Number</FormLabel> | ||
<FormInput | ||
type="tel" | ||
name="number" | ||
value={number} | ||
onChange={handleInputChange} | ||
pattern="\+?\d{1,4}?[ .\-\s]?\(?\d{1,3}?\)?[ .\-\s]?\d{1,4}[ .\-\s]?\d{1,4}[ .\-\s]?\d{1,9}" | ||
required | ||
/> | ||
|
||
<FormButton type="submit">Add contact</FormButton> | ||
</Form> | ||
); | ||
}; | ||
|
||
export default ContactForm; |
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,52 @@ | ||
import styled from "styled-components"; | ||
export const Form = styled.form` | ||
display: flex; | ||
flex-direction: column; | ||
max-width: 420px; | ||
padding: 10px; | ||
border-radius: 2px; | ||
box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.5); | ||
margin: 30px 20px; | ||
`; | ||
|
||
export const FormLabel = styled.label` | ||
margin-top: 0; | ||
margin-bottom: 12px; | ||
font-weight: 500; | ||
font-size: 18px; | ||
`; | ||
|
||
export const FormInput = styled.input` | ||
height: 20px; | ||
font-size: 16px; | ||
width: 400px; | ||
margin-bottom: 6px; | ||
padding: 5px; | ||
border: none; | ||
border-bottom: 1px solid teal; | ||
&:focus, | ||
&:hover, | ||
&:active { | ||
outline: 0; | ||
outline-offset: 0; | ||
border: none; | ||
border-bottom: 1.5px solid teal; | ||
outline: none; | ||
} | ||
`; | ||
|
||
export const FormButton = styled.button` | ||
width: 100px; | ||
height: 28px; | ||
margin-left: 5px; | ||
margin-top: 5px; | ||
border-width: inherit; | ||
border-radius: 5px; | ||
outline: none; | ||
background-color: #3645ab; | ||
color: white; | ||
cursor: pointer; | ||
&:focus { | ||
background-color: #2b3788; | ||
} | ||
`; |
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,46 @@ | ||
import { useEffect } from 'react'; | ||
import { | ||
List, | ||
ContactItem, | ||
CardWrapper, | ||
ButtonDelete, | ||
Info, | ||
} from './ContactList.styled'; | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
// import { | ||
// deleteContact, | ||
// getContacts, | ||
// } from '../../redux/contacts/phoneBookSlice'; | ||
// import { selectFilteredContacts } from 'redux/contacts/contactsSelectors'; | ||
import { contactsSelectors, contactsSlices } from 'redux/contacts'; | ||
|
||
const ContactList = () => { | ||
const visibleContacts = useSelector(contactsSelectors.selectFilteredContacts); | ||
const dispatch = useDispatch(); | ||
|
||
useEffect(() => { | ||
dispatch(contactsSlices.getContacts()); | ||
}, [dispatch]); | ||
|
||
const handleDeleteContact = contactId => { | ||
dispatch(contactsSlices.deleteContact(contactId)); | ||
}; | ||
|
||
return ( | ||
<List> | ||
{visibleContacts.map(({ name, phone, id }) => ( | ||
<ContactItem key={id}> | ||
<CardWrapper> | ||
<Info>{name}</Info> | ||
<Info>{phone}</Info> | ||
<ButtonDelete onClick={() => handleDeleteContact(id)}> | ||
Delete | ||
</ButtonDelete> | ||
</CardWrapper> | ||
</ContactItem> | ||
))} | ||
</List> | ||
); | ||
}; | ||
|
||
export default ContactList; |
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,51 @@ | ||
import styled from 'styled-components'; | ||
|
||
export const List = styled.ul` | ||
display: flex; | ||
flex-wrap: wrap; | ||
margin: 20px; | ||
flex-direction: column; | ||
gap: 10px; | ||
`; | ||
|
||
export const ContactItem = styled.li` | ||
max-width: 400px; | ||
padding: 20px; | ||
background: white; | ||
border-radius: 2px; | ||
box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.5); | ||
transition: all 0.3s ease-out; | ||
&:hover { | ||
transform: scale(1.05); | ||
}`; | ||
|
||
export const CardWrapper = styled.div` | ||
display: flex; | ||
height: 100px; | ||
flex-direction: row; | ||
align-items: center; | ||
gap: 8px; | ||
justify-content: space-between; | ||
`; | ||
|
||
export const Info = styled.p` | ||
font-size: 18px; | ||
font-weight: 500; | ||
letter-spacing: -0.3px; | ||
`; | ||
|
||
export const ButtonDelete = styled.button` | ||
width: 70px; | ||
height: 40px; | ||
margin-left: 5px; | ||
border-width: inherit; | ||
border-radius: 5px; | ||
outline: none; | ||
background-color: #e22626; | ||
color: white; | ||
cursor: pointer; | ||
&:focus { | ||
background-color: #c72323; | ||
} | ||
`; |
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,14 @@ | ||
import { useSelector } from 'react-redux'; | ||
import { WrapperError } from './Error.styled'; | ||
// import { selectContactsError } from 'redux/contacts/contactsSelectors'; | ||
import { contactsSelectors } from 'redux/contacts'; | ||
|
||
export const Error = () => { | ||
const error = useSelector(contactsSelectors.selectContactsError); | ||
|
||
return ( | ||
<WrapperError> | ||
<p>We're sorry, {error}</p> | ||
</WrapperError> | ||
); | ||
}; |
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,11 @@ | ||
import styled from 'styled-components'; | ||
|
||
export const WrapperError = styled.div` | ||
text-align: center; | ||
margin-top: 30px; | ||
padding: 10px; | ||
width: 400px; | ||
font-weight: 500; | ||
font-size: 20px; | ||
background-color: #fa0e0ef6; | ||
`; |
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,30 @@ | ||
import React from 'react'; | ||
import { FilterContainer, FilterLabel, FilterInput } from './Filter.styled'; | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
// import { setFilterTerm } from '../../redux/contacts/filterSlice'; | ||
// import { selectContactsFilterTerm } from 'redux/contacts/contactsSelectors'; | ||
import { contactsSelectors, filterSlice } from 'redux/contacts'; | ||
const Filter = () => { | ||
const dispatch = useDispatch(); | ||
const filterTerm = useSelector(contactsSelectors.selectContactsFilterTerm); | ||
|
||
const changeFilter = event => { | ||
const { value } = event.currentTarget; | ||
dispatch(filterSlice.setFilterTerm(value)); | ||
}; | ||
return ( | ||
<FilterContainer> | ||
<FilterLabel> | ||
Find contact... | ||
<FilterInput | ||
type="text" | ||
value={filterTerm} | ||
placeholder="Enter name..." | ||
onChange={changeFilter} | ||
/> | ||
</FilterLabel> | ||
</FilterContainer> | ||
); | ||
}; | ||
|
||
export default Filter; |
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,34 @@ | ||
import styled from 'styled-components'; | ||
|
||
export const FilterContainer = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
max-width: 420px; | ||
margin: 20px; | ||
padding: 10px; | ||
border-radius: 2px; | ||
box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.5); | ||
`; | ||
|
||
export const FilterLabel = styled.label` | ||
margin: 0px; | ||
font-size: 18px; | ||
`; | ||
|
||
export const FilterInput = styled.input` | ||
max-width: 240px; | ||
font-size: 14px; | ||
padding: 5px; | ||
display: block; | ||
border: none; | ||
border-bottom: 1px solid teal; | ||
&:focus, | ||
&:hover, | ||
&:active { | ||
outline: 0; | ||
outline-offset: 0; | ||
border: none; | ||
border-bottom: 1.5px solid teal; | ||
} | ||
`; |
Oops, something went wrong.