Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

contact-list #68

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39,104 changes: 8,764 additions & 30,340 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@testing-library/user-event": "^12.8.3",
"bootstrap": "^5.2.3",
"prop-types": "^15.8.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"react-router-dom": "^5.3.4",
"react-scripts": "^5.0.1",
"web-vitals": "^1.1.1"
},
"scripts": {
Expand Down
Binary file removed public/logo192.png
Binary file not shown.
Binary file removed public/logo512.png
Binary file not shown.
10 changes: 0 additions & 10 deletions public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
Expand Down
74 changes: 74 additions & 0 deletions src/AddContact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useState } from "react";
import { Link, Redirect } from "react-router-dom";
import PropTypes from 'prop-types';

const AddContact = ({handleContactChange}) => {
// used this to redirect back to the home page after form submission
const [isSubmitted, setIsSubmitted] = useState(false);
// component for adding a new contact to newContact state
let [newContact, setNewContact] = useState({
contact: {
id: Math.round(Math.random() * 100000000),
name: '',
email: '',
phoneNumber: '',
profilePicture: ''
}
})

// function for retrieving users input from form and adding it to newContact state
const handleInput = (e) => {
setNewContact({
...newContact,
contact: {
...newContact.contact,
[e.target.name] : e.target.value
}
})
}

// function to handle the submission of the user to add a new contact to the contacts array
const handleSubmit = (e) => {
e.preventDefault();
handleContactChange(newContact.contact);
setIsSubmitted(true);
}

return (
<div className="container add-contact">
<h1 className='text-center mt-4'>Contact List</h1>
<form onSubmit={handleSubmit} className="col-8 offset-2">
<div className="form-group">
<label className='pt-3 pb-3' htmlFor='full-name-input'>Full Name</label>
<input name='name' value={newContact.contact.name} onChange={handleInput} className="form-control" id='full-name-input' type="text" placeholder='Enter Full Name' required={true} />
</div>
<div className="form-group">
<label className='pt-3 pb-3' htmlFor='email-input'>Email Address</label>
<input name='email' value={newContact.contact.email} onChange={handleInput} className="form-control" id='email-input' type="email" placeholder='Enter Email' required={true}/>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need more indentation here

</div>
<div className="form-group">
<label className='pt-3 pb-3' htmlFor='phone-number-input'>Phone Number</label>
<input name='phoneNumber' value={newContact.contact.phoneNumber} onChange={handleInput}className="form-control" id='phone-number-input' type="number" placeholder='Enter Phone Number' required={true}/>
</div>
<div className="form-group">
<label className='pt-3 pb-3' htmlFor='url-input'>Image URL</label>
<input name='profilePicture' value={newContact.contact.profilePicture} onChange={handleInput} className="form-control" id='url-input' type="text" placeholder='Enter Image URL' required={true}/>
</div>
<div className="pt-4">
<button to='/contacts' className="btn btn-primary">Add Contact</button>
<Link to={'/'} className='btn btn-danger ms-3'>Back</Link>
</div>
</form>
{isSubmitted && (
<Redirect to='/' />
)}
</div>
);
}

//propTypes check
AddContact.propTypes = {
handleContactChange: PropTypes.func.isRequired
}

export default AddContact;
41 changes: 4 additions & 37 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,38 +1,5 @@
.App {
text-align: center;
}

.App-logo {
height: 40vmin;
pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}

.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}

.App-link {
color: #61dafb;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
67 changes: 46 additions & 21 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,50 @@
import logo from './logo.svg';
import './App.css';
import React, { useState } from "react";
import ContactList from "./ContactList";
import AddContact from './AddContact';
import ContactDetails from './ContactDetails';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import johnDoe from './john-doe.jpg';
import janeDoe from './jane-doe.jpg';
import jimmyChu from './jimmy-chu.jpg';
import batman from './batman.jpg';

const App = () => {
// contacts state using useState hook and functional component
const [contacts, setContacts] = useState([
{ id: 1, name: 'John Doe', email: '[email protected]', phoneNumber: 2124569900, profilePicture: johnDoe },
{ id: 2, name: 'Jane Doe', email: '[email protected]', phoneNumber: 2124563319, profilePicture: janeDoe },
{ id: 3, name: 'Jimmy Chu', email: '[email protected]', phoneNumber: 9092234518, profilePicture: jimmyChu },
{ id: 4, name: 'Batman', email: '[email protected]', phoneNumber: 4403447876, profilePicture: batman }
]);

// function for deleting a post on home page
const handleDelete = (id) => {
const newContacts = contacts.filter((contact) => contact.id !== id);
setContacts(newContacts);
}

// function for adding new contact into contacts state
const handleContactChange = (newData) => {
setContacts(contacts.concat(newData));
}

function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
<BrowserRouter>
<div className="app">
<Switch>
<Route exact path='/'>
<ContactList contacts={contacts} handleDelete={handleDelete}/>
</Route>
<Route path='/contacts/new'>
<AddContact handleContactChange={handleContactChange}/>
</Route>
<Route path='/contacts/:id'>
<ContactDetails contacts={contacts} />
</Route>
</Switch>
</div>
</BrowserRouter>
);
}

