@@ -29,6 +29,10 @@ const routes: Routes = [ | |||||
{ | { | ||||
path: 'booking', | path: 'booking', | ||||
loadChildren: () => import('./booking/booking.module').then( m => m.BookingPageModule) | loadChildren: () => import('./booking/booking.module').then( m => m.BookingPageModule) | ||||
}, | |||||
{ | |||||
path: 'booking-details', | |||||
loadChildren: () => import('./booking-details/booking-details.module').then( m => m.BookingDetailsPageModule) | |||||
} | } | ||||
]; | ]; | ||||
@NgModule({ | @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-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"> | <div class="image-holder"> | ||||
<figure> | <figure> | ||||
<img [src]="matchDay.staduim.sideView"> | <img [src]="matchDay.staduim.sideView"> | ||||
@@ -170,79 +170,4 @@ ion-slides { | |||||
font-size: 0.9rem; | font-size: 0.9rem; | ||||
line-height: 1.5; | 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 { IonSlides } from '@ionic/angular'; | ||||
import * as faker from 'faker'; | import * as faker from 'faker'; | ||||
import * as moment from 'moment'; | import * as moment from 'moment'; | ||||
import { Router } from '@angular/router'; | |||||
@Component({ | @Component({ | ||||
selector: 'app-booking', | selector: 'app-booking', | ||||
@@ -74,7 +75,9 @@ export class BookingPage implements OnInit { | |||||
}> | }> | ||||
}> = []; | }> = []; | ||||
constructor() { } | |||||
constructor( | |||||
private router: Router | |||||
) { } | |||||
getFormattedDateTime(dateTime: Date) { | getFormattedDateTime(dateTime: Date) { | ||||
return moment(dateTime).format('DD MMM'); | return moment(dateTime).format('DD MMM'); | ||||
@@ -111,7 +114,9 @@ export class BookingPage implements OnInit { | |||||
let price = faker.commerce.price(); | 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({ | this.bookingSeatsData[i].seatsAvailable[j].seats.push({ | ||||
id: this.bookingSeatsData[i].seatsAvailable[j].stand + '##' + k.toString(), | id: this.bookingSeatsData[i].seatsAvailable[j].stand + '##' + k.toString(), | ||||
price | price | ||||
@@ -140,4 +145,8 @@ export class BookingPage implements OnInit { | |||||
this.slides.slideTo(index); | this.slides.slideTo(index); | ||||
} | } | ||||
showBookingDetails(matchData) { | |||||
this.router.navigate(['/booking-details' , { matchData: JSON.stringify(matchData) }]); | |||||
} | |||||
} | } |