import { Injectable } from '@angular/core'; import { Action, Store } from '@ngrx/store'; import { Actions, Effect } from '@ngrx/effects'; import { Observable, of, forkJoin } from 'rxjs'; import { catchError, debounceTime, map, mergeMap, exhaustMap, withLatestFrom } from 'rxjs/operators'; import { getRouterState, State } from 'app/store/reducers'; import { getMailsState } from 'app/main/apps/mail-ngrx/store/selectors'; import * as MailsActions from 'app/main/apps/mail-ngrx/store/actions/mails.actions'; import * as fromRoot from 'app/store'; import { Mail } from 'app/main/apps/mail-ngrx/mail.model'; import { MailNgrxService } from 'app/main/apps/mail-ngrx/mail.service'; @Injectable() export class MailsEffect { routerState: any; constructor( private actions: Actions, private mailService: MailNgrxService, private store: Store ) { this.store.select(getRouterState).subscribe(routerState => { if ( routerState ) { this.routerState = routerState.state; } }); } /** * Get Mails with router parameters * @type {Observable} */ @Effect() getMails: Observable = this.actions .ofType(MailsActions.GET_MAILS) .pipe( exhaustMap((action) => { let handle = { id : '', value: '' }; const routeParams = of('labelHandle', 'filterHandle', 'folderHandle'); routeParams.subscribe(param => { if ( this.routerState.params[param] ) { handle = { id : param, value: this.routerState.params[param] }; } }); return this.mailService.getMails(handle) .pipe( map((mails: Mail[]) => { return new MailsActions.GetMailsSuccess({ loaded: handle, mails : mails }); }), catchError(err => of(new MailsActions.GetMailsFailed(err))) ); }) ); /** * Update Mail * @type {Observable} */ @Effect() updateMail: Observable = this.actions .ofType(MailsActions.UPDATE_MAIL) .pipe( exhaustMap((action) => { return this.mailService.updateMail(action.payload).pipe( map(() => { return new MailsActions.UpdateMailSuccess(action.payload); }) ); }) ); /** * UpdateMails * @type {Observable} */ @Effect() updateMails: Observable = this.actions .ofType(MailsActions.UPDATE_MAILS) .pipe( exhaustMap((action) => { return forkJoin( action.payload.map(mail => this.mailService.updateMail(mail)), () => { return new MailsActions.UpdateMailsSuccess(); }); }) ); /** * Set Current Mail * @type {Observable} */ @Effect() setCurrentMail: Observable = this.actions .ofType(MailsActions.SET_CURRENT_MAIL) .pipe( withLatestFrom(this.store.select(getMailsState)), map(([action, state]) => { return new MailsActions.SetCurrentMailSuccess(state.entities[action.payload]); }) ); /** * Check Current Mail * Navigate to parent directory if not exist in mail list * Update Current Mail if exist in mail list * @type {Observable} */ @Effect() checkCurrentMail: Observable = this.actions .ofType(MailsActions.CHECK_CURRENT_MAIL) .pipe( withLatestFrom(this.store.select(getMailsState)), map(([action, state]) => { if ( !state.entities[this.routerState.params.mailId] ) { return new fromRoot.Go({path: [this.routerState.url.replace(this.routerState.params.mailId, '')]}); } return new MailsActions.SetCurrentMailSuccess(state.entities[this.routerState.params.mailId]); }) ); /** * On Get Mails Success * @type {Observable} */ @Effect() getMailsSuccess: Observable = this.actions .ofType(MailsActions.GET_MAILS_SUCCESS) .pipe( mergeMap(() => [ new MailsActions.CheckCurrentMail() ]) ); /** * On Update Mails Success * @type {Observable} */ @Effect() updateMailsSuccess: Observable = this.actions .ofType(MailsActions.UPDATE_MAILS_SUCCESS) .pipe( mergeMap(() => [ new MailsActions.DeselectAllMails(), new MailsActions.GetMails() ]) ); /** * On Update Mail Success * @type {Observable} */ @Effect() updateMailSuccess: Observable = this.actions .ofType(MailsActions.UPDATE_MAIL_SUCCESS) .pipe( debounceTime(500), map(() => { return new MailsActions.GetMails(); }) ); /** * Set Folder on Selected Mails * @type {Observable} */ @Effect() setFolderOnSelectedMails: Observable = this.actions .ofType(MailsActions.SET_FOLDER_ON_SELECTED_MAILS) .pipe( withLatestFrom( this.store.select(getMailsState)), map(([action, state]) => { const entities = {...state.entities}; let mailsToUpdate = []; state.selectedMailIds .map(id => { mailsToUpdate = [ ...mailsToUpdate, entities[id] = { ...entities[id], folder: action.payload } ]; }); return new MailsActions.UpdateMails(mailsToUpdate); }) ); /** * Add Label on Selected Mails * @type {Observable} */ @Effect() addLabelOnSelectedMails: Observable = this.actions .ofType(MailsActions.ADD_LABEL_ON_SELECTED_MAILS) .pipe( withLatestFrom(this.store.select(getMailsState)), map(([action, state]) => { const entities = {...state.entities}; let mailsToUpdate = []; state.selectedMailIds .map(id => { let labels = [...entities[id].labels]; if ( !entities[id].labels.includes(action.payload) ) { labels = [...labels, action.payload]; } mailsToUpdate = [ ...mailsToUpdate, entities[id] = { ...entities[id], labels } ]; }); return new MailsActions.UpdateMails(mailsToUpdate); }) ); }