Skip to content

This is a solution to the Dine Website Challenge challenge on Frontend Mentor using Angular.

Notifications You must be signed in to change notification settings

Chanda-Abdul/Frontend-Mentor-Angular-Dine-Restaurant

Repository files navigation

Frontend Mentor - Dine Website Challenge solution

This is a solution to the Dine Website Challenge challenge on Frontend Mentor. Frontend Mentor challenges help you improve your coding skills by building realistic projects.

Table of contents

Overview

Links

The challenge

Users should be able to:

  • View the optimal layout for each page depending on their device's screen size
    • Mobile @ 375px
    • Tablet @ 768px
    • Desktop @ 1440px
  • See hover states for all interactive elements throughout the site
  • See the correct content for the Family Gatherings, Special Events, and Social Events section when the user clicks each tab
  • Receive an error message when the booking form is submitted if:
    • The Name or Email Address fields are empty should show "This field is required"
    • The Email Address is not formatted correctly should show "Please use a valid email address"
    • Any of the Pick a date or Pick a time fields are empty should show "This field is incomplete"

Screenshots

Mobile Screenshots @ 375px

Home

Event Slides

Booking

Error States

Valid Form

Confirmation after form submission

Tablet Screenshots @ 768px

Home

Event Slides

Booking

Error States

Valid Form

Confirmation after form submission

Desktop Screenshots @ 1440px

Home

Event Slides

Booking

Error States

Valid Form

Confirmation after form submission

My process

Built with

  • Angular (JavaScript framework)
    • Angular Material
    • Reactive Forms 😭
    • RxJs - library for composing asynchronous and event-based programs by using observable sequences.
    • TypeScript
    • JavaScript
      • Moment.js - To validate reservation dates and times
  • Figma
  • Sass/CSS custom properties(❗️this project required ALOT of CSS)
  • Semantic HTML5 markup

What I learned

How to build Angular Reactive Forms with custom validation

I created the reservation form in the booking component using Angular Reactive forms. I also added custom validation for input and select

rezzo-form.component.html

<form novalidate
        class="rezForm"
        (ngSubmit)="saveReservation()"
        [formGroup]="rezzoForm">
        ...
        <!-- Name Input -->
      <input class="form-control form-input full"
             type="text"
             placeholder="Name"
             formControlName="name"
             [ngClass]="{'alert-danger': nameValidationErrorMessage }" />
      <span class="alert-danger">
        {{nameValidationErrorMessage}}
      </span>
          ...

  <div class="group">
        <!-- Date Input -->
        <div class="error">
          <h3 
          [ngClass]="{'alert-danger': 
          dateValidationErrorMessage }">Pick a Date</h3> 
          <span class="alert-danger">{{dateValidationErrorMessage}}</span>
        </div>
        <div formGroupName="dateGroup"
             class="dates">
          <!-- Month Select -->
          <select formControlName="month"
                  type="text"
                  class="form-control form-select small date"
                  [ngClass]="{'alert-danger': dateValidationErrorMessage }">
            <option disabled>MM</option>
            <option *ngFor="let month of months">
              {{ month }}
            </option>
          </select>
              ...
        </div>
      </div>
      <span class="alert-danger mobile">{{dateValidationErrorMessage}}</span>
          ...
          <button class="btn btn-light"
              type="submit"
              [disabled]="!rezzoForm.valid"> Make
        Reservation</button>
    </div>

Custom validation in the component class rezzo-form.component.ts

private nameValidationMessages: any = {
    required: 'Please enter your name.',
    minlength: 'Name must be longer than 4 characters.'
  }
...

this.rezzoForm = this.fb.group({
  name: ['', [Validators.required, Validators.minLength(4)]],
  ...
});

...

const nameControl = this.rezzoForm.get('name');
nameControl.valueChanges.pipe(
  debounceTime(1000)
  ).subscribe(
    (value: any) =>
    this.setNameValidationErrorMessage(nameControl));
...

setNameValidationErrorMessage(n: AbstractControl): void {
    this.nameValidationErrorMessage = '';
    if ((n.touched || n.dirty) && n.errors) {
      this.nameValidationErrorMessage = Object.keys(n.errors).map(
        key => this.nameValidationMessages[key]).join(' ')
    }
  }
...

Creating a custom component to display responsive images

This project contained many images that would change at each breakpoint. I created a seperate component to render images responsively, using Attribute Binding

The template

picture-responsive.html

<picture>
  <source media="(min-width: 900px)"
          srcset='/assets/images/homepage/{{imageTitle}}-desktop.jpg'>
  <source media="(min-width: 600px)"
          srcset='/assets/images/homepage/{{imageTitle}}-tablet.jpg'>
  <img src='/assets/images/homepage/{{imageTitle}}-mobile.jpg' />
</picture>

The component class

<app-picture-responsive *ngIf="selectedEvent"
  imageTitle="{{selectedEvent.imageTitle}}"
  class="event-photo"></app-picture-responsive>

The data

...
EventItem[] = [
  {
    id: 1,
    ...
    imageTitle: "family-gathering",
    mobileImage: "../assets/images/homepage/family-gathering-mobile.jpg",
    tabletImage: "../assets/images/homepage/family-gathering-tablet.jpg",
    desktopImage: "../assets/images/homepage/family-gathering-desktop.jpg"
  },
  ...

Moment.js library for custom form validation

I used the Moment.js library to validate the date and time selects before displaying error messages

rezzo-form.component.ts

...

setDateValidationErrorMessage(month, day, year): void {
  this.dateValidationErrorMessage = '';
  let now = moment();
  let reservation = moment([year.value, moment(month.value, 'MMM').month(), day.value]);
  let later = moment().add(6, 'months');

  if (!reservation.isValid() || now > reservation || reservation > later) {
    this.dateValidationErrorMessage = 'Please select a valid date within the next 6 months'
  }
}
...

Continued development

This Dine project would be a good opportunity to add several useful/interesting features. Usually it is challenging to create ideas for extras to add to these projects. A few features I would like to add are listed below.

Features to Add

Cool animations, this could be a good project to practice parallex, and play with Angular or CSS animations

Authenticate/Authorization with ability to update

  • Add authentication /Authorization
  • Login/logout, with a password, for managers/admins so that they can update menu options, reservations, and events
    • view/edit menu options
    • view/edit menu event options
    • view/edit menu reservations
  • button? reset to default menu/event data default. for testing purposes

Authenticate/Authorization with ability to view only

  • add a view only option for admins to view menu, reservations, and events

Menu Page

  • add menu component to show list of all current offerings.

About page

  • add about chef/restaraunt section/page

Event Booking Component

  • add event booking component so that users can book events, similar to the reservation component

Useful resources

Author

Acknowledgments