| @@ -29,6 +29,10 @@ const routes: Routes = [ | |||
| { | |||
| path: 'booking', | |||
| loadChildren: () => import('./booking/booking.module').then( m => m.BookingPageModule) | |||
| }, | |||
| { | |||
| path: 'booking-details', | |||
| loadChildren: () => import('./booking-details/booking-details.module').then( m => m.BookingDetailsPageModule) | |||
| } | |||
| ]; | |||
| @NgModule({ | |||
| @@ -0,0 +1,17 @@ | |||
| import { NgModule } from '@angular/core'; | |||
| import { Routes, RouterModule } from '@angular/router'; | |||
| import { BookingDetailsPage } from './booking-details.page'; | |||
| const routes: Routes = [ | |||
| { | |||
| path: '', | |||
| component: BookingDetailsPage | |||
| } | |||
| ]; | |||
| @NgModule({ | |||
| imports: [RouterModule.forChild(routes)], | |||
| exports: [RouterModule], | |||
| }) | |||
| export class BookingDetailsPageRoutingModule {} | |||
| @@ -0,0 +1,20 @@ | |||
| import { NgModule } from '@angular/core'; | |||
| import { CommonModule } from '@angular/common'; | |||
| import { FormsModule } from '@angular/forms'; | |||
| import { IonicModule } from '@ionic/angular'; | |||
| import { BookingDetailsPageRoutingModule } from './booking-details-routing.module'; | |||
| import { BookingDetailsPage } from './booking-details.page'; | |||
| @NgModule({ | |||
| imports: [ | |||
| CommonModule, | |||
| FormsModule, | |||
| IonicModule, | |||
| BookingDetailsPageRoutingModule | |||
| ], | |||
| declarations: [BookingDetailsPage] | |||
| }) | |||
| export class BookingDetailsPageModule {} | |||
| @@ -0,0 +1,53 @@ | |||
| <ion-content> | |||
| <div class="content-container"> | |||
| <section class="action-buttons"> | |||
| <div class="nav"> | |||
| <button (click)="back()"> <ion-icon name="chevron-back-outline"></ion-icon> <span> BACK </span> </button> | |||
| </div> | |||
| <header> {{ matchDay.matchDetails.home.name }} v/s {{ matchDay.matchDetails.away.name }} <br> <span> {{ matchDay.staduim.name }} Stadium </span> </header> | |||
| <div class="action"> | |||
| <button> <ion-icon name="share-social-outline"></ion-icon> </button> | |||
| </div> | |||
| </section> | |||
| <section class="upfold"> | |||
| <img class="bg-img" [src]="matchDay.staduim.sideView"> | |||
| <ul class="quadrants"> | |||
| <li *ngFor="let stands of matchDay.seatsAvailable" | |||
| [ngClass]="{'active' : selectedStand === stands.stand}" | |||
| (click)="selectedStand = stands.stand"> | |||
| <label> {{ stands.stand }} Stand </label> | |||
| </li> | |||
| </ul> | |||
| <figure class="active"> | |||
| <img src="assets/home-team/stadium-sv.svg"> | |||
| <img [src]="matchDay.staduim.topView"> | |||
| </figure> | |||
| </section> | |||
| <section class="seating-details"> | |||
| <header> | |||
| <h3> Stands </h3> | |||
| </header> | |||
| <ul class="stand-list"> | |||
| <li *ngFor="let stands of matchDay.seatsAvailable" | |||
| [ngClass]="{'active' : selectedStand === stands.stand}" | |||
| (click)="selectedStand = stands.stand"> | |||
| <label> | |||
| {{ getFirstChar(stands.stand) }} | |||
| </label> | |||
| <p> | |||
| {{ stands.seats.length }} seats remaining, starts from <strong> ₹ {{ stands.seats[0].price }} </strong> | |||
| </p> | |||
| </li> | |||
| </ul> | |||
| </section> | |||
| </div> | |||
| </ion-content> | |||
| @@ -0,0 +1,330 @@ | |||
| $dark-blue: #161e2d; | |||
| $blue-grey: #949599; | |||
| $sea-blue: #2ea9f5; | |||
| ion-content { | |||
| --background: transparent; | |||
| background-color: $dark-blue; | |||
| } | |||
| .action-buttons { | |||
| display: flex; | |||
| justify-content: space-between; | |||
| align-items: flex-start; | |||
| padding: 0 3% 0 0%; | |||
| height: 50px; | |||
| position: sticky; | |||
| position: -webkit-sticky; | |||
| left: 0; | |||
| top: 0; | |||
| background-color: lighten($blue-grey, 35%); | |||
| z-index: 2; | |||
| width: 100%; | |||
| align-items: center; | |||
| box-shadow: 0px 0px 5px $dark-blue; | |||
| button { | |||
| background-color: transparent; | |||
| border: none; | |||
| } | |||
| .nav button { | |||
| color: $blue-grey; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: flex-start; | |||
| ion-icon { | |||
| font-size: 24px; | |||
| } | |||
| span { | |||
| font-size: 0.9rem; | |||
| font-size: 14px; | |||
| } | |||
| } | |||
| header { | |||
| flex-grow: 1; | |||
| padding: 0 10px; | |||
| font-size: 14px; | |||
| color: darken($blue-grey, 30%); | |||
| font-weight: 500; | |||
| text-align: left; | |||
| white-space: nowrap; | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| span { | |||
| font-weight: 400; | |||
| color: $blue-grey; | |||
| font-size: 10px; | |||
| } | |||
| } | |||
| .action { | |||
| display: flex; | |||
| justify-content: flex-end; | |||
| } | |||
| .action button { | |||
| width: 35px; | |||
| height: 35px; | |||
| border: 1px solid $blue-grey; | |||
| background-color: rgba($blue-grey, 0.1); | |||
| border-radius: 50%; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| margin-left: 15px; | |||
| ion-icon { | |||
| color: $blue-grey; | |||
| font-size: 17px; | |||
| } | |||
| } | |||
| } | |||
| .upfold { | |||
| height: 100vw; | |||
| width: 100vw; | |||
| position: sticky; | |||
| position: -webkit-sticky; | |||
| left: 0; | |||
| top: 50px; | |||
| z-index: 0; | |||
| overflow: hidden; | |||
| .quadrants { | |||
| position: absolute; | |||
| z-index: 2; | |||
| left: 0; | |||
| top: 0; | |||
| display: flex; | |||
| justify-content: center; | |||
| width: 100%; | |||
| height: 100%; | |||
| padding: 0; | |||
| margin: 0; | |||
| list-style: none; | |||
| flex-wrap: wrap; | |||
| border-radius: 50%; | |||
| overflow: hidden; | |||
| transform: scale(0); | |||
| animation: popOut 0.3s forwards; | |||
| animation-delay: 1s; | |||
| li { | |||
| width: 50%; | |||
| height: 50%; | |||
| background-color: rgba($dark-blue, 0.2); | |||
| display: flex; | |||
| justify-content: center; | |||
| color: white; | |||
| font-weight: 700; | |||
| letter-spacing: 0.5px; | |||
| padding: 30px; | |||
| transition: background-color 0.3s, color 0.3s; | |||
| &:nth-child(1n + 1) { | |||
| justify-content: flex-end; | |||
| } | |||
| &:nth-child(2n) { | |||
| justify-content: flex-start; | |||
| } | |||
| &:nth-child(1) { | |||
| border-right: 1px solid white; | |||
| align-items: flex-end; | |||
| } | |||
| &:nth-child(2) { | |||
| align-items: flex-end; | |||
| } | |||
| &:nth-child(3) { | |||
| border-right: 1px solid white; | |||
| border-top: 1px solid white; | |||
| } | |||
| &:nth-child(4) { | |||
| border-top: 1px solid white; | |||
| } | |||
| &.active { | |||
| background-color: rgba($dark-blue, 0.9); | |||
| } | |||
| } | |||
| } | |||
| @keyframes popOut { | |||
| from { | |||
| transform: scale(0); | |||
| } to { | |||
| transform: scale(1); | |||
| } | |||
| } | |||
| .bg-img { | |||
| position: absolute; | |||
| left: 0; | |||
| top: 0; | |||
| width: 100%; | |||
| height: 100%; | |||
| object-fit: cover; | |||
| object-position: center; | |||
| filter: brightness(50%); | |||
| opacity: 0; | |||
| z-index: 0; | |||
| animation: fadeInSlow 3s forwards; | |||
| animation-delay: 1s; | |||
| } | |||
| @keyframes fadeInSlow { | |||
| from { | |||
| opacity: 0; | |||
| } to { | |||
| opacity: 1; | |||
| } | |||
| } | |||
| figure { | |||
| position: relative; | |||
| margin: 0; | |||
| display: block; | |||
| width: 100%; | |||
| height: 100%; | |||
| transition: filter 0.3s; | |||
| border: 0px; | |||
| padding: 0; | |||
| border-radius: 7px; | |||
| overflow: hidden; | |||
| z-index: 1; | |||
| -webkit-perspective: 1200px; | |||
| -moz-perspective: 1200px; | |||
| -ms-perspective: 1200px; | |||
| perspective: 1200px; | |||
| &.active { | |||
| img { | |||
| &:nth-child(1) { | |||
| animation: sideViewOut 0.3s forwards; | |||
| animation-delay: 0.5s; | |||
| } | |||
| &:nth-child(2) { | |||
| animation: topViewIn 0.3s forwards; | |||
| animation-delay: 0.5s; | |||
| } | |||
| } | |||
| } | |||
| img { | |||
| height: 90%; | |||
| object-fit: contain; | |||
| display: block; | |||
| width: 90%; | |||
| margin: 0 auto; | |||
| position: absolute; | |||
| left: 5%; | |||
| top: 5%; | |||
| -webkit-transform-style: preserve-3d; | |||
| -moz-transform-style: preserve-3d; | |||
| -ms-transform-style: preserve-3d; | |||
| transform-style: preserve-3d; | |||
| transform-origin: 50px 0; | |||
| &:nth-child(2) { | |||
| transform: translateY(50%)rotateX(90deg); | |||
| opacity: 0; | |||
| } | |||
| } | |||
| } | |||
| @keyframes sideViewOut { | |||
| 0% { | |||
| transform: translateY(0%)rotateX(0deg); | |||
| } | |||
| 100% { | |||
| transform: translateY(50%)rotateX(-90deg); | |||
| width: 80%; | |||
| height: 50%; | |||
| opacity: 0; | |||
| } | |||
| } | |||
| @keyframes topViewIn { | |||
| 0% { | |||
| transform: translateY(50%)rotateX(90deg); | |||
| opacity: 0; | |||
| } | |||
| 100% { | |||
| transform: translateY(0%)rotateX(0deg); | |||
| opacity: 1; | |||
| } | |||
| } | |||
| } | |||
| .seating-details { | |||
| position: relative; | |||
| background-color: white; | |||
| z-index: 1; | |||
| padding: 5px 5% 10px 5%; | |||
| border-top-left-radius: 7px; | |||
| border-top-right-radius: 7px; | |||
| overflow: hidden; | |||
| min-height: calc(100vh - 100vw - 50px); | |||
| header h3 { | |||
| margin: 0; | |||
| color: lighten($dark-blue, 10%); | |||
| font-weight: 700; | |||
| letter-spacing: 1px; | |||
| font-size: 1.1rem; | |||
| } | |||
| header { | |||
| padding: 10px 0; | |||
| border-bottom: 1px solid $blue-grey; | |||
| } | |||
| } | |||
| .stand-list { | |||
| list-style: none; | |||
| padding: 0; | |||
| margin: 10px 0px 0px 0px; | |||
| li { | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: flex-start; | |||
| padding: 10px 0; | |||
| } | |||
| label { | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| border-radius: 7px; | |||
| width: 30px; | |||
| height: 30px; | |||
| overflow: hidden; | |||
| color: white; | |||
| font-weight: 500; | |||
| letter-spacing: 1px; | |||
| background-color: $sea-blue; | |||
| font-size: 0.8rem; | |||
| margin-right: 10px; | |||
| } | |||
| p { | |||
| margin: 0; | |||
| color: $blue-grey; | |||
| line-height: 1.5; | |||
| font-size: 1rem; | |||
| } | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| import { async, ComponentFixture, TestBed } from '@angular/core/testing'; | |||
| import { IonicModule } from '@ionic/angular'; | |||
| import { BookingDetailsPage } from './booking-details.page'; | |||
| describe('BookingDetailsPage', () => { | |||
| let component: BookingDetailsPage; | |||
| let fixture: ComponentFixture<BookingDetailsPage>; | |||
| beforeEach(async(() => { | |||
| TestBed.configureTestingModule({ | |||
| declarations: [ BookingDetailsPage ], | |||
| imports: [IonicModule.forRoot()] | |||
| }).compileComponents(); | |||
| fixture = TestBed.createComponent(BookingDetailsPage); | |||
| component = fixture.componentInstance; | |||
| fixture.detectChanges(); | |||
| })); | |||
| it('should create', () => { | |||
| expect(component).toBeTruthy(); | |||
| }); | |||
| }); | |||
| @@ -0,0 +1,32 @@ | |||
| import { Component, OnInit } from '@angular/core'; | |||
| import { ActivatedRoute } from '@angular/router'; | |||
| import { Location } from '@angular/common'; | |||
| @Component({ | |||
| selector: 'app-booking-details', | |||
| templateUrl: './booking-details.page.html', | |||
| styleUrls: ['./booking-details.page.scss'], | |||
| }) | |||
| export class BookingDetailsPage implements OnInit { | |||
| matchDay: any; | |||
| selectedStand: string = ''; | |||
| constructor( | |||
| private route: ActivatedRoute, | |||
| private location: Location | |||
| ) { } | |||
| ngOnInit() { | |||
| this.matchDay = JSON.parse(this.route.snapshot.paramMap.get('matchData')); | |||
| console.log(this.matchDay); | |||
| } | |||
| back() { | |||
| this.location.back(); | |||
| } | |||
| getFirstChar(text: string) { | |||
| return text.charAt(0) | |||
| } | |||
| } | |||
| @@ -14,7 +14,8 @@ | |||
| <ion-slides #slides [options]="slideOpts" (ionSlideDidChange)="selectMatchDate()"> | |||
| <ion-slide *ngFor="let matchDay of bookingSeatsData"> | |||
| <ion-slide *ngFor="let matchDay of bookingSeatsData" | |||
| (click)="showBookingDetails(matchDay)"> | |||
| <div class="image-holder"> | |||
| <figure> | |||
| <img [src]="matchDay.staduim.sideView"> | |||
| @@ -170,79 +170,4 @@ ion-slides { | |||
| font-size: 0.9rem; | |||
| line-height: 1.5; | |||
| } | |||
| } | |||
| // figure { | |||
| // margin: 0; | |||
| // display: block; | |||
| // width: 100%; | |||
| // height: 100%; | |||
| // transition: filter 0.3s; | |||
| // border: 0px; | |||
| // padding: 0; | |||
| // border-radius: 7px; | |||
| // overflow: hidden; | |||
| // -webkit-perspective: 1200px; | |||
| // -moz-perspective: 1200px; | |||
| // -ms-perspective: 1200px; | |||
| // perspective: 1200px; | |||
| // &.active { | |||
| // img { | |||
| // &:nth-child(1) { | |||
| // animation: sideViewOut 0.3s forwards; | |||
| // } | |||
| // &:nth-child(2) { | |||
| // animation: topViewIn 0.3s forwards; | |||
| // animation-delay: 0.1s; | |||
| // } | |||
| // } | |||
| // } | |||
| // img { | |||
| // height: 80%; | |||
| // object-fit: contain; | |||
| // display: block; | |||
| // width: 80%; | |||
| // margin: 0 auto; | |||
| // position: absolute; | |||
| // left: 10%; | |||
| // top: 0; | |||
| // -webkit-transform-style: preserve-3d; | |||
| // -moz-transform-style: preserve-3d; | |||
| // -ms-transform-style: preserve-3d; | |||
| // transform-style: preserve-3d; | |||
| // transform-origin: 50px 0; | |||
| // &:nth-child(2) { | |||
| // transform: translateY(50%)rotateX(90deg); | |||
| // opacity: 0; | |||
| // } | |||
| // } | |||
| // } | |||
| // @keyframes sideViewOut { | |||
| // 0% { | |||
| // transform: translateY(0%)rotateX(0deg); | |||
| // } | |||
| // 100% { | |||
| // transform: translateY(50%)rotateX(-90deg); | |||
| // width: 80%; | |||
| // height: 50%; | |||
| // opacity: 0; | |||
| // } | |||
| // } | |||
| // @keyframes topViewIn { | |||
| // 0% { | |||
| // transform: translateY(50%)rotateX(90deg); | |||
| // opacity: 0; | |||
| // } | |||
| // 100% { | |||
| // transform: translateY(0%)rotateX(0deg); | |||
| // opacity: 1; | |||
| // } | |||
| // } | |||
| } | |||
| @@ -2,6 +2,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; | |||
| import { IonSlides } from '@ionic/angular'; | |||
| import * as faker from 'faker'; | |||
| import * as moment from 'moment'; | |||
| import { Router } from '@angular/router'; | |||
| @Component({ | |||
| selector: 'app-booking', | |||
| @@ -74,7 +75,9 @@ export class BookingPage implements OnInit { | |||
| }> | |||
| }> = []; | |||
| constructor() { } | |||
| constructor( | |||
| private router: Router | |||
| ) { } | |||
| getFormattedDateTime(dateTime: Date) { | |||
| return moment(dateTime).format('DD MMM'); | |||
| @@ -111,7 +114,9 @@ export class BookingPage implements OnInit { | |||
| let price = faker.commerce.price(); | |||
| for (let k = 0; k < 5; k += 1) { | |||
| let randomNumber = Math.random() * (4 - 0) + 0; | |||
| for (let k = 0; k < randomNumber; k += 1) { | |||
| this.bookingSeatsData[i].seatsAvailable[j].seats.push({ | |||
| id: this.bookingSeatsData[i].seatsAvailable[j].stand + '##' + k.toString(), | |||
| price | |||
| @@ -140,4 +145,8 @@ export class BookingPage implements OnInit { | |||
| this.slides.slideTo(index); | |||
| } | |||
| showBookingDetails(matchData) { | |||
| this.router.navigate(['/booking-details' , { matchData: JSON.stringify(matchData) }]); | |||
| } | |||
| } | |||