Skip to content

Commit

Permalink
feat(app): implement contact management with addition, search, and de…
Browse files Browse the repository at this point in the history
…letion functionalities
  • Loading branch information
Valik3201 committed Jan 20, 2024
1 parent 403d2d0 commit a77646c
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 52 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
**Contact Management App**
# Contact Management App

This React application serves as a straightforward contact management system,
offering essential features for adding, searching, and deleting contacts.

**Features**
## Features

1. **Add Contacts:** Use the provided form to easily add new contacts, including
names and phone numbers.
Expand All @@ -14,7 +14,7 @@ offering essential features for adding, searching, and deleting contacts.
3. **Contact Deletion:** Conveniently delete contacts that are no longer needed,
enhancing the user's control over their contact list.

**Usage**
## Usage

- **Adding New Contacts:**

Expand All @@ -36,7 +36,7 @@ offering essential features for adding, searching, and deleting contacts.
- Look for a delete or remove option associated with each contact.
- Click on the delete option to remove unwanted contacts from your list.

**Project Structure**
## Project Structure

The project structure follows a modular approach with the following components:

Expand Down
89 changes: 46 additions & 43 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
"homepage": "https://goitacademy.github.io/react-homework-template/",
"dependencies": {
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.2",
"react": "^18.1.0",
"nanoid": "^5.0.4",
"react": "^18.2.0",
"react-bootstrap": "^2.10.0",
"react-dom": "^18.1.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.3"
},
Expand Down Expand Up @@ -38,5 +38,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@testing-library/react": "^14.1.2"
}
}
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Contact Management App</title>
<title>Phonebook</title>

<!-- Start Single Page Apps for GitHub Pages -->
<script type="text/javascript">
Expand Down
51 changes: 50 additions & 1 deletion src/components/App.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,68 @@
import { Component } from 'react';
import { ContactForm } from './ContactForm';
import { ContactList } from './ContactList';
import { Filter } from './Filter';

export default class App extends Component {
constructor(props) {
super(props);

this.state = {
contacts: [],
filter: '',
};

this.addContact = this.addContact.bind(this);
this.handleFilterChange = this.handleFilterChange.bind(this);
this.handleDeleteContact = this.handleDeleteContact.bind(this);
}

addContact = newContact => {
this.setState(prevState => ({
contacts: [...prevState.contacts, newContact],
}));
};

handleFilterChange = e => {
this.setState({ filter: e.target.value.toLowerCase() });
};

handleDeleteContact = contactId => {
this.setState(prevState => ({
contacts: prevState.contacts.filter(contact => contact.id !== contactId),
}));
};

render() {
const { contacts, filter } = this.state;

const filteredContacts = contacts.filter(contact =>
contact.name.toLowerCase().includes(filter)
);

return (
<div
style={{
height: '100vh',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
fontSize: 40,
color: '#010101',
}}
>
Contact Management App
Phonebook
<ContactForm
addContact={this.addContact}
contacts={this.state.contacts}
/>
Contacts
<Filter value={filter} onChange={this.handleFilterChange} />
<ContactList
contacts={filteredContacts}
onDeleteContact={this.handleDeleteContact}
/>
</div>
);
}
Expand Down
76 changes: 76 additions & 0 deletions src/components/ContactForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Component } from 'react';
import { nanoid } from 'nanoid';

export class ContactForm extends Component {
constructor(props) {
super(props);

this.state = {
name: '',
number: '',
};

this.handleChange = this.handleChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}

handleChange = e => {
this.setState({ [e.target.name]: e.target.value });
};

handleFormSubmit = e => {
e.preventDefault();

const { name, number } = this.state;
const { contacts, addContact } = this.props;

if (contacts.some(contact => contact.name === name)) {
alert(`Contact with name "${name}" already exists!`);
return;
}

const newContact = {
id: nanoid(),
name,
number,
};

addContact(newContact);

this.setState({ name: '', number: '' });
};

render() {
const { name, number } = this.state;

return (
<form onSubmit={this.handleFormSubmit}>
<label>
Name:
<input
type="text"
name="name"
value={name}
onChange={this.handleChange}
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>
Phone Number:
<input
type="tel"
name="number"
value={number}
onChange={this.handleChange}
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
/>
</label>
<button type="submit">Add Contact</button>
</form>
);
}
}
Loading

0 comments on commit a77646c

Please sign in to comment.