Make it multiplayer
This commit is contained in:
parent
19aad2b2af
commit
1598260ce3
27 changed files with 459 additions and 327 deletions
|
|
@ -5,7 +5,7 @@
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
"build": "ng build",
|
"build": "ng build",
|
||||||
"build:prod": "ng build --prod --base-href /life-qa/",
|
"build:prod": "ng build --prod",
|
||||||
"format:fix": "pretty-quick --staged",
|
"format:fix": "pretty-quick --staged",
|
||||||
"precommit": "run-s format:fix lint",
|
"precommit": "run-s format:fix lint",
|
||||||
"format:check": "prettier --config ./.prettierrc --list-different \"src/{app,environments,assets}/**/*{.ts,.js,.json,.css,.scss}\"",
|
"format:check": "prettier --config ./.prettierrc --list-different \"src/{app,environments,assets}/**/*{.ts,.js,.json,.css,.scss}\"",
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import { TasksComponent } from './components/pages/page/tower/tasks/tasks.compon
|
||||||
import { ColorPipe } from './pipes/color.pipe';
|
import { ColorPipe } from './pipes/color.pipe';
|
||||||
import { BlocksComponent } from './components/modal/modals/blocks/blocks.component';
|
import { BlocksComponent } from './components/modal/modals/blocks/blocks.component';
|
||||||
import { FormatDatePipe } from './pipes/format-date.pipe';
|
import { FormatDatePipe } from './pipes/format-date.pipe';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|
@ -43,7 +44,7 @@ import { FormatDatePipe } from './pipes/format-date.pipe';
|
||||||
BlocksComponent,
|
BlocksComponent,
|
||||||
FormatDatePipe
|
FormatDatePipe
|
||||||
],
|
],
|
||||||
imports: [BrowserModule, AppRoutingModule, FormsModule, BrowserAnimationsModule, DragDropModule],
|
imports: [BrowserModule, AppRoutingModule, FormsModule, BrowserAnimationsModule, DragDropModule, HttpClientModule],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,8 @@
|
||||||
|
|
||||||
<p *ngIf="page.towers.length == 5">There can be a maximum of <strong>5</strong> towers on each page.</p>
|
<p *ngIf="page.towers.length == 5">There can be a maximum of <strong>5</strong> towers on each page.</p>
|
||||||
|
|
||||||
|
<input id="token" type="text" [(ngModel)]="token" />
|
||||||
|
|
||||||
|
<button (click)="setNewToken()">Set token</button>
|
||||||
|
|
||||||
<button (click)="$event.stopPropagation() || deletePage()">Delete current page</button>
|
<button (click)="$event.stopPropagation() || deletePage()">Delete current page</button>
|
||||||
|
|
|
||||||
|
|
@ -31,4 +31,12 @@
|
||||||
p {
|
p {
|
||||||
font-size: var(--medium-font-size);
|
font-size: var(--medium-font-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type='text'] {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,56 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ModalService } from '../../../../services/modal.service';
|
import { ModalService } from '../../../../services/modal.service';
|
||||||
import { DataService } from '../../../../services/data.service';
|
import { DataService } from '../../../../services/data.service';
|
||||||
import { Page } from '../../../../model/page';
|
import { Page } from '../../../../model/page';
|
||||||
|
import { Data } from '../../../../model/data';
|
||||||
|
import { Subscription } from 'rxjs/internal/Subscription';
|
||||||
|
import { MapStoreService } from '../../../../services/map-store.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-settings',
|
selector: 'app-settings',
|
||||||
templateUrl: './settings.component.html',
|
templateUrl: './settings.component.html',
|
||||||
styleUrls: ['./settings.component.scss']
|
styleUrls: ['./settings.component.scss']
|
||||||
})
|
})
|
||||||
export class SettingsComponent implements OnInit {
|
export class SettingsComponent implements OnInit, OnDestroy {
|
||||||
|
data: Data;
|
||||||
page: Page;
|
page: Page;
|
||||||
constructor(public modalService: ModalService, public dataService: DataService) {}
|
|
||||||
|
private dataSubscription: Subscription;
|
||||||
|
private pageSubscription: Subscription;
|
||||||
|
|
||||||
|
token: string;
|
||||||
|
|
||||||
|
constructor(public modalService: ModalService, private store: MapStoreService) {
|
||||||
|
this.token = store.userToken;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.modalService.active.input.subscribe(p => (this.page = p));
|
const { data$, page$ } = this.modalService.active.input;
|
||||||
|
|
||||||
|
this.dataSubscription = data$.subscribe(d => (this.data = d));
|
||||||
|
this.pageSubscription = page$.subscribe(p => (this.page = p));
|
||||||
}
|
}
|
||||||
|
|
||||||
async deletePage() {
|
async deletePage() {
|
||||||
try {
|
try {
|
||||||
await this.modalService.showRemovePage(this.page.name);
|
await this.modalService.showRemovePage(this.page.name);
|
||||||
this.dataService.removePage(this.page);
|
this.data.removePage(this.page);
|
||||||
this.modalService.submit();
|
this.modalService.submit();
|
||||||
} catch {
|
} catch {
|
||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setNewToken() {
|
||||||
|
this.store.userToken = this.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.dataSubscription) {
|
||||||
|
this.dataSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
if (this.pageSubscription) {
|
||||||
|
this.pageSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,7 @@ export class TowerComponent implements OnInit {
|
||||||
return this.styledBlocks.filter(b => b.shouldDraw);
|
return this.styledBlocks.filter(b => b.shouldDraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public constructor(private modalService: ModalService, private changeDetection: ChangeDetectorRef) {
|
public constructor(private modalService: ModalService, private changeDetection: ChangeDetectorRef) {}
|
||||||
console.log('oo');
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.tower$.subscribe(value => {
|
this.tower$.subscribe(value => {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import { DataService } from '../../services/data.service';
|
||||||
import { ModalService } from '../../services/modal.service';
|
import { ModalService } from '../../services/modal.service';
|
||||||
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { Data } from '../../model/data';
|
||||||
|
import { of } from 'rxjs/internal/observable/of';
|
||||||
|
|
||||||
const USER_DATA_KEY = 'life-towers.user-data.v.2';
|
const USER_DATA_KEY = 'life-towers.user-data.v.2';
|
||||||
|
|
||||||
|
|
@ -17,6 +19,7 @@ export class PagesComponent implements OnInit {
|
||||||
@ViewChild('page') page: ElementRef;
|
@ViewChild('page') page: ElementRef;
|
||||||
@ViewChild('bottom') bottom: ElementRef;
|
@ViewChild('bottom') bottom: ElementRef;
|
||||||
|
|
||||||
|
data: Data;
|
||||||
pages: Array<Page>;
|
pages: Array<Page>;
|
||||||
isDragHappening = false;
|
isDragHappening = false;
|
||||||
|
|
||||||
|
|
@ -44,8 +47,10 @@ export class PagesComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.dataService.children$.subscribe(pages => {
|
this.dataService.children$.subscribe(dataContainer => {
|
||||||
if (pages) {
|
if (dataContainer && dataContainer.length > 0) {
|
||||||
|
this.data = dataContainer[0];
|
||||||
|
const pages = this.data.pages;
|
||||||
if (this.pages && !pages.includes(this._selectedPage.getValue().latestVersion)) {
|
if (this.pages && !pages.includes(this._selectedPage.getValue().latestVersion)) {
|
||||||
this.selectedPageName = null;
|
this.selectedPageName = null;
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +87,7 @@ export class PagesComponent implements OnInit {
|
||||||
|
|
||||||
if (this.pages && name) {
|
if (this.pages && name) {
|
||||||
if (!this.pageNames.includes(name)) {
|
if (!this.pageNames.includes(name)) {
|
||||||
this.dataService.addPage(name);
|
this.data.addPage(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = this.pageNames.indexOf(name);
|
const index = this.pageNames.indexOf(name);
|
||||||
|
|
@ -95,7 +100,10 @@ export class PagesComponent implements OnInit {
|
||||||
|
|
||||||
async openSettings() {
|
async openSettings() {
|
||||||
try {
|
try {
|
||||||
await this.modalService.showSettings(this.selectedPage$);
|
await this.modalService.showSettings({
|
||||||
|
page$: this.selectedPage$,
|
||||||
|
data$: of(this.data)
|
||||||
|
});
|
||||||
} catch {
|
} catch {
|
||||||
// pass
|
// pass
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
export interface IBlock {
|
import { IUnique } from './unique';
|
||||||
|
|
||||||
|
export interface IBlock extends IUnique {
|
||||||
created: Date;
|
created: Date;
|
||||||
tag: string;
|
tag: string;
|
||||||
isDone: boolean;
|
isDone: boolean;
|
||||||
|
|
|
||||||
6
src/app/interfaces/persistance/data.ts
Normal file
6
src/app/interfaces/persistance/data.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { IPage } from './page';
|
||||||
|
import { IUnique } from './unique';
|
||||||
|
|
||||||
|
export interface IData extends IUnique {
|
||||||
|
pages: Array<IPage>;
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import { ITower } from './tower';
|
import { ITower } from './tower';
|
||||||
import { Range } from '../range';
|
import { Range } from '../range';
|
||||||
|
import { IUnique } from './unique';
|
||||||
|
|
||||||
export interface IPage {
|
export interface IPage extends IUnique {
|
||||||
name: string;
|
name: string;
|
||||||
towers: ITower[];
|
towers: ITower[];
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
hideCreateTowerButton?: boolean;
|
hideCreateTowerButton: boolean;
|
||||||
defaultDateRange?: Range<Date>;
|
defaultDateRange: Range<Date>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { IBlock } from './block';
|
import { IBlock } from './block';
|
||||||
import { IColor } from '../color';
|
import { IColor } from '../color';
|
||||||
|
import { IUnique } from './unique';
|
||||||
|
|
||||||
export interface ITower {
|
export interface ITower extends IUnique {
|
||||||
name: string;
|
name: string;
|
||||||
blocks: IBlock[];
|
blocks: IBlock[];
|
||||||
baseColor: IColor;
|
baseColor: IColor;
|
||||||
|
|
|
||||||
3
src/app/interfaces/persistance/unique.ts
Normal file
3
src/app/interfaces/persistance/unique.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface IUnique {
|
||||||
|
id?: string;
|
||||||
|
}
|
||||||
3
src/app/interfaces/serializable.ts
Normal file
3
src/app/interfaces/serializable.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface ISerializable {
|
||||||
|
serialize(referenceSerializer: (ref: object) => any): object;
|
||||||
|
}
|
||||||
|
|
@ -1,23 +1,36 @@
|
||||||
import { Serializable } from './serializable';
|
|
||||||
import { IBlock } from '../interfaces/persistance/block';
|
import { IBlock } from '../interfaces/persistance/block';
|
||||||
import { InnerNodeState } from '../store/inner-node';
|
import { InnerNode, InnerNodeState } from '../store/inner-node';
|
||||||
|
|
||||||
export interface BlockState extends IBlock, InnerNodeState {}
|
export interface BlockState extends IBlock, InnerNodeState {}
|
||||||
|
|
||||||
export class Block extends Serializable implements IBlock, BlockState {
|
export class Block extends InnerNode implements IBlock, BlockState {
|
||||||
readonly created: Date;
|
|
||||||
readonly isDone: boolean;
|
|
||||||
readonly description: string;
|
|
||||||
readonly tag: string;
|
readonly tag: string;
|
||||||
|
readonly description: string;
|
||||||
|
readonly isDone: boolean;
|
||||||
|
readonly created: Date;
|
||||||
|
|
||||||
constructor(props: IBlock) {
|
constructor(props: IBlock, referenceDeserializer: (from: any) => any = e => e) {
|
||||||
|
super([], props.id);
|
||||||
if (props.created.constructor.name !== 'Date') {
|
if (props.created.constructor.name !== 'Date') {
|
||||||
props.created = new Date(props.created);
|
props.created = new Date(props.created);
|
||||||
}
|
}
|
||||||
super(props, 'Block');
|
this.tag = props.tag;
|
||||||
|
this.description = props.description;
|
||||||
|
this.isDone = props.isDone;
|
||||||
|
this.created = props.created;
|
||||||
}
|
}
|
||||||
|
|
||||||
changeKeys(props: Partial<BlockState>): this {
|
changeKeys(props: Partial<BlockState>): this {
|
||||||
return super.changeKeys<BlockState>(props);
|
return super.changeKeys<BlockState>(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serialize(referenceSerializer: (ref: object) => any): IBlock {
|
||||||
|
return {
|
||||||
|
...super.serialize(referenceSerializer),
|
||||||
|
tag: this.tag,
|
||||||
|
description: this.description,
|
||||||
|
isDone: this.isDone,
|
||||||
|
created: this.created
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
44
src/app/model/data.ts
Normal file
44
src/app/model/data.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { InnerNode, InnerNodeState } from '../store/inner-node';
|
||||||
|
import { IData } from '../interfaces/persistance/data';
|
||||||
|
import { Page } from './page';
|
||||||
|
|
||||||
|
export interface DataState extends IData, InnerNodeState {}
|
||||||
|
|
||||||
|
export class Data extends InnerNode implements IData, DataState {
|
||||||
|
constructor(props: IData, referenceDeserializer: (from: any) => any = e => e) {
|
||||||
|
super(props.pages.map(p => new Page(referenceDeserializer(p), referenceDeserializer)), props.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
get pages(): Array<Page> {
|
||||||
|
return this.children as Array<Page>;
|
||||||
|
}
|
||||||
|
|
||||||
|
addPage(name: string) {
|
||||||
|
const page = new Page({
|
||||||
|
name,
|
||||||
|
userData: {
|
||||||
|
hideCreateTowerButton: false,
|
||||||
|
defaultDateRange: {
|
||||||
|
from: null,
|
||||||
|
to: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
towers: []
|
||||||
|
});
|
||||||
|
this.addChildren([page]);
|
||||||
|
page.addTower();
|
||||||
|
}
|
||||||
|
|
||||||
|
removePage(page: Page) {
|
||||||
|
this.changeKeys<any>({
|
||||||
|
children: this.children.filter(c => c !== page)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(referenceSerializer: (ref: object) => any): IData {
|
||||||
|
return {
|
||||||
|
...super.serialize(referenceSerializer),
|
||||||
|
pages: this.pages.map(referenceSerializer)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,25 +1,24 @@
|
||||||
import { Serializable } from './serializable';
|
|
||||||
import { IPage } from '../interfaces/persistance/page';
|
import { IPage } from '../interfaces/persistance/page';
|
||||||
|
import { Range } from '../interfaces/range';
|
||||||
import { Tower } from './tower';
|
import { Tower } from './tower';
|
||||||
import { InnerNodeState } from '../store/inner-node';
|
import { InnerNode, InnerNodeState } from '../store/inner-node';
|
||||||
|
|
||||||
export interface PageState extends InnerNodeState, IPage {
|
export interface PageState extends InnerNodeState, IPage {
|
||||||
towers: Array<Tower>;
|
towers: Array<Tower>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Page extends Serializable implements IPage, PageState {
|
export class Page extends InnerNode implements IPage, PageState {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
|
|
||||||
readonly userData: {
|
readonly userData: {
|
||||||
hideCreateTowerButton: boolean;
|
hideCreateTowerButton: boolean;
|
||||||
defaultDateRange: {
|
defaultDateRange: Range<Date>;
|
||||||
from: Date;
|
|
||||||
to: Date;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: IPage) {
|
constructor(props: IPage, referenceDeserializer: (from: any) => any = e => e) {
|
||||||
super(props, 'Page', props.towers.map(t => new Tower(t)));
|
super(props.towers.map(t => new Tower(referenceDeserializer(t), referenceDeserializer)), props.id);
|
||||||
|
this.name = props.name;
|
||||||
|
this.userData = props.userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
get towers(): Array<Tower> {
|
get towers(): Array<Tower> {
|
||||||
|
|
@ -84,4 +83,13 @@ export class Page extends Serializable implements IPage, PageState {
|
||||||
towers: this.towers.filter(t => t !== tower)
|
towers: this.towers.filter(t => t !== tower)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serialize(referenceSerializer: (ref: object) => any): IPage {
|
||||||
|
return {
|
||||||
|
...super.serialize(referenceSerializer),
|
||||||
|
name: this.name,
|
||||||
|
userData: this.userData,
|
||||||
|
towers: this.towers.map(referenceSerializer)
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
import { InnerNode } from '../store/inner-node';
|
|
||||||
|
|
||||||
export class Serializable extends InnerNode {
|
|
||||||
static childrenMap: {
|
|
||||||
[type: string]: {
|
|
||||||
childrenConstructor: typeof Serializable;
|
|
||||||
childrenListName: string;
|
|
||||||
childrenType: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
private static propertyList: any = {};
|
|
||||||
protected type: string;
|
|
||||||
|
|
||||||
protected constructor(properties: any, type: string, children: Array<InnerNode> = []) {
|
|
||||||
super(children);
|
|
||||||
|
|
||||||
const compiledType = this.constructor.name;
|
|
||||||
if (!Serializable.propertyList.hasOwnProperty(compiledType)) {
|
|
||||||
Serializable.propertyList[compiledType] = [];
|
|
||||||
}
|
|
||||||
for (const property in properties) {
|
|
||||||
if (properties.hasOwnProperty(property)) {
|
|
||||||
if (property !== Serializable.childrenMap[type].childrenListName) {
|
|
||||||
this[property] = properties[property];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Serializable.propertyList[compiledType].includes(property)) {
|
|
||||||
Serializable.propertyList[compiledType].push(property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(): object {
|
|
||||||
return Serializable.propertyList[this.constructor.name].reduce(
|
|
||||||
(object, property) => ({
|
|
||||||
[property]: this[property],
|
|
||||||
...object
|
|
||||||
}),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import { ITower } from '../interfaces/persistance/tower';
|
import { ITower } from '../interfaces/persistance/tower';
|
||||||
import { lighten } from '../utils/color';
|
import { lighten } from '../utils/color';
|
||||||
import { Block } from './block';
|
import { Block } from './block';
|
||||||
import { Serializable } from './serializable';
|
|
||||||
import { hash } from '../utils/hash';
|
import { hash } from '../utils/hash';
|
||||||
import { IColor } from '../interfaces/color';
|
import { IColor } from '../interfaces/color';
|
||||||
import { InnerNodeState } from '../store/inner-node';
|
import { InnerNode, InnerNodeState } from '../store/inner-node';
|
||||||
|
|
||||||
export type ColoredBlock = Block & { color: IColor };
|
export type ColoredBlock = Block & { color: IColor };
|
||||||
|
|
||||||
|
|
@ -12,14 +11,16 @@ export interface TowerState extends ITower, InnerNodeState {
|
||||||
blocks: Array<Block>;
|
blocks: Array<Block>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Tower extends Serializable implements ITower, TowerState {
|
export class Tower extends InnerNode implements ITower, TowerState {
|
||||||
tags: string[];
|
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
coloredBlocks: Array<ColoredBlock>;
|
|
||||||
readonly baseColor: IColor;
|
readonly baseColor: IColor;
|
||||||
|
tags: string[];
|
||||||
|
coloredBlocks: Array<ColoredBlock>;
|
||||||
|
|
||||||
constructor(props: ITower) {
|
constructor(props: ITower, referenceDeserializer: (from: any) => any = e => e) {
|
||||||
super(props, 'Tower', props.blocks.map(b => new Block(b)));
|
super(props.blocks.map(b => new Block(referenceDeserializer(b), referenceDeserializer)), props.id);
|
||||||
|
this.name = props.name;
|
||||||
|
this.baseColor = props.baseColor;
|
||||||
this.onAfterClone();
|
this.onAfterClone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,6 +53,15 @@ export class Tower extends Serializable implements ITower, TowerState {
|
||||||
return lighten((hash(tag) - 0.5) * 50, this.baseColor);
|
return lighten((hash(tag) - 0.5) * 50, this.baseColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serialize(referenceSerializer: (ref: object) => any): ITower {
|
||||||
|
return {
|
||||||
|
...super.serialize(referenceSerializer),
|
||||||
|
name: this.name,
|
||||||
|
baseColor: this.baseColor,
|
||||||
|
blocks: this.blocks.map(referenceSerializer)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
protected onAfterClone() {
|
protected onAfterClone() {
|
||||||
this.blocks.sort((a, b) => {
|
this.blocks.sort((a, b) => {
|
||||||
return a.created.getTime() - b.created.getTime();
|
return a.created.getTime() - b.created.getTime();
|
||||||
|
|
|
||||||
53
src/app/services/api.service.ts
Normal file
53
src/app/services/api.service.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
|
import { Unique } from '../store/unique';
|
||||||
|
|
||||||
|
const API_URI = 'https://schmelczer.dev/api/store/';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ApiService {
|
||||||
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
|
private static getAuthorizationHeader(id: string): HttpHeaders {
|
||||||
|
return new HttpHeaders().set('Authorization', `life-towers-v3 ${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async track(id: string): Promise<void> {
|
||||||
|
await this.http.post(`${API_URI}me`, {}, { headers: ApiService.getAuthorizationHeader(id) }).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
async register(id: string): Promise<void> {
|
||||||
|
await this.http.post(API_URI, { token: id }).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getObject(userId: string, objectId: string): Promise<Unique> {
|
||||||
|
return await this.http
|
||||||
|
.get<Unique>(`${API_URI}me/${objectId}`, { headers: ApiService.getAuthorizationHeader(userId) })
|
||||||
|
.toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
async postObject(userId: string, objectId: string, serializedObject: string): Promise<void> {
|
||||||
|
await this.http
|
||||||
|
.post(
|
||||||
|
`${API_URI}me/${objectId}`,
|
||||||
|
{ data: serializedObject },
|
||||||
|
{ headers: ApiService.getAuthorizationHeader(userId) }
|
||||||
|
)
|
||||||
|
.toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRootId(userId: string): Promise<string> {
|
||||||
|
return await this.http
|
||||||
|
// @ts-ignore
|
||||||
|
.get<string>(`${API_URI}me/root`, { headers: ApiService.getAuthorizationHeader(userId), responseType: 'text' })
|
||||||
|
.toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
async setRootId(userId: string, rootId: string): Promise<void> {
|
||||||
|
await this.http
|
||||||
|
.put(`${API_URI}me/root`, { root_id: rootId }, { headers: ApiService.getAuthorizationHeader(userId) })
|
||||||
|
.toPromise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,72 +1,35 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { StoreService } from './store.service';
|
|
||||||
import { Page } from '../model/page';
|
|
||||||
import { Root } from '../store/root';
|
import { Root } from '../store/root';
|
||||||
import { Serializable } from '../model/serializable';
|
import { MapStoreService } from './map-store.service';
|
||||||
import { Tower } from '../model/tower';
|
import { Data } from '../model/data';
|
||||||
import { Block } from '../model/block';
|
|
||||||
import { IPage } from '../interfaces/persistance/page';
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class DataService extends Root<Page> {
|
export class DataService extends Root<Data> {
|
||||||
constructor(private storeService: StoreService<Array<IPage>>) {
|
private shouldSave = true;
|
||||||
|
constructor(private store: MapStoreService) {
|
||||||
super();
|
super();
|
||||||
this.init().catch();
|
|
||||||
}
|
|
||||||
|
|
||||||
get pages(): Array<Page> {
|
this.store.data.subscribe(d => {
|
||||||
return this.children;
|
if (d) {
|
||||||
|
this.shouldSave = false;
|
||||||
|
this.changeKeys({ children: [d] });
|
||||||
}
|
}
|
||||||
|
|
||||||
save(timeout: number) {
|
|
||||||
this.storeService.scheduleSave(this.pages, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
addPage(name: string) {
|
|
||||||
const page = new Page({
|
|
||||||
name,
|
|
||||||
userData: {},
|
|
||||||
towers: []
|
|
||||||
});
|
});
|
||||||
this.addChildren([page]);
|
|
||||||
page.addTower();
|
|
||||||
}
|
|
||||||
|
|
||||||
removePage(page: Page) {
|
|
||||||
this.changeKeys<any>({
|
|
||||||
children: this.children.filter(c => c !== page)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async init() {
|
|
||||||
const pages = await this.storeService.load();
|
|
||||||
Serializable.childrenMap = {
|
|
||||||
Page: {
|
|
||||||
childrenListName: 'towers',
|
|
||||||
childrenConstructor: Tower,
|
|
||||||
childrenType: 'Tower'
|
|
||||||
},
|
|
||||||
Tower: {
|
|
||||||
childrenListName: 'blocks',
|
|
||||||
childrenConstructor: Block,
|
|
||||||
childrenType: 'Block'
|
|
||||||
},
|
|
||||||
Block: {
|
|
||||||
childrenListName: null,
|
|
||||||
childrenConstructor: null,
|
|
||||||
childrenType: null
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.children$.subscribe(_ => {
|
this.children$.subscribe(_ => {
|
||||||
this.log();
|
this.log();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addChildren(pages.map(p => new Page(p)));
|
this.children$.subscribe(data => {
|
||||||
|
if (data && data.length && data[0]) {
|
||||||
this.children$.subscribe(_ => {
|
if (!this.shouldSave) {
|
||||||
this.save(0);
|
this.shouldSave = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.store.save(data[0]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue