From 2c01414b1d9c999a45e2a991034e53835b04f040 Mon Sep 17 00:00:00 2001 From: TheEnd023 Date: Thu, 2 May 2019 20:27:09 +0200 Subject: [PATCH 01/20] feat: Changed Event class to interface --- .../components/events/events.component.ts | 10 +++--- libs/calendar/src/index.ts | 1 - libs/calendar/src/lib/calendar.component.ts | 11 +++--- libs/calendar/src/lib/calendar.interfaces.ts | 9 +++++ libs/calendar/src/lib/lib/event.ts | 34 ------------------- 5 files changed, 19 insertions(+), 46 deletions(-) delete mode 100644 libs/calendar/src/lib/lib/event.ts diff --git a/apps/frontend/src/app/modules/events/components/events/events.component.ts b/apps/frontend/src/app/modules/events/components/events/events.component.ts index e5e49b6b4..53fbf41b3 100644 --- a/apps/frontend/src/app/modules/events/components/events/events.component.ts +++ b/apps/frontend/src/app/modules/events/components/events/events.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit } from '@angular/core' -import { Event, Settings } from '@verseghy/calendar' +import { CalendarEvent, Settings } from '@verseghy/calendar' import { EVENTS_FEATURE_KEY, EventsState } from '../../reducer/events.reducer' import { select, Store } from '@ngrx/store' import { MonthChange } from '../../reducer/events.actions' -import { map, delay } from 'rxjs/operators' +import { map } from 'rxjs/operators' import { Observable } from 'rxjs' @Component({ @@ -32,7 +32,7 @@ export class EventsComponent implements OnInit { today: 'Ma', moreEvent: 'Több esemény', } - calendarEvents: Observable + calendarEvents: Observable constructor(private store: Store) {} @@ -40,9 +40,9 @@ export class EventsComponent implements OnInit { this.calendarEvents = this.store.pipe( select(EVENTS_FEATURE_KEY), map((data: EventsState) => { - let calendarEvents: Event[] = [] + let calendarEvents: CalendarEvent[] = [] for (const item of data.list) { - calendarEvents = [...calendarEvents, new Event(item.id, item.title, item.description, item.date_from, item.date_to, item.color)] + calendarEvents = [...calendarEvents, {id: item.id, title: item.title, description: item.description, startDate: item.date_from, endDate: item.date_to, color: item.color}] } return calendarEvents }) diff --git a/libs/calendar/src/index.ts b/libs/calendar/src/index.ts index 7d7c6c177..364f1fc7d 100644 --- a/libs/calendar/src/index.ts +++ b/libs/calendar/src/index.ts @@ -1,4 +1,3 @@ export * from './lib/calendar.module' export * from './lib/calendar.interfaces' export * from './lib/calendar.component' -export * from './lib/lib/event' diff --git a/libs/calendar/src/lib/calendar.component.ts b/libs/calendar/src/lib/calendar.component.ts index 4688a293d..25fa8f5a5 100644 --- a/libs/calendar/src/lib/calendar.component.ts +++ b/libs/calendar/src/lib/calendar.component.ts @@ -1,6 +1,5 @@ import { AfterViewInit, Component, ElementRef, EventEmitter, HostListener, Input, OnInit, Output, ViewChild } from '@angular/core' -import { DisplayedEvent, Settings } from '@verseghy/calendar' -import { Event } from './lib/event' +import { DisplayedEvent, Settings, CalendarEvent } from '@verseghy/calendar' import { Cell } from './lib/cell' import { addMonths, @@ -30,7 +29,7 @@ import { Renderer } from './lib/renderer' export class CalendarComponent implements OnInit, AfterViewInit { private _cells: Cell[] = [] private _date = new Date() - private _events: Event[] = [] + private _events: CalendarEvent[] = [] private _displayedEvents: DisplayedEvent[] = [] private _settings: Settings private _renderer = new Renderer() @@ -151,7 +150,7 @@ export class CalendarComponent implements OnInit, AfterViewInit { this.date = new Date() } - private _isArrayContainsId(array: Event[], id: Number): boolean { + private _isArrayContainsId(array: CalendarEvent[], id: Number): boolean { for (const item of array) { if (item.id === id) { return true @@ -160,7 +159,7 @@ export class CalendarComponent implements OnInit, AfterViewInit { return false } - @Input('events') public set events(events: Event[]) { + @Input('events') public set events(events: CalendarEvent[]) { if (!events) return if (events.length) { let tempEvents = [] @@ -268,7 +267,7 @@ export class CalendarComponent implements OnInit, AfterViewInit { return displayedEvents } - private _getEvent(id: number): Event { + private _getEvent(id: number): CalendarEvent { for (const item of this._events) { if (item.id === id) { return item diff --git a/libs/calendar/src/lib/calendar.interfaces.ts b/libs/calendar/src/lib/calendar.interfaces.ts index e1117424c..7545a12b4 100644 --- a/libs/calendar/src/lib/calendar.interfaces.ts +++ b/libs/calendar/src/lib/calendar.interfaces.ts @@ -13,3 +13,12 @@ export interface Settings { today?: string moreEvent?: string } + +export interface CalendarEvent { + id: number, + title: string, + description: string, + startDate: Date, + endDate: Date, + color: string +} \ No newline at end of file diff --git a/libs/calendar/src/lib/lib/event.ts b/libs/calendar/src/lib/lib/event.ts deleted file mode 100644 index 8526842d5..000000000 --- a/libs/calendar/src/lib/lib/event.ts +++ /dev/null @@ -1,34 +0,0 @@ -export class Event { - constructor( - private _id: number, - private _title: string, - private _description: string = '', - private _startDate: Date, - private _endDate: Date = _startDate, - private _color: string = '#3f51b5' - ) {} - - get id() { - return this._id - } - - get title() { - return this._title - } - - get description() { - return this._description - } - - get startDate() { - return this._startDate - } - - get endDate() { - return this._endDate - } - - get color() { - return this._color - } -} From b16883211132788fb8ab842cd0d5811f4bd8e0db Mon Sep 17 00:00:00 2001 From: TheEnd023 Date: Thu, 2 May 2019 21:44:02 +0200 Subject: [PATCH 02/20] feat: add popup module --- libs/calendar/src/index.ts | 1 - libs/calendar/src/lib/calendar.component.ts | 2 ++ libs/calendar/src/lib/calendar.interfaces.ts | 10 ++++++ libs/calendar/src/lib/calendar.module.ts | 3 +- libs/calendar/src/lib/calendar.service.ts | 13 ++++++++ libs/calendar/src/lib/lib/cell.ts | 19 ++++------- libs/calendar/src/lib/lib/popup.ts | 15 +++++++++ .../src/lib/popup/popup.component.css | 32 ------------------- .../src/lib/popup/popup.component.html | 4 --- .../calendar/src/lib/popup/popup.component.ts | 21 ------------ 10 files changed, 48 insertions(+), 72 deletions(-) create mode 100644 libs/calendar/src/lib/lib/popup.ts delete mode 100644 libs/calendar/src/lib/popup/popup.component.css delete mode 100644 libs/calendar/src/lib/popup/popup.component.html delete mode 100644 libs/calendar/src/lib/popup/popup.component.ts diff --git a/libs/calendar/src/index.ts b/libs/calendar/src/index.ts index 364f1fc7d..b866cf0c1 100644 --- a/libs/calendar/src/index.ts +++ b/libs/calendar/src/index.ts @@ -1,3 +1,2 @@ export * from './lib/calendar.module' export * from './lib/calendar.interfaces' -export * from './lib/calendar.component' diff --git a/libs/calendar/src/lib/calendar.component.ts b/libs/calendar/src/lib/calendar.component.ts index 25fa8f5a5..e5eb3bd37 100644 --- a/libs/calendar/src/lib/calendar.component.ts +++ b/libs/calendar/src/lib/calendar.component.ts @@ -1,6 +1,7 @@ import { AfterViewInit, Component, ElementRef, EventEmitter, HostListener, Input, OnInit, Output, ViewChild } from '@angular/core' import { DisplayedEvent, Settings, CalendarEvent } from '@verseghy/calendar' import { Cell } from './lib/cell' +import { popUpHandler } from './lib/popup' import { addMonths, differenceInDays, @@ -34,6 +35,7 @@ export class CalendarComponent implements OnInit, AfterViewInit { private _settings: Settings private _renderer = new Renderer() private _ready = false + private _popUpHandler = new popUpHandler() public moreEventsPopupVisible = false public moreEventsPopupTop: number diff --git a/libs/calendar/src/lib/calendar.interfaces.ts b/libs/calendar/src/lib/calendar.interfaces.ts index 7545a12b4..ceeebe7fd 100644 --- a/libs/calendar/src/lib/calendar.interfaces.ts +++ b/libs/calendar/src/lib/calendar.interfaces.ts @@ -21,4 +21,14 @@ export interface CalendarEvent { startDate: Date, endDate: Date, color: string +} + +export interface EventDetailsPopUpSettings { + visible: boolean, + top: number, + left: number, + date: string, + title: string, + description: string, + color: string } \ No newline at end of file diff --git a/libs/calendar/src/lib/calendar.module.ts b/libs/calendar/src/lib/calendar.module.ts index 219f4e5d0..f8982e134 100644 --- a/libs/calendar/src/lib/calendar.module.ts +++ b/libs/calendar/src/lib/calendar.module.ts @@ -1,11 +1,10 @@ import { NgModule } from '@angular/core' import { CommonModule } from '@angular/common' import { CalendarComponent } from './calendar.component' -import { PopupComponent } from './popup/popup.component' @NgModule({ imports: [CommonModule], - declarations: [CalendarComponent, PopupComponent], + declarations: [CalendarComponent], exports: [CalendarComponent], }) export class CalendarModule {} diff --git a/libs/calendar/src/lib/calendar.service.ts b/libs/calendar/src/lib/calendar.service.ts index bb9d11ec8..332e2db4a 100644 --- a/libs/calendar/src/lib/calendar.service.ts +++ b/libs/calendar/src/lib/calendar.service.ts @@ -1,8 +1,21 @@ import { Injectable } from '@angular/core' +import { BehaviorSubject } from 'rxjs'; +import { EventDetailsPopUpSettings } from './calendar.interfaces'; @Injectable({ providedIn: 'root', }) export class NgxCalendarLibService { + eventDetailsPopUpSettings: EventDetailsPopUpSettings = { + visible: false, + top: 0, + left: 0, + date: '', + title: '', + description: '', + color: '' + } + eventDetailsPopUp$: BehaviorSubject = new BehaviorSubject(this.eventDetailsPopUpSettings) + constructor() {} } diff --git a/libs/calendar/src/lib/lib/cell.ts b/libs/calendar/src/lib/lib/cell.ts index 5783fe5fe..8a20ae5fc 100644 --- a/libs/calendar/src/lib/lib/cell.ts +++ b/libs/calendar/src/lib/lib/cell.ts @@ -2,7 +2,6 @@ import { format, getDate, getMonth } from 'date-fns' import { Settings } from '../calendar.interfaces' export class Cell { - private _id: number private _rows: { id: number row: number @@ -12,21 +11,17 @@ export class Cell { color: string placeholder: boolean }[] = [] - private _date: Date - private _today: boolean - private _maxRows: number private _moreEventsTop: string private _moreEventsCount = 0 - private _settings: Settings private _moreEventsVisible: boolean - constructor(id: number, today: boolean, date: Date, maxRows: number, settings: Settings) { - this._id = id - this._today = today - this._date = date - this._maxRows = maxRows - this._settings = settings - } + constructor( + private _id: number, + private _today: boolean, + private _date: Date, + private _maxRows: number, + private _settings: Settings + ) {} public getRow(width: number): number { for (const item of Object.keys(this._rows)) { diff --git a/libs/calendar/src/lib/lib/popup.ts b/libs/calendar/src/lib/lib/popup.ts new file mode 100644 index 000000000..1ea75d33f --- /dev/null +++ b/libs/calendar/src/lib/lib/popup.ts @@ -0,0 +1,15 @@ +import { NgxCalendarLibService } from '../calendar.service'; +import { BehaviorSubject } from 'rxjs'; +import { EventDetailsPopUpSettings } from '../calendar.interfaces'; + +export class popUpHandler { + eventDetailsPopUp$: BehaviorSubject + + constructor(private calendarService: NgxCalendarLibService) { + this.eventDetailsPopUp$ = calendarService.eventDetailsPopUp$ + } + + public closeEventDetailsPopup() { + this.eventDetailsPopUp$.next() + } +} \ No newline at end of file diff --git a/libs/calendar/src/lib/popup/popup.component.css b/libs/calendar/src/lib/popup/popup.component.css deleted file mode 100644 index 280c969b5..000000000 --- a/libs/calendar/src/lib/popup/popup.component.css +++ /dev/null @@ -1,32 +0,0 @@ -:host { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} - -:host > div { - position: absolute; - z-index: 14; - top: 0; - left: -12px; - right: -12px; -} - -.moreEvents { - box-shadow: 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12), 0 11px 15px -7px rgba(0, 0, 0, 0.2); - background: #fff; - padding: 12px; -} - -.event { - height: 22px; - padding: 0 8px; - line-height: 20px; - color: #fff; - font-size: 12px; - border-radius: 2px; - display: block; - margin: 2px 0; -} diff --git a/libs/calendar/src/lib/popup/popup.component.html b/libs/calendar/src/lib/popup/popup.component.html deleted file mode 100644 index d3fd7a42a..000000000 --- a/libs/calendar/src/lib/popup/popup.component.html +++ /dev/null @@ -1,4 +0,0 @@ -
- {{ item.title }} -
-
diff --git a/libs/calendar/src/lib/popup/popup.component.ts b/libs/calendar/src/lib/popup/popup.component.ts deleted file mode 100644 index 331cfe041..000000000 --- a/libs/calendar/src/lib/popup/popup.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component, HostListener, Input, OnInit } from '@angular/core' - -@Component({ - selector: 'verseghy-popup', - templateUrl: './popup.component.html', - styleUrls: ['./popup.component.css'], -}) -export class PopupComponent implements OnInit { - @Input() event: Event | Event[] - @Input() moreEvents = false - public show = false - - constructor() {} - - ngOnInit() {} - - @HostListener('click') - onClick() { - this.show = !this.show - } -} From 2fa8b3cf670bb7657a0dcb7f3ee2d77297335434 Mon Sep 17 00:00:00 2001 From: TheEnd023 Date: Thu, 2 May 2019 21:47:49 +0200 Subject: [PATCH 03/20] feat: add popup reducer --- libs/calendar/src/lib/+state/popup.actions.ts | 30 +++++++++++ .../src/lib/+state/popup.effects.spec.ts | 35 ++++++++++++ libs/calendar/src/lib/+state/popup.effects.ts | 23 ++++++++ .../src/lib/+state/popup.reducer.spec.ts | 36 +++++++++++++ libs/calendar/src/lib/+state/popup.reducer.ts | 44 +++++++++++++++ .../src/lib/+state/popup.selectors.spec.ts | 53 +++++++++++++++++++ .../src/lib/+state/popup.selectors.ts | 41 ++++++++++++++ libs/calendar/src/lib/calendar.module.ts | 10 +++- 8 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 libs/calendar/src/lib/+state/popup.actions.ts create mode 100644 libs/calendar/src/lib/+state/popup.effects.spec.ts create mode 100644 libs/calendar/src/lib/+state/popup.effects.ts create mode 100644 libs/calendar/src/lib/+state/popup.reducer.spec.ts create mode 100644 libs/calendar/src/lib/+state/popup.reducer.ts create mode 100644 libs/calendar/src/lib/+state/popup.selectors.spec.ts create mode 100644 libs/calendar/src/lib/+state/popup.selectors.ts diff --git a/libs/calendar/src/lib/+state/popup.actions.ts b/libs/calendar/src/lib/+state/popup.actions.ts new file mode 100644 index 000000000..ba20b7f17 --- /dev/null +++ b/libs/calendar/src/lib/+state/popup.actions.ts @@ -0,0 +1,30 @@ +import { Action } from '@ngrx/store' +import { Entity } from './popup.reducer' + +export enum PopupActionTypes { + LoadPopup = '[Popup] Load Popup', + PopupLoaded = '[Popup] Popup Loaded', + PopupLoadError = '[Popup] Popup Load Error', +} + +export class LoadPopup implements Action { + readonly type = PopupActionTypes.LoadPopup +} + +export class PopupLoadError implements Action { + readonly type = PopupActionTypes.PopupLoadError + constructor(public payload: any) {} +} + +export class PopupLoaded implements Action { + readonly type = PopupActionTypes.PopupLoaded + constructor(public payload: Entity[]) {} +} + +export type PopupAction = LoadPopup | PopupLoaded | PopupLoadError + +export const fromPopupActions = { + LoadPopup, + PopupLoaded, + PopupLoadError, +} diff --git a/libs/calendar/src/lib/+state/popup.effects.spec.ts b/libs/calendar/src/lib/+state/popup.effects.spec.ts new file mode 100644 index 000000000..6b8f20f96 --- /dev/null +++ b/libs/calendar/src/lib/+state/popup.effects.spec.ts @@ -0,0 +1,35 @@ +import { TestBed, async } from '@angular/core/testing' + +import { Observable } from 'rxjs' + +import { EffectsModule } from '@ngrx/effects' +import { StoreModule } from '@ngrx/store' +import { provideMockActions } from '@ngrx/effects/testing' + +import { NxModule } from '@nrwl/nx' +import { DataPersistence } from '@nrwl/nx' +import { hot } from '@nrwl/nx/testing' + +import { PopupEffects } from './popup.effects' +import { LoadPopup, PopupLoaded } from './popup.actions' + +describe('PopupEffects', () => { + let actions: Observable + let effects: PopupEffects + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [NxModule.forRoot(), StoreModule.forRoot({}), EffectsModule.forRoot([])], + providers: [PopupEffects, DataPersistence, provideMockActions(() => actions)], + }) + + effects = TestBed.get(PopupEffects) + }) + + describe('loadPopup$', () => { + it('should work', () => { + actions = hot('-a-|', { a: new LoadPopup() }) + expect(effects.loadPopup$).toBeObservable(hot('-a-|', { a: new PopupLoaded([]) })) + }) + }) +}) diff --git a/libs/calendar/src/lib/+state/popup.effects.ts b/libs/calendar/src/lib/+state/popup.effects.ts new file mode 100644 index 000000000..64f7ef856 --- /dev/null +++ b/libs/calendar/src/lib/+state/popup.effects.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core' +import { Effect, Actions } from '@ngrx/effects' +import { DataPersistence } from '@nrwl/nx' + +import { PopupPartialState } from './popup.reducer' +import { LoadPopup, PopupLoaded, PopupLoadError, PopupActionTypes } from './popup.actions' + +@Injectable() +export class PopupEffects { + @Effect() loadPopup$ = this.dataPersistence.fetch(PopupActionTypes.LoadPopup, { + run: (action: LoadPopup, state: PopupPartialState) => { + // Your custom REST 'load' logic goes here. For now just return an empty list... + return new PopupLoaded([]) + }, + + onError: (action: LoadPopup, error) => { + console.error('Error', error) + return new PopupLoadError(error) + }, + }) + + constructor(private actions$: Actions, private dataPersistence: DataPersistence) {} +} diff --git a/libs/calendar/src/lib/+state/popup.reducer.spec.ts b/libs/calendar/src/lib/+state/popup.reducer.spec.ts new file mode 100644 index 000000000..655030499 --- /dev/null +++ b/libs/calendar/src/lib/+state/popup.reducer.spec.ts @@ -0,0 +1,36 @@ +import { PopupLoaded } from './popup.actions' +import { PopupState, Entity, initialState, popupReducer } from './popup.reducer' + +describe('Popup Reducer', () => { + const getPopupId = it => it['id'] + let createPopup + + beforeEach(() => { + createPopup = (id: string, name = ''): Entity => ({ + id, + name: name || `name-${id}`, + }) + }) + + describe('valid Popup actions ', () => { + it('should return set the list of known Popup', () => { + const popups = [createPopup('PRODUCT-AAA'), createPopup('PRODUCT-zzz')] + const action = new PopupLoaded(popups) + const result: PopupState = popupReducer(initialState, action) + const selId: string = getPopupId(result.list[1]) + + expect(result.loaded).toBe(true) + expect(result.list.length).toBe(2) + expect(selId).toBe('PRODUCT-zzz') + }) + }) + + describe('unknown action', () => { + it('should return the initial state', () => { + const action = {} as any + const result = popupReducer(initialState, action) + + expect(result).toBe(initialState) + }) + }) +}) diff --git a/libs/calendar/src/lib/+state/popup.reducer.ts b/libs/calendar/src/lib/+state/popup.reducer.ts new file mode 100644 index 000000000..46f5e4c0c --- /dev/null +++ b/libs/calendar/src/lib/+state/popup.reducer.ts @@ -0,0 +1,44 @@ +import { PopupAction, PopupActionTypes } from './popup.actions' + +export const POPUP_FEATURE_KEY = 'popup' + +/** + * Interface for the 'Popup' data used in + * - PopupState, and + * - popupReducer + * + * Note: replace if already defined in another module + */ + +/* tslint:disable:no-empty-interface */ +export interface Entity {} + +export interface PopupState { + list: Entity[] // list of Popup; analogous to a sql normalized table + selectedId?: string | number // which Popup record has been selected + loaded: boolean // has the Popup list been loaded + error?: any // last none error (if any) +} + +export interface PopupPartialState { + readonly [POPUP_FEATURE_KEY]: PopupState +} + +export const initialState: PopupState = { + list: [], + loaded: false, +} + +export function popupReducer(state: PopupState = initialState, action: PopupAction): PopupState { + switch (action.type) { + case PopupActionTypes.PopupLoaded: { + state = { + ...state, + list: action.payload, + loaded: true, + } + break + } + } + return state +} diff --git a/libs/calendar/src/lib/+state/popup.selectors.spec.ts b/libs/calendar/src/lib/+state/popup.selectors.spec.ts new file mode 100644 index 000000000..42194b8ea --- /dev/null +++ b/libs/calendar/src/lib/+state/popup.selectors.spec.ts @@ -0,0 +1,53 @@ +import { Entity, PopupState } from './popup.reducer' +import { popupQuery } from './popup.selectors' + +describe('Popup Selectors', () => { + const ERROR_MSG = 'No Error Available' + const getPopupId = it => it['id'] + + let storeState + + beforeEach(() => { + const createPopup = (id: string, name = ''): Entity => ({ + id, + name: name || `name-${id}`, + }) + storeState = { + popup: { + list: [createPopup('PRODUCT-AAA'), createPopup('PRODUCT-BBB'), createPopup('PRODUCT-CCC')], + selectedId: 'PRODUCT-BBB', + error: ERROR_MSG, + loaded: true, + }, + } + }) + + describe('Popup Selectors', () => { + it('getAllPopup() should return the list of Popup', () => { + const results = popupQuery.getAllPopup(storeState) + const selId = getPopupId(results[1]) + + expect(results.length).toBe(3) + expect(selId).toBe('PRODUCT-BBB') + }) + + it('getSelectedPopup() should return the selected Entity', () => { + const result = popupQuery.getSelectedPopup(storeState) + const selId = getPopupId(result) + + expect(selId).toBe('PRODUCT-BBB') + }) + + it("getLoaded() should return the current 'loaded' status", () => { + const result = popupQuery.getLoaded(storeState) + + expect(result).toBe(true) + }) + + it("getError() should return the current 'error' storeState", () => { + const result = popupQuery.getError(storeState) + + expect(result).toBe(ERROR_MSG) + }) + }) +}) diff --git a/libs/calendar/src/lib/+state/popup.selectors.ts b/libs/calendar/src/lib/+state/popup.selectors.ts new file mode 100644 index 000000000..64037ad6b --- /dev/null +++ b/libs/calendar/src/lib/+state/popup.selectors.ts @@ -0,0 +1,41 @@ +import { createFeatureSelector, createSelector } from '@ngrx/store' +import { POPUP_FEATURE_KEY, PopupState } from './popup.reducer' + +// Lookup the 'Popup' feature state managed by NgRx +const getPopupState = createFeatureSelector(POPUP_FEATURE_KEY) + +const getLoaded = createSelector( + getPopupState, + (state: PopupState) => state.loaded +) +const getError = createSelector( + getPopupState, + (state: PopupState) => state.error +) + +const getAllPopup = createSelector( + getPopupState, + getLoaded, + (state: PopupState, isLoaded) => { + return isLoaded ? state.list : [] + } +) +const getSelectedId = createSelector( + getPopupState, + (state: PopupState) => state.selectedId +) +const getSelectedPopup = createSelector( + getAllPopup, + getSelectedId, + (popup, id) => { + const result = popup.find(it => it['id'] === id) + return result ? Object.assign({}, result) : undefined + } +) + +export const popupQuery = { + getLoaded, + getError, + getAllPopup, + getSelectedPopup, +} diff --git a/libs/calendar/src/lib/calendar.module.ts b/libs/calendar/src/lib/calendar.module.ts index f8982e134..8f504279d 100644 --- a/libs/calendar/src/lib/calendar.module.ts +++ b/libs/calendar/src/lib/calendar.module.ts @@ -1,9 +1,17 @@ import { NgModule } from '@angular/core' import { CommonModule } from '@angular/common' import { CalendarComponent } from './calendar.component' +import { StoreModule } from '@ngrx/store' +import { EffectsModule } from '@ngrx/effects' +import { POPUP_FEATURE_KEY, initialState as popupInitialState, popupReducer } from './+state/popup.reducer' +import { PopupEffects } from './+state/popup.effects' @NgModule({ - imports: [CommonModule], + imports: [ + CommonModule, + StoreModule.forFeature(POPUP_FEATURE_KEY, popupReducer, { initialState: popupInitialState }), + EffectsModule.forFeature([PopupEffects]), + ], declarations: [CalendarComponent], exports: [CalendarComponent], }) From f78437fc1f8401e30d15e2a0d84592450f321b5d Mon Sep 17 00:00:00 2001 From: TheEnd023 Date: Thu, 2 May 2019 23:13:42 +0200 Subject: [PATCH 04/20] feat: popup reducer --- libs/calendar/src/lib/+state/popup.actions.ts | 42 ++++++---- libs/calendar/src/lib/+state/popup.effects.ts | 15 +--- libs/calendar/src/lib/+state/popup.reducer.ts | 79 ++++++++++++++----- libs/calendar/src/lib/calendar.component.html | 14 ++-- libs/calendar/src/lib/calendar.component.ts | 62 ++++++--------- libs/calendar/src/lib/calendar.interfaces.ts | 12 ++- libs/calendar/src/lib/lib/popup.ts | 15 ---- .../services/popup-handler.service.spec.ts | 12 +++ .../src/lib/services/popup-handler.service.ts | 64 +++++++++++++++ 9 files changed, 202 insertions(+), 113 deletions(-) delete mode 100644 libs/calendar/src/lib/lib/popup.ts create mode 100644 libs/calendar/src/lib/services/popup-handler.service.spec.ts create mode 100644 libs/calendar/src/lib/services/popup-handler.service.ts diff --git a/libs/calendar/src/lib/+state/popup.actions.ts b/libs/calendar/src/lib/+state/popup.actions.ts index ba20b7f17..712dfd50f 100644 --- a/libs/calendar/src/lib/+state/popup.actions.ts +++ b/libs/calendar/src/lib/+state/popup.actions.ts @@ -1,30 +1,40 @@ import { Action } from '@ngrx/store' -import { Entity } from './popup.reducer' +import { CalendarEvent, PopupSettings } from '../calendar.interfaces'; export enum PopupActionTypes { - LoadPopup = '[Popup] Load Popup', - PopupLoaded = '[Popup] Popup Loaded', - PopupLoadError = '[Popup] Popup Load Error', + HideEventDetailsPopup = '[Popup] Hide Event Details Popup ', + SetEventDetailsPopup = '[Popup] Set Event Details Popup', + HideMoreEventsPopup = '[Popup] Hide More Events Popup', + SetMoreEventsPopup = '[Popup] Set More Events Popup', } -export class LoadPopup implements Action { - readonly type = PopupActionTypes.LoadPopup +export class HideEventDetailsPopup implements Action { + readonly type = PopupActionTypes.HideEventDetailsPopup } -export class PopupLoadError implements Action { - readonly type = PopupActionTypes.PopupLoadError - constructor(public payload: any) {} +export class SetEventDetailsPopup implements Action { + readonly type = PopupActionTypes.SetEventDetailsPopup + constructor(public payload: PopupSettings) {} } -export class PopupLoaded implements Action { - readonly type = PopupActionTypes.PopupLoaded - constructor(public payload: Entity[]) {} +export class HideMoreEventsPopup implements Action { + readonly type = PopupActionTypes.HideMoreEventsPopup } -export type PopupAction = LoadPopup | PopupLoaded | PopupLoadError +export class SetMoreEventsPopup implements Action { + readonly type = PopupActionTypes.SetMoreEventsPopup + constructor(public payload: PopupSettings) {} +} export const fromPopupActions = { - LoadPopup, - PopupLoaded, - PopupLoadError, + HideEventDetailsPopup, + SetEventDetailsPopup, + HideMoreEventsPopup, + SetMoreEventsPopup } + +export type PopupAction + = HideEventDetailsPopup + | SetEventDetailsPopup + | HideMoreEventsPopup + | SetMoreEventsPopup \ No newline at end of file diff --git a/libs/calendar/src/lib/+state/popup.effects.ts b/libs/calendar/src/lib/+state/popup.effects.ts index 64f7ef856..68a7013c3 100644 --- a/libs/calendar/src/lib/+state/popup.effects.ts +++ b/libs/calendar/src/lib/+state/popup.effects.ts @@ -1,23 +1,10 @@ import { Injectable } from '@angular/core' -import { Effect, Actions } from '@ngrx/effects' +import { Actions } from '@ngrx/effects' import { DataPersistence } from '@nrwl/nx' import { PopupPartialState } from './popup.reducer' -import { LoadPopup, PopupLoaded, PopupLoadError, PopupActionTypes } from './popup.actions' @Injectable() export class PopupEffects { - @Effect() loadPopup$ = this.dataPersistence.fetch(PopupActionTypes.LoadPopup, { - run: (action: LoadPopup, state: PopupPartialState) => { - // Your custom REST 'load' logic goes here. For now just return an empty list... - return new PopupLoaded([]) - }, - - onError: (action: LoadPopup, error) => { - console.error('Error', error) - return new PopupLoadError(error) - }, - }) - constructor(private actions$: Actions, private dataPersistence: DataPersistence) {} } diff --git a/libs/calendar/src/lib/+state/popup.reducer.ts b/libs/calendar/src/lib/+state/popup.reducer.ts index 46f5e4c0c..85fc8c44e 100644 --- a/libs/calendar/src/lib/+state/popup.reducer.ts +++ b/libs/calendar/src/lib/+state/popup.reducer.ts @@ -1,23 +1,11 @@ import { PopupAction, PopupActionTypes } from './popup.actions' +import { PopupSettings } from '../calendar.interfaces'; -export const POPUP_FEATURE_KEY = 'popup' - -/** - * Interface for the 'Popup' data used in - * - PopupState, and - * - popupReducer - * - * Note: replace if already defined in another module - */ - -/* tslint:disable:no-empty-interface */ -export interface Entity {} +export const POPUP_FEATURE_KEY = 'ui-calendar-popup' export interface PopupState { - list: Entity[] // list of Popup; analogous to a sql normalized table - selectedId?: string | number // which Popup record has been selected - loaded: boolean // has the Popup list been loaded - error?: any // last none error (if any) + eventDetailsPopup: PopupSettings, + moreEventsPopup: PopupSettings } export interface PopupPartialState { @@ -25,17 +13,66 @@ export interface PopupPartialState { } export const initialState: PopupState = { - list: [], - loaded: false, + eventDetailsPopup: { + visible: false, + top: 0, + left: 0, + date: '', + title: '', + description: '', + color: '', + }, + moreEventsPopup: { + visible: false, + top: 0, + left: 0, + date: '', + events: [] + } } export function popupReducer(state: PopupState = initialState, action: PopupAction): PopupState { switch (action.type) { - case PopupActionTypes.PopupLoaded: { + case PopupActionTypes.HideEventDetailsPopup: { + state = { + ...state, + eventDetailsPopup: { + ...state.eventDetailsPopup, + visible: false + } + } + break + } + + case PopupActionTypes.SetEventDetailsPopup: { + state = { + ...state, + eventDetailsPopup: { + ...state.eventDetailsPopup, + ...action.payload + } + } + break + } + + case PopupActionTypes.HideMoreEventsPopup: { + state = { + ...state, + moreEventsPopup: { + ...state.moreEventsPopup, + visible: false + } + } + break + } + + case PopupActionTypes.SetMoreEventsPopup: { state = { ...state, - list: action.payload, - loaded: true, + eventDetailsPopup: { + ...state.moreEventsPopup, + ...action.payload + } } break } diff --git a/libs/calendar/src/lib/calendar.component.html b/libs/calendar/src/lib/calendar.component.html index 9d4312428..7fc4393f9 100644 --- a/libs/calendar/src/lib/calendar.component.html +++ b/libs/calendar/src/lib/calendar.component.html @@ -57,18 +57,18 @@

{{ moreEventsPopupDate }}

- -