Compare commits

...
This repository has been archived on 2023-08-16. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.

10 commits

Author SHA1 Message Date
Unknown
f96dd0bfe2 WIP 2018-05-14 16:52:33 +01:00
Unknown
5fb33cffbf amended package lock json 2018-03-13 16:37:57 +00:00
Unknown
dc1e740889 Merge remote-tracking branch 'origin/theslby/pushapi' into theslby/pushapi 2018-03-13 16:37:03 +00:00
Unknown
9997cf7ee5 Merge remote-tracking branch 'origin/development' into theslby/pushapi 2018-03-13 16:33:59 +00:00
piratefinn
aa8763d5a6 Merge branch 'development' into theslby/pushapi 2018-03-07 13:09:14 +00:00
piratefinn
700ee3c155 fixes 2018-03-07 12:27:16 +00:00
Unknown
ff0fe0202f /pushapi: Auto stash before merge of "theslby/pushapi" and "development"
Push Frontend
2018-03-06 15:41:13 +00:00
Unknown
59cbc920c2 Merge branch 'development' into theslby/pushapi 2018-03-06 12:25:58 +00:00
Unknown
175c2decdd Merge remote-tracking branch 'origin/master' into theslby/pushapi 2018-01-19 13:40:17 +00:00
Unknown
6e0b059241 push stuff 2018-01-19 13:39:54 +00:00
22 changed files with 3014 additions and 2336 deletions

View file