export default App;
export default App;
8 changes: 0 additions & 8 deletions src/App.test.js

This file was deleted.

40 changes: 40 additions & 0 deletions src/ContactDetails.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Link, useParams } from "react-router-dom";
import PropTypes from 'prop-types';

const ContactDetails = ({contacts}) => {
const {id} = useParams();
const contact = contacts.find((contact) => contact.id === Number(id));
// error logic for if contact doesn't exist in contacts array
if (!contact) {
return <div className='text-center'>
<h2>Error: That contact does not exist in your contact list</h2>
</div>;
}

// displays single contact out of contacts array
return (
<div className='container text-center contact-details'>
<h1 className='mt-4 mb-4'>Contact List</h1>
<div className='row border border-dark rounded'>
<div className='col-3 mx-auto p-0'>
<img className='img-fluid' src={contact.profilePicture} alt='profile'/>
</div>
<div className="row mx-auto">
<div className="col mt-3">
<h2><strong>Name: </strong>{contact.name}</h2>
<h2><strong>Email: </strong>{contact.email}</h2>
<h2><strong>Phone: </strong>{contact.phoneNumber}</h2>
<Link to='/' className='btn btn-danger mt-2'>Back</Link>
</div>
</div>
</div>
</div>
);
};

// propTypes check
ContactDetails.propTypes = {
contacts: PropTypes.arrayOf(PropTypes.object).isRequired,
}

export default ContactDetails;
43 changes: 43 additions & 0 deletions src/ContactList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { NavLink } from "react-router-dom";
import PropTypes from 'prop-types';

const ContactList = ({contacts, handleDelete}) => {
// component to display the contacts state
return (
<div className="container contact-list">
<h1 className='text-center mt-4'>Contact List</h1>
<div className="row text-center">
<div className="col ms-1">
<NavLink to='/contacts/new' className='btn btn-primary m-2'>Add Contact</NavLink>
</div>
</div>
<div>
{contacts.map(contact => (
<div className="row border border-dark rounded m-4 text-center d-flex align-items-center" key={contact.id}>
<div className="col-md-6">
<NavLink className='text-decoration-none text-dark d-block' to={`/contacts/${contact.id}`}>
<img className='img-fluid' src={contact.profilePicture} alt='contact profile' style={{'height': '250px'}}/>
</NavLink>
</div>
<div className="col-md-6">
<NavLink className='text-decoration-none text-dark d-block' to={`/contacts/${contact.id}`}>
<p><strong>Name: </strong>{contact.name}</p>
<p><strong>Email: </strong>{contact.email}</p>
<p><strong>Phone: </strong>{contact.phoneNumber}</p>
</NavLink>
<button onClick={() => handleDelete(contact.id)} className='btn btn-danger'>Delete Contact</button>
</div>
</div>
))}
</div>
</div>
);
}

// propTypes check
ContactList.propTypes = {
contacts: PropTypes.arrayOf(PropTypes.object).isRequired,
handleDelete: PropTypes.func.isRequired
}

export default ContactList;
Binary file added src/batman.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 9 additions & 3 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}

body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
11 changes: 3 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import './App.css'
import 'bootstrap/dist/css/bootstrap.css';

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
);
Binary file added src/jane-doe.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/jimmy-chu.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/john-doe.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion src/logo.svg

This file was deleted.

13 changes: 0 additions & 13 deletions src/reportWebVitals.js

This file was deleted.

5 changes: 0 additions & 5 deletions src/setupTests.js

This file was deleted.