Merge pull request #34 from Pear-Trading/Release-v0.0.4

v0.0.4
This commit is contained in:
Tom Bloor 2017-11-28 18:03:07 +00:00 committed by GitHub
commit f13546a6fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1835 additions and 2295 deletions

View file

@ -2,6 +2,14 @@
# Next Release # Next Release
# v0.0.4
* Info window on map replaced with modals
* Loading modals added to maps
* Lancaster Independent Story markers added
* Code dependencies updated
* Angular code updated to Angular 5 and made fixes to account for it
# v0.0.3 # v0.0.3
* Customer Leaderboards added * Customer Leaderboards added

3624
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{ {
"name": "localloop-web", "name": "localloop-web",
"version": "0.0.3", "version": "0.0.4",
"description": "LocalLoop Web - Web interface for LocalLoop app", "description": "LocalLoop Web - Web interface for LocalLoop app",
"author": "", "author": "",
"url": "http://www.peartrade.org", "url": "http://www.peartrade.org",
@ -18,51 +18,49 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@agm/core": "^1.0.0-beta.1", "@agm/core": "1.0.0-beta.2",
"@agm/js-marker-clusterer": "^1.0.0-beta.2", "@agm/js-marker-clusterer": "1.0.0-beta.2",
"@angular/common": "4.0.3", "@angular/common": "5.0.1",
"@angular/compiler": "4.0.3", "@angular/compiler": "5.0.1",
"@angular/core": "4.0.3", "@angular/core": "5.0.1",
"@angular/forms": "4.0.3", "@angular/forms": "5.0.1",
"@angular/http": "4.0.3", "@angular/platform-browser": "5.0.1",
"@angular/platform-browser": "4.0.3", "@angular/platform-browser-dynamic": "5.0.1",
"@angular/platform-browser-dynamic": "4.0.3", "@angular/router": "5.0.1",
"@angular/router": "4.0.3", "@angular/upgrade": "5.0.1",
"@angular/upgrade": "4.0.3", "@types/moment": "2.13.0",
"@types/moment": "^2.13.0", "chart.js": "2.7.1",
"angular-in-memory-web-api": "^0.3.1", "core-js": "2.5.1",
"chart.js": "2.5.0", "js-marker-clusterer": "1.0.0",
"core-js": "2.4.1", "moment": "^2.19.2",
"js-marker-clusterer": "^1.0.0",
"moment": "^2.18.1",
"ng2-charts": "1.6.0", "ng2-charts": "1.6.0",
"ng2-validation-manager": "^0.3.1", "ng2-validation-manager": "0.5.3",
"ngx-bootstrap": "1.6.6", "ngx-bootstrap": "2.0.0-beta.8",
"ngx-pagination": "^3.0.1", "ngx-pagination": "3.0.3",
"rxjs": "5.4.2", "rxjs": "5.5.2",
"ts-helpers": "1.1.2", "ts-helpers": "1.1.2",
"webpack": "3.5.4", "webpack": "3.8.1",
"webpack-dev-server": "2.7.1", "webpack-dev-server": "2.9.4",
"zone.js": "0.8.9" "zone.js": "0.8.18"
}, },
"devDependencies": { "devDependencies": {
"@angular/cli": "1.3.0", "@angular/cli": "1.5.0",
"@angular/compiler-cli": "4.0.3", "@angular/compiler-cli": "5.0.1",
"@types/jasmine": "2.5.54", "@types/jasmine": "2.8.2",
"@types/jasminewd2": "2.0.2", "@types/jasminewd2": "2.0.3",
"@types/node": "8.0.24", "@types/node": "8.0.52",
"codelyzer": "2.1.1", "codelyzer": "4.0.1",
"jasmine-core": "2.7.0", "jasmine-core": "2.8.0",
"jasmine-spec-reporter": "4.2.1", "jasmine-spec-reporter": "4.2.1",
"karma": "1.7.0", "karma": "1.7.1",
"karma-chrome-launcher": "2.2.0", "karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1", "karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "1.3.0", "karma-coverage-istanbul-reporter": "1.3.0",
"karma-jasmine": "1.1.0", "karma-jasmine": "1.1.0",
"karma-jasmine-html-reporter": "0.2.2", "karma-jasmine-html-reporter": "0.2.2",
"protractor": "5.1.2", "protractor": "5.2.0",
"ts-node": "3.3.0", "ts-node": "3.3.0",
"tslint": "4.5.1", "tslint": "5.8.0",
"typescript": "2.4.2" "typescript": "2.4.2"
} }
} }

View file

