Commit 015c2164 authored by Rron Jahja's avatar Rron Jahja
Browse files

Merge branch 'master' into 15-find-the-street-name-by-geo-location-data

# Conflicts:
#	src/app/app.module.ts
#	src/app/home/home.page.html
#	src/app/home/home.page.ts
parents 6579b622 e4ee9426
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="true">193.196.52.237</domain>
</domain-config>
</network-security-config>
</network-security-config>
\ No newline at end of file
......@@ -18,11 +18,21 @@ const routes: Routes = [
{
path: 'login',
loadChildren: () => import('./auth/login/login.module').then( m => m.LoginPageModule)
},
{
path: 'register',
loadChildren: () => import('./auth/register/register.module').then( m => m.RegisterPageModule)
}, {
path: 'register',
loadChildren: () => import('./auth/register/register.module').then( m => m.RegisterPageModule)
path: 'myreservation',
loadChildren: () => import('./myreservation/myreservation.module').then( m => m.MyreservationPageModule)
},
{
path: 'hirebike',
loadChildren: () => import('./hirebike/hirebike.module').then( m => m.HirebikePageModule)
}
];
@NgModule({
......
<ion-app>
<ion-split-pane contentId="main-content">
<ion-menu contentId="main-content" type="overlay">
<ion-menu contentId="main-content" type="overlay" *ngIf="restService.isUserLoggedIn && !restService.isLoginPage">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
......
......@@ -3,6 +3,10 @@ import { Component } from '@angular/core';
import { Platform } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { Storage } from '@ionic/storage';
import { Router } from '@angular/router';
import { RestService } from './rest.service';
@Component({
selector: 'app-root',
......@@ -10,12 +14,20 @@ import { StatusBar } from '@ionic-native/status-bar/ngx';
styleUrls: ['app.component.scss']
})
export class AppComponent {
isLoginPage = false;
public appPages = [
{
title: 'Home',
url: '/home',
icon: 'home'
},
{
title: 'My Reservation',
url: '/myreservation',
icon: 'clipboard'
},
{
title: 'Logout',
url: '/login',
......@@ -26,9 +38,26 @@ export class AppComponent {
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar
) {
private statusBar: StatusBar,
public restService: RestService,
private storage: Storage,
private router: Router) {
this.initializeApp();
let href = window.location.pathname
if(href === "/login") {
this.restService.isLoginPage = true;
} else {
this.restService.isLoginPage = false;
}
this.storage.get('token').then((token) => {
if(token === "") {
this.router.navigateByUrl('/login');
} else {
this.restService.isUserLoggedIn = true;
}
});
}
initializeApp() {
......
......@@ -15,6 +15,7 @@ import { NativeGeocoder, NativeGeocoderOptions } from '@ionic-native/native-geoc
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { RestService } from './rest.service';
import { ToastService } from './services/toast.service';
@NgModule({
declarations: [AppComponent],
......@@ -32,6 +33,7 @@ import { RestService } from './rest.service';
SplashScreen,
RestService,
NativeGeocoder,
ToastService,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
......
......@@ -38,17 +38,16 @@ export class LoginPage implements OnInit {
});
this.loginApi
.subscribe((data) => {
console.log('my data: ', data);
//console.log('my data: ', data);
this.restService.setToken(data.token);
this.restService.isLoginPage = false;
this.router.navigateByUrl('/home');
}, (error) => {
console.log(error);
console.log(JSON.stringify(error));
this.correctCredentials = true;
});
}
register() {
this.router.navigateByUrl('/register');
}
}
......@@ -29,7 +29,7 @@
</ion-item>
</div>
<div id="correctCredentialsmsg" padding *ngIf="correctCredentials">
<div id="correctCredentialsmsg" padding *ngIf="correctCredentials">
Wrong Credentials !
</div>
......
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { RestService } from 'src/app/rest.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-register',
......@@ -7,14 +10,33 @@ import { Observable } from 'rxjs';
styleUrls: ['./register.page.scss'],
})
export class RegisterPage implements OnInit {
httpClient: any;
registerApi: Observable<any>;
restService: any;
router: any;
correctCredentials: boolean;
constructor() { }
email: "";
password: "";
lastName: "";
firstName: "";
constructor(private router: Router, public httpClient: HttpClient, public restService: RestService) { }
ngOnInit() {
}
submitRegister() {
this.registerApi = this.httpClient.post('http://193.196.52.237:8081/register', {
"email": this.email,
"password": this.password,
"firstname": this.firstName,
"lastname": this.lastName
});
this.registerApi
.subscribe((data) => {
console.log('my data: ', data);
this.restService.setToken(data.token);
this.router.navigateByUrl('/login');
}, (error) => {
console.log(error);
this.correctCredentials = true;
});
}
}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HirebikePage } from './hirebike.page';
const routes: Routes = [
{
path: '',
component: HirebikePage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class HirebikePageRoutingModule {}
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { HirebikePageRoutingModule } from './hirebike-routing.module';
import { HirebikePage } from './hirebike.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
HirebikePageRoutingModule
],
declarations: [HirebikePage]
})
export class HirebikePageModule {}
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title slot="start">
Hire Bike
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div>
<ion-item>
<ion-input type="text" [(ngModel)]="Destination" placeholder="Enter Destination"></ion-input>
</ion-item>
</div>
<div #mapElement style="width: 100%; height: 100%" id="mapContainer"></div>
</ion-content>
<ion-footer>
<div class="bike-details-container" *ngIf="!isBikeHired">
<div class="inner">
<div class="button-container">
<ion-grid>
<ion-row>
<ion-col>Bike Name</ion-col>
<ion-col>{{bikeDetails.name}}</ion-col>
</ion-row>
<ion-row>
<ion-col>Bike Location</ion-col>
<ion-col>{{bikeDetails.address}}</ion-col>
</ion-row>
<ion-row>
<ion-col>
<ion-button size="medium" expand="block" (click)="startTrip()">Start Trip</ion-button>
</ion-col>
</ion-row>
</ion-grid>
</div>
</div>
</div>
<div class="problem-container" *ngIf="isBikeHired">
<div class="inner">
<div class="button-container">
<ion-grid>
<ion-row>
<ion-col>Any Problems?</ion-col>
</ion-row>
<ion-row>
<ion-col>
<ion-button size="medium" expand="block" (click)="CancelTrip()">Cancel Trip</ion-button>
</ion-col>
</ion-row>
</ion-grid>
</div>
</div>
</div>
</ion-footer>
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { HirebikePage } from './hirebike.page';
describe('HirebikePage', () => {
let component: HirebikePage;
let fixture: ComponentFixture<HirebikePage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HirebikePage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(HirebikePage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { Geolocation } from '@ionic-native/geolocation/ngx';
import { RestService } from '../rest.service';
import { Observable } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Storage } from '@ionic/storage';
import { ToastService } from '../services/toast.service';
import { Router } from '@angular/router';
declare var H: any;
@Component({
selector: 'app-hirebike',
templateUrl: './hirebike.page.html',
styleUrls: ['./hirebike.page.scss'],
})
export class HirebikePage implements OnInit {
private platform: any;
private map: any;
// Get an instance of the routing service:
private mapRouter: any;
reservedBike: any = {};
bikeDetails: any = {};
isBikeHired=false;
noReservation = true;
private currentLocation = { lat: 0, lng: 0 };
// Create the parameters for the routing request:
private routingParameters = {
// The routing mode:
mode: 'shortest;pedestrian',
// The start point of the route:
waypoint0: 'geo!50.1120423728813,8.68340740740811',
// The end point of the route:
waypoint1: 'geo!52.5309916298853,13.3846220493377',
// To retrieve the shape of the route we choose the route
// representation mode 'display'
representation: 'display'
};
@ViewChild("mapElement", { static: false })
public mapElement: ElementRef;
constructor(private geolocation: Geolocation,
public restService: RestService,
public httpClient: HttpClient,
private storage: Storage,
private toastService: ToastService,
private router: Router) {
this.platform = new H.service.Platform({
'apikey': 'tiVTgBnPbgV1spie5U2MSy-obhD9r2sGiOCbBzFY2_k'
});
this.mapRouter = this.platform.getRoutingService();
}
ngOnInit() {
this.getReservedBike();
}
ngAfterViewInit() {
}
getReservedBike() {
this.storage.get('token').then((token) => {
const headers = new HttpHeaders().set("Authorization", "Bearer " + token);
//call reserved bike api
let reserveUrl = 'http://193.196.52.237:8081/active-rent';
let bikeReservationStatusApi = this.httpClient.get(reserveUrl, { headers });
bikeReservationStatusApi.subscribe((resp: any) => {
console.log('Reserved Bike', resp);
if (resp.data) {
this.reservedBike = resp.data;
//Call Bike Details api
let bikeDetailsUrl = 'http://193.196.52.237:8081/bikes/' + this.reservedBike.bikeId;
let bikeDetailsApi = this.httpClient.get(bikeDetailsUrl, { headers });
bikeDetailsApi.subscribe((resp: any) => {
console.log('Bike Details', resp);
this.bikeDetails = resp.data;
this.noReservation = false;
// display map
setTimeout(() => {
this.loadmap();
}, 1000);
window.addEventListener('resize', () => this.map.getViewPort().resize());
}, (reservedBikeError) => console.log(reservedBikeError));
}
}, (bikeDetailsError) => console.log(bikeDetailsError));
});
}
startTrip(){
this.storage.get('token').then((token) => {
let url = 'http://193.196.52.237:8081/rent' + '?bikeId=' + this.bikeDetails.id;
const headers = new HttpHeaders().set("Authorization", "Bearer " + token);
let bikeApi = this.httpClient.get(url, { headers });
bikeApi.subscribe((resp) => {
console.log('my data: ', resp);
this.toastService.showToast("Trip Started");
this.isBikeHired=true;
}, (error) => {
console.log(error)
this.toastService.showToast("Unable to Hire Bike")
});
});
}
loadmap() {
var defaultLayers = this.platform.createDefaultLayers();
this.map = new H.Map(
this.mapElement.nativeElement,
defaultLayers.raster.normal.map,
{
zoom: 17,
pixelRatio: window.devicePixelRatio || 1
}
);
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(this.map));
var ui = H.ui.UI.createDefault(this.map, defaultLayers);
ui.removeControl("mapsettings");
// create custom one
var ms = new H.ui.MapSettingsControl({
baseLayers: [{
label: "3D", layer: defaultLayers.vector.normal.map
}, {
label: "Normal", layer: defaultLayers.raster.normal.map
}, {
label: "Satellite", layer: defaultLayers.raster.satellite.map
}, {
label: "Terrain", layer: defaultLayers.raster.terrain.map
}
],
layers: [{
label: "layer.traffic", layer: defaultLayers.vector.normal.traffic
},
{
label: "layer.incidents", layer: defaultLayers.vector.normal.trafficincidents
}
]
});
ui.addControl("customized", ms);
var mapSettings = ui.getControl('customized');
var zoom = ui.getControl('zoom');
mapSettings.setAlignment('top-right');
zoom.setAlignment('left-top');
//get user location
this.getLocation(this.map);
var img = ['../../../assets/images/100_percent.png', '../../../assets/images/75_percent.png', '../../../assets/images/50_percent.png', '../../../assets/images/25_percent.png', '../../../assets/images/0_percent.png'];
if (this.bikeDetails.batteryPercentage < 100 && this.bikeDetails.batteryPercentage >= 75) {
this.addMarker(Number(this.bikeDetails.lat), Number(this.bikeDetails.lon), img[0]);
}
else if (this.bikeDetails.batteryPercentage < 75 && this.bikeDetails.batteryPercentage >= 50) {
this.addMarker(Number(this.bikeDetails.lat), Number(this.bikeDetails.lon), img[1]);
}
else if (this.bikeDetails.batteryPercentage < 50 && this.bikeDetails.batteryPercentage >= 25) {
this.addMarker(Number(this.bikeDetails.lat), Number(this.bikeDetails.lon), img[2]);
} else if (this.bikeDetails.batteryPercentage < 25 && this.bikeDetails.batteryPercentage >= 0) {
this.addMarker(Number(this.bikeDetails.lat), Number(this.bikeDetails.lon), img[3]);
}
}
getLocation(map) {
this.geolocation.getCurrentPosition(
{
maximumAge: 1000, timeout: 5000,
enableHighAccuracy: true
}
).then((resp) => {
let lat = resp.coords.latitude
let lng = resp.coords.longitude
this.currentLocation.lat = resp.coords.latitude;
this.currentLocation.lng = resp.coords.longitude;
this.moveMapToGiven(map, lat, lng);
// set routing params
this.routingParameters.waypoint1 = 'geo!' + this.bikeDetails.lat + ',' + this.bikeDetails.lon;
this.routingParameters.waypoint0 = 'geo!' + this.currentLocation.lat + ',' + this.currentLocation.lng;
// show route on map
this.mapRouter.calculateRoute(this.routingParameters, this.onResult.bind(this),
(error) => {
alert(error.message);
});
}, er => {
alert('Can not retrieve Location')
}).catch((error) => {
alert('Error getting location - ' + JSON.stringify(error))
});
}
moveMapToGiven(map, lat, lng) {
var icon = new H.map.Icon('../../../assets/images/current_location.png');
// Create a marker using the previously instantiated icon:
var marker = new H.map.Marker({ lat: lat, lng: lng }, { icon: icon });
// Add the marker to the map:
map.addObject(marker);
map.setCenter({ lat: lat, lng: lng });
}
addMarker(lat, lng, img) {
var icon = new H.map.Icon(img);
// Create a marker using the previously instantiated icon:
var marker = new H.map.Marker({ lat: lat, lng: lng }, { icon: icon });
// Add the marker to the map:
this.map.addObject(marker);
}
// Define a callback function to process the routing response:
onResult(result) {
var route,
routeShape,
startPoint,
endPoint,
linestring;
if (result.response.route) {
// Pick the first route from the response:
route = result.response.route[0];
// Pick the route's shape:
routeShape = route.shape;
// Create a linestring to use as a point source for the route line
linestring = new H.geo.LineString();
// Push all the points in the shape into the linestring:
routeShape.forEach(function (point) {
var parts = point.split(',');
linestring.pushLatLngAlt(parts[0], parts[1]);
});
// Retrieve the mapped positions of the requested waypoints:
startPoint = route.waypoint[0].mappedPosition;
endPoint = route.waypoint[1].mappedPosition;
// Create a polyline to display the route:
var routeLine = new H.map.Polyline(linestring, {
/* style: {
lineWidth: 10,
fillColor: 'white',
strokeColor: 'rgba(255, 255, 255, 1)',
lineDash: [0, 2],
lineTailCap: 'arrow-tail',
lineHeadCap: 'arrow-head'
} */
style: {
lineWidth: 6,
strokeColor: 'rgba(0, 72, 255, 0.8)',
lineDash: [0, 2]
}
});
// Add the route polyline and the two markers to the map:
this.map.addObjects([routeLine]);
// Set the map's viewport to make the whole route visible:
this.map.getViewModel().setLookAtData({ bounds: routeLine.getBoundingBox() });
//this.map.setZoom(this.map.getZoom() - 4.3, true);
}
};
}
......@@ -12,12 +12,15 @@
</ion-item>
</ion-toolbar>
</ion-header>
<ion-content>
<div #mapElement2d style="width: 100%; height: 100%" id="mapContainer" *ngIf="!is3DChecked"></div>
<div #mapElement3d style="width: 100%; height: 100%" id="mapContainer" *ngIf="is3DChecked"></div>
<!--div #mapElement style="width: 100%; height: 100%" id="mapContainer"></div-->
<ion-fab class="get-position" vertical="bottom" horizontal="end" (click)="getCurrentPosition()" slot="fixed">
<ion-fab-button>
<ion-icon name="locate"></ion-icon>
</ion-fab-button>
......@@ -26,22 +29,90 @@
<ion-footer>
<div class="bike-list-container">
<div class="bike-list-container" *ngIf="!isDetailsVisible">
<div class="bike-container" *ngFor="let bike of bikes">
<div class="bike-name">
{{bike.name}}
<div class="inner" (click)="showBikeDetails(bike)">
<div class="bike-name">
{{bike.name}}
</div>
<div class="battery-info">
<div>
<ion-icon class="battery-icon" name="battery-charging"></ion-icon>
</div>
<div>{{bike.batteryPercentage + " %"}}</div>
</div>
<div class="address-info">
<div class="disance">{{bike.distance + " km"}}</div>
<div class="address">{{bike.address+" "+bike.HouseNumber+ ", " +bike.PostalCode}}</div>
</div>
</div>
<div class="battery-info">
</div>
</div>
<div class="bike-details-container" *ngIf="isDetailsVisible">
<div class="inner">
<!-- <div class="battery-info">
<div>
<ion-icon class="battery-icon" name="battery-charging"></ion-icon>
</div>
<div>{{bike.batteryPercentage + " %"}}</div>
<div>{{selectedBike.batteryPercentage + " %"}}</div>
</div>
<div class="address-info">
<div class="disance">{{bike.distance + " km"}}</div>
<div class="address">{{bike.address+" "+bike.HouseNumber+ ", " +bike.PostalCode}}</div>
<div class="disance">{{selectedBike.distance + "m"}}</div>
<div class="address">{{selectedBike.address}}</div>
</div> -->
<div class="button-container">
<ion-grid>
<ion-row>
<ion-col>
Bike Name
</ion-col>
<ion-col>
{{selectedBike.name}}
</ion-col>
</ion-row>
<ion-row>
<ion-col>
Battery Level
</ion-col>
<ion-col>
<ion-icon class="battery-icon" name="battery-charging"></ion-icon>
{{selectedBike.batteryPercentage + " %"}}
</ion-col>
</ion-row>
<ion-row>
<ion-col>
Bike Location
</ion-col>
<ion-col>
{{selectedBike.address}}
</ion-col>
</ion-row>
<ion-row>
<ion-col>
Bike Distance
</ion-col>
<ion-col>
{{selectedBike.distance + " km"}}
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<ion-button size="medium" expand="block" (click)="reserveBike()">Reserve</ion-button>
</ion-col>
<ion-col>
<ion-button size="medium" expand="block" (click)="navigatetoBike()">Navigate</ion-button>
</ion-col>
</ion-row>
</ion-grid>
</div>
</div>
</div>
</ion-footer>
\ No newline at end of file
......@@ -99,4 +99,8 @@ ion-footer{
.get-position{
margin-bottom:10px;
}
.button-container{
clear: both;
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import { RestService } from '../rest.service';
import { Observable } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Storage } from '@ionic/storage';
import { ToastService } from '../services/toast.service';
declare var H: any;
......@@ -25,6 +26,9 @@ export class HomePage {
private currentLocation = { lat: 0, lng: 0 };
public is3DChecked = false;
public isDetailsVisible = false;
public selectedBike ={id: 0};
public isBikeReserved= false;
public tempArr = [1, 2];
public locationArr = [{ lat: 48.778409, lng: 9.179252 },
......@@ -44,7 +48,8 @@ export class HomePage {
constructor(private geolocation: Geolocation,
public restService: RestService,
public httpClient: HttpClient,
private storage: Storage) {
private storage: Storage,
private toastService: ToastService) {
this.platform = new H.service.Platform({
'apikey': 'tiVTgBnPbgV1spie5U2MSy-obhD9r2sGiOCbBzFY2_k'
......@@ -58,14 +63,14 @@ export class HomePage {
ngAfterViewInit() {
setTimeout(() => {
this.loadmap("2D");
}, 200);
}, 700);
window.addEventListener('resize', () => this.map.getViewPort().resize());
}
getBikesList() {
this.geolocation.getCurrentPosition({
maximumAge: 1000, timeout: 1000,
maximumAge: 1000, timeout: 4000,
enableHighAccuracy: true
}).then((resp) => {
this.currentLocation.lat = resp.coords.latitude;
......@@ -95,10 +100,6 @@ export class HomePage {
});
}
loadmap(style) {
// Obtain the default map types from the platform object
var mapStyle = "raster";
......@@ -231,6 +232,7 @@ export class HomePage {
}, 100);
}
reverseGeocode(platform, lat, lng, index) {
var prox = lat + ',' + lng + ',56';
var geocoder = platform.getGeocodingService(),
......@@ -257,11 +259,31 @@ export class HomePage {
}
showBikeDetails(bike) {
this.selectedBike=bike;
this.selectedBike.id=bike.id;
this.isDetailsVisible = true;
}
reserveBike() {
//this.selectedBike=bikeS;
this.storage.get('token').then((token) => {
let url = 'http://193.196.52.237:8081/reservation' + '?bikeId=' + this.selectedBike.id;
const headers = new HttpHeaders().set("Authorization", "Bearer " + token);
this.bikeApi = this.httpClient.get(url, { headers });
this.bikeApi.subscribe((resp) => {
console.log('my data: ', resp);
this.isBikeReserved=true;
this.toastService.showToast("Reservation Successful!");
}, (error) => {
console.log(error)
this.toastService.showToast("Only one bike may be reserved or rented at a time")
});
});
}
}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MyreservationPage } from './myreservation.page';
const routes: Routes = [
{
path: '',
component: MyreservationPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class MyreservationPageRoutingModule {}
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { MyreservationPageRoutingModule } from './myreservation-routing.module';
import { MyreservationPage } from './myreservation.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
MyreservationPageRoutingModule
],
declarations: [MyreservationPage]
})
export class MyreservationPageModule {}
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title slot="start">
My Reservation
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card *ngIf="noReservation">
<ion-card-content>
No reservation found
</ion-card-content>
</ion-card>
<div #mapElement style="width: 100%; height: 100%" id="mapContainer" *ngIf="!noReservation"></div>
</ion-content>
<ion-footer>
<div class="bike-details-container" *ngIf="!noReservation">
<div class="inner">
<div class="button-container">
<ion-grid>
<ion-row>
<ion-col>Bike Name</ion-col>
<ion-col>{{bikeDetails.name}}</ion-col>
</ion-row>
<ion-row>
<ion-col>Battery Level</ion-col>
<ion-col>
<ion-icon class="battery-icon" name="battery-charging"></ion-icon>
{{bikeDetails.batteryPercentage +" %"}}
</ion-col>
</ion-row>
<ion-row>
<ion-col>Bike Location</ion-col>
<ion-col>{{bikeDetails.address}}</ion-col>
</ion-row>
<ion-row>
<ion-col>Bike Distance</ion-col>
<ion-col>{{ bikeDetails.distance +" m"}}</ion-col>
</ion-row>
<ion-row>
<ion-col>
<ion-button size="medium" expand="block" (click)="hireBike()">Hire</ion-button>
</ion-col>
<ion-col>
<ion-button size="medium" expand="block" (click)="cancelReservation()">Cancel Reservation</ion-button>
</ion-col>
</ion-row>
</ion-grid>
</div>
</div>
</div>
</ion-footer>
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment