src/app/community/community.component.ts
import { Component, OnInit, OnDestroy, ViewEncapsulation, HostListener } from '@angular/core';
import { Subject, forkJoin, of, throwError } from 'rxjs';
import { takeUntil, finalize, switchMap, map, catchError, tap } from 'rxjs/operators';
import { StateService } from '../shared/state.service';
import { NewsService } from '../news/news.service';
import { DialogsFormService } from '../shared/dialogs/dialogs-form.service';
import { DialogsLoadingService } from '../shared/dialogs/dialogs-loading.service';
import { MatDialog } from '@angular/material/dialog';
import { CommunityLinkDialogComponent } from './community-link-dialog.component';
import { TeamsService } from '../teams/teams.service';
import { DialogsPromptComponent } from '../shared/dialogs/dialogs-prompt.component';
import { CouchService } from '../shared/couchdb.service';
import { PlanetMessageService } from '../shared/planet-message.service';
import { UserService } from '../shared/user.service';
import { UsersService } from '../users/users.service';
import { findDocuments } from '../shared/mangoQueries';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { CustomValidators } from '../validators/custom-validators';
import { environment } from '../../environments/environment';
import { planetAndParentId } from '../manager-dashboard/reports/reports.utils';
import { DeviceInfoService, DeviceType } from '../shared/device-info.service';
@Component({
selector: 'planet-community',
templateUrl: './community.component.html',
preserveWhitespaces: true,
styleUrls: [ './community.scss' ],
encapsulation: ViewEncapsulation.None
})
export class CommunityComponent implements OnInit, OnDestroy {
configuration: any = {};
teamId = planetAndParentId(this.stateService.configuration);
team: any = { _id: this.teamId, teamType: 'sync', teamPlanetCode: this.stateService.configuration.code, type: 'services' };
user = this.userService.get();
news: any[] = [];
links: any[] = [];
finances: any[] = [];
councillors: any[] = [];
reports: any[] = [];
showNewsButton = true;
deleteMode = false;
onDestroy$ = new Subject<void>();
isCommunityLeader = this.user.isUserAdmin || this.user.roles.indexOf('leader') > -1;
planetCode: string | null;
shareTarget: string;
servicesDescriptionLabel: 'Add' | 'Edit';
resizeCalendar: any = false;
deviceType: DeviceType;
deviceTypes = DeviceType;
constructor(
private dialog: MatDialog,
private route: ActivatedRoute,
private stateService: StateService,
private newsService: NewsService,
private dialogsFormService: DialogsFormService,
private dialogsLoadingService: DialogsLoadingService,
private teamsService: TeamsService,
private couchService: CouchService,
private planetMessageService: PlanetMessageService,
private userService: UserService,
private usersService: UsersService,
private deviceInfoService: DeviceInfoService
) {
this.deviceType = this.deviceInfoService.getDeviceType();
}
ngOnInit() {
const newsSortValue = (item: any) => item.sharedDate || item.doc.time;
this.getCommunityData();
this.newsService.newsUpdated$.pipe(takeUntil(this.onDestroy$)).subscribe(news => {
this.news = news.sort((a, b) => newsSortValue(b) - newsSortValue(a));
});
this.usersService.usersListener(true).pipe(takeUntil(this.onDestroy$)).subscribe(users => {
if (!this.planetCode) {
this.setCouncillors(users);
}
});
this.stateService.couchStateListener('child_users').pipe(takeUntil(this.onDestroy$)).subscribe(childUsers => {
if (this.planetCode && childUsers) {
const users = childUsers.newData.filter(user => user.planetCode === this.planetCode).map(user => ({ ...user, doc: user }));
this.setCouncillors(users);
}
});
}
@HostListener('window:resize') onResize() {
this.deviceType = this.deviceInfoService.getDeviceType();
}
ngOnDestroy() {
this.onDestroy$.next();
this.onDestroy$.complete();
}
getCommunityData() {
const setShareTarget = (type) => type === 'center' ? 'nation' : type === 'nation' ? 'community' : undefined;
this.route.paramMap.pipe(
switchMap((params: ParamMap) => {
this.planetCode = params.get('code');
this.shareTarget = this.planetCode ? undefined : setShareTarget(this.stateService.configuration.planetType);
return this.planetCode ?
this.couchService.findAll('communityregistrationrequests', { selector: { code: this.planetCode } }) :
of([ this.stateService.configuration ]);
}),
switchMap(configurations => {
this.configuration = configurations[0];
this.team = this.teamObject(this.planetCode);
this.teamId = this.team._id;
this.requestNewsAndUsers(this.planetCode);
return this.getLinks(this.planetCode);
}),
switchMap((res) => {
this.setLinksAndFinances(res);
return this.couchService.get(`teams/${this.teamId}`);
}),
catchError(err => err.statusText === 'Object Not Found' ? of(this.team) : throwError(err))
).subscribe(team => {
this.team = team;
this.servicesDescriptionLabel = this.team.description ? 'Edit' : 'Add';
});
}
requestNewsAndUsers(planetCode?: string) {
this.newsService.requestNews({
selectors: {
'$or': [
{ messagePlanetCode: planetCode ? planetCode : this.configuration.code, viewableBy: 'community' },
{ viewIn: { '$elemMatch': { '_id': this.teamId, section: 'community' } } }
]
},
viewId: this.teamId
});
if (planetCode) {
this.stateService.requestData('child_users', 'local');
} else {
this.usersService.requestUsers();
}
}
openAddMessageDialog(message = '') {
this.dialogsFormService.openDialogsForm(
$localize`Add Voice`,
[ { name: 'message', placeholder: $localize`Your Voice`, type: 'markdown', required: true, imageGroup: 'community' } ],
{ message: [ message, CustomValidators.requiredMarkdown ] },
{ autoFocus: true, onSubmit: this.postMessage.bind(this) }
);
}
postMessage(message) {
this.newsService.postNews({
viewIn: [ { '_id': this.teamId, section: 'community' } ],
messageType: 'sync',
messagePlanetCode: this.configuration.code,
...message
}, $localize`Message has been posted successfully`).pipe(
switchMap(() => forkJoin([
this.usersService.getAllUsers(),
this.couchService.findAll('notifications', findDocuments({ status: 'unread', type: 'communityMessage' }))
])),
switchMap(([ users, notifications ]: [ any[], any[] ]) => {
const docs = users.filter(user => {
return this.user._id !== user._id &&
user._id !== 'satellite' &&
notifications.every(notification => notification.user !== user._id);
}).map(user => this.sendNotifications(user._id, this.user._id));
return this.couchService.updateDocument('notifications/_bulk_docs', { docs });
}),
finalize(() => this.dialogsLoadingService.stop())
).subscribe(() => this.dialogsFormService.closeDialogsForm());
}
sendNotifications(user, currentUser) {
return {
'user': user,
'message': $localize`<b>${currentUser.split(':')[1]}</b> posted a <b>new story</b>.`,
'link': '/',
'type': 'communityMessage',
'priority': 1,
'status': 'unread',
'time': this.couchService.datePlaceholder,
planetCode: user.userPlanetCode
};
}
teamObject(planetCode?: string) {
const code = planetCode || this.stateService.configuration.code;
const parentCode = planetCode ? this.stateService.configuration.code : this.stateService.configuration.parentCode;
const teamId = `${code}@${parentCode}`;
return { _id: teamId, teamType: 'sync', teamPlanetCode: code, type: 'services' };
}
getLinks(planetCode?) {
return this.teamsService.getTeamMembers(this.team || this.teamObject(planetCode), true).pipe(map((docs) => {
const { link: links, transaction: finances, report: reports } = docs.reduce((docObject, doc) => ({
...docObject, [doc.docType]: [ ...(docObject[doc.docType] || []), doc ]
}), { link: [], transaction: [] });
return { links, finances, reports };
}));
}
setLinksAndFinances({ links, finances, reports }) {
this.links = links;
this.deleteMode = this.deleteMode && this.links.length !== 0;
this.finances = finances;
this.reports = reports;
}
dataChanged() {
this.getLinks().subscribe(res => this.setLinksAndFinances(res));
}
setCouncillors(users) {
const planetCode = this.planetCode ? this.planetCode : this.stateService.configuration.code;
this.couchService.findAll('attachments').subscribe((attachments: any[]) => {
this.councillors = users
.filter(user => planetCode === user.doc.planetCode && (user.doc.isUserAdmin || user.doc.roles.indexOf('leader')) !== -1)
.map(user => {
const { _id: userId, planetCode: userPlanetCode, name } = user.doc;
const attachmentId = `org.couchdb.user:${name}@${userPlanetCode}`;
const attachmentDoc: any = attachments.find(attachment => attachment._id === attachmentId);
const avatar = attachmentDoc ?
`${environment.couchAddress}/attachments/${attachmentId}/${Object.keys(attachmentDoc._attachments)[0]}` :
(user.imageSrc || 'assets/image.png');
return { avatar, userDoc: user, userId, name: user.doc.name, userPlanetCode: user.doc.planetCode, ...user };
});
});
}
openAddLinkDialog() {
this.dialog.open(CommunityLinkDialogComponent, {
width: '50vw',
maxHeight: '90vh',
data: {
getLinks: () => this.getLinks().pipe(tap(res => this.setLinksAndFinances(res))),
excludeIds: this.links.map(link => link.linkId || link.route.replace('/teams/view/', '').replace('/enterprises/view/', ''))
}
});
}
openDeleteLinkDialog(link) {
const deleteDialog = this.dialog.open(DialogsPromptComponent, {
data: {
okClick: {
request: this.couchService.updateDocument('teams', { ...link, _deleted: true }).pipe(switchMap(() => this.getLinks())),
onNext: (res) => {
this.setLinksAndFinances(res);
this.planetMessageService.showMessage($localize`${link.title} deleted`);
deleteDialog.close();
},
onError: () => this.planetMessageService.showAlert($localize`There was an error deleting ${link.title}`)
},
changeType: 'delete',
type: 'link',
displayName: link.title
}
});
}
toggleShowButton(data) {
this.showNewsButton = data._id === 'root';
}
toggleDeleteMode() {
this.deleteMode = !this.deleteMode;
}
openChangeTitleDialog({ member: councillor }) {
this.dialogsFormService.openDialogsForm(
councillor.doc.leadershipTitle ? $localize`Change Leader Title` : $localize`Add Leader Title`,
[ { name: 'leadershipTitle', placeholder: $localize`Title`, type: 'textbox' } ],
{ leadershipTitle: councillor.doc.leadershipTitle || '' },
{ autoFocus: true, onSubmit: this.updateTitle(councillor).bind(this) }
);
}
updateTitle(councillor) {
return ({ leadershipTitle }) => {
if (leadershipTitle === councillor.doc.leadershipTitle) {
this.dialogsFormService.closeDialogsForm();
this.dialogsLoadingService.stop();
return;
}
this.userService.updateUser({ ...councillor.userDoc.doc, leadershipTitle }).pipe(
finalize(() => this.dialogsLoadingService.stop())
).subscribe(() => {
const msg = !leadershipTitle ?
$localize`Title deleted` :
!councillor.doc.leadershipTitle ?
$localize`Title added` :
$localize`Title updated`;
this.dialogsFormService.closeDialogsForm();
this.planetMessageService.showMessage(msg);
this.usersService.requestUsers();
});
};
}
openDescriptionDialog() {
const submitDescription = ({ description }) => {
this.teamsService.updateTeam({ ...this.team, description: description.text }).pipe(
finalize(() => this.dialogsLoadingService.stop())
).subscribe(newTeam => {
this.team = newTeam;
this.servicesDescriptionLabel = newTeam.description ? 'Edit' : 'Add';
});
this.dialogsFormService.closeDialogsForm();
};
this.dialogsFormService.openDialogsForm(
this.team.description ? $localize`Edit Description` : $localize`Add Description`,
[ { name: 'description', placeholder: $localize`Description`, type: 'markdown', required: true, imageGroup: 'community' } ],
{ description: this.team.description || '' },
{ autoFocus: true, onSubmit: submitDescription }
);
}
tabChanged({ index }) {
if (index === 5) {
this.resizeCalendar = true;
} else {
this.resizeCalendar = false;
}
}
}