Skip to content
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
34 changes: 34 additions & 0 deletions app/components/contact-API.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

export const ContactApi = {
//making an array to hold Contacts
contacts: [
{
id: 70219577,
name: 'Albert Einstein',
image_url: "https://images.squarespace-cdn.com/content/v1/62ec2bc76a27db7b37a2b32f/625c7248-8056-4505-a1da-a1058c830d92/albert-einstein-with-blue-hair-large.jpg",
email: 'aeinstein@example.com',
phone_number: '1555555555'

},
{
id:12345678,
name: 'Snoopy',
image_url: 'https://upload.wikimedia.org/wikipedia/en/5/53/Snoopy_Peanuts.png',
email: 'snoopy@example.com',
phone_number: '1222222222'
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You are using snake case (phone_number) here which is mostly just used in Python. JS we recommend using camel case (phoneNumber).

}
],
//function to access all contacts
all: function () {
return this.contacts
},
//function to add contacts with required information
addContact: function ({id, name, image_url, email, phone_number}) {
this.contacts.push({id, name, image_url, email, phone_number});
},
//function to access an individual contact bases upon their assigned id
get: function (id) {
const isContact = (contact) => contact.id === id;
return this.contacts.find(isContact);
},
};
60 changes: 60 additions & 0 deletions app/components/displayContact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Link from 'next/link';
import 'bootstrap/dist/css/bootstrap.min.css';
import PropTypes from 'prop-types';
import React from 'react';

const DisplayContacts = ({ allContacts }) => {
return (
<table className='table'>
<thead className='table-primary'>
<tr>
<th scope='col'>Profile Pic</th>
<th scope='col'>Name</th>
<th scope='col'>Email</th>
<th scope='col'>Phone</th>
<th scope='col'></th>
<th scope='col'></th>
</tr>
</thead>
<tbody className='table'>
{allContacts.map((contact) => (
<tr key={contact.id}>
<td className='col'>
<img
style={{
height: 120,
width: 120,
borderRadius: '50%',
}}
src={contact.image_url}
></img>
</td>
<td className='col'>
<Link id='blue' href={`/contacts/${contact.id}`}>
{contact.name}
</Link>
</td>
<td className='col'>{contact.email}</td>
<td className='col'>{contact.phone_number}</td>
<td className='col text-primary'>Edit</td>
<td className='col text-danger'>Delete</td>
</tr>
))}
</tbody>
</table>
);
};

DisplayContacts.PropTypes = {
allContacts: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
image_url: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
email: PropTypes.string.isRequired,
phone_number: PropTypes.number.isRequired,
})
).isRequired,
};

export default DisplayContacts;
36 changes: 36 additions & 0 deletions app/contacts/[id]/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use client';

import { ContactApi } from '@/app/components/contact-API';
import { useParams } from 'next/navigation';
import Link from 'next/link';

export default function Contact() {
const { id } = useParams();

const contact = ContactApi.get(parseInt(id, 10));

//error handling if contact is not found with id
if (!contact) {
return <div> Sorry, but the Contact was not found</div>;
}

//segment that returns the contact information
return (
<main>
<div className='col-6 offset-3 text-center'>
<h1 className='fw-bold'>Contact Info</h1>
<br />
<Link href='/contacts'>Back</Link>
<br />
<h1>{contact.name}</h1>
<br />
<img className='img-fluid ' src={contact.image_url} />
<br />
<br />
<h5>{contact.email}</h5>
<br />
<h5>{contact.phone_number}</h5>
</div>
</main>
);
}
105 changes: 105 additions & 0 deletions app/contacts/new/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
'use client';

import { ContactApi } from '@/app/components/contact-API';
import { useState } from 'react';
import { useRouter } from 'next/navigation';

function NewContact() {
//the use state for contact information
const [name, setName] = useState(null);
const [email, setEmail] = useState(null);
const [image_url, setImage_Url] = useState(null);
const [phone_number, setPhone_Number] = useState(null);
const router = useRouter();

//button function to add contact information and then reroute page back to main contacts page
const handleSubmitContactClick = () => {
if (!name || !email || !image_url || !phone_number) {
alert('Please fill in all fields of data');
} else {
ContactApi.addContact({
name,
email,
image_url,
phone_number,
//sets id number by default
id: Math.round(Math.random() * 100000000),
});
router.push('/contacts');
}
};
//returns input areas for contact information that is inputted. Changes the useState of each parameter on event changes for each input. Has submit button at the bottom
return (
<div>
<div>
<h1 className='text-center'>Add New Contact</h1>
</div>
<div className='container'>
<form>
<div className='mb-3'>
<label className='form-label text-center'>Name</label>
<input
type='text'
required
className='form-control'
onChange={(event) => setName(event.target.value)}
/>
</div>

<br />

<div className='mb-3'>
<label className='form-label text-center'>Email</label>
<input
type='email'
required
className='form-control'
onChange={(event) => setEmail(event.target.value)}
/>
</div>

<br />

<div className='mb-3'>
<label className='form-label text-center'>
Profile Picture URL
</label>
<input
type='url'
required
className='form-control'
onChange={(event) =>
setImage_Url(event.target.value)
}
/>
</div>

<br />

<div className='mb-3'>
<label className='form-label text-center'>
Phone Number
</label>
<input
required
type='number'
className='form-control'
onChange={(event) =>
setPhone_Number(event.target.value)
}
/>
</div>
</form>
<button
type='button'
className='btn btn-primary'
onClick={handleSubmitContactClick}
>
Submit
</button>
</div>
</div>
);
}

export default NewContact;
29 changes: 29 additions & 0 deletions app/contacts/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use client';
import { useState } from 'react';
import { ContactApi } from '../components/contact-API';
import Link from 'next/link';
import NewContact from './new/page';
import DisplayContacts from '../components/displayContact';

export default function Contacts() {
//gets all the contact information and keeps track of useState
const [allContacts, _] = useState(ContactApi.all());

//returns main home page that has a header, new contact button, then a table with all the contacts.

return (
<div className='text-center'>
<br />
<br />
<h1>All Contacts</h1>
<Link href='/contacts/new'>
<button type='button' className='btn btn-primary'>
New Contact
</button>
</Link>
<br />
<br />
<DisplayContacts allContacts={allContacts} />
</div>
);
}
106 changes: 3 additions & 103 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -1,107 +1,7 @@
:root {
--max-width: 1100px;
--border-radius: 12px;
--font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;

--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;

--primary-glow: conic-gradient(
from 180deg at 50% 50%,
#16abff33 0deg,
#0885ff33 55deg,
#54d6ff33 120deg,
#0071ff33 160deg,
transparent 360deg
);
--secondary-glow: radial-gradient(
rgba(255, 255, 255, 1),
rgba(255, 255, 255, 0)
);

--tile-start-rgb: 239, 245, 249;
--tile-end-rgb: 228, 232, 233;
--tile-border: conic-gradient(
#00000080,
#00000040,
#00000030,
#00000020,
#00000010,
#00000010,
#00000080
);

--callout-rgb: 238, 240, 241;
--callout-border-rgb: 172, 175, 176;
--card-rgb: 180, 185, 188;
--card-border-rgb: 131, 134, 135;
}

@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;

--primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
--secondary-glow: linear-gradient(
to bottom right,
rgba(1, 65, 255, 0),
rgba(1, 65, 255, 0),
rgba(1, 65, 255, 0.3)
);

--tile-start-rgb: 2, 13, 46;
--tile-end-rgb: 2, 5, 19;
--tile-border: conic-gradient(
#ffffff80,
#ffffff40,
#ffffff30,
#ffffff20,
#ffffff10,
#ffffff10,
#ffffff80
);

--callout-rgb: 20, 20, 20;
--callout-border-rgb: 108, 108, 108;
--card-rgb: 100, 100, 100;
--card-border-rgb: 200, 200, 200;
}
}

* {
box-sizing: border-box;
padding: 0;
margin: 0;
}

html,
body {
max-width: 100vw;
overflow-x: hidden;
}

body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
}

a {
color: inherit;
text-decoration: none;
text-align: center;
}

@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
}
#blue {
color: blue;
}
10 changes: 6 additions & 4 deletions app/layout.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Inter } from 'next/font/google'
import './globals.css'
import { Inter } from 'next/font/google';
import 'bootstrap/dist/css/bootstrap.css';
import './globals.css';


const inter = Inter({ subsets: ['latin'] })

export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
title: 'Contacts List',
description: 'Contacts app',
}

export default function RootLayout({ children }) {
Expand Down
Loading