{"id":20178704,"url":"https://github.com/chanda-abdul/frontend-mentor-angular-dine-restaurant","last_synced_at":"2026-04-13T13:31:58.357Z","repository":{"id":41377550,"uuid":"508908367","full_name":"Chanda-Abdul/Frontend-Mentor-Angular-Dine-Restaurant","owner":"Chanda-Abdul","description":"This is a solution to the Dine Website Challenge challenge on Frontend Mentor using Angular.","archived":false,"fork":false,"pushed_at":"2022-12-12T23:11:14.000Z","size":62861,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-17T05:32:24.231Z","etag":null,"topics":["angular","css","moment-js","reactive-forms","rxjs","sass","typescript"],"latest_commit_sha":null,"homepage":"https://phenomenal-crisp-7a42d8.netlify.app/","language":"SCSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Chanda-Abdul.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-06-30T02:33:48.000Z","updated_at":"2022-12-12T22:15:51.000Z","dependencies_parsed_at":"2023-01-28T02:45:53.460Z","dependency_job_id":null,"html_url":"https://github.com/Chanda-Abdul/Frontend-Mentor-Angular-Dine-Restaurant","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Chanda-Abdul/Frontend-Mentor-Angular-Dine-Restaurant","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FFrontend-Mentor-Angular-Dine-Restaurant","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FFrontend-Mentor-Angular-Dine-Restaurant/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FFrontend-Mentor-Angular-Dine-Restaurant/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FFrontend-Mentor-Angular-Dine-Restaurant/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Chanda-Abdul","download_url":"https://codeload.github.com/Chanda-Abdul/Frontend-Mentor-Angular-Dine-Restaurant/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chanda-Abdul%2FFrontend-Mentor-Angular-Dine-Restaurant/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31754850,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T13:27:56.013Z","status":"ssl_error","status_checked_at":"2026-04-13T13:21:23.512Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","css","moment-js","reactive-forms","rxjs","sass","typescript"],"created_at":"2024-11-14T02:23:03.806Z","updated_at":"2026-04-13T13:31:58.333Z","avatar_url":"https://github.com/Chanda-Abdul.png","language":"SCSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Frontend Mentor - Dine Website Challenge solution\n\n![](./src/assets/preview.jpg)\n\nThis is a solution to the [Dine Website Challenge challenge on Frontend Mentor](https://www.frontendmentor.io/challenges/dine-restaurant-website-yAt7Vvxt7). Frontend Mentor challenges help you improve your coding skills by building realistic projects.\n\n## Table of contents\n\n- [Overview](#overview)\n  - [Links](#links)\n  - [The challenge](#the-challenge)\n  - [Screenshots](#screenshots)\n- [My process](#my-process)\n  - [Built with](#built-with)\n  - [What I learned](#what-i-learned)\n  - [Continued development](#continued-development)\n  - [Useful resources](#useful-resources)\n- [Author](#author)\n- [Acknowledgments](#acknowledgments)\n\n# Overview\n## Links\n\n- Solution URL: [Github Solution](https://github.com/Chanda-Abdul/Frontend-Mentor-Angular-Dine-Restaurant-Website-Challenge)\n- Live Site URL: [Live Site ](https://phenomenal-crisp-7a42d8.netlify.app/)\n## The challenge\n\n### Users should be able to:\n\n- [x] View the optimal layout for each page depending on their device's screen size\n  - [x] Mobile @ `375px`\n  - [x] Tablet @ `768px`\n  - [x] Desktop @ `1440px`\n- [x] See hover states for all interactive elements throughout the site\n- [x] See the correct content for the \u003ci\u003eFamily Gatherings\u003c/i\u003e, \u003ci\u003eSpecial Events\u003c/i\u003e, and \u003ci\u003eSocial Events\u003c/i\u003e section when the user clicks each tab\n- [x] Receive an error message when the booking form is submitted if:\n  - [x] The `Name` or `Email Address` fields are empty should show \u003cb\u003e\"This field is required\"\u003c/b\u003e\n  - [x] The `Email Address` is not formatted correctly should show \u003cb\u003e\"Please use a valid email address\"\u003c/b\u003e\n  - [x] Any of the `Pick a date` or `Pick a time` fields are empty should show \u003cb\u003e\"This field is incomplete\"\u003c/b\u003e\n\n## Screenshots\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003e Mobile Screenshots @ 375px\u003c/b\u003e\u003c/summary\u003e\n\n### Home\n\u003cimg src=\"src/assets/screens/mobile_home_initial.png\" width=\"375px\"/\u003e\n\n### Event Slides\n\u003cimg src=\"src/assets/screens/mobile_home_slide_1.png\" width=\"375px\"/\u003e\n\u003cimg src=\"src/assets/screens/mobile_home_slide_2.png\"  width=\"375px\"/\u003e\n\n\u003cimg src=\"src/assets/screens/mobile_home_slide_3.png\" width=\"375px\"/\u003e\n\n### Booking\n\u003cimg src=\"src/assets/screens/mobile_booking_initial.png\" width=\"375px\"/\u003e\n\n### Error States\n\u003cimg src=\"src/assets/screens/mobile_booking_error.png\" width=\"375px\"/\u003e\n\n### Valid Form\n\u003cimg src=\"src/assets/screens/mobile_booking_valid.png\" width=\"375px\"/\u003e\n\n### Confirmation after form submission\n\u003cimg src=\"src/assets/screens/mobile_booking_confirm.png\"  width=\"375px\"/\u003e\n\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eTablet Screenshots @ 768px\u003c/b\u003e\u003c/summary\u003e\n\n\n### Home\n\n\u003cimg src=\"src/assets/screens/mobile_home_initial.png\"  width=\"768px\"/\u003e\n\n### Event Slides\n\u003cimg src=\"src/assets/screens/tablet_home_slide_1.png\" width=\"768px\"/\u003e\n\u003cimg src=\"src/assets/screens/tablet_home_slide_2.png\"  width=\"768px\"/\u003e\n\n\u003cimg src=\"src/assets/screens/tablet_home_slide_3.png\"  width=\"768px\"/\u003e\n\n### Booking\n\u003cimg src=\"src/assets/screens/tablet_booking_initial.png\"  width=\"768px\"/\u003e\n\n### Error States\n\u003cimg src=\"src/assets/screens/tablet_booking_error.png\"  width=\"768px\"/\u003e\n\n### Valid Form\n\u003cimg src=\"src/assets/screens/tablet_booking_valid.png\"  width=\"768px\"/\u003e\n\n### Confirmation after form submission\n\u003cimg src=\"src/assets/screens/tablet_booking_confirm.png\"  width=\"768px\"/\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eDesktop Screenshots @ 1440px\u003c/b\u003e\u003c/summary\u003e\n\n###  Home\n\u003cimg src=\"src/assets/screens/desktop_home_initial.png\" width=\"\" height=\"100%\"/\u003e\n\n### Event Slides\n\u003cimg src=\"src/assets/screens/desktop_home_slide_1.png\" /\u003e\n\n\u003cimg src=\"src/assets/screens/desktop_home_slide_2.png\" /\u003e\n\n\u003cimg src=\"src/assets/screens/desktop_home_slide_3.png\" width=\"600px\"/\u003e\n\n### Booking\n\u003cimg src=\"src/assets/screens/desktop_booking_initial.png\" width=\"600px\"/\u003e\n\n### Error States\n\u003cimg src=\"src/assets/screens/desktop_booking_error.png\" width=\"600px\"/\u003e\n\n### Valid Form\n\u003cimg src=\"src/assets/screens/desktop_booking_valid.png\" width=\"600px\"/\u003e\n\n### Confirmation after form submission\n\u003cimg src=\"src/assets/screens/desktop_booking_confirm.png\"/\u003e\n\n\u003c/details\u003e\n\n\n\n## My process\n\n### Built with\n\n- \u003cb\u003e[Angular](https://angular.io/)\u003c/b\u003e (\u003cb\u003eJavaScript\u003c/b\u003e framework)\n  - \u003cs\u003e[Angular Material](https://material.angular.io/)\u003c/s\u003e\n  - Reactive Forms 😭\n  - [RxJs](https://rxjs.dev/guide/overview) - library for composing asynchronous and event-based programs by using observable sequences.\n  - TypeScript\n  - JavaScript\n    - ⏰ [Moment.js ](https://momentjs.com/docs) - To validate reservation dates and times\n- \u003cb\u003eFigma\u003c/b\u003e\n- \u003cb\u003eSass/CSS\u003c/b\u003e custom properties(❗️this project required \u003ci\u003eALOT\u003c/i\u003e of CSS)\n  - \u003cs\u003e\u003cb\u003e[fxLayout API](https://github.com/angular/flex-layout/wiki/fxLayout-API)\u003c/b\u003e Angular Flexbox API\u003c/s\u003e\n  - \u003cb\u003eMobile-first\u003c/b\u003e workflow\n- Semantic \u003cb\u003eHTML5\u003c/b\u003e markup\n\n\n## What I learned\n\n## How to build Angular Reactive Forms with custom validation\nI created the reservation form in the `booking` component using [Angular Reactive forms](https://angular.io/guide/reactive-forms).  I also added custom validation for `input` and `select`\n### `rezzo-form.component.html`\n```html\n\u003cform novalidate\n        class=\"rezForm\"\n        (ngSubmit)=\"saveReservation()\"\n        [formGroup]=\"rezzoForm\"\u003e\n        ...\n        \u003c!-- Name Input --\u003e\n      \u003cinput class=\"form-control form-input full\"\n             type=\"text\"\n             placeholder=\"Name\"\n             formControlName=\"name\"\n             [ngClass]=\"{'alert-danger': nameValidationErrorMessage }\" /\u003e\n      \u003cspan class=\"alert-danger\"\u003e\n        {{nameValidationErrorMessage}}\n      \u003c/span\u003e\n          ...\n\n  \u003cdiv class=\"group\"\u003e\n        \u003c!-- Date Input --\u003e\n        \u003cdiv class=\"error\"\u003e\n          \u003ch3 \n          [ngClass]=\"{'alert-danger': \n          dateValidationErrorMessage }\"\u003ePick a Date\u003c/h3\u003e \n          \u003cspan class=\"alert-danger\"\u003e{{dateValidationErrorMessage}}\u003c/span\u003e\n        \u003c/div\u003e\n        \u003cdiv formGroupName=\"dateGroup\"\n             class=\"dates\"\u003e\n          \u003c!-- Month Select --\u003e\n          \u003cselect formControlName=\"month\"\n                  type=\"text\"\n                  class=\"form-control form-select small date\"\n                  [ngClass]=\"{'alert-danger': dateValidationErrorMessage }\"\u003e\n            \u003coption disabled\u003eMM\u003c/option\u003e\n            \u003coption *ngFor=\"let month of months\"\u003e\n              {{ month }}\n            \u003c/option\u003e\n          \u003c/select\u003e\n              ...\n        \u003c/div\u003e\n      \u003c/div\u003e\n      \u003cspan class=\"alert-danger mobile\"\u003e{{dateValidationErrorMessage}}\u003c/span\u003e\n          ...\n          \u003cbutton class=\"btn btn-light\"\n              type=\"submit\"\n              [disabled]=\"!rezzoForm.valid\"\u003e Make\n        Reservation\u003c/button\u003e\n    \u003c/div\u003e\n```\n### Custom validation in the component class `rezzo-form.component.ts`\n```ts\n\nprivate nameValidationMessages: any = {\n    required: 'Please enter your name.',\n    minlength: 'Name must be longer than 4 characters.'\n  }\n...\n\nthis.rezzoForm = this.fb.group({\n  name: ['', [Validators.required, Validators.minLength(4)]],\n  ...\n});\n\n...\n\nconst nameControl = this.rezzoForm.get('name');\nnameControl.valueChanges.pipe(\n  debounceTime(1000)\n  ).subscribe(\n    (value: any) =\u003e\n    this.setNameValidationErrorMessage(nameControl));\n...\n\nsetNameValidationErrorMessage(n: AbstractControl): void {\n    this.nameValidationErrorMessage = '';\n    if ((n.touched || n.dirty) \u0026\u0026 n.errors) {\n      this.nameValidationErrorMessage = Object.keys(n.errors).map(\n        key =\u003e this.nameValidationMessages[key]).join(' ')\n    }\n  }\n...\n```\n## Creating a custom component to display responsive images\nThis project contained many images that would change at each breakpoint.  I created a seperate component to render images responsively, using [Attribute Binding](https://angular.io/guide/attribute-binding)\n### The template\n`picture-responsive.html`\n```html\n\u003cpicture\u003e\n  \u003csource media=\"(min-width: 900px)\"\n          srcset='/assets/images/homepage/{{imageTitle}}-desktop.jpg'\u003e\n  \u003csource media=\"(min-width: 600px)\"\n          srcset='/assets/images/homepage/{{imageTitle}}-tablet.jpg'\u003e\n  \u003cimg src='/assets/images/homepage/{{imageTitle}}-mobile.jpg' /\u003e\n\u003c/picture\u003e\n```\n### The component class\n```ts\n\u003capp-picture-responsive *ngIf=\"selectedEvent\"\n  imageTitle=\"{{selectedEvent.imageTitle}}\"\n  class=\"event-photo\"\u003e\u003c/app-picture-responsive\u003e\n```\n\n### The data\n\n```ts\n\n...\nEventItem[] = [\n  {\n    id: 1,\n    ...\n    imageTitle: \"family-gathering\",\n    mobileImage: \"../assets/images/homepage/family-gathering-mobile.jpg\",\n    tabletImage: \"../assets/images/homepage/family-gathering-tablet.jpg\",\n    desktopImage: \"../assets/images/homepage/family-gathering-desktop.jpg\"\n  },\n  ...\n  ```\n## ⏰ [Moment.js](https://momentjs.com/docs) library for custom form validation\nI used the [Moment.js](https://momentjs.com/docs) library to validate the `date` and `time` selects before displaying error messages\n\u003cimg src=\"/src/assets/screens/date_error_msg.png\" /\u003e\n\n\n### `rezzo-form.component.ts`\n\n```ts\n...\n\nsetDateValidationErrorMessage(month, day, year): void {\n  this.dateValidationErrorMessage = '';\n  let now = moment();\n  let reservation = moment([year.value, moment(month.value, 'MMM').month(), day.value]);\n  let later = moment().add(6, 'months');\n\n  if (!reservation.isValid() || now \u003e reservation || reservation \u003e later) {\n    this.dateValidationErrorMessage = 'Please select a valid date within the next 6 months'\n  }\n}\n...\n  ```\n\n## Continued development\nThis \u003cb\u003eDine\u003c/b\u003e 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.\n### Features to Add\n\n➕ \u003cb\u003e Cool animations\u003c/b\u003e, this could be a good project to practice [parallex](https://webflow.com/blog/parallax-scrolling), and play with Angular or CSS animations\n\n➕ \u003cb\u003e Authenticate/Authorization with ability to update\u003c/b\u003e\n\n  - [ ] Add authentication /Authorization\n  - [ ] Login/logout, with a password, for managers/admins so that they can update menu options, reservations, and events\n    - [ ] view/edit menu options\n    - [ ] view/edit menu event options\n    - [ ] view/edit menu reservations\n  - [ ] button? reset to default menu/event data default. for testing purposes\n  \n➕ \u003cb\u003e Authenticate/Authorization with ability to view only\u003c/b\u003e\n  - [ ] add a view only option for admins to view menu, reservations, and events\n\n➕ \u003cb\u003e Menu Page\u003c/b\u003e\n  - [ ] add menu component to show list of all current offerings.\n\u003c!-- many resturaunt sites have a menu for users to view. --\u003e\n➕ \u003cb\u003e About page\u003c/b\u003e\n  - [ ] add about chef/restaraunt section/page\n\n➕ \u003cb\u003e Event Booking Component\u003c/b\u003e\n  - [ ] add event booking component so that users can book events, similar to the reservation component\n#\n### Useful resources\n\n- 🙌🏾 [Angular Reactive Forms By Deborah Kurata(Pluralsight Course)](https://app.pluralsight.com/library/courses/angular-2-reactive-forms/table-of-contents) - This is an amazing YouTube which helped me understand how to build Reactive Forms with Angular. I'd recommend it to anyone still learning this concept.\n- ⏰ [Moment.js ](https://momentjs.com/docs) - To validate reservation dates and times\n- [Reactive forms](https://angular.io/guide/reactive-forms) - This helped me... I really liked this pattern and will use it going forward.\n- 🙌🏾 [Angular Reactive Forms in 10 Minutes](https://youtu.be/MMP_OcjWNQo) - This is an amazing YouTube which helped me finally understand how to build Reactive Forms with Angular. I'd recommend it to anyone still learning this concept.\n- [/angular/flex-layout](https://github.com/angular/flex-layout) - \u003cs\u003eThis helped me because it's much easier to incorporate \u003cb\u003eFlexbox\u003c/b\u003e into a \u003cb\u003etemplate\u003c/b\u003e than a \u003cb\u003eCSS\u003c/b\u003e stylesheet 🤔 . I really liked this pattern and will use it going forward.\u003c/s\u003e Now, I prefer to create flex styles with \u003ci\u003eSass\u003c/i\u003e\n- [Udemy: Angular (Full App) with Angular Material, Angularfire \u0026 NgRx Created by Maximilian Schwarzmüller](https://www.udemy.com/share/101WvC3@iwU-zs0EjLuBHrh2IFqrITl0TXzocf5BeqTXM5rBHhVGmHco65hhIW8VnrsMxYA=/) - Great Tutorials. Would Recommend.\n- [Managing Image Breakpoints With Angular](https://www.smashingmagazine.com/2019/02/image-breakpoints-angular/) - Yes. Then I moved the resonsive images into a seperate component👌🏽\n- [Using forms for user input](https://angular.io/start/start-forms) - 🤷🏽‍♀️\n- [Angular 13 Select Dropdown with Reactive Forms Examples](https://www.positronx.io/angular-select-dropdown-with-reactive-forms-examples/) - This is an amazing article which helped me finally understand XYZ. I'd recommend it to anyone still learning this concept.\n\n## Author\n\n- Frontend Mentor - [@Chanda-Abdul](https://www.frontendmentor.io/profile/Chanda-Abdul)\n- Website - [Chanda Codes](https://chandacodes.com/)\n- GitHub - [github.com/Chanda-Abdul](https://github.com/Chanda-Abdul)\n\n## Acknowledgments\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanda-abdul%2Ffrontend-mentor-angular-dine-restaurant","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchanda-abdul%2Ffrontend-mentor-angular-dine-restaurant","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanda-abdul%2Ffrontend-mentor-angular-dine-restaurant/lists"}