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
62 changes: 62 additions & 0 deletions app/ContactList/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client'
import 'bootstrap/dist/css/bootstrap.css'
import Image from "next/image"
import Link from 'next/link'

export default function ContactList({ prop }) {
const link = () => {
alert('Sorry, but this does not function!')
}

return (
<div className='container'>
<div className='row text-center'>
<div className="col">
<div className="border-0 list-group-item"><u>Profile Picture</u></div>
</div>
<div className="col">
<div className="border-0 list-group-item"><u>Name</u></div>
</div>
<div className="col">
<div className="border-0 list-group-item"><u>Email</u></div>
</div>
<div className="col">
<div className="border-0 list-group-item"><u>Phone Number</u></div>
</div>
<div className="col">
<div className="border-0 list-group-item"><u>Actions</u></div>
</div>
</div>

<br />

{prop.map((c) => (
<div className="row text-center p-1" key={c.id}>
<div className="col">
<div className="border-0 list-group-item">
<Image width={40} height={40} alt="unc" src={c.image_url} />
</div>
</div>
<div className="col">
<div className="border-0 list-group-item">
<Link id={c.id} href={{ pathname: '/contacts/contact', query: { id: c.id } }}>
{c.name}
</Link>
</div>
</div>
<div className="col">
<div className="border-0 list-group-item">{c.email}</div>
</div>
<div className="col">
<div className="border-0 list-group-item">{c.phone_number}</div>
</div>
<div className="col">
<div className="border-0 list-group-item">
<button onClick={link} className='btn btn-link'>Edit/Delete</button>
</div>
</div>
</div>
))}
</div>
)
}
49 changes: 49 additions & 0 deletions app/Data/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const Data = {
contacts: [
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

what is the difference between this and get all contacts?

{
"id": 1,
"name": "John Doe",
"image_url": "/media/JohnDoe.jpg",
"email": "john.doe@example.com",
"phone_number": "+1-555-123-4567"
},
{
"id": 2,
"name": "Jane Smith",
"image_url": "/media/JaneSmith.jpg",
"email": "jane.smith@example.com",
"phone_number": "+1-555-234-5678"
},
{
"id": 3,
"name": "Michael Johnson",
"image_url": "/media/MichaelJohnson.jpg",
"email": "michael.johnson@example.com",
"phone_number": "+1-555-345-6789"
},
{
"id": 4,
"name": "Emily Davis",
"image_url": "/media/EmilyDavis.jpg",
"email": "emily.davis@example.com",
"phone_number": "+1-555-456-7890"
},
{
"id": 5,
"name": "Chris Lee",
"image_url": "/media/ChrisLee.jpg",
"email": "chris.lee@example.com",
"phone_number": "+1-555-567-8901"
}
],
addContact: function (id, name, image_url, email, phone_number) {
this.contacts.push({id, name, image_url, email, phone_number })
},
get: function (id) {
const isContact = (c) => c.id === id
return this.contacts.find(isContact)
}
}


export default Data;
2 changes: 2 additions & 0 deletions app/contacts/contact/contact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// TODO
// Create dynamic contact display here
33 changes: 33 additions & 0 deletions app/contacts/contact/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use client'
import Data from "@/app/Data/page";
import Image from "next/image";
import Link from "next/link";
import 'bootstrap/dist/css/bootstrap.css'



export default function Contact(prop) {
const id = JSON.parse(prop.searchParams.id)

const contact = Data.get(id)

if (!contact) {
return (
<div className="text-center">
<h1>Error: Contact Not Found</h1>
<Link href={'/contacts'}>Back</Link>
</div>
)
} else {
return (
<div className="text-center">
<h1>Contact Info</h1>
<Link href={'/contacts'}>Back</Link>
<h1>{contact.name}</h1>
<Image src={contact.image_url} alt="Profile Picture" height={300} width={300} />
<h1>{contact.email}</h1>
<h1>{contact.phone_number}</h1>
</div>
)
}
}
73 changes: 73 additions & 0 deletions app/contacts/new/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use client';
import Link from "next/link";
import { useState, useRef } from "react";
import { useRouter } from "next/navigation";
import Data from "@/app/Data/page";
import 'bootstrap/dist/css/bootstrap.css';

export default function NewContact() {
const nameInput = useRef('');
const imgInput = useRef('');
const emailInput = useRef('');
const phoneInput = useRef('');

const router = useRouter();

const [isDisabled, setIsDisabled] = useState(true)
const [errorMessage, setErrorMessage] = useState('')

const addCon = (e) => {
e.preventDefault()
const id = Math.round(Math.random() * 100)

Data.addContact(id, nameInput.current.value, imgInput.current.value, emailInput.current.value, phoneInput.current.value);

nameInput.current.value = '';
imgInput.current.value = '';
emailInput.current.value = '';
phoneInput.current.value = '';

alert('Contact Added')

router.push('/contacts')
}
const renderInputs = (label, type, ref) => {
return (
<div className="form-group">
<label><u>{label}</u></label>
<br />
<input onChange={enableSubmit} required ref={ref} className="input-group-text m-auto" type={type}></input>
<br />
</div>
)
}
const enableSubmit = () => {
const urlValid = imgInput.current.checkValidity();

if (nameInput.current.value === '' || urlValid === false || emailInput.current.value === '' || phoneInput.current.value === '' || imgInput.current.value === '') {
setIsDisabled(true)
if (imgInput.current.value.trim() !== '' && urlValid === false) {
setErrorMessage('Please use a valid image url')
} else {
setErrorMessage('')
}
} else {
setIsDisabled(false)
}
}
return (
<>
<h1 className="text-center p-3">Add New Contact</h1>
<form className="text-center p-3 mx-auto border rounded w-25 p-3">
{renderInputs('Name', 'text', nameInput)}
{renderInputs('Image URL', 'url', imgInput)}
{renderInputs('Email', 'email', emailInput)}
{renderInputs('Phone Number', 'text', phoneInput)}
<button className="btn btn-primary" disabled={isDisabled} onClick={addCon}>Add Contact</button>
<br />
<Link href='/contacts'>Cancel</Link>
<h3 style={{ color: "red" }}>{errorMessage}</h3>
</form>
</>
)
}
35 changes: 35 additions & 0 deletions app/contacts/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use client';
import Link from "next/link";
import ContactList from "../ContactList/page";
import { useState } from 'react'
import Data from "../Data/page";


export default function Contacts() {
const [search, setSearch] = useState(Data.contacts)
const searchCon = (e) => {
const normData = e.target.value.toLowerCase()
if (e.target.value.trim() === '') {
setSearch(Data.contacts)
} else {
const newList = Data.contacts.filter((c) => {
return c.name.toLowerCase().includes(normData)// Normalizes Input and Response
})
setSearch(newList)
}
};
return (
<main>
<div className='text-center'>
<h1 className='display-4'>All Contacts</h1>
<Link className='btn btn-primary' href='/contacts/new'>Add Contact</Link>
</div>
<br />
<div >
<input id="con-search" onChange={searchCon} className="input-group-text m-auto" placeholder="Search Contacts By Name" type="text"></input>
<br />
<ContactList prop={search} />
</div>
</main>
);
};
107 changes: 0 additions & 107 deletions app/globals.css

This file was deleted.

1 change: 0 additions & 1 deletion app/layout.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Inter } from 'next/font/google'
import './globals.css'

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

Expand Down
Loading