Appointment Planner

Hello everyone. I’ve finished this project and wanted to leave my solution hanging in case someone is having some problems!

App.js

import React from "react";
import { Switch, Route, Redirect, NavLink } from "react-router-dom";
import { useState } from 'react';
import { AppointmentsPage } from "./containers/appointmentsPage/AppointmentsPage";
import { ContactsPage } from "./containers/contactsPage/ContactsPage";

function App() {
  // state variables for contacts and appointments 
  const [contacts, setContacts] =  useState([]);
  const [appointments, setAppointments] = useState([]);

  const ROUTES = {
    CONTACTS: "/contacts",
    APPOINTMENTS: "/appointments",
  };

  // functions to add data to contacts and appointments
  const addContact = (name, phone, email ) => {
    setContacts( prev => [...prev, {name, phone, email}]);
  };
  const addAppointment = (title, contact, date, time) => {
    setAppointments( prev =>  [...prev, {title, contact, date, time}]);
  };

  return (
    <>
      <nav>
        <NavLink to={ROUTES.CONTACTS} activeClassName="active">
          Contacts
        </NavLink>
        <NavLink to={ROUTES.APPOINTMENTS} activeClassName="active">
          Appointments
        </NavLink>
      </nav>
      <main>
        <Switch>
          <Route exact path="/">
            <Redirect to={ROUTES.CONTACTS} />
          </Route>
          <Route path={ROUTES.CONTACTS}>
             {/* Add props to ContactsPage */}
            <ContactsPage 
              addContact={addContact}
              contacts={contacts}
              />
          </Route>
          <Route path={ROUTES.APPOINTMENTS}>
            {/* Add props to AppointmentsPage */}
            <AppointmentsPage 
              addAppointment={addAppointment}
              appointments={appointments}
              contacts={contacts}
              />
          </Route>
        </Switch>
      </main>
    </>
  );
}

export default App;

AppointmentsPage.js

import React from "react";
import { useState, useEffect } from 'react';
import { AppointmentForm } from '../../components/appointmentForm/AppointmentForm';
import { TileList } from '../../components/tileList/TileList';

export const AppointmentsPage = (props) => {
  // Define state variables for appointment info
  const appointments = props.appointments;
  const contacts = props.contacts;
  const addAppointment = props.addAppointment;
  // local States
  const [title, setTitle] = useState('');
  const [contact, setContact] = useState('');
  const [date, setDate] = useState('');
  const [time, setTime] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    // Add contact info and clear data 
    addAppointment(title, contact, date, time);
    // reseting values
    setTitle('');
    setContact('');
    setDate('');
    setTime('');
};

  return (
    <div>
      <section>
        <h2>Add Appointment</h2>
        <AppointmentForm 
          title={title}
          setTitle={setTitle}
          contact={contact}
          setContact={setContact}
          date={date}
          setDate={setDate}
          time={time}
          setTime={setTime}
          handleSubmit={handleSubmit}
          contacts={contacts}
        />
      </section>
      <hr />
      <section>
        <h2>Appointments</h2>
        <TileList objArr={appointments}/>
      </section>
    </div>
  );
};

AppointmentForm.js

import React from "react";
import {ContactPicker} from '../contactPicker/ContactPicker';
export const AppointmentForm = ({
  contacts,
  title,
  setTitle,
  contact,
  setContact,
  date,
  setDate,
  time,
  setTime,
  handleSubmit
}) => {
  const getTodayString = () => {
    const [month, day, year] = new Date()
      .toLocaleDateString("en-US")
      .split("/");
    return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")}`;
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text"
        value={title}
        onChange={({target}) => setTitle(target.value)}
      />
      <input 
        type="date"
        value={date}
        min={getTodayString()}
        onChange={({target}) => setDate(target.value)}
      />
      <input 
        type="time"
        value={time}
        onChange={({target}) => setTime(target.value)}
      />
      <ContactPicker 
        contacts={contacts}
        value={contact}
        onChange={({target}) => setContact(target.value)}
      />
      <input type="submit"/>
    </form>
  );
};

