Livebeat is now able to send, store and show beats

This commit is contained in:
2020-10-23 00:39:36 +02:00
parent f722ee9595
commit 13f8437f29
52 changed files with 1948 additions and 442 deletions

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { APIService } from './api.service';
describe('APIService', () => {
let service: APIService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(APIService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,62 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
export interface ILogin {
token: string;
}
export interface IBeat {
coordinate?: number[];
accuracy: number;
speed: number;
battery?: number;
phone: any;
createdAt?: Date;
}
@Injectable({
providedIn: 'root'
})
export class APIService {
private token: string;
username: string;
API_ENDPOINT = 'http://192.168.178.26:8040'
constructor(private httpClient: HttpClient) { }
async login(username: string, password: string): Promise<ILogin> {
return new Promise<ILogin>((resolve, reject) => {
console.log('POST');
this.httpClient.post(this.API_ENDPOINT + '/user/login', { username, password }, { responseType: 'json' })
.subscribe(token => {
console.log(token);
this.token = (token as ILogin).token;
this.username = username;
resolve(token as ILogin);
});
});
}
async getBeats(): Promise<IBeat[]> {
return new Promise<IBeat[]>((resolve, reject) => {
if (this.token === undefined) { reject([]); }
const headers = new HttpHeaders({ token: this.token });
this.httpClient.get(this.API_ENDPOINT + '/beat', { responseType: 'json', headers })
.subscribe(beats => {
console.log(beats);
resolve(beats as IBeat[]);
});
});
}
hasSession(): boolean {
return this.token !== undefined;
}
}

View File

@@ -1,17 +1,22 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { NbAuthComponent, NbLoginComponent } from '@nebular/auth';
import { AppComponent } from './app.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { LoginComponent } from './login/login.component';
const routes: Routes = [
{
path: '',
component: NbAuthComponent,
children: [
{
path: '',
component: NbLoginComponent
}
]
component: AppComponent
},
{
path: 'login',
component: LoginComponent
},
{
path: 'dashboard',
component: DashboardComponent
}
];

View File

@@ -1,3 +1,12 @@
<nb-auth-block>
<nb-login></nb-login>
</nb-auth-block>
<div id="header">
<p>Header</p>
<div class="left">
<span class="ident" *ngIf="this.api.hasSession()">Logged in as {{this.api.username}}</span>
</div>
</div>
<router-outlet></router-outlet>
<!-- Display start page -->
<div id="startpage" *ngIf="false">
<h1>Livebeat</h1>
</div>

View File

@@ -0,0 +1,10 @@
#header {
width: 100vw;
height: fit-content;
padding-top: 0.4rem;
padding-bottom: 0.4rem;
background-color: #1d1d1dd9;
backdrop-filter: blur(20px);
box-shadow: 10px 10px 50px 0px rgba(0,0,0,0.85);
}

View File

@@ -1,4 +1,6 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { APIService } from './api.service';
@Component({
selector: 'app-root',
@@ -7,4 +9,7 @@ import { Component } from '@angular/core';
})
export class AppComponent {
title = 'Livebeat';
constructor(public api: APIService, private router: Router) {
}
}

View File

@@ -8,16 +8,26 @@ import { NbCardModule, NbLayoutModule, NbSidebarModule, NbThemeModule } from '@n
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { FormsModule } from '@angular/forms';
import { DashboardComponent } from './dashboard/dashboard.component';
import { NgxMapboxGLModule } from 'ngx-mapbox-gl';
@NgModule({
declarations: [
AppComponent
AppComponent,
LoginComponent,
DashboardComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
FormsModule,
HttpClientModule,
NgxMapboxGLModule.withConfig({
accessToken: 'pk.eyJ1IjoibW9uZGVpMSIsImEiOiJja2dsY2ZtaG0xZ2o5MnR0ZWs0Mm82OTBpIn0.NzDWN3P6jJLmci_v3MM1tA'
}),
NbThemeModule.forRoot({ name: 'dark' }),
NbLayoutModule,
NbEvaIconsModule,

View File

@@ -0,0 +1,13 @@
<mgl-map [style]="'mapbox://styles/mapbox/outdoors-v11'">
<mgl-geojson-source id="locHistory" [data]="data"></mgl-geojson-source>
<mgl-layer
id="locHisotryLines"
type="line"
source="locHistory"
[paint]="{
'line-color': '#ff0000',
'line-width': 4
}"
>
</mgl-layer>
</mgl-map>

View File

@@ -0,0 +1,8 @@
mgl-map {
position: absolute;
z-index: -1;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
}

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DashboardComponent } from './dashboard.component';
describe('DashboardComponent', () => {
let component: DashboardComponent;
let fixture: ComponentFixture<DashboardComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DashboardComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,32 @@
import { AfterViewInit, Component, OnInit } from '@angular/core';
import { Map } from 'mapbox-gl';
import { APIService } from '../api.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements AfterViewInit {
map: Map;
data: GeoJSON.FeatureCollection<GeoJSON.LineString> = {
type: 'FeatureCollection', features: [
{
type: 'Feature',
properties: null,
geometry: { type: 'LineString', coordinates: [] }
}]
};
constructor(private api: APIService) { }
async ngAfterViewInit(): Promise<void> {
const beats = await this.api.getBeats();
beats.forEach((beat) => {
this.data.features[0].geometry.coordinates.push([beat.coordinate[1], beat.coordinate[0]]);
});
console.log("Now:", this.data.features);
}
}

View File

@@ -0,0 +1,16 @@
<div id="login">
<h2>Login</h2>
<p>Please authenticate yourself to proceed.</p>
<form>
<div id="username">
<label>Username</label><br>
<input type="text" name="username" placeholder="Username" [(ngModel)]="username">
</div>
<div id="password">
<label>Password</label><br>
<input type="password" name="password" placeholder="Password" [(ngModel)]="password">
</div>
<button (click)="perfomLogin()">Login</button>
</form>
</div>

View File

@@ -0,0 +1,13 @@
#login {
position: relative;
margin: 0 auto;
display: block;
height: fit-content;
width: fit-content;
padding: 5rem;
border-radius: 20px;
background: #1d1d1d;
box-shadow: 20px 20px 60px #191919,
-20px -20px 60px #212121;
}

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LoginComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,31 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { APIService } from '../api.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
username = '';
password = '';
constructor(private api: APIService, private router: Router) { }
ngOnInit(): void {
}
async perfomLogin(): Promise<any> {
console.log('Clicked!');
if ((await this.api.login(this.username, this.password)).token !== undefined) {
console.log('Login was successful!');
this.router.navigate(['dashboard']);
} else {
console.log('Login was not successful!');
}
}
}

View File

@@ -61,3 +61,4 @@ import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
(window as any).global = window;

View File

@@ -2,9 +2,18 @@
@import '~@nebular/auth/styles/globals';
@import '~@nebular/theme/styles/globals';
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;700;900&display=swap');
@include nb-install() {
@include nb-theme-global();
@include nb-auth-global();
@include nb-theme-global();
};
body {
background-color: #1d1d1d;
color: #fff;
font-family: 'Inter', sans-serif;
margin: 0;
padding: 0;
}
/* You can add global styles to this file, and also import other style files */