├── src ├── assets │ ├── .gitkeep │ ├── __MACOSX │ │ ├── ._images │ │ └── images │ │ │ ├── ._buffet.png │ │ │ ├── ._logo.png │ │ │ ├── ._alberto.png │ │ │ ├── ._vadonut.png │ │ │ ├── ._uthappizza.png │ │ │ ├── ._zucchipakoda.png │ │ │ ├── ._.DS_Store │ │ │ └── ._elaicheesecake.png │ └── _db284e833226b010f3e252d9220f85d5_images.zip ├── app │ ├── app.component.scss │ ├── home │ │ ├── home.component.scss │ │ ├── home.component.spec.ts │ │ ├── home.component.ts │ │ └── home.component.html │ ├── aboutus │ │ ├── aboutus.component.scss │ │ ├── aboutus.component.spec.ts │ │ ├── aboutus.component.ts │ │ └── aboutus.component.html │ ├── login │ │ ├── login.component.scss │ │ ├── login.component.spec.ts │ │ ├── login.component.ts │ │ └── login.component.html │ ├── shared │ │ ├── baseurl.ts │ │ ├── comment.ts │ │ ├── leader.ts │ │ ├── promotion.ts │ │ ├── restConfig.ts │ │ ├── feedback.ts │ │ ├── dish.ts │ │ ├── promotions.ts │ │ ├── leaders.ts │ │ └── dishes.ts │ ├── menu │ │ ├── menu.component.scss │ │ ├── menu.component.ts │ │ ├── menu.component.html │ │ └── menu.component.spec.ts │ ├── contact │ │ ├── contact.component.scss │ │ ├── contact.component.spec.ts │ │ ├── contact.component.ts │ │ └── contact.component.html │ ├── app.component.ts │ ├── directives │ │ ├── highlight.directive.spec.ts │ │ └── highlight.directive.ts │ ├── footer │ │ ├── footer.component.ts │ │ ├── footer.component.spec.ts │ │ ├── footer.component.scss │ │ └── footer.component.html │ ├── app.component.html │ ├── dishdetail │ │ ├── dishdetail.component.scss │ │ ├── dishdetail.component.spec.ts │ │ ├── dishdetail.component.html │ │ └── dishdetail.component.ts │ ├── services │ │ ├── dish.service.spec.ts │ │ ├── leader.service.spec.ts │ │ ├── feedback.service.spec.ts │ │ ├── promotion.service.spec.ts │ │ ├── process-httpmsg.service.spec.ts │ │ ├── feedback.service.ts │ │ ├── process-httpmsg.service.ts │ │ ├── leader.service.ts │ │ ├── promotion.service.ts │ │ └── dish.service.ts │ ├── app-routing │ │ ├── app-routing.module.ts │ │ └── routes.ts │ ├── header │ │ ├── header.component.scss │ │ ├── header.component.ts │ │ ├── header.component.spec.ts │ │ └── header.component.html │ ├── app.component.spec.ts │ ├── animations │ │ └── app.animation.ts │ └── app.module.ts ├── favicon.ico ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── illstruation_img │ └── Template.png ├── typings.d.ts ├── tsconfig.app.json ├── tsconfig.spec.json ├── main.ts ├── index.html ├── test.ts ├── styles.scss └── polyfills.ts ├── .editorconfig ├── e2e ├── tsconfig.e2e.json ├── app.po.ts └── app.e2e-spec.ts ├── tsconfig.json ├── .gitignore ├── protractor.conf.js ├── karma.conf.js ├── .angular-cli.json ├── package.json ├── tslint.json └── README.md /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/home/home.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/aboutus/aboutus.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/login/login.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/shared/baseurl.ts: -------------------------------------------------------------------------------- 1 | 2 | export const baseURL = 'http://localhost:3000/'; -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/app/menu/menu.component.scss: -------------------------------------------------------------------------------- 1 | .container{ 2 | color:black; 3 | margin:20px; 4 | display:flex; 5 | } -------------------------------------------------------------------------------- /src/assets/__MACOSX/._images: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/assets/__MACOSX/._images -------------------------------------------------------------------------------- /src/illstruation_img/Template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/illstruation_img/Template.png -------------------------------------------------------------------------------- /src/assets/__MACOSX/images/._buffet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/assets/__MACOSX/images/._buffet.png -------------------------------------------------------------------------------- /src/assets/__MACOSX/images/._logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/assets/__MACOSX/images/._logo.png -------------------------------------------------------------------------------- /src/app/shared/comment.ts: -------------------------------------------------------------------------------- 1 | export class Comment{ 2 | rating:number; 3 | comment:string; 4 | author:string; 5 | date:string; 6 | } -------------------------------------------------------------------------------- /src/assets/__MACOSX/images/._alberto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/assets/__MACOSX/images/._alberto.png -------------------------------------------------------------------------------- /src/assets/__MACOSX/images/._vadonut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/assets/__MACOSX/images/._vadonut.png -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/__MACOSX/images/._uthappizza.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/assets/__MACOSX/images/._uthappizza.png -------------------------------------------------------------------------------- /src/assets/__MACOSX/images/._zucchipakoda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/assets/__MACOSX/images/._zucchipakoda.png -------------------------------------------------------------------------------- /src/assets/__MACOSX/images/._.DS_Store: -------------------------------------------------------------------------------- 1 | Mac OS X  2Fx ATTRxx -------------------------------------------------------------------------------- /src/assets/__MACOSX/images/._elaicheesecake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/assets/__MACOSX/images/._elaicheesecake.png -------------------------------------------------------------------------------- /src/assets/_db284e833226b010f3e252d9220f85d5_images.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NH1900/Online_Restaurant/HEAD/src/assets/_db284e833226b010f3e252d9220f85d5_images.zip -------------------------------------------------------------------------------- /src/app/shared/leader.ts: -------------------------------------------------------------------------------- 1 | export class Leader{ 2 | id:number; 3 | name:string; 4 | image:string; 5 | designation:string; 6 | abbr:string; 7 | featured:boolean; 8 | description:string; 9 | } -------------------------------------------------------------------------------- /src/app/shared/promotion.ts: -------------------------------------------------------------------------------- 1 | export class Promotion{ 2 | id:number; 3 | name:string; 4 | image:string; 5 | label:string; 6 | price:string; 7 | featured:boolean; 8 | description:string; 9 | } -------------------------------------------------------------------------------- /src/app/shared/restConfig.ts: -------------------------------------------------------------------------------- 1 | 2 | import { baseURL } from './baseurl'; 3 | 4 | // Function for settting the default restangular configuration 5 | export function RestangularConfigFactory (RestangularProvider) { 6 | RestangularProvider.setBaseUrl(baseURL); 7 | } -------------------------------------------------------------------------------- /src/app/contact/contact.component.scss: -------------------------------------------------------------------------------- 1 | .full-width { 2 | width: 95% 3 | } 4 | 5 | .half-width { 6 | width: 45% 7 | } 8 | 9 | .form-size { 10 | width: 75% 11 | } 12 | 13 | .form-size{ 14 | color:black; 15 | background-color:lightblue; 16 | } -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | title = 'app'; 10 | } 11 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/app/shared/feedback.ts: -------------------------------------------------------------------------------- 1 | export class Feedback { 2 | firstname: string; 3 | lastname: string; 4 | telnum: number; 5 | email: string; 6 | agree: boolean; 7 | contacttype: string; 8 | message: string; 9 | }; 10 | 11 | export const ContactType = ['None', 'Tel', 'Email']; -------------------------------------------------------------------------------- /src/app/directives/highlight.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { HighlightDirective } from './highlight.directive'; 2 | 3 | describe('HighlightDirective', () => { 4 | it('should create an instance', () => { 5 | // const directive = new HighlightDirective(); 6 | //expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/shared/dish.ts: -------------------------------------------------------------------------------- 1 | import {Comment} from './comment'; 2 | 3 | export class Dish{ 4 | id:number; 5 | name:string; 6 | image:string; 7 | category:string; 8 | label:string; 9 | price:string; 10 | featured:boolean; 11 | description:string; 12 | comments: Comment[]; 13 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/footer/footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer', 5 | templateUrl: './footer.component.html', 6 | styleUrls: ['./footer.component.scss'] 7 | }) 8 | export class FooterComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "types": [ 8 | "jasmine", 9 | "node" 10 | ] 11 | }, 12 | "files": [ 13 | "test.ts" 14 | ], 15 | "include": [ 16 | "**/*.spec.ts", 17 | "**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/app/dishdetail/dishdetail.component.scss: -------------------------------------------------------------------------------- 1 | h2{ 2 | color:black; 3 | margin:20px; 4 | display:flex; 5 | } 6 | 7 | p{ 8 | color:black; 9 | margin:20px; 10 | display:flex; 11 | } 12 | 13 | .form-size{ 14 | color:black; 15 | background-color:lightblue; 16 | } 17 | 18 | .full-width { 19 | width: 95% 20 | } 21 | 22 | .form{ 23 | background-color:lightblue; 24 | color:black; 25 | } 26 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/app/services/dish.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { DishService } from './dish.service'; 4 | 5 | describe('DishService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [DishService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([DishService], (service: DishService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ConFusion 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/app/services/leader.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { LeaderService } from './leader.service'; 4 | 5 | describe('LeaderService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [LeaderService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([LeaderService], (service: LeaderService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /src/app/services/feedback.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { FeedbackService } from './feedback.service'; 4 | 5 | describe('FeedbackService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [FeedbackService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([FeedbackService], (service: FeedbackService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo(link: string) { 5 | return browser.get(link); 6 | } 7 | 8 | getParagraphText(selector: string) { 9 | return element(by.css(selector)).getText(); 10 | } 11 | 12 | getElement(selector: string) { 13 | return element(by.css(selector)); 14 | } 15 | 16 | getAllElements(selector: string) { 17 | return element.all(by.css(selector)); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/app/services/promotion.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { PromotionService } from './promotion.service'; 4 | 5 | describe('PromotionService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [PromotionService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([PromotionService], (service: PromotionService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /src/app/services/process-httpmsg.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { ProcessHttpmsgService } from './process-httpmsg.service'; 4 | 5 | describe('ProcessHttpmsgService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [ProcessHttpmsgService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([ProcessHttpmsgService], (service: ProcessHttpmsgService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /src/app/shared/promotions.ts: -------------------------------------------------------------------------------- 1 | import {Promotion} from './promotion'; 2 | 3 | export const PROMOTIONS: Promotion[] = [{ 4 | id: 0, 5 | name: 'Weekend Grand Buffet', 6 | image: '/assets/images/buffet.png', 7 | label: 'New', 8 | price: '19.99', 9 | featured: true, 10 | description: 'Featuring mouthwatering combinations with a choice of five different salads, six enticing appetizers, six main entrees and five choicest desserts. Free flowing bubbly and soft drinks. All for just $19.99 per person' 11 | }]; -------------------------------------------------------------------------------- /src/app/app-routing/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import {RouterModule, Routes} from '@angular/router'; 4 | 5 | import {routes} from './routes'; 6 | 7 | 8 | @NgModule({ 9 | imports: [ 10 | CommonModule, 11 | RouterModule.forRoot(routes) 12 | ], 13 | //we want to use this app routes module in app module so we add a exports decorator to this module 14 | exports:[RouterModule], 15 | declarations: [] 16 | }) 17 | export class AppRoutingModule { } 18 | -------------------------------------------------------------------------------- /src/app/header/header.component.scss: -------------------------------------------------------------------------------- 1 | $lt-gray: #ddd; 2 | $background-moredark:#4527A0; 3 | $background-dark: #512DA8; 4 | $background-light: #9575CD; 5 | $background-pale: #D1C4E9; 6 | 7 | @mixin zero-margin($pad-up-down, $pad-left-right) { 8 | margin: 0px auto; 9 | padding: $pad-up-down $pad-left-right; 10 | } 11 | 12 | .jumbotron { 13 | @include zero-margin(70px,30px); 14 | background: $background-light ; 15 | color:floralwhite; 16 | min-height: 100px; 17 | max-height: 120px; 18 | } 19 | 20 | .active{ 21 | background: $background-moredark; 22 | } -------------------------------------------------------------------------------- /src/app/directives/highlight.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, Renderer2, HostListener } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[appHighlight]' 5 | }) 6 | export class HighlightDirective { 7 | 8 | constructor(private el: ElementRef, 9 | private renderer: Renderer2) { } 10 | 11 | @HostListener('mouseenter') onMouseEnter() { 12 | this.renderer.addClass(this.el.nativeElement, 'highlight'); 13 | } 14 | 15 | @HostListener('mouseleave') onMouseLeave() { 16 | this.renderer.removeClass(this.el.nativeElement, 'highlight'); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/app/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { LoginComponent } from '../login/login.component'; 3 | import { MdDialog, MdDialogRef } from '@angular/material'; 4 | 5 | @Component({ 6 | selector: 'app-header', 7 | templateUrl: './header.component.html', 8 | styleUrls: ['./header.component.scss'] 9 | }) 10 | export class HeaderComponent implements OnInit { 11 | 12 | 13 | constructor(public dialog:MdDialog) { } 14 | 15 | ngOnInit() { 16 | } 17 | 18 | openLoginForm() { 19 | this.dialog.open(LoginComponent, {width: '500px', height: '450px'}); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/app/services/feedback.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Observable } from 'rxjs/Observable'; 3 | import { Feedback } from '../shared/feedback'; 4 | //这个傻逼of要单独加。 5 | import 'rxjs/add/observable/of'; 6 | import 'rxjs/add/operator/delay'; 7 | 8 | import { ProcessHttpmsgService } from './process-httpmsg.service'; 9 | //import 'rxjs/add/operator/catch'; 10 | import { RestangularModule, Restangular } from 'ngx-restangular'; 11 | @Injectable() 12 | export class FeedbackService { 13 | 14 | constructor(private restangular: Restangular, 15 | private processHTTPMsgService: ProcessHttpmsgService) { } 16 | 17 | submitFeedback(fb: Feedback){ 18 | this.restangular.all('feedback').post(fb); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /menu\.component\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /dist-server 6 | /tmp 7 | /out-tsc 8 | 9 | # dependencies 10 | /node_modules 11 | 12 | # IDEs and editors 13 | /.idea 14 | .project 15 | .classpath 16 | .c9/ 17 | *.launch 18 | .settings/ 19 | *.sublime-workspace 20 | 21 | # IDE - VSCode 22 | .vscode/* 23 | !.vscode/settings.json 24 | !.vscode/tasks.json 25 | !.vscode/launch.json 26 | !.vscode/extensions.json 27 | 28 | # misc 29 | /.sass-cache 30 | /connect.lock 31 | /coverage 32 | /libpeerconnection.log 33 | npm-debug.log 34 | yarn-error.log 35 | testem.log 36 | /typings 37 | 38 | # e2e 39 | /e2e/*.js 40 | /e2e/*.map 41 | 42 | # System Files 43 | .DS_Store 44 | Thumbs.db 45 | -------------------------------------------------------------------------------- /src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/footer/footer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FooterComponent } from './footer.component'; 4 | 5 | describe('FooterComponent', () => { 6 | let component: FooterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FooterComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FooterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/header/header.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HeaderComponent } from './header.component'; 4 | 5 | describe('HeaderComponent', () => { 6 | let component: HeaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HeaderComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HeaderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/aboutus/aboutus.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AboutusComponent } from './aboutus.component'; 4 | 5 | describe('AboutusComponent', () => { 6 | let component: AboutusComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AboutusComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AboutusComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/contact/contact.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ContactComponent } from './contact.component'; 4 | 5 | describe('ContactComponent', () => { 6 | let component: ContactComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ContactComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ContactComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/dishdetail/dishdetail.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DishdetailComponent } from './dishdetail.component'; 4 | 5 | describe('DishdetailComponent', () => { 6 | let component: DishdetailComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DishdetailComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DishdetailComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/app-routing/routes.ts: -------------------------------------------------------------------------------- 1 | import {Routes} from '@angular/router'; 2 | 3 | import { MenuComponent } from '../menu/menu.component'; 4 | import { DishdetailComponent } from '../dishdetail/dishdetail.component'; 5 | import { HomeComponent } from '../home/home.component'; 6 | import { AboutusComponent } from '../aboutus/aboutus.component'; 7 | import { ContactComponent } from '../contact/contact.component'; 8 | 9 | export const routes: Routes = [ 10 | {path:'home',component:HomeComponent}, 11 | {path:'menu',component:MenuComponent}, 12 | //deflaut location if there is no URL provided 13 | {path: 'dishdetail/:id',component: DishdetailComponent}, 14 | {path: 'contactus',component:ContactComponent}, 15 | {path: 'aboutus', component:AboutusComponent}, 16 | {path:'',redirectTo:'/home',pathMatch:'full'} 17 | ]; 18 | -------------------------------------------------------------------------------- /src/app/footer/footer.component.scss: -------------------------------------------------------------------------------- 1 | $lt-gray: #ddd; 2 | $background-dark: #512DA8; 3 | $background-light: #9575CD; 4 | $background-pale: #D1C4E9; 5 | 6 | @mixin zero-margin($pad-up-down, $pad-left-right) { 7 | margin: 0px auto; 8 | padding: $pad-up-down $pad-left-right; 9 | } 10 | 11 | .footer{ 12 | background-color: $background-pale; 13 | @include zero-margin(20px, 0px); 14 | } 15 | 16 | .btn-facebook {color:#fff!important; background-color:#3b5998!important;} 17 | .btn-google-plus{color:#fff!important;background-color:#dd4b39!important;} 18 | .btn-youtube{color:#fff!important;background-color:#ff4b39!important;} 19 | .btn-linkedin{color:#fff!important;background-color:#007bb6!important;} 20 | .btn-twitter{color:#fff!important;background-color:#55acee!important;} 21 | .btn-mail{color:#fff!important;background-color:#512DA8!important;} -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/app/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import {MdDialog, MdDialogRef} from '@angular/material'; 4 | 5 | 6 | @Component({ 7 | selector: 'app-login', 8 | templateUrl: './login.component.html', 9 | styleUrls: ['./login.component.scss'] 10 | }) 11 | export class LoginComponent implements OnInit { 12 | 13 | user = {username: '', password: '', remember: false}; 14 | //create the a object of dialog (reference) to login component 15 | constructor(public dialogRef: MdDialogRef) { } 16 | 17 | ngOnInit() { 18 | } 19 | 20 | //we can check console content in browser Javascript consoler 21 | onSubmit() { 22 | //put value to console 23 | console.log("User: ", this.user); 24 | //invoke close method to close the dialog 25 | this.dialogRef.close(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/aboutus/aboutus.component.ts: -------------------------------------------------------------------------------- 1 | import { Leader } from '../shared/leader'; 2 | import { LeaderService } from '../services/leader.service'; 3 | import { flyInOut,expand } from '../animations/app.animation'; 4 | import { Component, OnInit ,Inject} from '@angular/core'; 5 | 6 | @Component({ 7 | selector: 'app-aboutus', 8 | templateUrl: './aboutus.component.html', 9 | styleUrls: ['./aboutus.component.scss'], 10 | host: { 11 | '[@flyInOut]': 'true', 12 | 'style': 'display: block;' 13 | }, 14 | animations: [ 15 | flyInOut(), 16 | expand() 17 | ] 18 | }) 19 | export class AboutusComponent implements OnInit { 20 | leaders: Leader[]; 21 | leaderErrMess: string; 22 | constructor(private leaderService:LeaderService, 23 | @Inject('BaseURL') private BaseURL) { } 24 | 25 | ngOnInit() { 26 | this.leaderService.getLeaders().subscribe(leaders => this.leaders = leaders,errmess => this.leaderErrMess = errmess); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/app/menu/menu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit ,Inject } from '@angular/core'; 2 | import{Dish} from '../shared/dish'; 3 | //import{DISHES} from '../shared/dishes'; 4 | import {DishService} from '../services/dish.service'; 5 | import { flyInOut, expand} from '../animations/app.animation'; 6 | 7 | @Component({ 8 | selector: 'app-menu', 9 | templateUrl: './menu.component.html', 10 | styleUrls: ['./menu.component.scss'], 11 | host: { 12 | '[@flyInOut]': 'true', 13 | 'style': 'display: block;' 14 | }, 15 | animations: [ 16 | flyInOut(), 17 | expand() 18 | ] 19 | }) 20 | export class MenuComponent implements OnInit { 21 | 22 | dishes: Dish[]; 23 | errMess: string; 24 | 25 | constructor(private dishService: DishService, 26 | @Inject('BaseURL') private BaseURL) { } 27 | 28 | ngOnInit() { 29 | this.dishService.getDishes() 30 | .subscribe(dishes => this.dishes = dishes, 31 | errmess => this.errMess = errmess); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/app/services/process-httpmsg.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Observable } from 'rxjs/Observable'; 3 | import { Http, Response } from '@angular/http'; 4 | import 'rxjs/add/observable/throw'; 5 | 6 | @Injectable() 7 | export class ProcessHttpmsgService { 8 | 9 | constructor() { } 10 | 11 | public extractData(res: Response) { 12 | let body = res.json(); 13 | console.log(body); 14 | return body || { }; 15 | } 16 | 17 | public handleError (error: Response | any) { 18 | // In a real world app, you might use a remote logging infrastructure 19 | let errMsg: string; 20 | if (error instanceof Response) { 21 | const body = error.json() || ''; 22 | const err = body.error || JSON.stringify(body); 23 | errMsg = `${error.status} - ${error.statusText || ''} ${err}`; 24 | } else { 25 | errMsg = error.message ? error.message : error.toString(); 26 | } 27 | console.error(errMsg); 28 | return Observable.throw(errMsg); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular/cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | angularCli: { 23 | environment: 'dev' 24 | }, 25 | reporters: ['progress', 'kjhtml'], 26 | port: 9876, 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: true, 30 | browsers: ['Chrome'], 31 | singleRun: false 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | describe('AppComponent', () => { 4 | beforeEach(async(() => { 5 | TestBed.configureTestingModule({ 6 | declarations: [ 7 | AppComponent 8 | ], 9 | }).compileComponents(); 10 | })); 11 | it('should create the app', async(() => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.debugElement.componentInstance; 14 | expect(app).toBeTruthy(); 15 | })); 16 | it(`should have as title 'app'`, async(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app.title).toEqual('app'); 20 | })); 21 | it('should render title in a h1 tag', async(() => { 22 | const fixture = TestBed.createComponent(AppComponent); 23 | fixture.detectChanges(); 24 | const compiled = fixture.debugElement.nativeElement; 25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser } from 'protractor'; 3 | describe('con-fusion App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display message saying Ristorante Con Fusion', () => { 11 | page.navigateTo('/'); 12 | expect(page.getParagraphText('app-root h1')).toEqual('NH1900 Con Fusion'); 13 | }); 14 | 15 | it('should navigate to about us page by clicking on the link', () => { 16 | page.navigateTo('/'); 17 | 18 | let navlink = page.getAllElements('a').get(1); 19 | navlink.click(); 20 | 21 | expect(page.getParagraphText('h3')).toBe('About Us') 22 | }); 23 | 24 | it('should enter a new comment for the first dish', () => { 25 | page.navigateTo('/dishdetail/0'); 26 | 27 | let newAuthor = page.getElement('input[type=text]'); 28 | newAuthor.sendKeys('Test Author'); 29 | 30 | let newComment = page.getElement('textarea'); 31 | newComment.sendKeys('Test Comment'); 32 | 33 | let newSubmitButton = page.getElement("button[type=submit]"); 34 | newSubmitButton.click(); 35 | 36 | browser.pause(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | @import '~@angular/material/prebuilt-themes/pink-bluegrey.css'; 3 | $primary-color-pale:gray; 4 | $primary-color-dark:#312DA8; 5 | $primary-color:#673AB7; 6 | $primary-color-light:#D1C4E9; 7 | $primary-color-text:#FFFFFF; 8 | $accent-color:#FFC107; 9 | $primary-text-color:#212121; 10 | $secondary-text-color:#757575; 11 | $divider-color:#BDBDBD; 12 | @mixin zero-margin($pad-up-down, $pad-left-right){ 13 | margin:0px auto; 14 | padding: $pad-up-down $pad-lefft-right; 15 | } 16 | 17 | body{ 18 | padding: 0; 19 | margin: 0; 20 | font-family: 'Times New Roman', Times, serif; 21 | } 22 | 23 | .container{ 24 | color:black; 25 | margin:20px; 26 | display:flex; 27 | } 28 | 29 | .background-primary{ 30 | background-color: $primary-text-color!important; 31 | } 32 | 33 | .background-accent{ 34 | background-color:$accent-color!important; 35 | } 36 | 37 | .text-floral-white{ 38 | color:floralwhite!important; 39 | } 40 | 41 | .text-spacer{ 42 | flex:1 1 auto; 43 | } 44 | 45 | .highlight { 46 | background-color: $primary-color-pale; 47 | border: 1px solid $primary-color-dark; 48 | z-index: 1; 49 | transform: scale(1.01); 50 | } -------------------------------------------------------------------------------- /src/app/animations/app.animation.ts: -------------------------------------------------------------------------------- 1 | import { trigger, state, style, animate, transition } from '@angular/animations'; 2 | 3 | export function visibility() { 4 | return trigger('visibility', [ 5 | state('shown', style({ 6 | transform: 'scale(1.0)', 7 | opacity: 1 8 | })), 9 | state('hidden', style({ 10 | transform: 'scale(0.5)', 11 | opacity: 0 12 | })), 13 | transition('* => *', animate('0.5s ease-in-out')) 14 | ]); 15 | } 16 | 17 | export function flyInOut() { 18 | return trigger('flyInOut',[ 19 | state('*', style({ opacity: 1, transform: 'translateX(0)'})), 20 | transition(':enter', [ 21 | style({ transform: 'translateX(-100%)', opacity:0 }), 22 | animate('500ms ease-in') 23 | ]), 24 | transition(':leave', [ 25 | animate('500ms ease-out', style({ transform: 'translateX(100%)', opacity: 0})) 26 | ]) 27 | ]); 28 | } 29 | 30 | export function expand() { 31 | return trigger('expand', [ 32 | state('*', style({ opacity: 1, transform: 'translateX(0)' })), 33 | transition(':enter', [ 34 | style({ transform: 'translateY(-50%)', opacity:0 }), 35 | animate('200ms ease-in', style({ opacity: 1, transform: 'translateX(0)' })) 36 | ]) 37 | ]); 38 | } -------------------------------------------------------------------------------- /.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "con-fusion" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "polyfills": "polyfills.ts", 17 | "test": "test.ts", 18 | "tsconfig": "tsconfig.app.json", 19 | "testTsconfig": "tsconfig.spec.json", 20 | "prefix": "app", 21 | "styles": [ 22 | "styles.scss", 23 | "../node_modules/font-awesome/scss/font-awesome.scss" 24 | ], 25 | "scripts": [], 26 | "environmentSource": "environments/environment.ts", 27 | "environments": { 28 | "dev": "environments/environment.ts", 29 | "prod": "environments/environment.prod.ts" 30 | } 31 | } 32 | ], 33 | "e2e": { 34 | "protractor": { 35 | "config": "./protractor.conf.js" 36 | } 37 | }, 38 | "lint": [ 39 | { 40 | "project": "src/tsconfig.app.json", 41 | "exclude": "**/node_modules/**" 42 | }, 43 | { 44 | "project": "src/tsconfig.spec.json", 45 | "exclude": "**/node_modules/**" 46 | }, 47 | { 48 | "project": "e2e/tsconfig.e2e.json", 49 | "exclude": "**/node_modules/**" 50 | } 51 | ], 52 | "test": { 53 | "karma": { 54 | "config": "./karma.conf.js" 55 | } 56 | }, 57 | "defaults": { 58 | "styleExt": "scss", 59 | "component": {} 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/app/header/header.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Home 4 | About 5 | Menu 6 | Contact 7 | 8 | Login 9 | 10 | 11 |
20 | 21 | 22 |
23 |

NH1900 Con Fusion

24 |

We take inspiration from the World's best cuisines, and create a unique fusion experience. Our lipsmacking creations 25 | will tickle your culinary senses!

26 |
27 |
28 | Logo 29 |
30 |
31 |
-------------------------------------------------------------------------------- /src/app/menu/menu.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Menu

5 |
6 |
7 |
8 | 9 |
10 | 11 | 12 | {{dishx.name}} 13 | 14 |

{{dishx.name | uppercase}}

15 |
16 |
17 |
18 |
19 |
20 |

Loading . . . Please Wait

21 |
22 |
23 |

Error

24 |

{{errMess}}

25 |
26 | 27 | 44 | 45 |
46 | -------------------------------------------------------------------------------- /src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit ,Inject} from '@angular/core'; 2 | 3 | import { Dish } from '../shared/dish'; 4 | import { DishService } from '../services/dish.service'; 5 | import { Promotion } from '../shared/promotion'; 6 | import { PromotionService } from '../services/promotion.service'; 7 | import { Leader } from '../shared/leader'; 8 | import { LeaderService } from '../services/leader.service'; 9 | import { flyInOut, expand } from '../animations/app.animation'; 10 | @Component({ 11 | selector: 'app-home', 12 | templateUrl: './home.component.html', 13 | styleUrls: ['./home.component.scss'], 14 | host: { 15 | '[@flyInOut]': 'true', 16 | 'style': 'display: block;' 17 | }, 18 | animations: [ 19 | flyInOut(), 20 | expand() 21 | ] 22 | }) 23 | export class HomeComponent implements OnInit { 24 | 25 | leader: Leader; 26 | dish: Dish; 27 | promotion: Promotion; 28 | dishErrMess: string; 29 | promotionErrMess: string; 30 | leaderErrMess: string; 31 | constructor(private dishservice: DishService, 32 | private promotionservice: PromotionService, 33 | private leaderservice: LeaderService, 34 | @Inject('BaseURL') private BaseURL) { } 35 | 36 | ngOnInit() { 37 | this.dishservice.getFeaturedDish().subscribe( dish => this.dish = dish,errmess => this.dishErrMess = errmess); 38 | this.promotionservice.getFeaturedPromotion().subscribe(promotion => this.promotion = promotion,errmess => this.promotionErrMess = errmess); 39 | this.leaderservice.getFeaturedLeader().subscribe(leader => this.leader = leader,errmess => this.leaderErrMess = errmess); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/app/services/leader.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Leader } from '../shared/leader'; 3 | import { LEADERS } from '../shared/leaders'; 4 | 5 | import { Observable } from 'rxjs/Observable'; 6 | //这个傻逼of要单独加。 7 | import 'rxjs/add/observable/of'; 8 | import 'rxjs/add/operator/delay'; 9 | 10 | import { ProcessHttpmsgService } from './process-httpmsg.service'; 11 | //import 'rxjs/add/operator/catch'; 12 | import { RestangularModule, Restangular } from 'ngx-restangular'; 13 | @Injectable() 14 | export class LeaderService { 15 | 16 | constructor(private restangular: Restangular, 17 | private processHTTPMsgService: ProcessHttpmsgService) { } 18 | 19 | // can write as getLeaders(): Leader[] no space between "getLeaders():" and "Leader[]" 20 | /*getLeaders():Promise{ 21 | return Promise.resolve(LEADERS); 22 | } 23 | 24 | getFeaturedLeader():Promise{ 25 | return Promise.resolve(LEADERS.filter((leader) => (leader.featured))[0]); 26 | }*/ 27 | 28 | //test latency using pormise 29 | /* 30 | getLeaders():Promise{ 31 | return new Promise(resolve=> { 32 | // Simulate server latency with 2 second delay 33 | setTimeout(() => resolve(LEADERS), 2000); 34 | }); 35 | }*/ 36 | 37 | getFeaturedLeader():Observable{ 38 | return this.restangular.all('leaders').getList({featured: true}) 39 | .map(leaders => leaders[0]); 40 | //Observable.of(LEADERS.filter((leader) => (leader.featured))[0]).delay(2000); 41 | } 42 | 43 | getLeaders():Observable{ 44 | return this.restangular.all('leaders').getList(); 45 | //Observable.of(LEADERS).delay(2000); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "con-fusion", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build --prod", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "^5.2.6", 16 | "@angular/cdk": "^2.0.0-beta.8", 17 | "@angular/common": "^5.2.0", 18 | "@angular/compiler": "^5.2.0", 19 | "@angular/core": "^5.2.0", 20 | "@angular/flex-layout": "^5.0.0-beta.13", 21 | "@angular/forms": "^5.2.0", 22 | "@angular/http": "^5.2.0", 23 | "@angular/material": "^2.0.0-beta.8", 24 | "@angular/platform-browser": "^5.2.0", 25 | "@angular/platform-browser-dynamic": "^5.2.0", 26 | "@angular/router": "^5.2.0", 27 | "core-js": "^2.4.1", 28 | "font-awesome": "^4.7.0", 29 | "hammerjs": "^2.0.8", 30 | "ngx-restangular": "^2.0.2", 31 | "rxjs": "^5.5.6", 32 | "zone.js": "^0.8.19" 33 | }, 34 | "devDependencies": { 35 | "@angular/cli": "~1.7.1", 36 | "@angular/compiler-cli": "^5.2.0", 37 | "@angular/language-service": "^5.2.0", 38 | "@types/jasmine": "~2.8.3", 39 | "@types/jasminewd2": "~2.0.2", 40 | "@types/node": "~6.0.60", 41 | "codelyzer": "^4.0.1", 42 | "jasmine-core": "~2.8.0", 43 | "jasmine-spec-reporter": "~4.2.1", 44 | "karma": "~2.0.0", 45 | "karma-chrome-launcher": "~2.2.0", 46 | "karma-coverage-istanbul-reporter": "^1.2.1", 47 | "karma-jasmine": "~1.1.0", 48 | "karma-jasmine-html-reporter": "^0.2.2", 49 | "protractor": "~5.1.2", 50 | "ts-node": "~4.1.0", 51 | "tslint": "~5.9.1", 52 | "typescript": "~2.5.3" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app/login/login.component.html: -------------------------------------------------------------------------------- 1 | 2 | Login 3 | 4 | 5 | 6 | 7 |

{{ user | json }}

8 | 9 |
10 | 11 | 12 |

13 | 14 | 15 | 16 | 17 | username is required 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | password is required 27 | 28 | 29 | 30 | Remember Me 31 |

32 |
33 | 34 | 35 | 36 | 37 | 38 |
-------------------------------------------------------------------------------- /src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |
7 | 8 | 9 | 10 |
11 | 12 |

{{dish.name | uppercase}}

13 |
14 |
15 | {{dish.name}} 16 | 17 |

{{dish.description}} 18 |

19 |
20 |
21 |
22 |

Loading . . . Please Wait

23 |
24 |
25 |

Error

26 |

{{errMess}}

27 |
28 | 29 | 30 | 31 |
32 | 33 |

{{promotion.name | uppercase}}

34 |
35 |
36 | {{promotion.name}} 37 | 38 |

{{promotion.description}} 39 |

40 |
41 |
42 |
43 |

Loading . . . Please Wait

44 |
45 |
46 |

Error

47 |

{{errMess}}

48 |
49 | 50 | 51 | 52 |
53 | 54 |

{{leader.name | uppercase}}

55 |
56 |
57 | {{leader.name}} 58 | 59 |

{{leader.description}} 60 |

61 |
62 |
63 |
64 |

Loading . . . Please Wait

65 |
66 |
67 |

Error

68 |

{{errMess}}

69 |
70 | 71 |
-------------------------------------------------------------------------------- /src/app/shared/leaders.ts: -------------------------------------------------------------------------------- 1 | import {Leader} from './leader'; 2 | 3 | export const LEADERS: Leader[] = [ 4 | { 5 | id: 0, 6 | name: 'Peter Pan', 7 | image: '/assets/images/Taki.jpg', 8 | designation: 'Chief Epicurious Officer', 9 | abbr: 'CEO', 10 | featured: false, 11 | description: "Our CEO, Peter, credits his hardworking East Asian immigrant parents who undertook the arduous journey to the shores of America with the intention of giving their children the best future. His mother's wizardy in the kitchen whipping up the tastiest dishes with whatever is available inexpensively at the supermarket, was his first inspiration to create the fusion cuisines for which The Frying Pan became well known. He brings his zeal for fusion cuisines to this restaurant, pioneering cross-cultural culinary connections." 12 | }, 13 | { 14 | id: 1, 15 | name: 'Dhanasekaran Witherspoon', 16 | image: '/assets/images/Taki.jpg', 17 | designation: 'Chief Food Officer', 18 | abbr: 'CFO', 19 | featured: false, 20 | description: 'Our CFO, Danny, as he is affectionately referred to by his colleagues, comes from a long established family tradition in farming and produce. His experiences growing up on a farm in the Australian outback gave him great appreciation for varieties of food sources. As he puts it in his own words, Everything that runs, wins, and everything that stays, pays!' 21 | }, 22 | { 23 | id: 2, 24 | name: 'Agumbe Tang', 25 | image: '/assets/images/Taki.jpg', 26 | designation: 'Chief Taste Officer', 27 | abbr: 'CTO', 28 | featured: false, 29 | description: 'Blessed with the most discerning gustatory sense, Agumbe, our CFO, personally ensures that every dish that we serve meets his exacting tastes. Our chefs dread the tongue lashing that ensues if their dish does not meet his exacting standards. He lives by his motto, You click only if you survive my lick.' 30 | }, 31 | { 32 | id: 3, 33 | name: 'Taki', 34 | image: '/assets/images/Taki.jpg', 35 | designation: 'Executive Chef', 36 | abbr: 'EC', 37 | featured: true, 38 | description: 'The most attractive role in film Your Name' 39 | } 40 | ]; -------------------------------------------------------------------------------- /src/app/footer/footer.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/menu/menu.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { MaterialModule } from '@angular/material'; 3 | import { FlexLayoutModule } from '@angular/flex-layout'; 4 | import { Dish } from '../shared/dish'; 5 | import { DishService } from '../services/dish.service'; 6 | import { DISHES } from '../shared/dishes'; 7 | import { baseURL } from '../shared/baseurl'; 8 | import { Observable } from 'rxjs/Observable'; 9 | import { MenuComponent } from './menu.component'; 10 | import { RouterTestingModule } from '@angular/router/testing'; 11 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 12 | import { By } from '@angular/platform-browser'; 13 | import { DebugElement } from '@angular/core'; 14 | 15 | describe('MenuComponent', () => { 16 | let component: MenuComponent; 17 | let fixture: ComponentFixture; 18 | 19 | beforeEach(async(() => { 20 | 21 | let dishServiceStub = { 22 | getDishes: function(): Observable { 23 | return Observable.of(DISHES); 24 | } 25 | }; 26 | 27 | TestBed.configureTestingModule({ 28 | imports: [ BrowserAnimationsModule, 29 | MaterialModule, 30 | FlexLayoutModule, 31 | RouterTestingModule.withRoutes([{ path: 'menu', component: MenuComponent }]) 32 | ], 33 | declarations: [ MenuComponent ], 34 | providers: [ 35 | { provide: DishService, useValue: dishServiceStub }, 36 | { provide: 'BaseURL', useValue: baseURL }, 37 | ] 38 | }) 39 | .compileComponents(); 40 | 41 | let dishservice = TestBed.get(DishService); 42 | 43 | })); 44 | 45 | beforeEach(() => { 46 | fixture = TestBed.createComponent(MenuComponent); 47 | component = fixture.componentInstance; 48 | fixture.detectChanges(); 49 | }); 50 | 51 | it('should create', () => { 52 | expect(component).toBeTruthy(); 53 | }); 54 | 55 | it('dishes items should be 4', () => { 56 | expect(component.dishes.length).toBe(4); 57 | expect(component.dishes[1].name).toBe('Zucchipakoda'); 58 | expect(component.dishes[3].featured).toBeFalsy(); 59 | }); 60 | 61 | it('should use dishes in the template', () => { 62 | fixture.detectChanges(); 63 | 64 | let de: DebugElement; 65 | let el: HTMLElement; 66 | de = fixture.debugElement.query(By.css('h1')); 67 | el = de.nativeElement; 68 | 69 | expect(el.textContent).toContain(DISHES[0].name.toUpperCase()); 70 | 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /src/app/services/promotion.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | import {Promotion} from '../shared/promotion'; 4 | //import {PROMOTIONS} from '../shared/promotions'; 5 | 6 | import { Observable } from 'rxjs/Observable'; 7 | //这个傻逼of要单独加。 8 | import 'rxjs/add/observable/of'; 9 | import 'rxjs/add/operator/delay'; 10 | import 'rxjs/add/operator/map'; 11 | import { Http, Response } from '@angular/http'; 12 | //import { baseURL } from '../shared/baseurl'; 13 | import { ProcessHttpmsgService } from './process-httpmsg.service'; 14 | //import 'rxjs/add/operator/catch'; 15 | import { RestangularModule, Restangular } from 'ngx-restangular'; 16 | @Injectable() 17 | export class PromotionService { 18 | 19 | constructor(private restangular: Restangular, 20 | private processHTTPMsgService: ProcessHttpmsgService) { } 21 | 22 | /*getPromotions():Promise{ 23 | return Promise.resolve(PROMOTIONS); 24 | } 25 | 26 | getPromotion(id: number):Promise{ 27 | return Promise.resolve(PROMOTIONS.filter((promo) => (promo.id === id))[0]); 28 | } 29 | 30 | getFeaturedPromotion():Promise{ 31 | //the filter will return a sub array of dishes so we point [0] to output only one element 32 | return Promise.resolve(PROMOTIONS.filter((promo) => (promo.featured))[0]); 33 | }*/ 34 | 35 | //test latency using promise 36 | /* 37 | getPromotions():Promise{ 38 | return new Promise(resolve=> { 39 | // Simulate server latency with 2 second delay 40 | setTimeout(() => resolve(PROMOTIONS), 2000); 41 | }); 42 | } 43 | 44 | getPromotion(id: number):Promise{ 45 | return new Promise(resolve=> { 46 | // Simulate server latency with 2 second delay 47 | setTimeout(() => resolve(PROMOTIONS.filter((promo) => (promo.id === id))[0]), 2000); 48 | }); 49 | } 50 | 51 | getFeaturedPromotion():Promise{ 52 | //the filter will return a sub array of dishes so we point [0] to output only one element 53 | return new Promise(resolve=> { 54 | // Simulate server latency with 2 second delay 55 | setTimeout(() => resolve(PROMOTIONS.filter((promo) => (promo.featured))[0]), 2000); 56 | }); 57 | } 58 | */ 59 | 60 | getPromotions():Observable{ 61 | return this.restangular.all('promotions').getList(); 62 | } 63 | 64 | getPromotion(id: number):Observable{ 65 | return this.restangular.one('promotions',id).get(); 66 | } 67 | 68 | getFeaturedPromotion():Observable{ 69 | return this.restangular.all('promotions').getList({featured: true}) 70 | .map(promotions => promotions[0]); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 3 | import { MaterialModule } from '@angular/material'; 4 | import { FlexLayoutModule } from '@angular/flex-layout'; 5 | import { NgModule } from '@angular/core'; 6 | import { HttpModule } from '@angular/http'; 7 | 8 | import 'hammerjs'; 9 | 10 | import { AppComponent } from './app.component'; 11 | //after installation thie menu component is automatically imported into app 12 | import { MenuComponent } from './menu/menu.component'; 13 | import { DishdetailComponent } from './dishdetail/dishdetail.component'; 14 | import { HeaderComponent } from './header/header.component'; 15 | import { FooterComponent } from './footer/footer.component'; 16 | import { HomeComponent } from './home/home.component'; 17 | import { AboutusComponent } from './aboutus/aboutus.component'; 18 | import { ContactComponent } from './contact/contact.component'; 19 | import { ReactiveFormsModule } from '@angular/forms'; 20 | 21 | import { DishService } from './services/dish.service'; 22 | import { PromotionService } from './services/promotion.service'; 23 | import { LeaderService } from './services/leader.service'; 24 | import { FeedbackService } from './services/feedback.service'; 25 | 26 | import { AppRoutingModule } from './app-routing/app-routing.module'; 27 | import { LoginComponent } from './login/login.component'; 28 | import { FormsModule } from '@angular/forms'; 29 | import { baseURL } from './shared/baseurl'; 30 | import { ProcessHttpmsgService } from './services/process-httpmsg.service'; 31 | import { RestangularModule, Restangular } from 'ngx-restangular'; 32 | import { RestangularConfigFactory } from './shared/restConfig'; 33 | import { HighlightDirective } from './directives/highlight.directive'; 34 | 35 | 36 | @NgModule({ 37 | declarations: [ 38 | AppComponent, 39 | MenuComponent, 40 | DishdetailComponent, 41 | HeaderComponent, 42 | FooterComponent, 43 | HomeComponent, 44 | ContactComponent, 45 | LoginComponent, 46 | AboutusComponent, 47 | HighlightDirective 48 | ], 49 | imports: [ 50 | BrowserAnimationsModule, 51 | MaterialModule, 52 | FlexLayoutModule, 53 | BrowserModule, 54 | AppRoutingModule, 55 | FormsModule, 56 | HttpModule, 57 | RestangularModule.forRoot(RestangularConfigFactory), 58 | ReactiveFormsModule 59 | ], 60 | entryComponents:[ 61 | LoginComponent 62 | ], 63 | providers: [DishService,PromotionService,LeaderService,ProcessHttpmsgService,FeedbackService, 64 | {provide: 'BaseURL', useValue: baseURL}], 65 | bootstrap: [AppComponent] 66 | }) 67 | export class AppModule { } 68 | -------------------------------------------------------------------------------- /src/app/aboutus/aboutus.component.html: -------------------------------------------------------------------------------- 1 |
4 | 5 |
6 |
7 |

About Us

8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 |

Our History

16 |

Started in 2018, NH1900

17 |

The restaurant traces its humble beginnings to The Frying Pan

18 |
19 |
20 | 21 | 22 | 23 |

Facts At a Glance

24 |
25 |
26 | 27 |
28 |
Started
29 |
3 Feb. 2013
30 |
Major Stake Holder
31 |
HK Fine Foods Inc.
32 |
Last Year's Turnover
33 |
$1,250,375
34 |
Employees
35 |
40
36 |
37 |
38 |
39 |
40 |
41 |
42 | 43 |
44 | 45 |
46 |

You better cut the pizza in four pieces because 47 | I'm not hungry enough to eat six.

48 |
-- Yogi Berra, 49 | The Wit and Wisdom of Yogi Berra, 50 | P. Pepe, Diversion Books, 2014 51 |
52 |
53 |
54 |
55 | 56 | 57 |
58 |

Corporate Leadership

59 | 60 | 61 | {{leader.name}} 62 | 63 |

{{leader.name | uppercase}}

64 |
65 |
66 |

Loading . . . Please Wait

67 |
68 |
69 |

Error

70 |

{{errMess}}

71 |
72 |
73 |
74 |
75 | 76 | 77 | 78 | 79 |
-------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Required to support Web Animations `@angular/platform-browser/animations`. 51 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 52 | **/ 53 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 54 | 55 | /** 56 | * By default, zone.js will patch all possible macroTask and DomEvents 57 | * user can disable parts of macroTask/DomEvents patch by setting following flags 58 | */ 59 | 60 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 61 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 62 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 63 | 64 | /* 65 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 66 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 67 | */ 68 | // (window as any).__Zone_enable_cross_context_check = true; 69 | 70 | /*************************************************************************************************** 71 | * Zone JS is required by default for Angular itself. 72 | */ 73 | import 'zone.js/dist/zone'; // Included with Angular CLI. 74 | 75 | 76 | 77 | /*************************************************************************************************** 78 | * APPLICATION IMPORTS 79 | */ 80 | -------------------------------------------------------------------------------- /src/app/contact/contact.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 3 | import { Feedback, ContactType } from '../shared/feedback'; 4 | import { flyInOut } from '../animations/app.animation'; 5 | import { FeedbackService } from '../services/feedback.service'; 6 | 7 | @Component({ 8 | selector: 'app-contact', 9 | templateUrl: './contact.component.html', 10 | styleUrls: ['./contact.component.scss'], 11 | host: { 12 | '[@flyInOut]': 'true', 13 | 'style': 'display: block;' 14 | }, 15 | animations: [ 16 | flyInOut() 17 | ] 18 | }) 19 | export class ContactComponent implements OnInit { 20 | 21 | formErrors = { 22 | 'firstname': '', 23 | 'lastname': '', 24 | 'telnum': '', 25 | 'email': '' 26 | }; 27 | validationMessages = { 28 | 'firstname': { 29 | 'required': 'First Name is required.', 30 | 'minlength': 'First Name must be at least 2 characters long.', 31 | 'maxlength': 'FirstName cannot be more than 25 characters long.' 32 | }, 33 | 'lastname': { 34 | 'required': 'Last Name is required.', 35 | 'minlength': 'Last Name must be at least 2 characters long.', 36 | 'maxlength': 'Last Name cannot be more than 25 characters long.' 37 | }, 38 | 'telnum': { 39 | 'required': 'Tel. number is required.', 40 | 'pattern': 'Tel. number must contain only numbers.' 41 | }, 42 | 'email': { 43 | 'required': 'Email is required.', 44 | 'email': 'Email not in valid format.' 45 | }, 46 | }; 47 | feedbackForm: FormGroup; 48 | feedback: Feedback; 49 | contactType = ContactType; 50 | constructor(private fb: FormBuilder,private fbservice: FeedbackService) { 51 | this.createForm(); 52 | } 53 | 54 | ngOnInit() { 55 | } 56 | 57 | createForm() { 58 | this.feedbackForm = this.fb.group({ 59 | firstname: ['',[Validators.required, Validators.minLength(2), Validators.maxLength(25)] ], 60 | lastname: ['',[Validators.required, Validators.minLength(2), Validators.maxLength(25)] ], 61 | telnum: ['',[Validators.required, Validators.pattern] ], 62 | email: ['', [Validators.required, Validators.email] ], 63 | agree: false, 64 | contacttype: 'None', 65 | message: '' 66 | }); 67 | this.feedbackForm.valueChanges 68 | .subscribe(data => this.onValueChanged(data)); 69 | 70 | this.onValueChanged(); // (re)set validation messages now 71 | } 72 | 73 | onValueChanged(data?: any) { 74 | if (!this.feedbackForm) { return; } 75 | const form = this.feedbackForm; 76 | for (const field in this.formErrors) { 77 | // clear previous error message (if any) 78 | this.formErrors[field] = ''; 79 | const control = form.get(field); 80 | if (control && control.dirty && !control.valid) { 81 | const messages = this.validationMessages[field]; 82 | for (const key in control.errors) { 83 | this.formErrors[field] += messages[key] + ' '; 84 | } 85 | } 86 | } 87 | } 88 | 89 | onSubmit() { 90 | this.feedback = this.feedbackForm.value; 91 | console.log(this.feedback); 92 | this.fbservice.submitFeedback(this.feedback); 93 | this.feedbackForm.reset({ 94 | firstname: '', 95 | lastname: '', 96 | telnum: '', 97 | email: '', 98 | agree: false, 99 | contacttype: 'None', 100 | message: '' 101 | }); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs", 22 | "rxjs/Rx" 23 | ], 24 | "import-spacing": true, 25 | "indent": [ 26 | true, 27 | "spaces" 28 | ], 29 | "interface-over-type-literal": true, 30 | "label-position": true, 31 | "max-line-length": [ 32 | true, 33 | 140 34 | ], 35 | "member-access": false, 36 | "member-ordering": [ 37 | true, 38 | { 39 | "order": [ 40 | "static-field", 41 | "instance-field", 42 | "static-method", 43 | "instance-method" 44 | ] 45 | } 46 | ], 47 | "no-arg": true, 48 | "no-bitwise": true, 49 | "no-console": [ 50 | true, 51 | "debug", 52 | "info", 53 | "time", 54 | "timeEnd", 55 | "trace" 56 | ], 57 | "no-construct": true, 58 | "no-debugger": true, 59 | "no-duplicate-super": true, 60 | "no-empty": false, 61 | "no-empty-interface": true, 62 | "no-eval": true, 63 | "no-inferrable-types": [ 64 | true, 65 | "ignore-params" 66 | ], 67 | "no-misused-new": true, 68 | "no-non-null-assertion": true, 69 | "no-shadowed-variable": true, 70 | "no-string-literal": false, 71 | "no-string-throw": true, 72 | "no-switch-case-fall-through": true, 73 | "no-trailing-whitespace": true, 74 | "no-unnecessary-initializer": true, 75 | "no-unused-expression": true, 76 | "no-use-before-declare": true, 77 | "no-var-keyword": true, 78 | "object-literal-sort-keys": false, 79 | "one-line": [ 80 | true, 81 | "check-open-brace", 82 | "check-catch", 83 | "check-else", 84 | "check-whitespace" 85 | ], 86 | "prefer-const": true, 87 | "quotemark": [ 88 | true, 89 | "single" 90 | ], 91 | "radix": true, 92 | "semicolon": [ 93 | true, 94 | "always" 95 | ], 96 | "triple-equals": [ 97 | true, 98 | "allow-null-check" 99 | ], 100 | "typedef-whitespace": [ 101 | true, 102 | { 103 | "call-signature": "nospace", 104 | "index-signature": "nospace", 105 | "parameter": "nospace", 106 | "property-declaration": "nospace", 107 | "variable-declaration": "nospace" 108 | } 109 | ], 110 | "unified-signatures": true, 111 | "variable-name": false, 112 | "whitespace": [ 113 | true, 114 | "check-branch", 115 | "check-decl", 116 | "check-operator", 117 | "check-separator", 118 | "check-type" 119 | ], 120 | "directive-selector": [ 121 | true, 122 | "attribute", 123 | "app", 124 | "camelCase" 125 | ], 126 | "component-selector": [ 127 | true, 128 | "element", 129 | "app", 130 | "kebab-case" 131 | ], 132 | "no-output-on-prefix": true, 133 | "use-input-property-decorator": true, 134 | "use-output-property-decorator": true, 135 | "use-host-property-decorator": true, 136 | "no-input-rename": true, 137 | "no-output-rename": true, 138 | "use-life-cycle-interface": true, 139 | "use-pipe-transform-interface": true, 140 | "component-class-suffix": true, 141 | "directive-class-suffix": true 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/app/dishdetail/dishdetail.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 | 7 |

{{disha.name | uppercase}}

8 |
9 |
10 | {{disha.name}} 11 | 12 |

{{disha.description}}

13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |

Loading . . . Please Wait

25 |
26 |
27 |

Error

28 |

{{errMess}}

29 |
30 |
31 | 32 |
33 | 34 |

Comment

35 | 36 |

{{dish2.comment}}

37 |

38 | {{dish2.rating}} Stars 39 |

40 | 41 |

--{{dish2.author}} {{dish2.date | date}}

42 |
43 | 44 | 45 |

{{commentForm.value.comment}}

46 |

5 Stars

47 |

--{{commentForm.value.author}}

48 |
49 |
50 |
51 |

Loading . . . Please Wait

52 |
53 |
54 |

Error

55 |

{{errMess}}

56 |
57 | 58 |
59 |

60 | 62 | 63 | 64 | 65 | {{formErrors.author}} 66 | 67 | 68 |

69 | 70 |

71 | 73 | 74 | 75 | 76 | {{formErrors.comment}} 77 | 78 | 79 |

80 | 81 |
82 | 83 |
84 |
-------------------------------------------------------------------------------- /src/app/services/dish.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Dish } from '../shared/dish'; 3 | //import {DISHES} from '../shared/dishes'; 4 | 5 | import { Observable } from 'rxjs/Observable'; 6 | //这个傻逼of要单独加。 7 | import 'rxjs/add/observable/of'; 8 | import 'rxjs/add/operator/map'; 9 | import 'rxjs/add/operator/delay'; 10 | import { Http, Response } from '@angular/http'; 11 | //import { baseURL } from '../shared/baseurl'; 12 | import { ProcessHttpmsgService } from './process-httpmsg.service'; 13 | //import 'rxjs/add/operator/catch'; 14 | import { RestangularModule, Restangular } from 'ngx-restangular'; 15 | 16 | @Injectable() 17 | export class DishService { 18 | 19 | 20 | //test just for resolve data using promise 21 | /*getDishes(): Promise { 22 | return Promise.resolve(DISHES); 23 | } 24 | 25 | getDish(id: number): Promise { 26 | return Promise.resolve(DISHES.filter((dish) => (dish.id === id))[0]); 27 | } 28 | 29 | getFeaturedDish(): Promise { 30 | return Promise.resolve(DISHES.filter((dish) => dish.featured)[0]); 31 | }*/ 32 | 33 | //test for lantency using promise 34 | /*getDishes(): Promise { 35 | return new Promise(resolve=> { 36 | // Simulate server latency with 2 second delay 37 | setTimeout(() => resolve(DISHES), 2000); 38 | }); 39 | } 40 | 41 | getDish(id: number): Promise { 42 | return new Promise(resolve=> { 43 | // Simulate server latency with 2 second delay 44 | setTimeout(() => resolve(DISHES.filter((dish) => (dish.id === id))[0]), 2000); 45 | }); 46 | } 47 | 48 | getFeaturedDish(): Promise { 49 | return new Promise(resolve=> { 50 | // Simulate server latency with 2 second delay 51 | setTimeout(() => resolve(DISHES.filter((dish) => dish.featured)[0]), 2000); 52 | }); 53 | }*/ 54 | 55 | //test observable 56 | 57 | 58 | /*本地http module连接 59 | constructor(private http: Http, 60 | private processHTTPMsgService: ProcessHttpmsgService) { } 61 | getDishes(): Observable { 62 | return this.http.get(baseURL + 'dishes') 63 | .map(res => { return this.processHTTPMsgService.extractData(res); }) 64 | .catch(error => { return this.processHTTPMsgService.handleError(error); }); 65 | } 66 | 67 | getDish(id: number): Observable { 68 | return this.http.get(baseURL + 'dishes/'+ id) 69 | .map(res => { return this.processHTTPMsgService.extractData(res); }) 70 | .catch(error => { return this.processHTTPMsgService.handleError(error); }); 71 | } 72 | 73 | getFeaturedDish(): Observable { 74 | return this.http.get(baseURL + 'dishes?featured=true') 75 | .map(res => { return this.processHTTPMsgService.extractData(res)[0]; }) 76 | .catch(error => { return this.processHTTPMsgService.handleError(error); }); 77 | } 78 | 79 | getDishIds(): Observable { 80 | return this.getDishes() 81 | .map(dishes => { return dishes.map(dish => dish.id) }); 82 | }*/ 83 | 84 | constructor(private restangular: Restangular, 85 | private processHTTPMsgService: ProcessHttpmsgService) { } 86 | getDishes(): Observable { 87 | return this.restangular.all('dishes').getList(); 88 | } 89 | 90 | getDish(id: number): Observable { 91 | return this.restangular.one('dishes',id).get(); 92 | } 93 | 94 | getFeaturedDish(): Observable { 95 | return this.restangular.all('dishes').getList({featured: true}) 96 | .map(dishes => dishes[0]); 97 | } 98 | 99 | getDishIds(): Observable { 100 | return this.getDishes() 101 | .map(dishes => { return dishes.map(dish => dish.id) }) 102 | 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/app/dishdetail/dishdetail.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject } from '@angular/core'; 2 | 3 | import {Dish} from '../shared/dish'; 4 | 5 | import { DishService } from '../services/dish.service'; 6 | import { Params, ActivatedRoute } from '@angular/router'; 7 | import { Location } from '@angular/common'; 8 | import { FormBuilder, FormGroup, Validators} from '@angular/forms'; 9 | import { Comment } from '../shared/comment'; 10 | import { visibility,expand } from '../animations/app.animation'; 11 | import 'rxjs/add/operator/switchMap'; 12 | 13 | @Component({ 14 | selector: 'app-dishdetail', 15 | templateUrl: './dishdetail.component.html', 16 | styleUrls: ['./dishdetail.component.scss'], 17 | animations: [ 18 | visibility(), 19 | expand() 20 | ] 21 | }) 22 | export class DishdetailComponent implements OnInit { 23 | 24 | formErrors = { 25 | 'author': '', 26 | 'comment': '' 27 | }; 28 | 29 | validationMessages = { 30 | 'author': { 31 | 'required': 'Name is required.', 32 | 'minlength': ' Name must be at least 2 characters long.' 33 | }, 34 | 'comment': { 35 | 'required': 'commet is required.' 36 | }, 37 | }; 38 | //@Input() 39 | disha: Dish; 40 | dishIds: number[]; 41 | prev: number; 42 | next: number; 43 | errMess: string; 44 | 45 | commentForm: FormGroup; 46 | commentdata: Comment; 47 | visibility = 'shown'; 48 | 49 | constructor(private dishservice: DishService, 50 | private route: ActivatedRoute, 51 | private location: Location, 52 | private db: FormBuilder, 53 | @Inject('BaseURL') private BaseURL) { 54 | this.createForm(); 55 | } 56 | 57 | createForm(){ 58 | this.commentForm = this.db.group({ 59 | rating: 0, 60 | comment: ['', [Validators.required]], 61 | author: ['', [Validators.required, Validators.minLength(2)]], 62 | }); 63 | this.commentForm.valueChanges 64 | .subscribe(data => this.onValueChanged(data)); 65 | this.onValueChanged(); 66 | } 67 | 68 | onValueChanged(data?: any) { 69 | if (!this.commentForm) { return; } 70 | const form = this.commentForm; 71 | for (const field in this.formErrors) { 72 | // clear previous error message (if any) 73 | this.formErrors[field] = ''; 74 | const control = form.get(field); 75 | if (control && control.dirty && !control.valid) { 76 | const messages = this.validationMessages[field]; 77 | for (const key in control.errors) { 78 | this.formErrors[field] += messages[key] + ' '; 79 | } 80 | } 81 | } 82 | } 83 | 84 | onSubmit() { 85 | //一定是.value才能获取值。所以访问属性的时候也是.value.对应的属性名 86 | this.commentdata = this.commentForm.value; 87 | this.disha.comments.push(this.commentdata); 88 | this.commentdata.date = new Date().toISOString(); 89 | console.log(this.commentdata); 90 | this.commentForm.reset({ 91 | rating: 0, 92 | comment: '', 93 | author: '' 94 | }); 95 | } 96 | 97 | ngOnInit() { 98 | this.createForm(); 99 | this.dishservice.getDishIds().subscribe(dishIds => this.dishIds = dishIds); 100 | this.route.params 101 | .switchMap((params: Params) => { this.visibility = 'hidden'; return this.dishservice.getDish(+params['id']); }) 102 | .subscribe(dish => { this.disha = dish; this.setPrevNext(dish.id); this.visibility = 'shown'; }, 103 | errmess => this.errMess = errmess); 104 | } 105 | 106 | setPrevNext(dishId: number) { 107 | let index = this.dishIds.indexOf(dishId); 108 | this.prev = this.dishIds[(this.dishIds.length + index - 1)%this.dishIds.length]; 109 | this.next = this.dishIds[(this.dishIds.length + index + 1)%this.dishIds.length]; 110 | } 111 | 112 | goBack(): void { 113 | this.location.back(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/app/contact/contact.component.html: -------------------------------------------------------------------------------- 1 |
4 | 5 |
6 |
7 |

Contact Us

8 |
9 |
10 |
11 | 12 |
13 |

Location Information

14 |
15 |
16 |

Our Address

17 |
18 | 121, Clear Water Bay Road
19 | Clear Water Bay, Kowloon
20 | HONG KONG
21 | : +852 1234 5678
22 | : +852 8765 4321
23 | : 24 | confusion@food.net 25 |
26 |

27 |
28 | Call 29 | Skype 30 | Email 31 |
32 |
33 |
34 |

Map of our Location

35 |
36 |
37 |
38 | 39 |
40 |

Send us your Feedback

41 |

{{ feedbackForm.value | json }} {{ feedbackForm.status | json }}

42 | 43 |
44 |

45 | 47 | 48 | 49 | 50 | {{formErrors.firstname}} 51 | 52 | 53 | 55 | 56 | 57 | 58 | {{formErrors.lastname}} 59 | 60 | 61 |

62 |

63 | 65 | 66 | 67 | 68 | {{formErrors.telnum}} 69 | 70 | 71 | 73 | 74 | 75 | 76 | {{formErrors.email}} 77 | 78 | 79 |

80 | 81 | 84 | 91 |
82 | May we contact you? 83 | 85 | 86 | 87 | {{ ctype }} 88 | 89 | 90 |
92 |

93 | 94 | 95 | 96 |

97 | 98 |
99 |
100 |
-------------------------------------------------------------------------------- /src/app/shared/dishes.ts: -------------------------------------------------------------------------------- 1 | import {Dish} from './dish'; 2 | 3 | export const DISHES:Dish[] = [ 4 | { 5 | id:0, 6 | name: 'Uthappizza', 7 | image: '/assets/images/uthappizza.png', 8 | category: 'mains', 9 | label: 'Hot', 10 | price: '4.99', 11 | featured:true, 12 | description: 'A unique combination of Indian Uthappam (pancake) and Italian pizza, topped with Cerignola olives, ripe vine cherry tomatoes, Vidalia onion, Guntur chillies and Buffalo Paneer.', 13 | comments: [ 14 | { 15 | rating: 5, 16 | comment: "Imagine all the eatables, living in conFusion!", 17 | author: "John Lemon", 18 | date: "2012-10-16T17:57:28.556094Z" 19 | }, 20 | { 21 | rating: 4, 22 | comment: "Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", 23 | author: "Paul McVites", 24 | date: "2014-09-05T17:57:28.556094Z" 25 | }, 26 | { 27 | rating: 3, 28 | comment: "Eat it, just eat it!", 29 | author: "Michael Jaikishan", 30 | date: "2015-02-13T17:57:28.556094Z" 31 | }, 32 | { 33 | rating: 4, 34 | comment: "Ultimate, Reaching for the stars!", 35 | author: "Ringo Starry", 36 | date: "2013-12-02T17:57:28.556094Z" 37 | }, 38 | { 39 | rating: 2, 40 | comment: "It's your birthday, we're gonna party!", 41 | author: "25 Cent", 42 | date: "2011-12-02T17:57:28.556094Z" 43 | } 44 | ] 45 | }, 46 | { 47 | id:1, 48 | name: 'Zucchipakoda', 49 | image: '/assets/images/zucchipakoda.png', 50 | category: 'appetizer', 51 | label: '', 52 | price: '1.99', 53 | featured:false, 54 | description: 'Deep fried Zucchini coated with mildly spiced Chickpea flour batter accompanied with a sweet-tangy tamarind sauce', 55 | comments: [ 56 | { 57 | rating: 5, 58 | comment: "Imagine all the eatables, living in conFusion!", 59 | author: "John Lemon", 60 | date: "2012-10-16T17:57:28.556094Z" 61 | }, 62 | { 63 | rating: 4, 64 | comment: "Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", 65 | author: "Paul McVites", 66 | date: "2014-09-05T17:57:28.556094Z" 67 | }, 68 | { 69 | rating: 3, 70 | comment: "Eat it, just eat it!", 71 | author: "Michael Jaikishan", 72 | date: "2015-02-13T17:57:28.556094Z" 73 | }, 74 | { 75 | rating: 4, 76 | comment: "Ultimate, Reaching for the stars!", 77 | author: "Ringo Starry", 78 | date: "2013-12-02T17:57:28.556094Z" 79 | }, 80 | { 81 | rating: 2, 82 | comment: "It's your birthday, we're gonna party!", 83 | author: "25 Cent", 84 | date: "2011-12-02T17:57:28.556094Z" 85 | } 86 | ] 87 | }, 88 | { 89 | id:2, 90 | name: 'Vadonut', 91 | image: '/assets/images/vadonut.png', 92 | category: 'appetizer', 93 | label: 'New', 94 | price: '1.99', 95 | featured:false, 96 | description: 'A quintessential ConFusion experience, is it a vada or is it a donut?', 97 | comments: [ 98 | { 99 | rating: 5, 100 | comment: "Imagine all the eatables, living in conFusion!", 101 | author: "John Lemon", 102 | date: "2012-10-16T17:57:28.556094Z" 103 | }, 104 | { 105 | rating: 4, 106 | comment: "Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", 107 | author: "Paul McVites", 108 | date: "2014-09-05T17:57:28.556094Z" 109 | }, 110 | { 111 | rating: 3, 112 | comment: "Eat it, just eat it!", 113 | author: "Michael Jaikishan", 114 | date: "2015-02-13T17:57:28.556094Z" 115 | }, 116 | { 117 | rating: 4, 118 | comment: "Ultimate, Reaching for the stars!", 119 | author: "Ringo Starry", 120 | date: "2013-12-02T17:57:28.556094Z" 121 | }, 122 | { 123 | rating: 2, 124 | comment: "It's your birthday, we're gonna party!", 125 | author: "25 Cent", 126 | date: "2011-12-02T17:57:28.556094Z" 127 | } 128 | ] 129 | }, 130 | { 131 | id:3, 132 | name: 'ElaiCheese Cake', 133 | image: '/assets/images/elaicheesecake.png', 134 | category: 'dessert', 135 | label: '', 136 | price: '2.99', 137 | featured:false, 138 | description: 'A delectable, semi-sweet New York Style Cheese Cake, with Graham cracker crust and spiced with Indian cardamoms', 139 | comments: [ 140 | { 141 | rating: 5, 142 | comment: "Imagine all the eatables, living in conFusion!", 143 | author: "John Lemon", 144 | date: "2012-10-16T17:57:28.556094Z" 145 | }, 146 | { 147 | rating: 4, 148 | comment: "Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", 149 | author: "Paul McVites", 150 | date: "2014-09-05T17:57:28.556094Z" 151 | }, 152 | { 153 | rating: 3, 154 | comment: "Eat it, just eat it!", 155 | author: "Michael Jaikishan", 156 | date: "2015-02-13T17:57:28.556094Z" 157 | }, 158 | { 159 | rating: 4, 160 | comment: "Ultimate, Reaching for the stars!", 161 | author: "Ringo Starry", 162 | date: "2013-12-02T17:57:28.556094Z" 163 | }, 164 | { 165 | rating: 2, 166 | comment: "It's your birthday, we're gonna party!", 167 | author: "25 Cent", 168 | date: "2011-12-02T17:57:28.556094Z" 169 | } 170 | ] 171 | } 172 | ]; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # [![template](src/illstruation_img/Template.png)](https://github.com/NH1900) 3 | # Catalog 4 | * [Background](#background) 5 | * [Usage](#usage) 6 | * [Content](#content) 7 | * Home 8 | * Log in 9 | * Menu 10 | * Contact us 11 | * About us 12 | * [Future](#future) 13 | 14 | # Background 15 | Built a Online restaurant for students to ordering dishes. 16 | # Usage 17 | ## Restaurant 18 | 19 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.7.1. 20 | 21 | ### Development server 22 | 23 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 24 | 25 | ### Code scaffolding 26 | 27 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 28 | 29 | ### Build 30 | 31 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. 32 | 33 | ### Running unit tests 34 | 35 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 36 | 37 | ### Running end-to-end tests 38 | 39 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 40 | 41 | ### Further help 42 | 43 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 44 | 45 | 46 | # Content 47 | ## Home 48 | In the home page, users can find specialty dishes and introduction ofthe resaurant. Users can directly slide images of dishes to add them to favorites dishes list. 49 | To obtain the data flow from backend, I use RestAPI of Angular to geet the observable of data. 50 | ```Typescript 51 | leader: Leader; 52 | dish: Dish; 53 | promotion: Promotion; 54 | dishErrMess: string; 55 | promotionErrMess: string; 56 | leaderErrMess: string; 57 | constructor(private dishservice: DishService, 58 | private promotionservice: PromotionService, 59 | private leaderservice: LeaderService, 60 | @Inject('BaseURL') private BaseURL) { } 61 | 62 | ngOnInit() { 63 | this.dishservice.getFeaturedDish().subscribe( dish => this.dish = dish,errmess => this.dishErrMess = errmess); 64 | this.promotionservice.getFeaturedPromotion().subscribe(promotion => this.promotion = promotion,errmess => this.promotionErrMess = errmess); 65 | this.leaderservice.getFeaturedLeader().subscribe(leader => this.leader = leader,errmess => this.leaderErrMess = errmess); 66 | } 67 | ``` 68 | ## Log in 69 | Users can log in to our restaurant or create an account. After logging in, our system will recommend users some dishes baes on their ordering history. 70 | Defining the format of an account and the valid input of password and username 71 | ```Typescript 72 | describe('LoginComponent', () => { 73 | let component: LoginComponent; 74 | let fixture: ComponentFixture; 75 | 76 | beforeEach(async(() => { 77 | TestBed.configureTestingModule({ 78 | declarations: [ LoginComponent ] 79 | }) 80 | .compileComponents(); 81 | })); 82 | 83 | beforeEach(() => { 84 | fixture = TestBed.createComponent(LoginComponent); 85 | component = fixture.componentInstance; 86 | fixture.detectChanges(); 87 | }); 88 | 89 | it('should create', () => { 90 | expect(component).toBeTruthy(); 91 | }); 92 | ``` 93 | ## Menu 94 | In Menu page, users can browser dishes to choose what they like 95 | For each dish after clicking corresponding image,user can get into another page introducing dishdetails for that specific dish 96 | In dishdetail page,users can leave message and add comments to that dish. 97 | ```Typescript 98 | createForm(){ 99 | this.commentForm = this.db.group({ 100 | rating: 0, 101 | comment: ['', [Validators.required]], 102 | author: ['', [Validators.required, Validators.minLength(2)]], 103 | }); 104 | this.commentForm.valueChanges 105 | .subscribe(data => this.onValueChanged(data)); 106 | this.onValueChanged(); 107 | } 108 | 109 | onValueChanged(data?: any) { 110 | if (!this.commentForm) { return; } 111 | const form = this.commentForm; 112 | for (const field in this.formErrors) { 113 | // clear previous error message (if any) 114 | this.formErrors[field] = ''; 115 | const control = form.get(field); 116 | if (control && control.dirty && !control.valid) { 117 | const messages = this.validationMessages[field]; 118 | for (const key in control.errors) { 119 | this.formErrors[field] += messages[key] + ' '; 120 | } 121 | } 122 | } 123 | } 124 | 125 | onSubmit() { 126 | this.commentdata = this.commentForm.value; 127 | this.disha.comments.push(this.commentdata); 128 | this.commentdata.date = new Date().toISOString(); 129 | console.log(this.commentdata); 130 | this.commentForm.reset({ 131 | rating: 0, 132 | comment: '', 133 | author: '' 134 | }); 135 | } 136 | 137 | ``` 138 | ## Contact us 139 | In the contact page, Users can fill out their information to leave a message or directly contact us for some problems during ordering. 140 | Still in this page,users' information will be stored in database. 141 | ```Typescript 142 | createForm() { 143 | this.feedbackForm = this.fb.group({ 144 | firstname: ['',[Validators.required, Validators.minLength(2), Validators.maxLength(25)] ], 145 | lastname: ['',[Validators.required, Validators.minLength(2), Validators.maxLength(25)] ], 146 | telnum: ['',[Validators.required, Validators.pattern] ], 147 | email: ['', [Validators.required, Validators.email] ], 148 | agree: false, 149 | contacttype: 'None', 150 | message: '' 151 | }); 152 | this.feedbackForm.valueChanges 153 | .subscribe(data => this.onValueChanged(data)); 154 | 155 | this.onValueChanged(); // (re)set validation messages now 156 | } 157 | 158 | onValueChanged(data?: any) { 159 | if (!this.feedbackForm) { return; } 160 | const form = this.feedbackForm; 161 | for (const field in this.formErrors) { 162 | // clear previous error message (if any) 163 | this.formErrors[field] = ''; 164 | const control = form.get(field); 165 | if (control && control.dirty && !control.valid) { 166 | const messages = this.validationMessages[field]; 167 | for (const key in control.errors) { 168 | this.formErrors[field] += messages[key] + ' '; 169 | } 170 | } 171 | } 172 | } 173 | 174 | onSubmit() { 175 | this.feedback = this.feedbackForm.value; 176 | console.log(this.feedback); 177 | this.fbservice.submitFeedback(this.feedback); 178 | this.feedbackForm.reset({ 179 | firstname: '', 180 | lastname: '', 181 | telnum: '', 182 | email: '', 183 | agree: false, 184 | contacttype: 'None', 185 | message: '' 186 | }); 187 | } 188 | ``` 189 | ## About us 190 | Users can find introduction about the restaurant and their owners 191 | # Future 192 | In the future based on customers' requirements I plan to add more functions suach as:self building service .... 193 | 194 | --------------------------------------------------------------------------------