feat: add CashboxExportDialog
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { CashboxExportApi } from '../../../../core/team/cashbox-export-api';
|
||||||
|
import { FileDownloadService } from '../../../../shared/file-download/file-download.service';
|
||||||
|
import { CashboxExportDialog } from './cashbox-export-dialog';
|
||||||
|
|
||||||
|
describe('CashboxExportDialog', () => {
|
||||||
|
let fixture: ComponentFixture<CashboxExportDialog>;
|
||||||
|
let exportCashbox: ReturnType<typeof vi.fn>;
|
||||||
|
let save: ReturnType<typeof vi.fn>;
|
||||||
|
let dialogRef: { close: ReturnType<typeof vi.fn> };
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
exportCashbox = vi.fn(() => of(new Blob(['csv content'])));
|
||||||
|
save = vi.fn();
|
||||||
|
dialogRef = { close: vi.fn() };
|
||||||
|
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [CashboxExportDialog],
|
||||||
|
providers: [
|
||||||
|
{ provide: MAT_DIALOG_DATA, useValue: { teamId: 5 } },
|
||||||
|
{ provide: MatDialogRef, useValue: dialogRef },
|
||||||
|
{ provide: CashboxExportApi, useValue: { exportCashbox } },
|
||||||
|
{ provide: FileDownloadService, useValue: { save } },
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
fixture = TestBed.createComponent(CashboxExportDialog);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps the download disabled until from <= to', () => {
|
||||||
|
fixture.componentInstance['form'].setValue({ from: '2026-08-31', to: '2026-08-01', format: 'csv' });
|
||||||
|
expect(fixture.componentInstance['form'].invalid).toBe(true);
|
||||||
|
|
||||||
|
fixture.componentInstance['download']();
|
||||||
|
expect(exportCashbox).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('downloads the file and closes the dialog on success', () => {
|
||||||
|
fixture.componentInstance['form'].setValue({ from: '2026-08-01', to: '2026-08-31', format: 'csv' });
|
||||||
|
|
||||||
|
fixture.componentInstance['download']();
|
||||||
|
|
||||||
|
expect(exportCashbox).toHaveBeenCalledWith(5, '2026-08-01', '2026-08-31', 'csv');
|
||||||
|
expect(save).toHaveBeenCalledWith(expect.any(Blob), 'kassenbuch_2026-08-01_2026-08-31.csv');
|
||||||
|
expect(dialogRef.close).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { FormBuilder, ReactiveFormsModule, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { CashboxExportApi } from '../../../../core/team/cashbox-export-api';
|
||||||
|
import { CashboxExportFormat } from '../../../../models/cashbox-export.model';
|
||||||
|
import { FileDownloadService } from '../../../../shared/file-download/file-download.service';
|
||||||
|
|
||||||
|
const rangeValid: ValidatorFn = (group): ValidationErrors | null => {
|
||||||
|
const from = group.get('from')?.value;
|
||||||
|
const to = group.get('to')?.value;
|
||||||
|
return from && to && from > to ? { rangeInvalid: true } : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-cashbox-export-dialog',
|
||||||
|
imports: [
|
||||||
|
ReactiveFormsModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatSelectModule,
|
||||||
|
],
|
||||||
|
template: `
|
||||||
|
<h2 mat-dialog-title>Kassenbuch exportieren</h2>
|
||||||
|
<form [formGroup]="form" (ngSubmit)="download()">
|
||||||
|
<mat-dialog-content>
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Von</mat-label>
|
||||||
|
<input matInput formControlName="from" type="date" />
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Bis</mat-label>
|
||||||
|
<input matInput formControlName="to" type="date" />
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field appearance="outline">
|
||||||
|
<mat-label>Format</mat-label>
|
||||||
|
<mat-select formControlName="format">
|
||||||
|
<mat-option value="csv">CSV</mat-option>
|
||||||
|
<mat-option value="pdf">PDF</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions align="end">
|
||||||
|
<button mat-button type="button" (click)="dialogRef.close()">Abbrechen</button>
|
||||||
|
<button mat-flat-button type="submit" [disabled]="form.invalid">Herunterladen</button>
|
||||||
|
</mat-dialog-actions>
|
||||||
|
</form>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class CashboxExportDialog {
|
||||||
|
protected readonly dialogRef = inject(MatDialogRef<CashboxExportDialog>);
|
||||||
|
private readonly data = inject<{ teamId: number }>(MAT_DIALOG_DATA);
|
||||||
|
private readonly formBuilder = inject(FormBuilder);
|
||||||
|
private readonly api = inject(CashboxExportApi);
|
||||||
|
private readonly fileDownload = inject(FileDownloadService);
|
||||||
|
|
||||||
|
protected readonly form = this.formBuilder.nonNullable.group(
|
||||||
|
{
|
||||||
|
from: ['', Validators.required],
|
||||||
|
to: ['', Validators.required],
|
||||||
|
format: ['csv' as CashboxExportFormat, Validators.required],
|
||||||
|
},
|
||||||
|
{ validators: rangeValid },
|
||||||
|
);
|
||||||
|
|
||||||
|
protected download(): void {
|
||||||
|
if (this.form.invalid) return;
|
||||||
|
const { from, to, format } = this.form.getRawValue();
|
||||||
|
this.api.exportCashbox(this.data.teamId, from, to, format).subscribe((blob) => {
|
||||||
|
this.fileDownload.save(blob, `kassenbuch_${from}_${to}.${format}`);
|
||||||
|
this.dialogRef.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user