Building a Project with JavaScript Objects.
Tags: javascript, programming, beginners, codenewbie
Published: 2021-02-19 19:58:27

Hello World!, this article is a project template. More like a complete project but just Javascript (i.e no HTML or CSS).

I have not been a fan of **JavaScript Objects** and Classes, not that I don't understand the fundamentals but I found it not too necessary to worry about as I considered _Functional Programming_ as a simpler approach. These have been my thoughts for long and all my projects so far were all with functional programming, but when I took the CodeCademy's JavaScript Course; I discovered my love for Object-Oriented Programming, and for me, I think it's way simpler, especially if using **Getters and Setters**.

So after I was done with the **JavaScript Objects** module of the course, there was this project they (CodeCademy) were going to build i.e **Meal Maker**. I couldn't access it as a free user, but I understood the purpose of making the project i.e to make use of _Getters and Setters_ in a real-life project.

There was one problem, I had no idea of what a **Meal Maker** does or how it usually works, but I had a great idea to practice _Getters and Setters_; an **Appointment Booking App**. Brilliant right? Yeah, I know, so what it does is simply book appointments for people with business users.

Say I am Elon Musk (which I am not), I can create an account with this app as such other users can book appointments with me.

Now Elon Musk is not gonna be the only user with a business account, we will use **Factory Functions** (not **Classes**) to duplicate and have any amount of business account we want.

This app may be basic, but it contains all the difficult parts of making an appointment booking app. Have in mind that the purpose of this article is not to show you one of the ways you can make an appointment booking app, but to show you how _Getters and Setters_ can be very handy in projects like this.

