src/app/teams/teams-reports.component.ts
import { Component, Input, Output, EventEmitter, ElementRef, DoCheck } from '@angular/core';
import { Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { DialogsFormService } from '../shared/dialogs/dialogs-form.service';
import { CustomValidators } from '../validators/custom-validators';
import { CouchService } from '../shared/couchdb.service';
import { TeamsService } from './teams.service';
import { DialogsLoadingService } from '../shared/dialogs/dialogs-loading.service';
import { TeamsReportsDialogComponent } from './teams-reports-dialog.component';
import { DialogsPromptComponent } from '../shared/dialogs/dialogs-prompt.component';
import { tap } from 'rxjs/operators';
import { convertUtcDate } from './teams.utils';
import { CsvService } from '../shared/csv.service';
@Component({
selector: 'planet-teams-reports',
styleUrls: [ './teams-reports.scss' ],
templateUrl: './teams-reports.component.html'
})
export class TeamsReportsComponent implements DoCheck {
@Input() reports: any[];
@Input() editable = false;
@Input() team;
@Output() reportsChanged = new EventEmitter<void>();
columns = 4;
minColumnWidth = 300;
constructor(
private couchService: CouchService,
private dialog: MatDialog,
private dialogsFormService: DialogsFormService,
private dialogsLoadingService: DialogsLoadingService,
private teamsService: TeamsService,
private csvService: CsvService,
private elementRef: ElementRef
) {}
ngDoCheck() {
const gridElement = this.elementRef.nativeElement.children['report-grid'];
if (!gridElement) {
return;
}
const newColumns = Math.floor(gridElement.offsetWidth / this.minColumnWidth);
if (this.columns !== newColumns) {
this.columns = newColumns;
}
}
openAddReportDialog(oldReport = {}) {
this.couchService.currentTime().subscribe((time: number) => {
const currentDate = new Date(time);
const lastMonthStart = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1);
const lastMonthEnd = currentDate.setDate(0);
this.dialogsFormService.openDialogsForm(
$localize`Add Report`,
[
{ name: 'startDate', placeholder: $localize`Start Date`, type: 'date', required: true },
{ name: 'endDate', placeholder: $localize`End Date`, type: 'date', required: true },
{ name: 'description', placeholder: $localize`Summary`, type: 'markdown', required: true },
{ name: 'beginningBalance', placeholder: $localize`Beginning Balance`, type: 'textbox', inputType: 'number', required: true },
{ name: 'sales', placeholder: $localize`Sales`, type: 'textbox', inputType: 'number', required: true, min: 0 },
{ name: 'otherIncome', placeholder: $localize`Other Income`, type: 'textbox', inputType: 'number', required: true, min: 0 },
{ name: 'wages', placeholder: $localize`Personnel`, type: 'textbox', inputType: 'number', required: true, min: 0 },
{ name: 'otherExpenses', placeholder: $localize`Non-Personnel`, type: 'textbox', inputType: 'number', required: true, min: 0 }
],
this.addFormInitialValues(oldReport, { startDate: lastMonthStart, endDate: lastMonthEnd }),
{
disableIfInvalid: true,
onSubmit: (newReport) => this.updateReport(oldReport, newReport).subscribe(() => {
this.dialogsFormService.closeDialogsForm();
})
}
);
});
}
openDeleteReportDialog(report) {
const deleteDialog = this.dialog.open(DialogsPromptComponent, {
data: {
changeType: 'delete',
type: 'report',
displayDates: report,
okClick: {
request: this.updateReport(report),
onNext: () => {
deleteDialog.close();
}
},
isDateUtc: true
}
});
}
addFormInitialValues(oldReport, { startDate, endDate }) {
const initialValues = {
description: '',
beginningBalance: 0,
sales: 0,
otherIncome: 0,
wages: 0,
otherExpenses: 0,
...oldReport,
startDate: new Date(convertUtcDate(oldReport.startDate) || startDate),
endDate: new Date(convertUtcDate(oldReport.endDate) || endDate)
};
const formControl = (initialValue, fieldName: string) => [
initialValue,
[ CustomValidators.required, this.addFormValidator(fieldName) ]
];
return Object.entries(initialValues).reduce(
(formObj, [ key, value ]) => ({ ...formObj, [key]: formControl(value, key) }), {}
);
}
addFormValidator(fieldName) {
return fieldName === 'endDate' ?
CustomValidators.endDateValidator() :
[ 'sales', 'otherIncome', 'wages', 'otherExpenses' ].indexOf(fieldName) > -1 ?
Validators.min(0) :
() => {};
}
updateReport(oldReport, newReport: any = {}) {
const dateFields = [ 'startDate', 'endDate' ];
const numberFields = [ 'beginningBalance', 'sales', 'otherIncome', 'wages', 'otherExpenses' ];
const transformFields = (key: string, value: Date | string) => dateFields.indexOf(key) > -1 ?
(<Date>value).getTime() :
numberFields.indexOf(key) > -1 ?
+value :
value;
const { _id, _rev, ...newDoc } = <any>Object.entries(newReport).reduce(
(obj, [ key, value ]: [ string, Date | string ]) => ({ ...obj, [key]: transformFields(key, value) }),
{}
);
const docs = [ { ...oldReport, status: 'archived' }, newDoc ].filter(doc => doc.startDate !== undefined);
return this.teamsService.updateAdditionalDocs(docs, this.team, 'report', { utcKeys: dateFields }).pipe(tap(() => {
this.reportsChanged.emit();
this.dialogsLoadingService.stop();
}));
}
openReportDialog(report) {
this.dialog.open(TeamsReportsDialogComponent, {
data: { report, team: this.team },
width: '70ch'
});
}
exportReports() {
const exportData = this.reports.map(report => ({
'Start Date': report.startDate,
'End Date': report.endDate,
'Created Date': report.createdDate,
'Updated Date': report.updatedDate,
'Beginning Balance': report.beginningBalance,
'Sales': report.sales,
'Other Income': report.otherIncome,
'Wages': report.wages,
'Other Expenses': report.otherExpenses,
'Profit/Loss': report.sales + report.otherIncome - report.wages - report.otherExpenses,
'Ending Balance': report.beginningBalance + report.sales + report.otherIncome - report.wages - report.otherExpenses
}));
this.csvService.exportCSV({ data: exportData, title: $localize`${this.team.name} Financial Report Summary` });
}
}