diff --git a/app/e2e/app.e2e-spec.ts b/app/e2e/app.e2e-spec.ts
index a1cf299..d1e06d8 100644
--- a/app/e2e/app.e2e-spec.ts
+++ b/app/e2e/app.e2e-spec.ts
@@ -7,7 +7,7 @@ describe('InsightApp', () => {
});
it('should have a title', () => {
- expect(browser.getTitle()).toEqual('Clickers');
+ expect(browser.getTitle()).toEqual('Blocks');
});
it('should have {nav}', () => {
@@ -15,30 +15,22 @@ describe('InsightApp', () => {
});
it('should have correct nav text for Home', () => {
- expect(element(by.css('ion-navbar:first-child')).getText()).toContain('Clickers');
+ expect(element(by.css('ion-navbar:first-child')).getText()).toContain('Blocks');
});
it('has a menu button that displays the left menu', () => {
element(by.css('.bar-button-menutoggle')).click()
.then(() => {
browser.driver.sleep(2000); // wait for the animation
- expect(element.all(by.css('.toolbar-title')).first().getText()).toEqual('Pages');
+ expect(element(by.css('ion-menu')).isPresent()).toEqual(true);
});
});
- it('the left menu has a link with title Clickers', () => {
+ it('the left menu has a link with title Blocks', () => {
element(by.css('.bar-button-menutoggle')).click()
.then(() => {
browser.driver.sleep(2000); // wait for the animation
- expect(element.all(by.css('ion-label')).first().getText()).toEqual('Clickers');
- });
- });
-
- it('the left menu has a link with title Goodbye Ionic', () => {
- element(by.css('.bar-button-menutoggle')).click()
- .then(() => {
- browser.driver.sleep(2000); // wait for the animation
- expect(element.all(by.css('ion-label')).last().getText()).toEqual('Goodbye Ionic');
+ expect(element.all(by.css('ion-label')).first().getText()).toEqual('Blocks');
});
});
});
diff --git a/app/e2e/page2.e2e-spec.ts b/app/e2e/broadcastTxPage.e2e-spec.ts
similarity index 64%
rename from app/e2e/page2.e2e-spec.ts
rename to app/e2e/broadcastTxPage.e2e-spec.ts
index 3b7647c..070ec27 100644
--- a/app/e2e/page2.e2e-spec.ts
+++ b/app/e2e/broadcastTxPage.e2e-spec.ts
@@ -1,20 +1,20 @@
import { browser, element, by, ElementFinder } from 'protractor';
-let message: ElementFinder = element(by.className('message'));
+let heading: ElementFinder = element(by.css('h1'));
-describe('Page2', () => {
+describe('BroadcastTxPage', () => {
beforeEach(() => {
browser.get('');
});
- it('should have correct text when Goodbye Ionic is selected', () => {
+ it('should have the temporary heading', () => {
element(by.css('.bar-button-menutoggle')).click().then(() => {
browser.driver.sleep(2000); // wait for the animation
element.all(by.className('input-wrapper')).then((items) => {
items[1].click();
browser.driver.sleep(2000); // wait for the animation
- expect(message.getText()).toEqual('SHOW SIMPLE ALERT\nSHOW MORE ADVANCED ALERT');
+ expect(heading.getText()).toEqual('Broadcast Transaction');
return items[1];
});
});
diff --git a/app/e2e/clickerList.e2e-spec.ts b/app/e2e/clickerList.e2e-spec.ts
deleted file mode 100644
index d332ca6..0000000
--- a/app/e2e/clickerList.e2e-spec.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { browser, element, by, ElementFinder } from 'protractor';
-
-let clickerField: ElementFinder = element(by.css('.text-input'));
-let addButton: ElementFinder = element.all(by.className('button-outline')).first();
-let removeButton: ElementFinder = element.all(by.css('.button-outline-md-danger')).first();
-let firstClicker: ElementFinder = element.all(by.tagName('clicker-button')).first().element(by.tagName('button'));
-
-describe('ClickerList', () => {
-
- beforeEach(() => {
- browser.get('');
- });
-
- it('should switch into clickers page from menu', () => {
- element(by.css('.bar-button-menutoggle')).click();
- expect(element.all(by.css('.toolbar-title')).last().getText()).toEqual('Clickers');
- });
-
- it('has an input box for new Clickers', () => {
- expect(element(by.css('.text-input')).isPresent()).toEqual(true);
- });
-
- it('should add a Clicker', () => {
- 'test clicker one'.split('').forEach((c) => clickerField.sendKeys(c));
- addButton.click();
- browser.driver.sleep(1000);
- expect(firstClicker.getText()).toEqual('TEST CLICKER ONE (0)');
- });
-
- it('should click a Clicker', () => {
- firstClicker.click();
- browser.driver.sleep(1000);
- expect(firstClicker.getText()).toEqual('TEST CLICKER ONE (1)');
- });
-
- it('should delete a Clicker', () => {
- removeButton.click();
- browser.driver.sleep(1000);
- element.all(by.className('clickerList')).count()
- .then((count) => expect(count).toEqual(0));
- });
-});
diff --git a/app/package.json b/app/package.json
index cd750d3..401b92f 100644
--- a/app/package.json
+++ b/app/package.json
@@ -57,5 +57,8 @@
"tslint-eslint-rules": "4.1.1",
"typescript": "2.3.3"
},
+ "engines": {
+ "node": ">=8"
+ },
"license": "MIT"
}
diff --git a/app/src/app/app.module.ts b/app/src/app/app.module.ts
index dbc1eb7..2f6d8c5 100644
--- a/app/src/app/app.module.ts
+++ b/app/src/app/app.module.ts
@@ -1,26 +1,22 @@
-import { NgModule, ErrorHandler } from '@angular/core';
-import { BrowserModule } from '@angular/platform-browser';
+import { HttpModule } from '@angular/http';
+import { NgModule, ErrorHandler } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
-import { StatusBar } from '@ionic-native/status-bar';
-import { SplashScreen } from '@ionic-native/splash-screen';
-import { InsightApp } from './app.component';
-import {
- PagesModule,
- BlocksPage,
- BroadcastTxPage,
- NodeStatusPage,
- VerifyMessagePage,
-} from '../pages';
-import { ClickersService, StorageService } from '../services';
+import { StatusBar } from '@ionic-native/status-bar';
+import { SplashScreen } from '@ionic-native/splash-screen';
+import { InsightApp } from './app.component';
+import { PagesModule, BlocksPage, BroadcastTxPage, NodeStatusPage, VerifyMessagePage } from '../pages';
+import { BlocksService, StorageService } from '../services';
@NgModule({
declarations: [
- InsightApp,
+ InsightApp
],
imports: [
BrowserModule,
+ HttpModule,
PagesModule,
- IonicModule.forRoot(InsightApp),
+ IonicModule.forRoot(InsightApp)
],
bootstrap: [IonicApp],
entryComponents: [
@@ -28,14 +24,14 @@ import { ClickersService, StorageService } from '../services';
BlocksPage,
BroadcastTxPage,
NodeStatusPage,
- VerifyMessagePage,
+ VerifyMessagePage
],
providers: [
StatusBar,
SplashScreen,
- ClickersService,
StorageService,
- {provide: ErrorHandler, useClass: IonicErrorHandler},
+ BlocksService,
+ {provide: ErrorHandler, useClass: IonicErrorHandler}
],
})
diff --git a/app/src/index.html b/app/src/index.html
index 3ec7764..dcd5b1e 100644
--- a/app/src/index.html
+++ b/app/src/index.html
@@ -2,7 +2,7 @@
- Clickers
+ Insight
@@ -10,7 +10,7 @@
-
+
diff --git a/app/src/models/block.spec.ts b/app/src/models/block.spec.ts
new file mode 100644
index 0000000..5264d19
--- /dev/null
+++ b/app/src/models/block.spec.ts
@@ -0,0 +1,46 @@
+import { Block, InsightBlockObject } from './block';
+
+describe('Block', () => {
+ it('initializes', () => {
+ let obj: InsightBlockObject = {
+ height: 474504,
+ size: 998221,
+ hash: '000000000000000001763ebcea127d82b5c49b620960e2d881c4ace719d5fe46',
+ time: 1499346191,
+ txlength: 1904,
+ poolInfo: {
+ poolName: 'AntMiner',
+ url: 'https://bitmaintech.com/'
+ }
+ };
+
+ let block: Block = new Block(obj);
+
+ expect(block.height).toEqual(obj.height);
+ expect(block.size).toEqual(obj.size);
+ expect(block.hash).toEqual(obj.hash);
+ expect(block.timestamp).toEqual(obj.time);
+ expect(block.transactionCount).toEqual(obj.txlength);
+ expect(block.poolName).toEqual(obj.poolInfo.poolName);
+ });
+
+ it('can handle empty poolInfo', () => {
+ let obj: InsightBlockObject = {
+ height: 474504,
+ size: 998221,
+ hash: '000000000000000001763ebcea127d82b5c49b620960e2d881c4ace719d5fe46',
+ time: 1499346191,
+ txlength: 1904,
+ poolInfo: { }
+ };
+
+ let block: Block = new Block(obj);
+
+ expect(block.height).toEqual(obj.height);
+ expect(block.size).toEqual(obj.size);
+ expect(block.hash).toEqual(obj.hash);
+ expect(block.timestamp).toEqual(obj.time);
+ expect(block.transactionCount).toEqual(obj.txlength);
+ expect(block.poolName).toEqual(obj.poolInfo.poolName);
+ });
+});
diff --git a/app/src/models/block.ts b/app/src/models/block.ts
new file mode 100644
index 0000000..193d847
--- /dev/null
+++ b/app/src/models/block.ts
@@ -0,0 +1,34 @@
+export class Block {
+
+ public readonly height: number;
+ public readonly size: number;
+ public readonly hash: string;
+ public readonly timestamp: number;
+ public readonly transactionCount: number;
+ public readonly poolName: string;
+
+ constructor(properties: InsightBlockObject) {
+ this.height = properties.height;
+ this.size = properties.size;
+ this.hash = properties.hash;
+ this.timestamp = properties.time;
+ this.transactionCount = properties.txlength;
+ this.poolName = properties.poolInfo && properties.poolInfo.poolName;
+ }
+
+ public getDate(): Date {
+ return new Date(this.timestamp * 1000);
+ }
+}
+
+export interface InsightBlockObject {
+ height?: number;
+ size?: number;
+ hash?: string;
+ time?: number;
+ txlength?: number;
+ poolInfo?: {
+ poolName?: string,
+ url?: string
+ };
+}
diff --git a/app/src/models/click.spec.ts b/app/src/models/click.spec.ts
deleted file mode 100644
index d4e148f..0000000
--- a/app/src/models/click.spec.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-'use strict';
-
-import { Click } from './click';
-
-describe('Click', () => {
-
- it('initialises with defaults', () => {
- let click: Click = new Click();
-
- // toString() prints out something like "Thu Jan 07 2016 14:05:14 GMT+1300 (NZDT)"
- // comparing millis directly sometimes fails test (as it will be one milli too late!)
- let currentDateString: string = new Date().toString();
- let defaultDateString: string = new Date(click.getTime()).toString();
-
- expect(currentDateString).toEqual(defaultDateString);
- expect(click.getLocation()).toEqual('TODO');
- });
-
- it('initialises with overrides', () => {
- let current: number = new Date().getTime();
- let location: string = 'MY LOCATION';
- let click: Click = new Click(current, location);
- expect(click.getTime()).toEqual(current);
- expect(click.getLocation()).toEqual(location);
- });
-});
diff --git a/app/src/models/click.ts b/app/src/models/click.ts
deleted file mode 100644
index 0d60220..0000000
--- a/app/src/models/click.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict';
-
-export class Click {
-
- private time: number;
- private location: string;
-
- constructor(time?: number, location?: string) {
- this.time = time || new Date().getTime();
- this.location = location || 'TODO';
- }
-
- public getTime(): number {
- return this.time;
- }
-
- public getLocation(): string {
- return this.location;
- }
-}
diff --git a/app/src/models/clicker.mock.ts b/app/src/models/clicker.mock.ts
deleted file mode 100644
index c69dc14..0000000
--- a/app/src/models/clicker.mock.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export class ClickerMock {
- public getCount(): number { return 10; };
- public getId(): string { return 'UUUUUID'; };
- public getName(): string { return 'TEST CLICKER'; };
-}
diff --git a/app/src/models/clicker.spec.ts b/app/src/models/clicker.spec.ts
deleted file mode 100644
index 395e8da..0000000
--- a/app/src/models/clicker.spec.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-'use strict';
-
-import { Clicker } from './clicker';
-
-describe('Clicker', () => {
-
- it('initialises with the correct name', () => {
- let clicker: Clicker = new Clicker('12434', 'testClicker');
- expect(clicker.getName()).toEqual('testClicker');
- });
-});
diff --git a/app/src/models/clicker.ts b/app/src/models/clicker.ts
deleted file mode 100644
index ddadec7..0000000
--- a/app/src/models/clicker.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict';
-
-import { Click } from './';
-
-// Represents a single Clicker
-export class Clicker {
-
- private id: string;
- private name: string;
- private clicks: Array;
-
- constructor(id: string, name: string) {
- this.id = id;
- this.name = name;
- this.clicks = [];
- }
-
- public doClick(): void {
- this.clicks.push(new Click());
- }
-
- public addClick(click: Click): void {
- this.clicks.push(click);
- }
-
- public getCount(): number {
- return this.clicks.length;
- }
-
- public getId(): string {
- return this.id;
- }
-
- public getName(): string {
- return this.name;
- }
-}
diff --git a/app/src/models/index.ts b/app/src/models/index.ts
index 00d5248..d814a5a 100644
--- a/app/src/models/index.ts
+++ b/app/src/models/index.ts
@@ -1,2 +1 @@
-export * from './click';
-export * from './clicker';
+export * from './block';
diff --git a/app/src/models/mocks.ts b/app/src/models/mocks.ts
index 799ce86..6b30123 100644
--- a/app/src/models/mocks.ts
+++ b/app/src/models/mocks.ts
@@ -1 +1 @@
-export * from './clicker.mock';
+// export * from './X.mock';
diff --git a/app/src/pages/blocksPage/blocksPage.html b/app/src/pages/blocksPage/blocksPage.html
index 155b627..faf5819 100644
--- a/app/src/pages/blocksPage/blocksPage.html
+++ b/app/src/pages/blocksPage/blocksPage.html
@@ -14,16 +14,16 @@
-
+
#{{block.height}}
- {{block.txlength}} transactions
+ {{block.transactionCount}} transactions
- {{block.poolInfo.poolName}}
+ {{block.poolName}}
diff --git a/app/src/pages/blocksPage/blocksPage.ts b/app/src/pages/blocksPage/blocksPage.ts
index 897d652..c7e83c6 100644
--- a/app/src/pages/blocksPage/blocksPage.ts
+++ b/app/src/pages/blocksPage/blocksPage.ts
@@ -1,19 +1,25 @@
-import { Component } from '@angular/core';
-import { NavController } from 'ionic-angular';
+import { Component } from '@angular/core';
+import { NavController } from 'ionic-angular';
+import { Observable } from 'rxjs';
+import { Block } from '../../models';
+import { BlocksService } from '../../services';
@Component({
- templateUrl: './blocksPage.html',
+ templateUrl: './blocksPage.html'
})
export class BlocksPage {
public title: string;
- private nav: NavController;
- private blocks: any;
+ public blocks: Observable;
- constructor(nav: NavController) {
+ constructor(private nav: NavController, private blocksService: BlocksService) {
this.nav = nav;
this.title = 'Blocks';
- this.blocks = [{"height":471569,"size":999095,"hash":"00000000000000000007bf61c6cf9efbb1353b919621768b553bd1ffb2948240","time":1497633772,"txlength":2561,"poolInfo":{}},{"height":471568,"size":999994,"hash":"000000000000000000fc2c10f1b4e55c9b86b8f9e804dc66683312b7d7d955dd","time":1497632268,"txlength":2011,"poolInfo":{}},{"height":471567,"size":989172,"hash":"000000000000000000d70effc2ec625999960bd7929d7a4298124456ecb29c23","time":1497632133,"txlength":1651,"poolInfo":{"poolName":"BTCC Pool","url":"https://pool.btcc.com/"}},{"height":471566,"size":998155,"hash":"00000000000000000127cbc53d017400eb9d17122a8ae36986c077ac7eea25fe","time":1497629915,"txlength":1130,"poolInfo":{"poolName":"AntMiner","url":"https://bitmaintech.com/"}},{"height":471565,"size":998103,"hash":"00000000000000000045844f32f6e9fc6e7575bb96eb71a9ce9fba2849892d5e","time":1497629731,"txlength":1986,"poolInfo":{}},{"height":471564,"size":998101,"hash":"0000000000000000009a5b3fc7ac517f8a275be73f4492adb0cb88943f5c1b9e","time":1497629348,"txlength":2378,"poolInfo":{}},{"height":471563,"size":998258,"hash":"00000000000000000048a5506f3415fcf790106a838953e04d86d8f2583ebd6a","time":1497628552,"txlength":1481,"poolInfo":{"poolName":"AntMiner","url":"https://bitmaintech.com/"}},{"height":471562,"size":998257,"hash":"0000000000000000016f6a483730bd9c1c48c8345782b8365762592a475aa330","time":1497628159,"txlength":646,"poolInfo":{"poolName":"AntMiner","url":"https://bitmaintech.com/"}},{"height":471561,"size":999016,"hash":"000000000000000001434fb0e5cc5e521de59bff70c325185a5c67bd5418c61a","time":1497627986,"txlength":1831,"poolInfo":{}},{"height":471560,"size":998229,"hash":"000000000000000000a1782a9d78672672e4291347c47ac3206ed8716bb4952b","time":1497627524,"txlength":791,"poolInfo":{"poolName":"SlushPool","url":"https://slushpool.com/"}},{"height":471559,"size":999152,"hash":"000000000000000000d58ba85b2ddedc1f467b1e1c49c47cf62d4d970dad7ab5","time":1497627347,"txlength":87,"poolInfo":{}},{"height":471558,"size":778220,"hash":"0000000000000000009a4e72a1863e42fdfe1e08e6d547d4528049065d69454c","time":1497627287,"txlength":1685,"poolInfo":{"poolName":"BTCC Pool","url":"https://pool.btcc.com/"}},{"height":471557,"size":707456,"hash":"00000000000000000068a8adc72fc41299105053e6059a3f6dcd2e0dc2fd2fcb","time":1497626859,"txlength":1661,"poolInfo":{"poolName":"BTCC Pool","url":"https://pool.btcc.com/"}}];
+ this.blocks = blocksService.latestBlocks;
+ // this.blocks.subscribe((blocks) => {
+ // console.log(blocks);
+ // });
+ blocksService.getLatestBlocks();
}
}
diff --git a/app/src/services/blocksService.mock.ts b/app/src/services/blocksService.mock.ts
new file mode 100644
index 0000000..b23a89b
--- /dev/null
+++ b/app/src/services/blocksService.mock.ts
@@ -0,0 +1,24 @@
+import { Subject } from 'rxjs';
+import { Block } from '../models';
+
+export class BlocksServiceMock {
+
+ public readonly latestBlocks: Subject> = new Subject();
+
+ public getLatestBlocks(): void {
+ this.latestBlocks.next([
+ new Block({
+ height: 474504,
+ size: 998221,
+ hash: '000000000000000001763ebcea127d82b5c49b620960e2d881c4ace719d5fe46',
+ time: 1499346191,
+ txlength: 1904,
+ poolInfo: {
+ poolName: 'AntMiner',
+ url: 'https://bitmaintech.com/'
+ }
+ })
+ ]);
+ }
+
+}
diff --git a/app/src/services/blocksService.spec.ts b/app/src/services/blocksService.spec.ts
new file mode 100644
index 0000000..cf99bfb
--- /dev/null
+++ b/app/src/services/blocksService.spec.ts
@@ -0,0 +1,17 @@
+import { BlocksService } from './blocksService';
+import { Block } from '../models';
+import { TestUtils } from '../test';
+
+let blocks: BlocksService = null;
+
+// describe('BlocksService', () => {
+
+// beforeEach(() => {
+// blocks = new BlocksService();
+// });
+
+// it('initializes', () => {
+// expect(blocks).not.toBeNull();
+// });
+
+// });
diff --git a/app/src/services/blocksService.ts b/app/src/services/blocksService.ts
new file mode 100644
index 0000000..747f49d
--- /dev/null
+++ b/app/src/services/blocksService.ts
@@ -0,0 +1,26 @@
+import { Http, Response } from '@angular/http';
+import { Injectable } from '@angular/core';
+import { Observable, Subject } from 'rxjs';
+import { Block, InsightBlockObject } from '../models';
+
+@Injectable()
+export class BlocksService {
+
+ public readonly latestBlocks: Subject> = new Subject();
+
+ constructor(private http: Http) {}
+
+ public getLatestBlocks(): void {
+ this.http.request('https://insight.bitpay.com/api/blocks').subscribe((res: Response) => {
+ const data: {
+ blocks: InsightBlockObject[],
+ length: number,
+ pagination: {}
+ } = res.json();
+ this.latestBlocks.next(data.blocks.map((obj) => {
+ return new Block(obj);
+ }));
+ });
+ }
+
+}
diff --git a/app/src/services/clickers.mock.ts b/app/src/services/clickers.mock.ts
deleted file mode 100644
index 1d8206a..0000000
--- a/app/src/services/clickers.mock.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-export class ClickersServiceMock {
-
- public doClick(): boolean {
- return true;
- }
-
- public newClicker(): boolean {
- return true;
- }
-
- public getClickers(): Array {
- return [];
- }
-}
diff --git a/app/src/services/clickers.spec.ts b/app/src/services/clickers.spec.ts
deleted file mode 100644
index 73d8faf..0000000
--- a/app/src/services/clickers.spec.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import { ClickersService } from './clickers';
-import { Clicker } from '../models';
-import { StorageMock } from './mocks';
-
-let clickers: ClickersService = null;
-
-describe('ClickersService', () => {
-
- beforeEach(() => {
- clickers = new ClickersService(new StorageMock());
- spyOn(clickers['storage'], 'set').and.callThrough();
- });
-
- it('initialises', () => {
- expect(clickers).not.toBeNull();
- });
-
- it('initialises with clickers from mock storage', (done: Function) => {
- clickers['init']()
- .then(() => {
- expect(clickers.getClickers().length).toEqual(StorageMock.CLICKER_IDS.length);
- done();
- });
- });
-
- it('can initialise a clicker from string', () => {
- let clickerString: string = '{"id":"0g2vt8qtlm","name":"harold","clicks":[{"time":1450410168819,"location":"TODO"},{"time":1450410168945,"location":"TODO"}]}';
- let clicker: Clicker = clickers['initClicker'](clickerString);
- expect(clicker.getName()).toEqual('harold');
- expect(clicker.getCount()).toEqual(2);
- });
-
- it('returns undefined for a bad id', () => {
- expect(clickers.getClicker('dave')).not.toBeDefined();
- });
-
- it('adds a new clicker with the correct name', (done: Function) => {
- clickers['init']()
- .then(() => {
- let idAdded: string = clickers.newClicker('dave');
- expect(clickers['storage'].set).toHaveBeenCalledWith(idAdded, jasmine.any(String));
- expect(clickers.getClickers()[3].getName()).toEqual('dave');
- done();
- });
- });
-
- it('removes a clicker by id', () => {
- let idToRemove: string = clickers.newClicker('dave');
- clickers.removeClicker(idToRemove);
- expect(clickers['storage'].set).toHaveBeenCalledWith(idToRemove, jasmine.any(String));
- });
-
- it('does a click', () => {
- let idToClick: string = clickers.newClicker('dave');
- let clickedClicker: Clicker = null;
- clickers.doClick(idToClick);
- expect(clickers['storage'].set).toHaveBeenCalledWith(idToClick, jasmine.any(String));
- clickedClicker = clickers.getClicker(idToClick);
- expect(clickedClicker.getCount()).toEqual(1);
- });
-
- it('loads empty list if given no argument', (done: Function) => {
- clickers['initIds'](false)
- .then((ids: Array) => {
- expect(ids).toEqual([]);
- done();
- });
- });
-
- it('loads IDs from storage', (done: Function) => {
- clickers['initIds']()
- .then((ids: Array) => {
- expect(ids).toEqual(StorageMock.CLICKER_IDS);
- done();
- });
- });
-
- it('loads clickers from storage', (done: Function) => {
- clickers['initClickers'](StorageMock.CLICKER_IDS)
- .then((resolvedClickers: Array) => {
- expect(resolvedClickers.length).toEqual(3);
- expect(resolvedClickers[0].getId()).toEqual(StorageMock.CLICKER_IDS[0]);
- expect(resolvedClickers[1].getId()).toEqual(StorageMock.CLICKER_IDS[1]);
- expect(resolvedClickers[2].getId()).toEqual(StorageMock.CLICKER_IDS[2]);
- done();
- });
- });
-});
diff --git a/app/src/services/clickers.ts b/app/src/services/clickers.ts
deleted file mode 100644
index f936f8b..0000000
--- a/app/src/services/clickers.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-'use strict';
-
-import { Injectable } from '@angular/core';
-import { StorageService } from './storage';
-import { Click, Clicker } from '../models';
-
-@Injectable()
-export class ClickersService {
-
- private clickers: Array;
- private ids: Array; // we need to keep a separate reference to ids so we can lookup when the app loads from scratch
- private storage: StorageService;
-
- // don't know why Injection isn't working without @Inject:
- // http://stackoverflow.com/questions/34449486/angular-2-0-injected-http-service-is-undefined
- constructor(storage: StorageService) {
- this.storage = storage;
- this.ids = [];
- this.clickers = [];
- this.init();
- }
-
- // as init is async separate logic here so it's testable
- private init(): Promise<{}> {
- return this.initIds()
- .then((ids: Array) => { this.ids = ids; })
- .then(() => this.initClickers(this.ids))
- .then((clickers: Array) => this.clickers = clickers);
- }
-
- // initialise Ids from SQL storage
- private initIds(load: boolean = true): Promise<{}> {
- return this.storage.get('ids') // return the promise so we can chain initClickers
- .then((rawIds: string) => {
- if (!rawIds || !load) return [];
- // ids are stored as stringified JSON array
- return JSON.parse(rawIds);
- });
- }
-
- // initialise Clickers from SQL storage given an array of ids
- private initClickers(ids: Array): Promise<{}> {
- // get all existing ids
- let proms: Array> = [];
-
- proms = ids.map(id => this.storage.get(id));
-
- return Promise.all(proms)
- .then(clickers => clickers.map(clicker => this.initClicker(clicker)));
- }
-
- // initialise a clicker from a raw JSON string out of the DB
- private initClicker(clicker: string): Clicker {
- const parsedClicker: Object = JSON.parse(clicker);
- const newClicker: Clicker = new Clicker(parsedClicker['id'], parsedClicker['name']);
-
- // add the clicks - need to re-instantiate object
- for (let click of parsedClicker['clicks']) {
- newClicker.addClick(new Click(click.time, click.location));
- }
-
- return newClicker;
- }
-
- public getClicker(id: string): Clicker {
- return this.clickers['find']((clicker: Clicker) => { return clicker.getId() === id; } );
- }
-
- public getClickers(): Array {
- return this.clickers;
- }
-
- public newClicker(name: string): string {
- const id: string = this.uid();
- const clicker: Clicker = new Clicker(id, name);
-
- // add the clicker to the service
- this.clickers.push(clicker);
- // add the id to the service (need to keep a separate reference of IDs so we can cold load clickers)
- this.ids.push(id);
- // save the clicker by id
- this.storage.set(id, JSON.stringify(clicker));
- // save the service's ids array
- this.storage.set('ids', JSON.stringify(this.ids));
-
- return id;
- }
-
- public removeClicker(id: string): void {
-
- // remove clicker from the service
- this.clickers = this.clickers.filter((clicker: Clicker) => { return clicker.getId() !== id; });
-
- // remove from ids array
- this.ids = this.ids.filter((filterId: string) => { return filterId !== id; });
-
- // null id in db
- this.storage.remove(id);
-
- // update service's ids array
- this.storage.set('ids', JSON.stringify(this.ids));
- }
-
- public doClick(id: string): void {
- const clicker: Clicker = this.getClicker(id);
- clicker.doClick();
- // save the clicker with updated click in storage
- this.storage.set(clicker.getId(), JSON.stringify(clicker));
- }
-
- private uid(): string {
- return Math.random().toString(35).substr(2, 10);
- }
-}
diff --git a/app/src/services/index.ts b/app/src/services/index.ts
index 2c57205..c6ee35d 100644
--- a/app/src/services/index.ts
+++ b/app/src/services/index.ts
@@ -1,2 +1,2 @@
-export * from './clickers';
-export * from './storage';
+export * from './blocksService';
+export * from './storageService';
diff --git a/app/src/services/mocks.ts b/app/src/services/mocks.ts
index 851dcb2..aaa47e6 100644
--- a/app/src/services/mocks.ts
+++ b/app/src/services/mocks.ts
@@ -1,2 +1,2 @@
-export * from './clickers.mock';
-export * from './storage.mock';
+export * from './blocksService.mock';
+export * from './storageService.mock';
diff --git a/app/src/services/storage.mock.ts b/app/src/services/storage.mock.ts
deleted file mode 100644
index 6c34b76..0000000
--- a/app/src/services/storage.mock.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-'use strict';
-
-export class StorageMock {
-
- public static CLICKER_IDS: Array = ['yy5d8klsj0', 'q20iexxg4a', 'wao2xajl8a'];
-
- public get(key: string): Promise<{}> {
- let rtn: string = null;
-
- switch (key) {
- case 'ids':
- rtn = JSON.stringify(StorageMock.CLICKER_IDS);
- break;
- case StorageMock.CLICKER_IDS[0]:
- rtn = `{"id":"${StorageMock.CLICKER_IDS[0]}","name":"test1","clicks":[{"time":1450410168819,"location":"TODO"}]}`;
- break;
- case StorageMock.CLICKER_IDS[1]:
- rtn = `{"id":"${StorageMock.CLICKER_IDS[1]}","name":"test2","clicks":[{"time":1450410168819,"location":"TODO"},{"time":1450410168945,"location":"TODO"}]}`;
- break;
- case StorageMock.CLICKER_IDS[2]:
- rtn = `{"id":"${StorageMock.CLICKER_IDS[2]}","name":"test3", "clicks":[{ "time": 1450410168819, "location": "TODO" }, { "time": 1450410168945, "location": "TODO" }] }`;
- break;
- default:
- rtn = 'SHOULD NOT BE HERE!';
- }
-
- return new Promise((resolve: Function) => {
- resolve(rtn);
- });
- }
-
- public set(key: string, value: string): Promise<{}> {
- return new Promise((resolve: Function) => {
- resolve({key: key, value: value});
- });
- }
-
- public remove(key: string): Promise<{}> {
- return new Promise((resolve: Function) => {
- resolve({key: key});
- });
- }
-}
diff --git a/app/src/services/storageService.mock.ts b/app/src/services/storageService.mock.ts
new file mode 100644
index 0000000..e15e968
--- /dev/null
+++ b/app/src/services/storageService.mock.ts
@@ -0,0 +1,42 @@
+export class StorageServiceMock {
+
+ public static CLICKER_IDS: Array = ['yy5d8klsj0', 'q20iexxg4a', 'wao2xajl8a'];
+
+ public get(key: string): Promise<{}> {
+ let rtn: string = null;
+
+ switch (key) {
+ case 'ids':
+ rtn = JSON.stringify(StorageServiceMock.CLICKER_IDS);
+ break;
+ case StorageServiceMock.CLICKER_IDS[0]:
+ rtn = `{"id":"${StorageServiceMock.CLICKER_IDS[0]}","name":"test1","clicks":[{"time":1450410168819,"location":"TODO"}]}`;
+ break;
+ case StorageServiceMock.CLICKER_IDS[1]:
+ rtn = `{"id":"${StorageServiceMock.CLICKER_IDS[1]}","name":"test2","clicks":[{"time":1450410168819,"location":"TODO"},{"time":1450410168945,"location":"TODO"}]}`;
+ break;
+ case StorageServiceMock.CLICKER_IDS[2]:
+ rtn = `{"id":"${StorageServiceMock.CLICKER_IDS[2]}","name":"test3", "clicks":[{ "time": 1450410168819, "location": "TODO" },
+ { "time": 1450410168945, "location": "TODO" }] }`;
+ break;
+ default:
+ rtn = 'SHOULD NOT BE HERE!';
+ }
+
+ return new Promise((resolve: Function) => {
+ resolve(rtn);
+ });
+ }
+
+ public set(key: string, value: string): Promise<{}> {
+ return new Promise((resolve: Function) => {
+ resolve({key: key, value: value});
+ });
+ }
+
+ public remove(key: string): Promise<{}> {
+ return new Promise((resolve: Function) => {
+ resolve({key: key});
+ });
+ }
+}
diff --git a/app/src/services/storage.spec.ts b/app/src/services/storageService.spec.ts
similarity index 100%
rename from app/src/services/storage.spec.ts
rename to app/src/services/storageService.spec.ts
diff --git a/app/src/services/storage.ts b/app/src/services/storageService.ts
similarity index 97%
rename from app/src/services/storage.ts
rename to app/src/services/storageService.ts
index c0772f0..85d394a 100644
--- a/app/src/services/storage.ts
+++ b/app/src/services/storageService.ts
@@ -1,4 +1,3 @@
-'use strict';
import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage';
diff --git a/app/src/test.ts b/app/src/test.ts
index 7a4cb7e..ee17df7 100644
--- a/app/src/test.ts
+++ b/app/src/test.ts
@@ -10,10 +10,12 @@ import 'zone.js/dist/fake-async-test';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { getTestBed, TestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
+import { HttpModule } from '@angular/http';
+import { MockBackend } from '@angular/http/testing';
import { App, Config, Form, IonicModule, Keyboard, DomController, MenuController, NavController, Platform, GestureController } from 'ionic-angular';
import { ConfigMock, PlatformMock } from './mocks';
-import { ClickersServiceMock } from './services/clickers.mock';
-import { ClickersService } from './services';
+import { BlocksServiceMock } from './services/mocks';
+import { BlocksService } from './services';
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare var __karma__: any;
@@ -44,7 +46,7 @@ export class TestUtils {
let fixture: any = TestBed.createComponent(components[0]);
return {
fixture: fixture,
- instance: fixture.debugElement.componentInstance,
+ instance: fixture.debugElement.componentInstance
};
});
}
@@ -52,19 +54,20 @@ export class TestUtils {
public static configureIonicTestingModule(components: Array): typeof TestBed {
return TestBed.configureTestingModule({
declarations: [
- ...components,
+ ...components
],
providers: [
App, Form, Keyboard, DomController, MenuController, NavController, GestureController,
{provide: Platform, useClass: PlatformMock},
{provide: Config, useClass: ConfigMock},
- {provide: ClickersService, useClass: ClickersServiceMock},
+ {provide: BlocksService, useClass: BlocksServiceMock}
],
imports: [
FormsModule,
IonicModule,
ReactiveFormsModule,
- ],
+ HttpModule
+ ]
});
}
diff --git a/app/tslint.json b/app/tslint.json
index c717a98..a96fe0a 100644
--- a/app/tslint.json
+++ b/app/tslint.json
@@ -36,7 +36,7 @@
"no-consecutive-blank-lines": true,
"no-console": [false],
"no-construct": false,
- "no-constructor-vars": true,
+ "no-constructor-vars": false,
"no-debugger": true,
"no-duplicate-key": true,
"no-duplicate-variable": true,
@@ -75,7 +75,7 @@
"trailing-comma": [
true,
{
- "multiline": "always",
+ "multiline": "never",
"singleline": "never"
}
],