|
| 1 | +import { Component, OnChanges, AfterViewInit, ViewChild, OnDestroy, Input, Output, EventEmitter } from '@angular/core'; |
| 2 | +import { CouchService } from '../shared/couchdb.service'; |
| 3 | +import { DialogsPromptComponent } from '../shared/dialogs/dialogs-prompt.component'; |
| 4 | +import { MatTableDataSource, MatPaginator, MatDialog, MatSort, MatDialogRef } from '@angular/material'; |
| 5 | +import { switchMap, takeUntil } from 'rxjs/operators'; |
| 6 | +import { forkJoin, of, Subject } from 'rxjs'; |
| 7 | +import { filterSpecificFields, sortNumberOrString } from '../shared/table-helpers'; |
| 8 | +import { DialogsViewComponent } from '../shared/dialogs/dialogs-view.component'; |
| 9 | +import { DialogsListService } from '../shared/dialogs/dialogs-list.service'; |
| 10 | +import { DialogsListComponent } from '../shared/dialogs/dialogs-list.component'; |
| 11 | +import { StateService } from '../shared/state.service'; |
| 12 | + |
| 13 | +@Component({ |
| 14 | + selector: 'planet-community-table', |
| 15 | + templateUrl: './community-table.component.html' |
| 16 | +}) |
| 17 | +export class CommunityTableComponent implements OnChanges, AfterViewInit, OnDestroy { |
| 18 | + |
| 19 | + @Input() data = []; |
| 20 | + @Input() hubs = []; |
| 21 | + @Input() hub: any = 'sandbox'; |
| 22 | + @Output() requestUpdate = new EventEmitter<void>(); |
| 23 | + communities = new MatTableDataSource(); |
| 24 | + nations = []; |
| 25 | + displayedColumns = [ |
| 26 | + 'name', |
| 27 | + 'code', |
| 28 | + 'localDomain', |
| 29 | + 'createdDate', |
| 30 | + 'action' |
| 31 | + ]; |
| 32 | + editDialog: any; |
| 33 | + viewNationDetailDialog: any; |
| 34 | + dialogRef: MatDialogRef<DialogsListComponent>; |
| 35 | + onDestroy$ = new Subject<void>(); |
| 36 | + planetType = this.stateService.configuration.planetType; |
| 37 | + |
| 38 | + @ViewChild(MatPaginator) paginator: MatPaginator; |
| 39 | + @ViewChild(MatSort) sort: MatSort; |
| 40 | + |
| 41 | + constructor( |
| 42 | + private couchService: CouchService, |
| 43 | + private dialogsListService: DialogsListService, |
| 44 | + private dialog: MatDialog, |
| 45 | + private stateService: StateService |
| 46 | + ) {} |
| 47 | + |
| 48 | + ngOnChanges() { |
| 49 | + this.communities.data = this.data; |
| 50 | + } |
| 51 | + |
| 52 | + ngAfterViewInit() { |
| 53 | + this.communities.sortingDataAccessor = sortNumberOrString; |
| 54 | + this.communities.paginator = this.paginator; |
| 55 | + this.communities.sort = this.sort; |
| 56 | + } |
| 57 | + |
| 58 | + ngOnDestroy() { |
| 59 | + this.onDestroy$.next(); |
| 60 | + this.onDestroy$.complete(); |
| 61 | + } |
| 62 | + |
| 63 | + updateClick(community, change) { |
| 64 | + this.editDialog = this.dialog.open(DialogsPromptComponent, { |
| 65 | + data: { |
| 66 | + okClick: this.updateCommunity(community, change), |
| 67 | + changeType: change, |
| 68 | + type: 'community', |
| 69 | + displayName: community.name |
| 70 | + } |
| 71 | + }); |
| 72 | + } |
| 73 | + |
| 74 | + updateCommunity(community, change) { |
| 75 | + // Return a function with community on its scope to pass to delete dialog |
| 76 | + return () => { |
| 77 | + // With object destructuring colon means different variable name assigned, i.e. 'id' rather than '_id' |
| 78 | + // Split community object into id, rev, and all other props in communityInfo |
| 79 | + const { _id: communityId, _rev: communityRev, ...communityInfo } = community; |
| 80 | + switch (change) { |
| 81 | + case 'delete': |
| 82 | + this.deleteCommunity(community); |
| 83 | + break; |
| 84 | + case 'accept': |
| 85 | + forkJoin([ |
| 86 | + // When accepting a registration request, add learner role to user from that community/nation, |
| 87 | + this.unlockUser(community), |
| 88 | + // update registration request to accepted |
| 89 | + this.couchService.put('communityregistrationrequests/' + communityId, { ...community, registrationRequest: 'accepted' }) |
| 90 | + ]).subscribe((data) => { |
| 91 | + this.requestUpdate.emit(); |
| 92 | + this.editDialog.close(); |
| 93 | + }, (error) => this.editDialog.componentInstance.message = 'Planet was not accepted'); |
| 94 | + } |
| 95 | + }; |
| 96 | + } |
| 97 | + |
| 98 | + // Checks response and creates couch call if a doc was returned |
| 99 | + addDeleteObservable(res, db) { |
| 100 | + if (res.docs.length > 0) { |
| 101 | + const doc = res.docs[0]; |
| 102 | + return this.couchService.delete(db + doc._id + '?rev=' + doc._rev); |
| 103 | + } |
| 104 | + return of({ 'ok': true }); |
| 105 | + } |
| 106 | + |
| 107 | + deleteCommunity(community) { |
| 108 | + // Return a function with community on its scope to pass to delete dialog |
| 109 | + const { _id: id, _rev: rev } = community; |
| 110 | + return this.pipeRemovePlanetUser(this.couchService.delete('communityregistrationrequests/' + id + '?rev=' + rev), community) |
| 111 | + .subscribe(([ data, userRes ]) => { |
| 112 | + // It's safer to remove the item from the array based on its id than to splice based on the index |
| 113 | + this.requestUpdate.emit(); |
| 114 | + this.editDialog.close(); |
| 115 | + }, (error) => this.editDialog.componentInstance.message = 'There was a problem deleting this community'); |
| 116 | + } |
| 117 | + |
| 118 | + pipeRemovePlanetUser(obs: any, community) { |
| 119 | + return obs.pipe( |
| 120 | + switchMap(data => { |
| 121 | + return forkJoin([ of(data), this.removePlanetUser(community) ]); |
| 122 | + }) |
| 123 | + ); |
| 124 | + } |
| 125 | + |
| 126 | + removePlanetUser(community) { |
| 127 | + return forkJoin([ |
| 128 | + this.couchService.post('_users/_find', { 'selector': { '_id': 'org.couchdb.user:' + community.adminName } }), |
| 129 | + this.couchService.post('shelf/_find', { 'selector': { '_id': 'org.couchdb.user:' + community.adminName } }) |
| 130 | + ]).pipe(switchMap(([ user, shelf ]) => { |
| 131 | + return forkJoin([ |
| 132 | + this.addDeleteObservable(user, '_users/'), |
| 133 | + this.addDeleteObservable(shelf, 'shelf/') |
| 134 | + ]); |
| 135 | + })); |
| 136 | + } |
| 137 | + |
| 138 | + // Gives the requesting user the 'learner' role & access to all DBs (as of April 2018) |
| 139 | + unlockUser(community) { |
| 140 | + return this.couchService.post('_users/_find', { 'selector': { 'requestId': community._id } }) |
| 141 | + .pipe(switchMap(data => { |
| 142 | + const user = data.docs[0]; |
| 143 | + return this.couchService.put('_users/' + user._id + '?rev=' + user._rev, |
| 144 | + { ...user, roles: [ 'learner' ] }); |
| 145 | + })); |
| 146 | + } |
| 147 | + |
| 148 | + view(planet) { |
| 149 | + this.viewNationDetailDialog = this.dialog.open(DialogsViewComponent, { |
| 150 | + width: '600px', |
| 151 | + autoFocus: false, |
| 152 | + data: { |
| 153 | + allData: planet, |
| 154 | + title: planet.planetType === 'nation' ? 'Nation Details' : 'Community Details' |
| 155 | + } |
| 156 | + }); |
| 157 | + } |
| 158 | + |
| 159 | + getChildPlanet(url: string) { |
| 160 | + this.dialogsListService.getListAndColumns('communityregistrationrequests', |
| 161 | + { 'registrationRequest': 'accepted' }, url) |
| 162 | + .pipe(takeUntil(this.onDestroy$)) |
| 163 | + .subscribe((planets) => { |
| 164 | + const data = { |
| 165 | + disableSelection: true, |
| 166 | + filterPredicate: filterSpecificFields([ 'name', 'code' ]), |
| 167 | + ...planets }; |
| 168 | + this.dialogRef = this.dialog.open(DialogsListComponent, { |
| 169 | + data: data, |
| 170 | + height: '500px', |
| 171 | + width: '600px', |
| 172 | + autoFocus: false |
| 173 | + }); |
| 174 | + }); |
| 175 | + } |
| 176 | + |
| 177 | + addHubClick(planetCode, hubName) { |
| 178 | + const { children, ...hub } = this.hubs.find((hb: any) => hb.name === hubName); |
| 179 | + hub.spokes.push(planetCode); |
| 180 | + this.couchService.post('hubs', hub).pipe(switchMap(() => { |
| 181 | + if (this.hub !== 'sandbox') { |
| 182 | + return this.removeFromHub(planetCode); |
| 183 | + } |
| 184 | + return of({}); |
| 185 | + })).subscribe(() => { |
| 186 | + this.requestUpdate.emit(); |
| 187 | + }); |
| 188 | + } |
| 189 | + |
| 190 | + removeHubClick(planetCode) { |
| 191 | + this.removeFromHub(planetCode).subscribe(() => this.requestUpdate.emit()); |
| 192 | + } |
| 193 | + |
| 194 | + removeFromHub(planetCode) { |
| 195 | + return this.couchService.post('hubs', { ...this.hub, spokes: this.hub.spokes.filter(code => code !== planetCode) }); |
| 196 | + } |
| 197 | + |
| 198 | +} |
0 commit comments