@ -28,7 +28,8 @@
"prod": "environments/environment.prod.ts",
"local": "environments/environment.local.ts",
"ci": "environments/environment.ci.ts"
}
},
"serviceWorker": true
}
],
"e2e": {

3
.gitignore vendored
View file

@ -48,6 +48,9 @@ testem.log
/src/environments/environment.ci.ts
/src/environments/environments.tar
# dist
/dist/*
# =========================
# Operating System Files
# =========================

4913
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -20,31 +20,41 @@
"dependencies": {
"@agm/core": "1.0.0-beta.2",
"@agm/js-marker-clusterer": "1.0.0-beta.2",
"@angular/animations": "5.2.1",
"@angular/cdk": "5.2.3",
"@angular/common": "5.2.0",
"@angular/compiler": "5.2.0",
"@angular/core": "5.2.0",
"@angular/forms": "5.2.0",
"@angular/http": "5.2.7",
"@angular/material": "5.2.3",
"@angular/platform-browser": "5.2.0",
"@angular/platform-browser-dynamic": "5.2.0",
"@angular/router": "5.2.0",
"@angular/service-worker": "5.2.4",
"@angular/upgrade": "5.2.0",
"@types/moment": "2.13.0",
"chart.js": "2.7.1",
"core-js": "2.5.1",
"http-server": "0.11.1",
"js-marker-clusterer": "1.0.0",
"moment": "^2.21.0",
"ng2-charts": "1.6.0",
"ng2-validation-manager": "0.5.3",
"ngx-bootstrap": "2.0.0-beta.8",
"ngx-pagination": "3.0.3",
"node-snackbar": "0.1.9",
"rxjs": "5.5.6",
"ts-helpers": "1.1.2",
"web-push": "3.2.5",
"webpack": "3.8.1",
"webpack-dev-server": "3.1.0",
"zone.js": "0.8.18"
},
"devDependencies": {
"@angular/cli": "1.7.3",
"@angular/compiler-cli": "5.2.0",
"@types/google.analytics": "0.0.39",
"@types/jasmine": "2.8.2",
"@types/jasminewd2": "2.0.3",
"@types/node": "8.0.52",
@ -60,6 +70,6 @@
"protractor": "5.2.0",
"ts-node": "3.3.0",
"tslint": "5.8.0",
"typescript": "2.6.x"
"typescript": "2.5.3"
}
}

View file

@ -1,5 +1,10 @@
import { HttpModule } from '@angular/http';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
@ -38,15 +43,20 @@ import { P500Component } from './pages/500.component';
import { AuthModule } from './auth/auth.module';
import { DashboardModule } from './dashboard/dashboard.module';
@NgModule({
imports: [
BrowserAnimationsModule,
BrowserModule,
HttpClientModule,
HttpModule,
NgxPaginationModule,
BsDropdownModule.forRoot(),
TabsModule.forRoot(),
AuthModule,
DashboardModule,
ServiceWorkerModule.register('/ngsw-worker.js', {enabled: environment.production}),
// Loaded last to allow for 404 catchall
AppRoutingModule,
],
@ -76,6 +86,15 @@ import { DashboardModule } from './dashboard/dashboard.module';
useClass: HashLocationStrategy
}
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
export class AppModule {
constructor () {
if (environment.enableAnalytics) {
(<any>window).ga('create', environment.analyticsKey, 'auto');
}
}
}

16
src/app/config.service.ts Normal file
View file

@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { environment } from './../environments/environment';
@Injectable()
export class ConfigService {
private _config:any = environment.config;
constructor() {
}
get(key: any) {
return this._config[key];
}
}

View file

@ -175,3 +175,16 @@
</div>
</div><!--/.row-->
</div>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<strong>Push Notification Settings</strong>
<small>Would you like to recieve notfications from companys about their latests offers?</small>
<div class="card-body">
<app-push></app-push>
</div>
</div>
</div>
</div>
</div>

View file

@ -1,9 +1,10 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import {Router, NavigationEnd} from "@angular/router";
import { GraphWidget } from '../widgets/graph-widget.component';
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
import { GraphPanel } from '../panels/graph-panel.component';
import { DataType } from '../shared/data-types.enum';
import { environment } from '../../environments/environment';
@Component({
templateUrl: 'dashboard.component.html'
@ -50,6 +51,14 @@ export class DashboardComponent {
dataType: DataType.currency,
},
];
constructor() { }
constructor(private router: Router) {
if (environment.enableAnalytics) {
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
(<any>window).ga('set', 'page', event.urlAfterRedirects);
(<any>window).ga('send', 'pageview');
}
});
}
}
}

View file

@ -18,6 +18,8 @@ import { FeedbackComponent } from './feedback.component';
import { TransactionLogComponent } from './transaction-log.component';
import { CategoryMonthComponent } from './category-month.component';
import { PayrollLogComponent } from './payroll-log.component';
import { OrgPushComponent } from './org-push.component';
import { LeaderboardComponent } from './leaderboard.component';
import { MapComponent } from './map.component';
import { TrailMapComponent } from './trail-map.component';
@ -35,6 +37,10 @@ import { TransactionResultComponent } from '../shared/transaction-result.compone
import { PayrollResultComponent } from '../shared/payroll-result.component';
import { LeaderboardResultComponent } from '../shared/leaderboard-result.component';
import { MatButtonModule } from '@angular/material/button';
import { ConfigService } from '../config.service';
import { PushComponent } from '../push/push.component';
// API key env variable import
import { environment } from '../../environments/environment';
@ -42,6 +48,7 @@ import { environment } from '../../environments/environment';
imports: [
// Angular imports
CommonModule,
MatButtonModule,
FormsModule,
ReactiveFormsModule,
ChartsModule,
@ -56,6 +63,7 @@ import { environment } from '../../environments/environment';
],
declarations: [
DashboardComponent,
PushComponent,
DashboardCustomerComponent,
AccountEditComponent,
AddDataComponent,
@ -66,6 +74,7 @@ import { environment } from '../../environments/environment';
TransactionResultComponent,
PayrollLogComponent,
PayrollResultComponent,
OrgPushComponent,
LeaderboardComponent,
LeaderboardResultComponent,
MapComponent,
@ -80,6 +89,7 @@ import { environment } from '../../environments/environment';
providers: [
CurrencyPipe,
GoogleMapsAPIWrapper,
ConfigService
],
})
export class DashboardModule { }

View file

@ -14,6 +14,7 @@ import { FeedbackComponent } from './feedback.component';
import { TransactionLogComponent } from './transaction-log.component';
import { CategoryMonthComponent } from './category-month.component';
import { PayrollLogComponent } from './payroll-log.component';
import { OrgPushComponent } from './org-push.component';
import { LeaderboardComponent } from './leaderboard.component';
import { MapComponent } from './map.component';
import { TrailMapComponent } from './trail-map.component';
@ -80,6 +81,12 @@ const routes: Routes = [
data: { title: 'Payroll Log' },
canActivate: [OrgGuard],
},
{
path: 'org-push',
component: OrgPushComponent,
data: { title: 'Push Notifications' },
canActivate: [OrgGuard],
},
{
path: 'feedback',
component: FeedbackComponent,

View file

@ -0,0 +1,47 @@
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<strong>Push Notifcations</strong>
<small>Here you can send push notifications about sales to users</small>
</div>
<form class="form-horizontal" [formGroup]="pushForm" (ngSubmit)="onSubmit()">
<div class="card-block">
<div class="form-group row">
<label class="col-md-3 form-control-label" for="text-input"><strong>Title</strong></label>
<div class="col-md-9">
<input type="text" class="form-control" formControlName="title">
</div>
</div>
</div>
<div class="card-block">
<div class="form-group row">
<label class="col-md-3 form-control-label" for="text-input"><strong>Body</strong></label>
<div class="col-md-9">
<input type="text" class="form-control" formControlName="body">
</div>
</div>
</div>
<div class="card-block">
<div class="form-group row">
<label class="col-md-3 form-control-label" for="text-input"><strong>Icon</strong></label>
<div class="col-md-9">
<input type="text" class="form-control" formControlName="icon">
<span class="help-block">Enter URL to Icon you would like to use.</span>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-md-3 form-control-label" for="text-input"><strong>Personalise Notifcations</strong></label>
<div class="col-md-9">
<input type="checkbox" class="form-control" formControlName="personalised" (change)="toggleEditable($event)" >
<span class="help-block">Tick if you want to personalise notifications adding the users name.</span>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-sm btn-primary"><i class="fa fa-dot-circle-o"></i> Submit</button>
</div>
</form>
</div>
</div>
</div>

View file

@ -0,0 +1,47 @@
import { Component} from '@angular/core';
import { ApiService } from '../providers/api-service';
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
@Component({
templateUrl: './org-push.component.html'
})
export class OrgPushComponent{
pushForm: FormGroup;
personalised = false;
constructor(
private formBuilder: FormBuilder,
private api: ApiService,
) {
this.pushForm = this.formBuilder.group({
title: ['', [Validators.required]],
body: ['', [Validators.required]],
icon: ['', [Validators.required]],
personalised: [true, [Validators.required]],
});
}
onSubmit(){
console.log(this.pushForm.value)
console.log(this.personalised)
this.api.sendNotification(this.pushForm.value)
.subscribe(
res => {
console.log('Message Sent', res)
},
err => {
console.log('Message Failed to send', err)
}
)
}
toggleEditable(event) {
if ( event.target.checked ) {
this.personalised = true;
}
}
}

View file

@ -20,7 +20,6 @@
</li>
</ul>
</header>
<div class="app-body">
<div class="sidebar">
<nav class="sidebar-nav">
@ -97,6 +96,14 @@
</div>
</a>
</li>
<li *ngIf="accountType == 'organisation'" class="nav-item">
<a class="nav-link" routerLinkActive="active" [routerLink]="['/org-push']">
<div class="row no-gutters align-items-center">
<div class="col-2"><i class="icon-envelope-letter"></i></div>
<div class="col-10">Push Notifications</div>
</div>
</a>
</li>
</ul>
</nav>
</div>
@ -116,7 +123,6 @@
</main>
</div>
<footer class="app-footer">
<a href="http://www.peartrade.org" target="_blank">&copy; 2017 Pear Trading Ltd.</a>
<span class="float-right">Powered by <a href="http://coreui.io">CoreUI</a></span>

View file

@ -240,6 +240,14 @@ export class ApiService {
);
}
public sendNotification(data) {
data.session_key = this.sessionKey;
return this.http.post<any>(
this.apiUrl + '/push/org_send_notification',
data
);
}
// Deletes account details on logout
public removeUserInfo() {
@ -273,6 +281,32 @@ export class ApiService {
localStorage.getItem('email');
}
//Push Api
public addSubscriber(data) {
const key = this.sessionKey;
console.log(data)
return this.http.post<any>(
this.apiUrl + '/subscription/add',
{
session_key : key,
data : data
}
);
}
public deleteSubscriber(data) {
const key = this.sessionKey;
console.log(data)
return this.http.post<any>(
this.apiUrl + '/subscription/delete',
{
session_key : key,
data : data
}
);
}
// Leaderboard Api
public leaderboard_fetch(

View file

@ -0,0 +1,3 @@
.button{
padding: 15px 32px;
}

View file

@ -0,0 +1,2 @@
<button mat-raised-button (click)="subscribeToPush()" [disabled]=subscribeButton>Subscribe To Pushs</button>
<button mat-raised-button (click)="unsubscribeFromPush()" [disabled]=unsubscribeButton>Unsubscribe From Push</button>

View file

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

View file

@ -0,0 +1,91 @@
import { Component, OnInit } from '@angular/core';
import { ConfigService } from './../config.service';
import { SwPush } from '@angular/service-worker';
import { ApiService } from '../providers/api-service';
import "rxjs/Rx";
@Component({
selector: 'app-push',
templateUrl: './push.component.html',
styleUrls: ['./push.component.css']
})
export class PushComponent implements OnInit {
subscribeButton = false;
unsubscribeButton = true;
private VAPID_PUBLIC_KEY: string;
tweets = []
constructor(private api: ApiService, private configService: ConfigService, private swPush: SwPush) {
}
ngOnInit() {
this.VAPID_PUBLIC_KEY = this.configService.get('VAPID_PUBLIC_KEY')
}
subscribeToPush() {
// Requesting messaging service to subscribe current client (browser)
this.swPush.requestSubscription({
serverPublicKey: this.VAPID_PUBLIC_KEY
})
.then(pushSubscription => {
// Passing subscription object to our backend
console.log(pushSubscription.endpoint)
console.log(pushSubscription.getKey)
this.api.addSubscriber(pushSubscription)
.subscribe(
res => {
console.log('[App] Add subscriber request answer', res)
this.subscribeButton = true;
this.unsubscribeButton = false;
},
err => {
console.log('[App] Add subscriber request failed', err)
}
)
})
.catch(err => {
console.error(err);
})
}
unsubscribeFromPush(){
this.subscribeButton = false;
this.unsubscribeButton = true;
// Get active subscription
this.swPush.subscription
.take(1)
.subscribe(pushSubscription => {
console.log('[App] pushSubscription', pushSubscription)
// Delete the subscription from the backend
this.api.deleteSubscriber(pushSubscription)
.subscribe(
res => {
console.log('[App] Delete subscriber request answer', res)
// Unsubscribe current client (browser)
pushSubscription.unsubscribe()
.then(success => {
console.log('[App] Unsubscription successful', success)
})
.catch(err => {
console.log('[App] Unsubscription failed', err)
})
},
err => {
console.log('[App] Delete subscription request failed', err)
}
)
})
}
}

View file

@ -5,6 +5,11 @@
export const environment = {
production: false,
apiUrl: 'https://dev.peartrade.org/api',
mapApiKey: 'CHANGEME',
apiUrl: 'http://localhost:3000/api',
mapApiKey: 'AIzaSyBhm0iaIGG0Ko5IsfZx-CpLt01YHkp4Y1w',
config: {
"VAPID_PUBLIC_KEY": "BMDZ6FANqsYRF9iGo3Ki0LdltGZZksgIFbgxBr_otO0H7jTFgcm3v2bGSgnVGJ5bidvLvuKStirfDNl4khVBiok"
},
enableAnalytics: false,
analyticsKey: ''
};

View file

@ -18,7 +18,6 @@
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
</head>
<body class="app header-fixed sidebar-fixed">
<!-- Enable bootstrap 4 theme -->
<script>window.__theme = 'bs4';</script>
@ -123,6 +122,15 @@
<div class="sk-cube3 sk-cube"></div>
</div>
</app-root>
<app-root></app-root>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-119198369-1', 'auto');
</script>
</body>
</html>

31
src/ngsw-config.json Normal file
View file

@ -0,0 +1,31 @@
{
"index": "/index.html",
"assetGroups": [{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html"
],
"versionedFiles": [
"/*.bundle.css",
"/*.bundle.js",
"/*.chunk.js"
]
}
}, {
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**"
]
}
}],
"push": {
"showNotifications": true,
"backgroundOnly": false
}
}

26
src/test.js Normal file
View file

@ -0,0 +1,26 @@
const webpush = require('web-push');
const options = {
vapidDetails: {
subject: 'http://127.0.0.1:8080',
publicKey: 'BMDZ6FANqsYRF9iGo3Ki0LdltGZZksgIFbgxBr_otO0H7jTFgcm3v2bGSgnVGJ5bidvLvuKStirfDNl4khVBiok',
privateKey: 'tZacTzAIA5W-B19SsaQ-4KGWrKPAAqth5HQfJsjyHYs'
},
TTL: 5000
}
// NgPushRegistration-Object from the browser
const pushSubscription = {"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/gAAAAABanrgBKoC1etG5UeixhypVGQhGJoV5VtY72jIxx7rp0Bh3O4LZ4OmeYvGQgl0RxYD0ENNIzzMYTe0pgaynEOysvkyo4ybM6mHu_xFYrc9imf2F7lIuBCILCEjANG1gDoAWVRmBEMk0ZlYE4mq0KcoBjxwQDKTZsM4gITPmJdFxaCWRSls","keys":{"auth":"0uFlXtWtJH4arEGej3L_dQ","p256dh":"BMi13v5aFEgFgTwlSVDBv4uaxLOAdZ50U_-ITaP_-Brt6X3WN9gsl4G4oxhxTIj25zECdLARItXTJZ-Sof-O5bU"}};
const payload = JSON.stringify({
notification: {
title: '*TITLE*',
body: '*BODY*',
}
});
webpush.sendNotification(
pushSubscription,
payload,
options
);