@ -1,7 +1,7 @@
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { LocationStrategy, HashLocationStrategy } from '@angular/common'; import { LocationStrategy, HashLocationStrategy } from '@angular/common';
import { HttpModule } from '@angular/http'; import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
@ -38,7 +38,7 @@ import { DashboardModule } from './dashboard/dashboard.module';
@NgModule({ @NgModule({
imports: [ imports: [
BrowserModule, BrowserModule,
HttpModule, HttpClientModule,
NgxPaginationModule, NgxPaginationModule,
BsDropdownModule.forRoot(), BsDropdownModule.forRoot(),
TabsModule.forRoot(), TabsModule.forRoot(),

View file

@ -1,6 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Validators, FormBuilder, FormGroup } from '@angular/forms'; import { Validators, FormBuilder, FormGroup } from '@angular/forms';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
import { Router, ActivatedRoute } from '@angular/router'; import { Router, ActivatedRoute } from '@angular/router';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
@ -15,7 +14,6 @@ export class LoginComponent implements OnInit {
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
private http: Http,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private router: Router, private router: Router,
private api: ApiService private api: ApiService

View file

@ -1,7 +1,6 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Validators, FormBuilder, FormGroup } from '@angular/forms'; import { Validators, FormBuilder, FormGroup } from '@angular/forms';
import { ValidationManager } from 'ng2-validation-manager'; import { ValidationManager } from 'ng2-validation-manager';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
import {Router } from '@angular/router'; import {Router } from '@angular/router';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
@ -19,7 +18,6 @@ export class RegisterComponent {
registerStatusError = 'Error received, please try again.'; registerStatusError = 'Error received, please try again.';
constructor( constructor(
private http: Http,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private router: Router, private router: Router,
private api: ApiService, private api: ApiService,

View file

@ -1,6 +1,5 @@
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { Validators, FormBuilder, FormGroup } from '@angular/forms'; import { Validators, FormBuilder, FormGroup } from '@angular/forms';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
@ -17,7 +16,6 @@ export class AccountEditComponent implements OnInit {
submitStatusError = 'Error received, please try again.'; submitStatusError = 'Error received, please try again.';
constructor( constructor(
private http: Http,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private api: ApiService, private api: ApiService,
) { ) {

View file

@ -1,6 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Validators, FormBuilder, FormGroup } from '@angular/forms'; import { Validators, FormBuilder, FormGroup } from '@angular/forms';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
import { OrgTableComponent } from '../shared/org-table.component'; import { OrgTableComponent } from '../shared/org-table.component';
import * as moment from 'moment'; import * as moment from 'moment';
@ -40,7 +39,6 @@ export class AddDataComponent implements OnInit {
minDate: any; minDate: any;
constructor( constructor(
private http: Http,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private api: ApiService, private api: ApiService,
) { ) {

View file

@ -21,11 +21,11 @@
<ul> <ul>
<li> <li>
<div class="text-muted">My Total Spend</div> <div class="text-muted">My Total Spend</div>
<strong>{{ basicStats.user_sum | currency:'GBP':true:'1.2-2' }}</strong> <strong>{{ basicStats.user_sum | currency:'GBP':'symbol':'1.2-2' }}</strong>
</li> </li>
<li> <li>
<div class="text-muted">Value to Local Economy</div> <div class="text-muted">Value to Local Economy</div>
<strong>{{ basicStats.user_sum * 2.3 | currency:'GBP':true:'1.2-2' }}</strong> <strong>{{ basicStats.user_sum * 2.3 | currency:'GBP':'symbol':'1.2-2' }}</strong>
</li> </li>
</ul> </ul>
</div> </div>
@ -34,7 +34,7 @@
<div class="col-sm-6 col-lg-3"> <div class="col-sm-6 col-lg-3">
<div class="card card-inverse card-primary"> <div class="card card-inverse card-primary">
<div class="card-block"> <div class="card-block">
<div class="h4 mb-0">{{ basicStats.today_sum | currency:'GBP':true:'1.2-2' }}</div> <div class="h4 mb-0">{{ basicStats.today_sum | currency:'GBP':'symbol':'1.2-2' }}</div>
<div>Total Today</div> <div>Total Today</div>
<!-- <div class="progress progress-white progress-xs mt-3"> <!-- <div class="progress progress-white progress-xs mt-3">
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div> <div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
@ -46,7 +46,7 @@
<div class="col-sm-6 col-lg-3"> <div class="col-sm-6 col-lg-3">
<div class="card card-inverse card-primary"> <div class="card card-inverse card-primary">
<div class="card-block"> <div class="card-block">
<div class="h4 mb-0">{{ basicStats.today_sum / (basicStats.today_count ? basicStats.today_count : 1) | currency:'GBP':true:'1.2-2' }}</div> <div class="h4 mb-0">{{ basicStats.today_sum / (basicStats.today_count ? basicStats.today_count : 1) | currency:'GBP':'symbol':'1.2-2' }}</div>
<div>Avg. Spend Today</div> <div>Avg. Spend Today</div>
<!-- <div class="progress progress-white progress-xs mt-3"> <!-- <div class="progress progress-white progress-xs mt-3">
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div> <div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
@ -58,7 +58,7 @@
<div class="col-sm-6 col-lg-3"> <div class="col-sm-6 col-lg-3">
<div class="card card-inverse card-primary"> <div class="card card-inverse card-primary">
<div class="card-block"> <div class="card-block">
<div class="h4 mb-0">{{ basicStats.week_sum | currency:'GBP':true:'1.2-2' }}</div> <div class="h4 mb-0">{{ basicStats.week_sum | currency:'GBP':'symbol':'1.2-2' }}</div>
<div>Last Week Total</div> <div>Last Week Total</div>
<!-- <div class="progress progress-white progress-xs mt-3"> <!-- <div class="progress progress-white progress-xs mt-3">
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div> <div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
@ -70,7 +70,7 @@
<div class="col-sm-6 col-lg-3"> <div class="col-sm-6 col-lg-3">
<div class="card card-inverse card-primary"> <div class="card card-inverse card-primary">
<div class="card-block"> <div class="card-block">
<div class="h4 mb-0">{{ basicStats.week_sum / (basicStats.week_count ? basicStats.week_count : 1) | currency:'GBP':true:'1.2-2' }}</div> <div class="h4 mb-0">{{ basicStats.week_sum / (basicStats.week_count ? basicStats.week_count : 1) | currency:'GBP':'symbol':'1.2-2' }}</div>
<div>Last Week Avg. Spend</div> <div>Last Week Avg. Spend</div>
<!-- <div class="progress progress-white progress-xs mt-3"> <!-- <div class="progress progress-white progress-xs mt-3">
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div> <div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
@ -82,7 +82,7 @@
<div class="col-sm-6 col-lg-3"> <div class="col-sm-6 col-lg-3">
<div class="card card-inverse card-primary"> <div class="card card-inverse card-primary">
<div class="card-block"> <div class="card-block">
<div class="h4 mb-0">{{ basicStats.month_sum | currency:'GBP':true:'1.2-2' }}</div> <div class="h4 mb-0">{{ basicStats.month_sum | currency:'GBP':'symbol':'1.2-2' }}</div>
<div>Last Month Total</div> <div>Last Month Total</div>
<!-- <div class="progress progress-white progress-xs mt-3"> <!-- <div class="progress progress-white progress-xs mt-3">
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div> <div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
@ -94,7 +94,7 @@
<div class="col-sm-6 col-lg-3"> <div class="col-sm-6 col-lg-3">
<div class="card card-inverse card-primary"> <div class="card card-inverse card-primary">
<div class="card-block"> <div class="card-block">
<div class="h4 mb-0">{{ basicStats.month_sum / (basicStats.month_count ? basicStats.month_count : 1) | currency:'GBP':true:'1.2-2' }}</div> <div class="h4 mb-0">{{ basicStats.month_sum / (basicStats.month_count ? basicStats.month_count : 1) | currency:'GBP':'symbol':'1.2-2' }}</div>
<div>Last Month Avg. Spend</div> <div>Last Month Avg. Spend</div>
<!-- <div class="progress progress-white progress-xs mt-3"> <!-- <div class="progress progress-white progress-xs mt-3">
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div> <div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
@ -106,7 +106,7 @@
<div class="col-sm-6 col-lg-3"> <div class="col-sm-6 col-lg-3">
<div class="card card-inverse card-primary"> <div class="card card-inverse card-primary">
<div class="card-block"> <div class="card-block">
<div class="h4 mb-0">{{ basicStats.user_sum | currency:'GBP':true:'1.2-2' }}</div> <div class="h4 mb-0">{{ basicStats.user_sum | currency:'GBP':'symbol':'1.2-2' }}</div>
<div>User Total</div> <div>User Total</div>
<!-- <div class="progress progress-white progress-xs mt-3"> <!-- <div class="progress progress-white progress-xs mt-3">
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div> <div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
@ -118,7 +118,7 @@
<div class="col-sm-6 col-lg-3"> <div class="col-sm-6 col-lg-3">
<div class="card card-inverse card-primary"> <div class="card card-inverse card-primary">
<div class="card-block"> <div class="card-block">
<div class="h4 mb-0">{{ basicStats.user_sum / (basicStats.user_count ? basicStats.user_count : 1) | currency:'GBP':true:'1.2-2' }}</div> <div class="h4 mb-0">{{ basicStats.user_sum / (basicStats.user_count ? basicStats.user_count : 1) | currency:'GBP':'symbol':'1.2-2' }}</div>
<div>User Avg. Spend</div> <div>User Avg. Spend</div>
<!-- <div class="progress progress-white progress-xs mt-3"> <!-- <div class="progress progress-white progress-xs mt-3">
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div> <div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>

View file

@ -1,5 +1,4 @@
import { Directive, Component, OnInit } from '@angular/core'; import { Directive, Component, OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { GraphWidget } from '../widgets/graph-widget.component'; import { GraphWidget } from '../widgets/graph-widget.component';
@ -36,7 +35,6 @@ export class DashboardCustomerComponent implements OnInit {
}; };
constructor( constructor(
private http: Http,
private api: ApiService, private api: ApiService,
) { ) {
this.api.basicStats().subscribe( this.api.basicStats().subscribe(

View file

@ -6,6 +6,7 @@ import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { NgxPaginationModule } from 'ngx-pagination'; import { NgxPaginationModule } from 'ngx-pagination';
import { AgmCoreModule, GoogleMapsAPIWrapper } from '@agm/core'; import { AgmCoreModule, GoogleMapsAPIWrapper } from '@agm/core';
import { AgmJsMarkerClustererModule } from '@agm/js-marker-clusterer'; import { AgmJsMarkerClustererModule } from '@agm/js-marker-clusterer';
import { ModalModule } from 'ngx-bootstrap/modal';
import { CurrencyPipe } from '@angular/common'; import { CurrencyPipe } from '@angular/common';
@ -18,6 +19,7 @@ import { TransactionLogComponent } from './transaction-log.component';
import { PayrollLogComponent } from './payroll-log.component'; import { PayrollLogComponent } from './payroll-log.component';
import { LeaderboardComponent } from './leaderboard.component'; import { LeaderboardComponent } from './leaderboard.component';
import { MapComponent } from './map.component'; import { MapComponent } from './map.component';
import { TrailMapComponent } from './trail-map.component';
import { GraphWidget } from '../widgets/graph-widget.component'; import { GraphWidget } from '../widgets/graph-widget.component';
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component'; import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
@ -47,6 +49,7 @@ import { environment } from '../../environments/environment';
BsDropdownModule, BsDropdownModule,
NgxPaginationModule, NgxPaginationModule,
DashboardRoutingModule, DashboardRoutingModule,
ModalModule.forRoot(),
], ],
declarations: [ declarations: [
DashboardComponent, DashboardComponent,
@ -62,6 +65,7 @@ import { environment } from '../../environments/environment';
LeaderboardComponent, LeaderboardComponent,
LeaderboardResultComponent, LeaderboardResultComponent,
MapComponent, MapComponent,
TrailMapComponent,
FeedbackComponent, FeedbackComponent,
GraphWidget, GraphWidget,
OrgBarSnippetComponent, OrgBarSnippetComponent,

View file

@ -15,6 +15,7 @@ import { TransactionLogComponent } from './transaction-log.component';
import { PayrollLogComponent } from './payroll-log.component'; import { PayrollLogComponent } from './payroll-log.component';
import { LeaderboardComponent } from './leaderboard.component'; import { LeaderboardComponent } from './leaderboard.component';
import { MapComponent } from './map.component'; import { MapComponent } from './map.component';
import { TrailMapComponent } from './trail-map.component';
// Using child path to allow for FullLayout theming // Using child path to allow for FullLayout theming
const routes: Routes = [ const routes: Routes = [
@ -62,6 +63,11 @@ const routes: Routes = [
component: MapComponent, component: MapComponent,
data: { title: 'Purchase Map' }, data: { title: 'Purchase Map' },
}, },
{
path: 'story-trail',
component: TrailMapComponent,
data: { title: 'Story Trail' },
},
{ {
path: 'payroll-log', path: 'payroll-log',
component: PayrollLogComponent, component: PayrollLogComponent,

View file

@ -1,6 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Validators, FormBuilder, FormGroup } from '@angular/forms'; import { Validators, FormBuilder, FormGroup } from '@angular/forms';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
@ -16,7 +15,6 @@ export class FeedbackComponent implements OnInit {
feedbackFormStatusError = 'Error received, please try again.'; feedbackFormStatusError = 'Error received, please try again.';
constructor( constructor(
private http: Http,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private api: ApiService, private api: ApiService,
) { ) {

View file

@ -1,5 +1,4 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
// import { PaginatePipe } from 'ngx-pagination'; // import { PaginatePipe } from 'ngx-pagination';
import {PaginationInstance} from 'ngx-pagination'; import {PaginationInstance} from 'ngx-pagination';
@ -29,7 +28,6 @@ export class LeaderboardComponent implements OnInit {
}; };
constructor( constructor(
private http: Http,
private api: ApiService, private api: ApiService,
) { } ) { }

View file

@ -6,37 +6,66 @@
<strong>Purchase Map</strong> <strong>Purchase Map</strong>
<small>Required Data marked in <strong>bold</strong>.</small> <small>Required Data marked in <strong>bold</strong>.</small>
</div> </div>
<div [ngSwitch]="dataReceived"> <div class="modal fade" bsModal #statusModal="bs-modal" [config]="{backdrop: false, animated: false}"
<div *ngSwitchCase="'no'"class="card-block"> tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="alert alert-danger" role="alert"> <div class="modal-dialog modal-sm h-100 d-flex flex-column justify-content-center my-0">
No map data received, check your connection. <div class="modal-content">
<div class="modal-header">
<h4 class="modal-title pull-left">Status</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="statusModal.hide()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div [ngSwitch]="dataReceived">
<div *ngSwitchCase="'no'">
<div class="alert alert-danger" role="alert">
No map data received, check your connection.
</div>
</div>
<div *ngSwitchCase="'loading'">
<div class="alert alert-warning" role="alert">
Map loading, please wait.
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
<div *ngSwitchCase="'yes'">
<!-- this creates a google map on the page with the given lat/lng from -->
<!-- the component as the initial center of the map: -->
<agm-map
(mapReady)="onMapReady($event)"
[latitude]="lat"
[longitude]="lng"
[zoom]="zoom"
[scaleControl]="true"
(idle)="viewBoundsChanged($event)">
<agm-marker-cluster maxZoom="13" imagePath="https://raw.githubusercontent.com/googlemaps/v3-utility-library/master/markerclustererplus/images/m">
<agm-marker
*ngFor="let m of markers"
[latitude]="m.latitude"
[longitude]="m.longitude"
[label]="m.name[0]">
<agm-info-window>
<strong>{{m.name}}</strong>
</agm-info-window>
</agm-marker>
</agm-marker-cluster>
</agm-map>
</div>
</div> </div>
<!-- this creates a google map on the page with the given lat/lng from -->
<!-- the component as the initial center of the map: -->
<agm-map (mapReady)="onMapReady($event)"
[latitude]="lat"
[longitude]="lng"
[zoom]="zoom"
[scaleControl]="true"
(idle)="viewBoundsChanged($event)">
<agm-marker-cluster maxZoom="13" imagePath="https://raw.githubusercontent.com/googlemaps/v3-utility-library/master/markerclustererplus/images/m">
<agm-marker
*ngFor="let m of markers"
[latitude]="m.latitude"
[longitude]="m.longitude"
[label]="m.name[0]"
[openInfoWindow]="false"
(markerClick)="onMarkerClick(m, template)">
</agm-marker>
</agm-marker-cluster>
</agm-map>
<ng-template #template>
<div class="modal-header d-flex justify-content-between">
<img src="assets/img/logo.png" class="w-15" alt="lis logo"><h4 class="modal-title">{{clickedMarker.name}}</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body text-right">
<h5>Located at:</h5>
<h6>{{clickedMarker.street_name}}</h6>
<h6>{{clickedMarker.town}}</h6>
<h6>{{clickedMarker.postcode}}</h6>
</div>
</ng-template>
</div> </div>
</div> </div>
</div><!--/.row--> </div><!--/.row-->

View file

@ -1,35 +1,52 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, AfterViewInit, Input, Output, EventEmitter, ViewChild, TemplateRef } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
import { AgmCoreModule } from '@agm/core'; import { AgmCoreModule } from '@agm/core';
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
@Component({ @Component({
templateUrl: 'map.component.html', templateUrl: 'map.component.html',
}) })
export class MapComponent implements OnInit { export class MapComponent implements OnInit, AfterViewInit {
@ViewChild('statusModal') myStatusModal: ModalDirective;
lat: number = 54.0466; lat: number = 54.0466;
lng: number = -2.8007; lng: number = -2.8007;
zoom: number = 12; zoom: number = 12;
public modalRef: BsModalRef;
clickedMarker: any;
dataReceived: string = 'yes'; dataReceived: string = 'loading';
markers: Array<{latitude: number, longitude: number, name: string}>; markers: Array<{latitude: number, longitude: number, name: string}>;
map: any; map: any;
constructor( constructor(
private http: Http,
private api: ApiService, private api: ApiService,
private modalService: BsModalService,
) { } ) { }
ngOnInit(): void { } ngOnInit(): void { }
ngAfterViewInit() {
this.myStatusModal.show();
}
public onMapReady(map: any) { public onMapReady(map: any) {
this.map = map; this.map = map;
} }
openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template);
}
public onMarkerClick(clickedMarker, template: TemplateRef<any>) {
console.log(clickedMarker);
this.clickedMarker = clickedMarker;
this.openModal(template);
}
public viewBoundsChanged() { public viewBoundsChanged() {
console.log("finding bounds"); console.log("finding bounds");
const resp = this.map.getBounds(); const resp = this.map.getBounds();
@ -50,11 +67,11 @@ export class MapComponent implements OnInit {
} }
this.api.getMapData(mapData).subscribe( this.api.getMapData(mapData).subscribe(
result => { result => {
this.dataReceived = 'yes'; this.myStatusModal.hide();
this.markers = result.suppliers; this.markers = result.suppliers;
}, },
error => { error => {
// this.dataReceived = 'no'; this.dataReceived = 'no';
console.log('Retrieval Error'); console.log('Retrieval Error');
console.log( error._body ); console.log( error._body );
} }

View file

@ -1,5 +1,4 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
// import { PaginatePipe } from 'ngx-pagination'; // import { PaginatePipe } from 'ngx-pagination';
import {PaginationInstance} from 'ngx-pagination'; import {PaginationInstance} from 'ngx-pagination';
@ -27,7 +26,6 @@ export class PayrollLogComponent implements OnInit {
}; };
constructor( constructor(
private http: Http,
private api: ApiService, private api: ApiService,
) { ) {
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm'); this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');

View file

@ -0,0 +1,73 @@
<div class="animated fadeIn">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<strong>Purchase Map</strong>
<small>Required Data marked in <strong>bold</strong>.</small>
</div>
<div class="modal fade" bsModal #statusModal="bs-modal" [config]="{backdrop: false, animated: false}"
tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm h-100 d-flex flex-column justify-content-center my-0">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title pull-left">Status</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="statusModal.hide()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div [ngSwitch]="dataReceived">
<div *ngSwitchCase="'no'">
<div class="alert alert-danger" role="alert">
No map data received, check your connection.
</div>
</div>
<div *ngSwitchCase="'loading'">
<div class="alert alert-warning" role="alert">
Map loading, please wait.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- this creates a google map on the page with the given lat/lng from -->
<!-- the component as the initial center of the map: -->
<agm-map
(mapReady)="onMapReady($event)"
[latitude]="lat"
[longitude]="lng"
[zoom]="zoom"
[scaleControl]="true"
(idle)="viewBoundsChanged($event)">
<agm-marker-cluster maxZoom="13" imagePath="https://raw.githubusercontent.com/googlemaps/v3-utility-library/master/markerclustererplus/images/m">
<agm-marker
*ngFor="let m of markers"
[iconUrl]="'/assets/img/map-pin-lis.png'"
[latitude]="m.latitude"
[longitude]="m.longitude"
[openInfoWindow]="false"
(markerClick)="onMarkerClick(m, template)">
</agm-marker>
</agm-marker-cluster>
</agm-map>
<ng-template #template>
<div class="modal-header d-flex justify-content-between">
<img src="assets/img/lis_logo.png" class="w-15" alt="lis logo"><h4 class="modal-title">{{clickedMarker.name}}</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body text-right">
<h5>Located at:</h5>
<h6>{{clickedMarker.street_name}}</h6>
<h6>{{clickedMarker.town}}</h6>
<h6>{{clickedMarker.postcode}}</h6>
</div>
</ng-template>
</div>
</div>
</div><!--/.row-->
</div>

View file

@ -0,0 +1,83 @@
import { Component, OnInit, AfterViewInit, Input, Output, EventEmitter, ViewChild, TemplateRef } from '@angular/core';
import { ApiService } from '../providers/api-service';
import { AgmCoreModule } from '@agm/core';
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
import 'rxjs/add/operator/map';
@Component({
templateUrl: 'trail-map.component.html',
})
export class TrailMapComponent implements OnInit, AfterViewInit {
@ViewChild('statusModal') myStatusModal: ModalDirective;
lat: number = 54.0466;
lng: number = -2.8007;
zoom: number = 12;
public modalRef: BsModalRef;
clickedMarker: any;
dataReceived: string = 'loading';
markers: Array<{latitude: number, longitude: number, name: string}>;
map: any;
constructor(
private api: ApiService,
private modalService: BsModalService,
) {}
ngOnInit(): void { }
ngAfterViewInit() {
this.myStatusModal.show();
}
public onMapReady(map: any) {
this.map = map;
}
openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template);
}
public onMarkerClick(clickedMarker, template: TemplateRef<any>) {
console.log(clickedMarker);
this.clickedMarker = clickedMarker;
this.openModal(template);
}
public viewBoundsChanged() {
console.log("finding bounds");
const resp = this.map.getBounds();
console.log("found bounds");
console.log(resp.getNorthEast().lat());
console.log(resp.getNorthEast().lng());
console.log(resp.getSouthWest().lat());
console.log(resp.getSouthWest().lng());
const mapData = {
north_east: {
latitude: resp.getNorthEast().lat(),
longitude: resp.getNorthEast().lng()
},
south_west: {
latitude: resp.getSouthWest().lat(),
longitude: resp.getSouthWest().lng()
},
}
this.api.getLisData(mapData).subscribe(
result => {
this.myStatusModal.hide();
this.markers = result.locations;
},
error => {
this.dataReceived = 'no';
console.log('Retrieval Error');
console.log( error._body );
}
);
}
}

View file

@ -1,5 +1,4 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ApiService } from '../providers/api-service'; import { ApiService } from '../providers/api-service';
// import { PaginatePipe } from 'ngx-pagination'; // import { PaginatePipe } from 'ngx-pagination';
import {PaginationInstance} from 'ngx-pagination'; import {PaginationInstance} from 'ngx-pagination';
@ -28,7 +27,6 @@ export class TransactionLogComponent implements OnInit {
}; };
constructor( constructor(
private http: Http,
private api: ApiService, private api: ApiService,
) { ) {
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm'); this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');

View file

@ -45,6 +45,11 @@
<i class="icon-map"></i> Purchase Map <i class="icon-map"></i> Purchase Map
</a> </a>
</li> </li>
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" [routerLink]="['/story-trail']">
<i class="icon-map"></i> Story Trail
</a>
</li>
<li *ngIf="accountType == 'customer'" class="nav-item"> <li *ngIf="accountType == 'customer'" class="nav-item">
<a class="nav-link" routerLinkActive="active" [routerLink]="['/leaderboard']"> <a class="nav-link" routerLinkActive="active" [routerLink]="['/leaderboard']">
<i class="icon-basket"></i> Leaderboard <i class="icon-basket"></i> Leaderboard

View file

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Http } from '@angular/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { environment } from '../../environments/environment'; import { environment } from '../../environments/environment';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
@ -11,7 +11,7 @@ export class ApiService {
private apiUrl = environment.apiUrl; private apiUrl = environment.apiUrl;
private sessionKey: string = null; private sessionKey: string = null;
constructor( constructor(
private http: Http, private http: HttpClient,
) { ) {
if (localStorage.getItem('sessionKey') ) { if (localStorage.getItem('sessionKey') ) {
this.sessionKey = localStorage.getItem('sessionKey'); this.sessionKey = localStorage.getItem('sessionKey');
@ -20,10 +20,10 @@ export class ApiService {
public post(url: string, data: any = {}) { public post(url: string, data: any = {}) {
data.session_key = this.sessionKey; data.session_key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + url, this.apiUrl + url,
data data
).map( response => response.json() ); );
} }
// Login API // Login API
@ -46,21 +46,21 @@ export class ApiService {
} }
public register(data) { public register(data) {
return this.http.post( return this.http.post<any>(
this.apiUrl + '/register', this.apiUrl + '/register',
data data
).map( response => response.json() ); );
} }
public login(data) { public login(data) {
return this.http return this.http
.post( .post<any>(
this.apiUrl + '/login', this.apiUrl + '/login',
data data
) )
.map( .map(
result => { result => {
const json = result.json(); const json = result;
this.setSessionKey(json.session_key); this.setSessionKey(json.session_key);
this.setUserInfo( this.setUserInfo(
json.email, json.email,
@ -76,7 +76,7 @@ export class ApiService {
console.log(this.sessionKey); console.log(this.sessionKey);
const key = this.sessionKey; const key = this.sessionKey;
return this.http return this.http
.post( .post<any>(
this.apiUrl + '/logout', this.apiUrl + '/logout',
{ session_key : key }, { session_key : key },
) )
@ -84,7 +84,7 @@ export class ApiService {
response => { response => {
localStorage.clear(); localStorage.clear();
this.sessionKey = null; this.sessionKey = null;
return response.json(); return response;
} }
); );
} }
@ -97,82 +97,82 @@ export class ApiService {
data.version_code = 'dev'; data.version_code = 'dev';
data.version_number = 'dev'; data.version_number = 'dev';
console.log(data); console.log(data);
return this.http.post( return this.http.post<any>(
this.apiUrl + '/feedback', this.apiUrl + '/feedback',
data data
).map( response => response.json() ); );
} }
// gets transaction list for log // gets transaction list for log
public transList(data) { public transList(data) {
const key = this.sessionKey; const key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/outgoing-transactions', this.apiUrl + '/outgoing-transactions',
{ {
session_key : key, session_key : key,
page : data page : data
} }
).map( response => response.json() ); );
} }
// Searches organisations used for transaction submission // Searches organisations used for transaction submission
public search(data) { public search(data) {
data.session_key = this.sessionKey; data.session_key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/search', this.apiUrl + '/search',
data data
).map( response => response.json() ); );
} }
// Uploads a transaction // Uploads a transaction
public upload(data) { public upload(data) {
data.session_key = this.sessionKey; data.session_key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/upload', this.apiUrl + '/upload',
data data
).map( response => response.json() ); );
} }
// gets payroll list for log // gets payroll list for log
public payrollList(data) { public payrollList(data) {
const key = this.sessionKey; const key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/v1/organisation/payroll', this.apiUrl + '/v1/organisation/payroll',
{ {
session_key : key, session_key : key,
page : data page : data
} }
).map( response => response.json() ); );
} }
// handles Org data added // handles Org data added
public orgPayroll(data) { public orgPayroll(data) {
data.session_key = this.sessionKey; data.session_key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/v1/organisation/payroll/add', this.apiUrl + '/v1/organisation/payroll/add',
data data
).map( response => response.json() ); );
} }
public orgSupplier(data) { public orgSupplier(data) {
data.session_key = this.sessionKey; data.session_key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/v1/organisation/supplier/add', this.apiUrl + '/v1/organisation/supplier/add',
data data
).map( response => response.json() ); );
} }
public orgEmployee(data) { public orgEmployee(data) {
data.session_key = this.sessionKey; data.session_key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/v1/organisation/employee/add', this.apiUrl + '/v1/organisation/employee/add',
data data
).map( response => response.json() ); );
} }
// Handles user data interaction // Handles user data interaction
@ -204,18 +204,18 @@ export class ApiService {
public accountFullLoad() { public accountFullLoad() {
const key = this.sessionKey; const key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/user', this.apiUrl + '/user',
{ session_key : key }, { session_key : key },
).map( response => response.json() ); );
} }
public accountEditUpdate(data) { public accountEditUpdate(data) {
data.session_key = this.sessionKey; data.session_key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/user/account', this.apiUrl + '/user/account',
data data
).map( response => response.json() ); );
} }
// Deletes account details on logout // Deletes account details on logout
@ -257,33 +257,42 @@ export class ApiService {
type: string, type: string,
page: number) { page: number) {
const key = this.sessionKey; const key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/stats/leaderboard/paged', this.apiUrl + '/stats/leaderboard/paged',
{ {
session_key : key, session_key : key,
type : type, type : type,
page: page, page: page,
} }
).map( response => response.json() ); );
} }
// Initial Map Data // Initial Map Data
public getMapData(data) { public getMapData(data) {
data.session_key = this.sessionKey; data.session_key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/v1/supplier/location', this.apiUrl + '/v1/supplier/location',
data data
).map( response => response.json() ); );
}
// Load LIS Data
public getLisData(data) {
data.session_key = this.sessionKey;
return this.http.post<any>(
this.apiUrl + '/v1/supplier/location/lis',
data
);
} }
// Basic Customer User stats API // Basic Customer User stats API
public basicStats() { public basicStats() {
const key = this.sessionKey; const key = this.sessionKey;
return this.http.post( return this.http.post<any>(
this.apiUrl + '/stats', this.apiUrl + '/stats',
{ {
session_key : key, session_key : key,
} }
).map( response => response.json() ); );
} }
} }

View file

@ -1,3 +1,3 @@
<td>{{ leaderboard.position }}</td> <td>{{ leaderboard.position }}</td>
<td class="text-truncate">{{ leaderboard.display_name }}</td> <td class="text-truncate">{{ leaderboard.display_name }}</td>
<td>{{ listType.includes('total') ? (leaderboard.value | currency:'GBP':true:'1.2-2') : (leaderboard.value | number:'1.0-0') }}</td> <td>{{ listType.includes('total') ? (leaderboard.value | currency:'GBP':'symbol':'1.2-2') : (leaderboard.value | number:'1.0-0') }}</td>

View file

@ -1,3 +1,3 @@
<td>{{payrollDate}}</td> <td>{{payrollDate}}</td>
<td>{{payroll.gross_payroll | currency:'GBP':true:'1.2-2' }}</td> <td>{{payroll.gross_payroll | currency:'GBP':'symbol':'1.2-2' }}</td>
<td>{{payroll.employee_amount}}</td> <td>{{payroll.employee_amount}}</td>

View file

@ -1,3 +1,3 @@
<td>{{transaction.seller}}</td> <td>{{transaction.seller}}</td>
<td>{{transaction.value | currency:'GBP':true:'1.2-2' }}</td> <td>{{transaction.value | currency:'GBP':'symbol':'1.2-2' }}</td>
<td>{{transactionDate}}</td> <td>{{transactionDate}}</td>

View file

@ -7,7 +7,7 @@
</li> </li>
<li class="hidden-sm-down"> <li class="hidden-sm-down">
<div class="text-muted">Money Spent This Month</div> <div class="text-muted">Money Spent This Month</div>
<strong>{{ thisMonthPurchasesTotal | currency:'GBP':true:'1.2-2'}}</strong> <strong>{{ thisMonthPurchasesTotal | currency:'GBP':'symbol':'1.2-2'}}</strong>
</li> </li>
<li class="hidden-sm-down"> <li class="hidden-sm-down">
<div class="text-muted">Customers Today</div> <div class="text-muted">Customers Today</div>
@ -15,7 +15,7 @@
</li> </li>
<li class="hidden-sm-down"> <li class="hidden-sm-down">
<div class="text-muted">Average Transaction Today</div> <div class="text-muted">Average Transaction Today</div>
<strong>{{ ( todaySalesTotal / todaySalesCount ) || 0 | currency:'GBP':true:'1.2-2'}}</strong> <strong>{{ ( todaySalesTotal / todaySalesCount ) || 0 | currency:'GBP':'symbol':'1.2-2'}}</strong>
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -4,7 +4,7 @@
<i [ngClass]="graphIcon"></i> <i [ngClass]="graphIcon"></i>
</button> </button>
<h4 *ngIf="dataType == availableDataTypes.number" class="mb-0">{{ graphSum }}</h4> <h4 *ngIf="dataType == availableDataTypes.number" class="mb-0">{{ graphSum }}</h4>
<h4 *ngIf="dataType == availableDataTypes.currency" class="mb-0">{{ graphSum | currency:'GBP':true:'1.2-2' }}</h4> <h4 *ngIf="dataType == availableDataTypes.currency" class="mb-0">{{ graphSum | currency:'GBP':'symbol':'1.2-2' }}</h4>
<p>{{ graphTitle }}</p> <p>{{ graphTitle }}</p>
</div> </div>
<div class="chart-wrapper px-3" style="height:70px;"> <div class="chart-wrapper px-3" style="height:70px;">

View file

@ -137,7 +137,7 @@ export class GraphWidget implements OnInit {
private tooltipLabelCallback(tooltipItem: any, data: any) { private tooltipLabelCallback(tooltipItem: any, data: any) {
const value = tooltipItem.yLabel; const value = tooltipItem.yLabel;
if ( this.dataType === DataType.currency ) { if ( this.dataType === DataType.currency ) {
return this.currencyPipe.transform(value, 'GBP', true, '1.2-2'); return this.currencyPipe.transform(value, 'GBP', 'symbol', '1.2-2');
} }
return value || '0'; return value || '0';
} }

BIN
src/assets/img/lis_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -20,6 +20,10 @@ agm-map {
height: 75vh; height: 75vh;
} }
.w-15 {
width: 15%;
}
// white title font variant on type-2 as defined in _widgets.css // white title font variant on type-2 as defined in _widgets.css
.horizontal-bars { .horizontal-bars {
padding: 0; padding: 0;