If you do not know JavaScript Getters and Setters or _JavaScript Objects_, i recommend going through [CodeCademy's JS Objects Course](https://codecademy.com).

Enough with the writing, let's get to coding. Scroll down to see the complete code or simply visit [GitHub for the code](https://github.com/Elijah-trillionz/appointment-booking-app).

```js
// alert: am tired of using John Doe, i wanna use Elon Musk
const elonMusk = {
  _hoursfree: [10, 12, 9], // currently hard-coded, but will change in time
};
```

The reason for the underscore (`_`) before the `hoursFree` property is because I intentionally do not want that to be accessed directly. A programmer should know that and keep to that. But we would need to access the hours Elon Musk is free, to do that we will use JavaScript Getters i.e

```js
const elonMusk = {
  _hoursFree: [10, 12, 9],

  get hoursFree() {
    return this._hoursFree; // can now be accessed legitimately
  },
};
```

Now we want to add more properties to the elonMusk object

```js
const elonMusk = {
  _hoursFree: [10, 12, 9],
  acceptedPurpose: 'any',
  pendingMeetongs: [], // meetings yet to be approved by Elon Musk
  declinedMeetings: [], // meetings not approved by Elon Musk
  approvedMeetings: [], // meetings approved by Elon Musk
  canceledMeetings: [], // meetings already approved but later canceled maybe something came up
  _feedback: '', // feedback to the booking user (user making the booking)

  get hoursFree() {
    return this._hoursFree;
  },

  get feedBack() {
    return this._feedback); // simply return a feedback
  },
};
```

The `acceptedPurpose` property simply represents the current purpose Elon Musk wants to accept. Let's say the design of the app has in it that the purpose of a meeting can be set weekly or daily as the case may be; by Elon Musk. Say the `acceptedPurpose` options provided by the app is _business, family, fun, or any_

So for now we are assuming Elon Musk is available for any type of meeting be it a business meeting, fun meeting, family meeting. _Currently hard-coded will change later._

Now let's begin using _Setters._ Say we want to book a meeting with Elon Musk, how would we do it

```js
  // still in the elonMusk object, just under the feedBack getter
  set newMeeting(time) {
    if (this._hoursFree.indexOf(time) !== -1) {
      this.pendingMeetings.push(time);
      this._feedback =
        'Your meeting was sent successfully. Elon Musk can now review and approve or decline';
    } else {
      this._feedback = 'Time not suitable for Elon Musk';
    }
  },

// outside of the elonMusk object
elonMusk.newMeeting = 10
console.log(elonMusk.feedBack)
```

This is very basic, there is more to setting a meeting which we will get back to. But first, let's analyze this;

- We checked if the time provided by the user is suitable with Elon Musk by comparing it to his provided free hours.
- If true, we added the time to the `pendingMeetings` array. and gave a feedback.
- If false, we simply return a feedback to the user making this booking.

A meeting should not just contain the time, Elon Musk of course would need more information about this meeting i.e

#### Creating Meetings:

```js
// still in the elonMusk object, just under the feedBack getter
  set newMeeting(meeting) {
    const { name, time, purpose } = meeting;

    if (
      this._hoursFree.indexOf(time) !== -1 &&
      this.acceptedPurpose === 'any'
    ) {
      this.pendingMeetings.push(meeting);

      this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
    } else if (this.acceptedPurpose === purpose.toLowerCase()) {
      this.pendingMeetings.push(meeting);

      this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
    } else {
      this._feedback = `${name}, this meeting is not suitable for Elon Musk`;
    }
  },
  }

// outside of the elonMusk object
const clientMeeting = {id: 10, name: 'Bill Gates', time: 10, purpose: 'fun'};

elonMusk.newMeeting = clientMeeting;
console.log(elonMusk.feedBack);
```

We just made it a little spicy, shouldn't be difficult to comprehend. We included id, name, and purpose to time to make up the meeting object.
The meeting will be sent successfully if;

- the `acceptedPurpose` of Elon Musk is set to any and if the time of meeting from booking user is an item in the `hoursFree` array of Elon Musk.
- the `acceptedPurpose` of Elon Musk is similar to the purpose provided by the booking user

Now let's start approving, declining, and canceling meetings

#### Approving Meetings:

```js
// still in the elonMusk object, right under the newMeeting
  set approveMeeting(id) {
    const previewingMeeting = this.pendingMeetings.filter((meeting) => {
      return meeting.id === id; // filter out a meeting with its id and preview
    })[0];

    // approve previewing meeting and mark the previewingMeeting.time as a booked hour
    this.approvedMeetings.push(previewingMeeting); // note that approvedMeetings with a 'd' is the array while approveMeeting without a 'd' is the setter
    this._hoursFree.splice(this._hoursFree.indexOf(previewingMeeting.time), 1);

    this._feedback = `${previewingMeeting.name}, your meeting has been approved, time of meeting: ${previewingMeeting.time}`;
  },

// outside the elonMusk object;
elonMusk.newMeeting = clientMeeting //clientMeeting already declared before, scroll up
elonMusk.approveMeeting = clientMeeting.id;
console.log(elonMusk.feedBack);
```

The `approveMeeting` setter is not having any conditional statement because it is meant to go straight to the point that is; approves the meeting. So this can be attributed to a button that says 'Approve Meeting', and when clicked by Elon, the meeting is approved and sent to the `approvedMeetings` array.

If a meeting is approved, then it means a particular hour of Elon Musk has been booked. For that, we should endeavor to remove that booked hour to avoid two or more meetings booked to a particular hour. So for that, we used the splice method to remove that hour. You can log the current `hoursFree` in the console to see the result of that i.e `console.log(elonMusk.hoursFree)`

#### Declining Meetings:

```js
// still in the elonMusk object, right under the approveMeeting
  set declineMeeting(id) {
    const previewingMeeting = this.pendingMeetings.filter((meeting) => {
      return meeting.id === id; // filter out a meeting with its id and preview
    })[0];


    this.declinedMeetings.push(previewingMeeting); // note that declinedMeetings with a 'd' is the array while declineMeeting without a 'd' is the setter

    this._feedback = `${previewingMeeting.name}, your meeting was declined for reasons best known to Elon Musk`;
  },

// outside the elonMusk object;
elonMusk.newMeeting = clientMeeting //clientMeeting already declared before, scroll up
elonMusk.declineMeeting = clientMeeting.id;
console.log(elonMusk.feedBack);
```

Something to note is that the `delineMeeting` setter is a manual declining by Elon Musk, automatic declining was never added to the `pendingBookings` array. In other words, bookings that were added to the `pendingBookings` array are bookings that needed the  business account owner (Elon Musk now) to review.

Automatic declining were done when either the time or purpose was not suitable for Elon Musk as provided in the `hoursFree` array and the `acceptedPurpose` string.

#### Canceling Meetings:

```js
// still in the elonMusk object, right under the declineMeeting
    set cancelMeeting(id) {
    // the meeting has to be approved first
    const previewingMeeting = this.approvedMeetings.filter((meeting) => {
      return meeting.id === id;
    })[0];

    this._hoursFree.push(previewingMeeting.time); // make the hour of the canceled meeting a free hour
    this.canceledMeetings.push(previewingMeeting); // add canceled meeting to the array of canceled meetings
    this.approvedMeetings.splice(previewingMeeting, 1); // remove canceled meeting from approved meeting array

    this._feedback = `${previewingMeeting.name}, your meeting with Elon Musk scheduled at ${previewingMeeting.time} has been canceled by Elon Musk. Don't ask me why? am not Elon Musk.`;
  },

// outside the elonMusk object
elonMusk.newMeeting = clientMeeting; //clientMeeting already declared above
elonMusk.approveMeeting = clientMeeting.id; // approve meeting first
elonMusk.cancelMeeting = clientMeeting.id;
console.log(elonMusk.feedBack);
```

Pretty straightforward. One thing you could add is a setter to remove free hours from the `hoursFree` array. If a meeting got canceled, the scheduled hour is automatically regarded as a free hour; but if Elon Musk doesn't want that hour to be free anymore He can simply click a button to remove that hour from being free (manually).

#### Requesting Free Hour Cancelation:

```js
// still in the elonMusk object, right under the cancelMeeting
  set requestHourCancelation(hr) {
    if (this._hoursFree.indexOf(hr) !== -1) {
      this._hoursFree.splice(this._hoursFree.indexOf(hr), 1);
    }
  }

// outside of the elonMusk object
elonMusk.requestHourCancelation = 10;
console.log(elonMusk.hoursFree);
```

#### Elon Musk Booking Object:

```js
const elonMusk = {
  _hoursFree: [10, 12, 9],
  acceptedPurpose: 'family',
  pendingMeetings: [], // meetings yet to be approved by Elon Musk
  declinedMeetings: [], // meetings not approved by Elon Musk
  approvedMeetings: [], // meetings approved by Elon Musk
  canceledMeetings: [], // meetings already approved but later canceled maybe something came up
  _feedback: '', // feedback to the booking user (user making the booking)

  get hoursFree() {
    return this._hoursFree;
  },

  get feedBack() {
    this._feedback; // simply return a feedback.
  },

  set newMeeting(meeting) {
    const { name, time, purpose } = meeting;

    if (
      this._hoursFree.indexOf(time) !== -1 &&
      this.acceptedPurpose === 'any'
    ) {
      this.pendingMeetings.push(meeting);

      this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
    } else if (this.acceptedPurpose === purpose.toLowerCase()) {
      this.pendingMeetings.push(meeting);

      this._feedback = `${name}, your meeting was sent successfully. Elon Musk can now review and approve or decline`;
    } else {
      this._feedback = `${name}, this meeting is not suitable for Elon Musk`;
    }
  },

  set approveMeeting(id) {
    const previewingMeeting = this.pendingMeetings.filter((meeting) => {
      return meeting.id === id;
    })[0];

    // approve previewing meeting and mark the previewingMeeting.time as a booked hour
    this.approvedMeetings.push(previewingMeeting); // note that approvedMeetings is the array while approveMeeting is the setter
    this._hoursFree.splice(this._hoursFree.indexOf(previewingMeeting.time), 1);

    this._feedback = `${previewingMeeting.name}, your meeting has been approved, time of meeting: ${previewingMeeting.time}`;
  },

  set declineMeeting(id) {
    const previewingMeeting = this.pendingMeetings.filter((meeting) => {
      return meeting.id === id;
    })[0];

    this.declinedMeetings.push(previewingMeeting); // note that declinedMeetings is the array while declineMeeting is the setter

    this._feedback = `${previewingMeeting.name}, your meeting was declined for reasons best known to Elon Musk`;
  },

  set cancelMeeting(id) {
    // the meeting has to be approved first
    const previewingMeeting = this.approvedMeetings.filter((meeting) => {
      return meeting.id === id;
    })[0];

    this._hoursFree.push(previewingMeeting.time); // make the hour of the canceled meeting a free hour
    this.canceledMeetings.push(previewingMeeting); // add canceled meeting to the array of canceled meetings
    this.approvedMeetings.splice(previewingMeeting, 1); // remove canceled meeting from approved meeting array

    this._feedback = `${previewingMeeting.name}, your meeting with Elon Musk scheduled at ${previewingMeeting.time} has been canceled by Elon Musk. Don't ask me why? am not Elon Musk.`;
  },

  set requestHourCancelation(hr) {
    if (this._hoursFree.indexOf(hr) !== -1) {
      this._hoursFree.splice(this._hoursFree.indexOf(hr), 1);
    }
  },
};
```

#### Have multiple business owners:

Say we want Bill Gate to have his business account and maybe Larry Page as well, we don't have to copy the codes in the `elonMusk` object and start pasting; that's just unnecessary. Since the getters and setters in the `elonMusk` object are going to be similar to the others (of course they should be), we would simply make instances for every user.

Usually, this can be done with JavaScript classes, but we will not use classes here (but we will in the future), instead, we will use factory functions which I recently learned from _Codecademy.com_.
This is how it's done.

```js
// make a function and return all properties, getters and setters in the elonMusk object
function businessUser(businessName, _hoursFree, acceptedPurpose) {
  // the three parameters above are properties of this object that are going to vary with different business users
  return {
    businessName,
    _hoursFree,
    acceptedPurpose,
    pendingMeetings: [], // meetings yet to be approved by Elon Musk
    declinedMeetings: [], // meetings not approved by Elon Musk
    approvedMeetings: [], // meetings approved by Elon Musk
    canceledMeetings: [], // meetings already approved but later canceled maybe something came up
    _feedback: '', // feedback to the booking user (user making the booking)

    get hoursFree() {
      return this._hoursFree;
    },

    get feedBack() {
      this._feedback; // simply return a feedback.
    },

    set newMeeting(meeting) {
      const { name, time, purpose } = meeting;

      if (
        this._hoursFree.indexOf(time) !== -1 &&
        this.acceptedPurpose === 'any'
      ) {
        this.pendingMeetings.push(meeting);

        this._feedback = `${name}, your meeting was sent successfully. ${this.businessName} can now review and approve or decline`;
      } else if (this.acceptedPurpose === purpose.toLowerCase()) {
        this.pendingMeetings.push(meeting);

        this._feedback = `${name}, your meeting was sent successfully. ${this.businessName} can now review and approve or decline`;
      } else {
        this._feedback = `${name}, this meeting is not suitable for ${this.businessName}`;
      }
    },

    set approveMeeting(id) {
      const previewingMeeting = this.pendingMeetings.filter((meeting) => {
        return meeting.id === id;
      })[0];

      // approve previewing meeting and mark the previewingMeeting.time as a booked hour
      this.approvedMeetings.push(previewingMeeting); // note that approvedMeetings is the array while approveMeeting is the setter
      this._hoursFree.splice(
        this._hoursFree.indexOf(previewingMeeting.time),
        1
      );

      this._feedback = `${previewingMeeting.name}, your meeting has been approved, time of meeting: ${previewingMeeting.time}`;
    },

    set declineMeeting(id) {
      const previewingMeeting = this.pendingMeetings.filter((meeting) => {
        return meeting.id === id;
      })[0];

      this.declinedMeetings.push(previewingMeeting); // note that declinedMeetings is the array while declineMeeting is the setter

      this._feedback = `${previewingMeeting.name}, your meeting was declined for reasons best known to ${this.businessName}`;
    },

    set cancelMeeting(id) {
      // the meeting has to be approved first
      const previewingMeeting = this.approvedMeetings.filter((meeting) => {
        return meeting.id === id;
      })[0];

      this._hoursFree.push(previewingMeeting.time); // make the hour of the canceled meeting a free hour
      this.canceledMeetings.push(previewingMeeting); // add canceled meeting to the array of canceled meetings
      this.approvedMeetings.splice(previewingMeeting, 1); // remove canceled meeting from approved meeting array

      this._feedback = `${previewingMeeting.name}, your meeting with ${this.businessName} scheduled at ${previewingMeeting.time} has been canceled by ${this.businessName}. Don't ask me why? am not ${this.businessName}.`;
    },

    set requestHourCancelation(hr) {
      if (this._hoursFree.indexOf(hr) !== -1) {
        this._hoursFree.splice(this._hoursFree.indexOf(hr), 1);
      }
    },
  };
}
```

Everything in the businessUser function is all we need to create a million functioning business accounts. Let's try creating three and accessing their properties

```js
const larryPage = businessUser('Larry Page', [15, 12, 9], 'any');
console.log(larryPage.hoursFree);
const willSmith = businessUser('Will Smith', [9, 10], 'fun');
console.log(willSmith.hoursFree);
const billGates = businessUser(
  'Bill Gates',
  [11, 10, 9, 8, 7, 6, 5, 4, 3, 2],
  'any'
); // Mr. Gates is always free.
console.log(billGates.hoursFree);
```
Get the code on GitHub, [Building a Project with JavaScript Objects](https://github.com/Elijah-trillionz/appointment-booking-app). Don't forget to leave a star.

### Conclusion

It is important to note that all of the setters above can be replaced with methods and will still work fine, but since we are focusing on setters we might as well use it all through. I intend to make a library on my next post using JavaScript Classes and Methods, it is completely different from this and more advanced and enjoyable than this. It's gonna be fun.


I hope you learned a lot as I did. Heads up, I have something (a project) awesome coming your way soon as a developer (you're gonna love it). Thanks for reading, don't forget to leave your comments below if you have any complaints or stories (I love stories), also don't forget to share with your colleagues. If you wish to support me then you can [buy me a coffee](https://www.buymeacoffee.com/elijahtrillionz). I appreciate.