import { Injectable , OnDestroy } from '@angular/core' ; import { Store } from 'rxjs-observable-store' ; import { Subject , Observable } from 'rxjs' ; import { takeUntil , tap , switchMap , retry } from 'rxjs/operators' ; import { CoffeeListStoreState } from './coffee-list.store.state' ; import { CoffeeListEndpoint } from './coffee-list.endpoint' ; import { ModalComponent } from '../../../shared/components/modal/modal.component' ; import { Candidate } from '../types/candidate' ; import * as candidateHelpers from '../helpers/candidate.helpers' ; import { UserStore } from '../../../core/user/services/user.store' ; import { User } from '../../../core/user/types/user' ; import { UserAction } from '../coffee-list.constants' ; import * as endpointHelpers from '../../../shared/helpers/endpoint.helpers' ; import { StoreRequestStateUpdater } from '../../../shared/types/store-request-state-updater' ; import { CustomRequestStateUpdater } from '../../../shared/types/custom-request-state-updater' ; import { Sort } from '../../../shared/types/sort' ; @ Injectable ( ) export class CoffeeListStore extends Store < CoffeeListStoreState > implements OnDestroy { private ngUnsubscribe$ : Subject < undefined > = new Subject ( ) ; private reloadCandidates$ : Subject < undefined > = new Subject ( ) ; private detailsModal : ModalComponent ; private storeRequestStateUpdater : StoreRequestStateUpdater ; constructor ( private endpoint , private userStore ) { super ( new CoffeeListStoreState ( ) ) ; } init ( ) { this . initReloadCandidates$ ( ) ; this . subscribeToUserUpdates ( ) ; this . storeRequestStateUpdater = endpointHelpers . getStoreRequestStateUpdater ( this ) ; } ngOnDestroy ( ) { this . ngUnsubscribe$ . next ( ) ; this . ngUnsubscribe$ . complete ( ) ; } reloadCandidates ( ) { this . reloadCandidates$ . next ( ) ; } setDetailsModal ( detailsModal ) { this . detailsModal = detailsModal ; } openDetailsModal ( candidate ) { this . setDetailsModalState ( candidate ) ; this . detailsModal . open ( ) ; } closeDetailsModal ( ) { this . setDetailsModalState ( null ) ; this . detailsModal . close ( ) ; } setDetailsModalState ( candidate ) { this . setState ( { ... this . state , detailsModal : { candidate : candidate , } , } ) ; } submitUserAction ( candidate , action ) { let request$ ; const requestStateUpdater = this . getUpdateCandidateRequestStateUpdater ( candidate ) ; if ( action === UserAction . AddVote ) { request$ = this . endpoint . addVote ( candidate , requestStateUpdater ) ; } if ( action === UserAction . RemoveVote ) { request$ = this . endpoint . removeVote ( candidate , requestStateUpdater ) ; } request$ . pipe ( tap ( ( ) => { this . reloadCandidates ( ) ; } ) ) . subscribe ( ) ; } sortCandidates ( sort ) { this . setState ( { ... this . state , candidateList : { ... this . state . candidateList , sort : sort , } , } ) ; this . reloadCandidates ( ) ; } private initReloadCandidates$ ( ) { this . reloadCandidates$ . pipe ( switchMap ( ( ) => { return this . endpoint . listCandidates ( this . state . candidateList . sort , this . storeRequestStateUpdater ) ; } ) , tap ( candidates => { this . updateCandidatesState ( candidates , this . userStore . user ) ; } ) , retry ( ) , takeUntil ( this . ngUnsubscribe$ ) ) . subscribe ( ) ; } private subscribeToUserUpdates ( ) { this . userStore . user$ . pipe ( takeUntil ( this . ngUnsubscribe$ ) ) . subscribe ( user => { this . updateCandidatesState ( this . state . candidateList . candidates , user ) ; } ) ; } private updateCandidatesState ( candidates , user ) { this . setState ( { ... this . state , candidateList : { ... this . state . candidateList , candidates : candidateHelpers . getCandidatesInStoreFormat ( candidates , user ) , } , } ) ; } private getUpdateCandidateRequestStateUpdater ( candidate ) { return requestState => { this . setState ( { ... this . state , candidateList : { ... this . state . candidateList , candidates : this . state . candidateList . candidates . map ( c => { if ( c . id === candidate . id ) { return { ... c , updateRequest : requestState } ; } return c ; } ) , } , } ) ; } ; } }