reportData.service.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import { Injectable, Inject } from '@angular/core';
  2. import { BehaviorSubject } from 'rxjs/BehaviorSubject';
  3. import { Subject } from 'rxjs/Subject';
  4. import { Report, NewReport, PS_REPORTS_KEY, RemoteData, isRemoteDataOK } from '../types';
  5. import { WindowService } from './window.service';
  6. declare global {
  7. interface Array<T> {
  8. filterWith<TKey extends keyof T, TValue extends T[TKey]>(member: TKey, value: TValue): T[];
  9. }
  10. }
  11. Array.prototype.filterWith = function<T, TKey extends keyof T, TValue extends T[TKey]>(this: T[], member: TKey, value: TValue): T[] {
  12. return this.filter(x => x[member] === value);
  13. }
  14. // Non-generics version.
  15. // function filter(reports: Report[], term: string): Report[] {
  16. // return reports.filter((r => r.description === term));
  17. // }
  18. // Generics versions
  19. const reports: Report[] = [];
  20. reports.filterWith('approved', true);
  21. @Injectable()
  22. export class ReportDataService {
  23. dataChange = new BehaviorSubject<RemoteData<Report[]>>({ kind: "notFetched" });
  24. reportCreated: Subject<Report> = new Subject();
  25. reportApprovedReject: Subject<{ report: Report, user: string }> = new Subject();
  26. constructor(@Inject(WindowService) private _window: Window) {
  27. this.fetch();
  28. }
  29. get remoteData(): RemoteData<Report[]> {
  30. return this.dataChange.value;
  31. }
  32. getReport(reportId: number): Promise<Report | undefined> {
  33. if (isRemoteDataOK(this.remoteData)) {
  34. return Promise.resolve(this.remoteData.data.find(r => r.id === reportId));
  35. } else {
  36. return Promise.resolve(undefined);
  37. }
  38. }
  39. add(report: NewReport) {
  40. if (isRemoteDataOK(this.remoteData)) {
  41. const newReport = {
  42. ...report,
  43. // Since this.data: Report[], rep is a Report, so it does have an id
  44. // property we can use, although Report.id is an optional number.
  45. // Which means we can tell the compiler it exists with a '!'.
  46. id: this.remoteData.data.reduce((biggestId, rep) => biggestId > rep.id ? biggestId : rep.id, 0) + 1,
  47. amount: report.items.reduce((sum, item) => sum + item.amount, 0)
  48. };
  49. const newData = [...this.remoteData.data, newReport];
  50. this.updateData(newData);
  51. this.reportCreated.next(newReport);
  52. }
  53. }
  54. save(report: Report) {
  55. if (isRemoteDataOK(this.remoteData)) {
  56. const reportIndex = this.remoteData.data.findIndex(r => r.id === report.id);
  57. const newData = [...this.remoteData.data];
  58. newData.splice(reportIndex, 1, report);
  59. this.updateData(newData);
  60. }
  61. }
  62. toggleApproval(report: Report, user: string) {
  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. this.reportApprovedReject.next({ report, user });
  69. }
  70. }
  71. private updateData(reports: Report[]) {
  72. this._window.localStorage.setItem(PS_REPORTS_KEY, JSON.stringify(reports));
  73. this._window.psExpenses = JSON.stringify(reports);
  74. this.dataChange.next({ kind: "ok", data: reports });
  75. }
  76. private fetch(): void {
  77. this.dataChange.next({ kind: "loading" });
  78. setTimeout(() => {
  79. const random = Math.floor((Math.random() * 10) + 1);
  80. const stringfiedReports = this._window.localStorage.getItem(PS_REPORTS_KEY);
  81. if (random > 3 && stringfiedReports) {
  82. this.dataChange.next({
  83. kind: "ok",
  84. data: JSON.parse(stringfiedReports)
  85. });
  86. } else {
  87. this.dataChange.next({
  88. kind: 'error',
  89. error: 'The were was an issue loading the data'
  90. })
  91. }
  92. }, 1000);
  93. }
  94. }