ContactsPage.js

import React from "react";
import { useState, useEffect } from 'react';
import { ContactForm } from '../../components/contactForm/ContactForm';
import { TileList } from '../../components/tileList/TileList';

export const ContactsPage = (props) => {
  // Define state variables for contact info and duplicate check
  const contacts = props.contacts;
  const addContact = props.addContact;
  // local states
  const [name, setName] = useState('');
  const [phone, setPhone] = useState('');
  const [email, setEmail] = useState('');
  const [duplicate, setDuplicate] = useState(false);

  const handleSubmit = (e) => {
    e.preventDefault();
    // Add contact info and clear data if the contact name is not a duplicate
    if (!duplicate) {

      addContact(name,phone, email);
      // reseting values
      setName('');
      setPhone('');
      setEmail('');
    }
  };


  // check for contact name in the contacts array variable in props
  useEffect( () => {
    for (const contact of contacts) {
      if (name === contact.name) {
        setDuplicate(true);
      }

      return;
    }
  });

  return (
    <div>
      <section>
        <h2>Add Contact</h2>
        <ContactForm 
          name={name}
          phone={phone}
          email={email}
          setName={setName}
          setPhone={setPhone}
          setEmail={setEmail}
          handleSubmit={handleSubmit}
        />
      </section>
      <hr />
      <section>
        <h2>Contacts</h2>
        <TileList
          objArr={props.contacts}
        />
      </section>
    </div>
  );
};

ContactForm.js

import React from "react";

export const ContactForm = ({
  name,
  setName,
  phone,
  setPhone,
  email,
  setEmail,
  handleSubmit
}) => {
  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text" 
        value={name}
        onChange={({target}) => {setName(target.value)}}
        required
      />
      <input 
        type="tel"
        value={phone}
        pattern="(^\+[0-9]{2}|^\+[0-9]{2}\(0\)|^\(\+[0-9]{2}\)\(0\)|^00[0-9]{2}|^0)([0-9]{9}$|[0-9\-\s]{10}$)"
        onChange={({target}) => {setPhone(target.value)}}
        required
      />
      <input 
        type="email"
        value={email}
        onChange={({target}) => {setEmail(target.value)}}
        required
      />
      <input
        type="submit"
      />
    </form>
  );
};

ContactPicker.js

import React from "react";

export const ContactPicker = (props) => {
  const contacts = props.contacts;
  const onChange = props.onChange;
  
  return (
    <select onChange={onChange}>
      <option value="">Select a contact</option>
      {contacts.map( contact => <option value={contact.name}>{contact.name}</option>)}
    </select>
  
  );
};

TileList.js

import React from "react";
import { Tile } from '../tile/Tile';


export const TileList = ({objArr}) => {
  
  return (
    <div>
      {objArr.map( (value, index) => <Tile value={value} key={index}/>)}
    </div>
  );
};

Tile.js

import React from "react";

export const Tile = ({value}) => {
  const array = Object.values(value);
  return (
    <div className="tile-container">
      {array.map( (data, index) => {
        if (index === 0 ) {
          return <p className="tile-title" key={index}>{data}</p>;
        }
          return <p className="tile" key={index}>{data}</p>;
        })
      }
    </div>
  );
};

Good coding!

4 Likes

thank you, I got stuck it how to make TileList render both appointments and contacts, you saved my life!

2 Likes

Couldn’t have done it without your help on it also!

Hello everyone,
Here is my completed appointment planner app, I customized it a little.
Any feedback is greatly appriciated!
appointment-planner

Howdy!

Here is my appointment planner build.
https://gist.github.com/2862558287fffd83c10243244529b4aa.

I customized the forms a wee bit, making each input to have a designated label so I could utilize default values in the form.

Any feedback is welcomed! If you want to know why I did somethings a certain way, feel free to ask and I will try my best to answer.

2 Likes