reportData.service.ts 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { Injectable, Inject } from '@angular/core';
  2. import { BehaviorSubject } from 'rxjs/BehaviorSubject';
  3. import { WindowService } from './window.service';
  4. import { Subject } from 'rxjs/Subject';
  5. import {isRemoteDataOk, NewReport, PS_REPORTS_KEY, RemoteData, Report} from '../types';
  6. @Injectable()
  7. export class ReportDataService {
  8. dataChange = new BehaviorSubject<RemoteData<Report[]>>({ kind: 'notFetched' });
  9. reportCreated: Subject<Report> = new Subject();
  10. reportApprovedReject: Subject<{ report: Report, user: string }> = new Subject();
  11. constructor(@Inject(WindowService) private _window: Window) {
  12. this.fetch();
  13. const stringfiedReports = _window.localStorage.getItem(PS_REPORTS_KEY);
  14. if (stringfiedReports) {
  15. this.dataChange.next(JSON.parse(stringfiedReports));
  16. }
  17. }
  18. fetch() {
  19. this.dataChange.next({ kind: 'loading' });
  20. setTimeout(() => {
  21. const random = Math.floor((Math.random() * 10) + 1);
  22. const stringifiedReports = this._window.localStorage.getItem(PS_REPORTS_KEY);
  23. if (random > 3 && stringifiedReports) {
  24. this.dataChange.next({
  25. kind: 'ok',
  26. data: JSON.parse(stringifiedReports),
  27. });
  28. } else {
  29. // some error.
  30. this.dataChange.next({
  31. kind: 'error',
  32. error: 'Loading the data has failed',
  33. });
  34. }
  35. }, 0);
  36. }
  37. get remoteData(): RemoteData<Report[]> {
  38. return this.dataChange.value;
  39. }
  40. getReport(reportId: number): Promise<Report | undefined> {
  41. if (isRemoteDataOk(this.remoteData)) {
  42. return Promise.resolve(this.remoteData.data.find(r => r.id === reportId));
  43. } else {
  44. return Promise.resolve(undefined);
  45. }
  46. }
  47. add(report: NewReport) {
  48. if (isRemoteDataOk(this.remoteData)) {
  49. const newReport = {
  50. ...report,
  51. // Since this.data: Report[], rep is a Report, so it does have an id
  52. // property we can use, although Report.id is an optional number.
  53. // Which means we can tell the compiler it exists with a '!'.
  54. id: this.remoteData.data.reduce((biggestId, rep) => biggestId > rep.id ? biggestId : rep.id, 0) + 1,
  55. amount: report.items.reduce((sum, item) => sum + item.amount, 0)
  56. };
  57. const newData = [...this.remoteData.data, newReport];
  58. this.updateData(newData);
  59. this.reportCreated.next(newReport);
  60. }
  61. }
  62. save(report: Report) {
  63. if (isRemoteDataOk(this.remoteData)) {
  64. const reportIndex = this.remoteData.data.findIndex(r => r.id === report.id);
  65. const newData = [...this.remoteData.data];
  66. newData.splice(reportIndex, 1, report);
  67. this.updateData(newData);
  68. }
  69. }
  70. toggleApproval(report: Report, user: string) {
  71. if (isRemoteDataOk(this.remoteData)) {
  72. const reportIndex = this.remoteData.data.findIndex(r => r.id === report.id);
  73. const newData = [...this.remoteData.data];
  74. newData.splice(reportIndex, 1, report);
  75. this.updateData(newData);
  76. this.reportApprovedReject.next({report, user});
  77. }
  78. }
  79. private updateData(reports: Report[]) {
  80. this._window.localStorage.setItem(PS_REPORTS_KEY, JSON.stringify(reports));
  81. this.dataChange.next({
  82. kind: 'ok',
  83. data: reports,
  84. });
  85. }
  86. }