use signal forms
This commit is contained in:
@@ -103,7 +103,7 @@ export class MembersContoller extends Controller {
|
|||||||
) {
|
) {
|
||||||
await this.membersService.scheduleDeletion(
|
await this.membersService.scheduleDeletion(
|
||||||
memberId,
|
memberId,
|
||||||
cancelDate,
|
cancelDate ? cancelDate : null,
|
||||||
request,
|
request,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,52 @@
|
|||||||
import { type MemberModel as DbMember } from "../generated/prisma/models.js";
|
import { type MemberModel as DbMember } from "../generated/prisma/models.js";
|
||||||
|
|
||||||
export interface MemberDto {
|
export interface MemberDto {
|
||||||
id: string | null;
|
id: string;
|
||||||
vorname: string | null;
|
vorname: string;
|
||||||
nachname: string | null;
|
nachname: string;
|
||||||
geburtsdatum: string | null;
|
geburtsdatum: string;
|
||||||
geburtsort: string | null;
|
geburtsort: string;
|
||||||
geschlecht: string | null;
|
geschlecht: string;
|
||||||
passnummer: string | null;
|
passnummer: string;
|
||||||
verein: boolean | null;
|
verein: boolean;
|
||||||
graduierung: string | null;
|
graduierung: string;
|
||||||
letztePruefung: string | null;
|
letztePruefung: string;
|
||||||
kontakt: string | null;
|
kontakt: string;
|
||||||
kuendigungzum: string | null;
|
kuendigungzum: string;
|
||||||
marker: boolean | null;
|
marker: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MemberCreateArgs implements Omit<MemberDto, "id"> {
|
export class MemberCreateArgs implements Omit<
|
||||||
vorname!: string | null;
|
MemberDto,
|
||||||
nachname!: string | null;
|
"id" | "kuendigungzum" | "letztePruefung"
|
||||||
geburtsdatum!: string | null;
|
> {
|
||||||
geburtsort!: string | null;
|
vorname!: string;
|
||||||
geschlecht!: string | null;
|
nachname!: string;
|
||||||
passnummer!: string | null;
|
geburtsdatum!: string;
|
||||||
verein!: boolean | null;
|
geburtsort!: string;
|
||||||
graduierung!: string | null;
|
geschlecht!: string;
|
||||||
letztePruefung!: string | null;
|
passnummer!: string;
|
||||||
kontakt!: string | null;
|
verein!: boolean;
|
||||||
kuendigungzum!: string | null;
|
graduierung!: string;
|
||||||
marker!: boolean | null;
|
kontakt!: string;
|
||||||
|
marker!: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapDbMemberToMember(dbMember: DbMember): MemberDto {
|
export function mapDbMemberToMember(dbMember: DbMember): MemberDto {
|
||||||
return {
|
return {
|
||||||
geburtsdatum: dbMember.geburtsdatum?.toDateString() ?? null,
|
geburtsdatum: dbMember.geburtsdatum?.toDateString() ?? "",
|
||||||
id: dbMember.id,
|
id: dbMember.id,
|
||||||
nachname: dbMember.nachname,
|
nachname: dbMember.nachname ?? "",
|
||||||
geburtsort: dbMember.geburtsort,
|
geburtsort: dbMember.geburtsort ?? "",
|
||||||
geschlecht: dbMember.geschlecht,
|
geschlecht: dbMember.geschlecht ?? "",
|
||||||
graduierung: dbMember.graduierung,
|
graduierung: dbMember.graduierung ?? "",
|
||||||
vorname: dbMember.vorname,
|
vorname: dbMember.vorname ?? "",
|
||||||
kontakt: dbMember.kontakt,
|
kontakt: dbMember.kontakt ?? "",
|
||||||
kuendigungzum: dbMember.kuendigungzum?.toDateString() ?? null,
|
kuendigungzum: dbMember.kuendigungzum?.toDateString() ?? "",
|
||||||
letztePruefung: dbMember.letztePruefung?.toDateString() ?? null,
|
letztePruefung: dbMember.letztePruefung?.toDateString() ?? "",
|
||||||
passnummer: dbMember.passnummer,
|
passnummer: dbMember.passnummer ?? "",
|
||||||
verein: dbMember.verein,
|
verein: dbMember.verein ?? false,
|
||||||
marker: dbMember.marker,
|
marker: dbMember.marker ?? false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,19 @@ export class MembersService {
|
|||||||
const modifiedMember = await this.database.doRequest(
|
const modifiedMember = await this.database.doRequest(
|
||||||
async prisma =>
|
async prisma =>
|
||||||
await prisma.member.update({
|
await prisma.member.update({
|
||||||
data: { ...member, id: id },
|
data: {
|
||||||
|
...member,
|
||||||
|
id: id,
|
||||||
|
letztePruefung: member.letztePruefung
|
||||||
|
? member.letztePruefung
|
||||||
|
: null,
|
||||||
|
geburtsdatum: member.geburtsdatum
|
||||||
|
? member.geburtsdatum
|
||||||
|
: null,
|
||||||
|
kuendigungzum: member.kuendigungzum
|
||||||
|
? member.kuendigungzum
|
||||||
|
: null,
|
||||||
|
},
|
||||||
where: { id: id },
|
where: { id: id },
|
||||||
}),
|
}),
|
||||||
request,
|
request,
|
||||||
@@ -79,7 +91,7 @@ export class MembersService {
|
|||||||
|
|
||||||
public async scheduleDeletion(
|
public async scheduleDeletion(
|
||||||
memberId: string,
|
memberId: string,
|
||||||
cancelDate: Date,
|
cancelDate: Date | null,
|
||||||
request: express.Request,
|
request: express.Request,
|
||||||
) {
|
) {
|
||||||
await this.database.doRequest(
|
await this.database.doRequest(
|
||||||
|
|||||||
+9
-5
@@ -1,13 +1,17 @@
|
|||||||
<form [formGroup]="form" (ngSubmit)="submit()">
|
<form>
|
||||||
<p>Name: {{ member.vorname }} {{ member.nachname }}</p>
|
<p>Name: {{ member.vorname }} {{ member.nachname }}</p>
|
||||||
<p>Passnummer: {{ member.passnummer }}</p>
|
<p>Passnummer: {{ member.passnummer }}</p>
|
||||||
<p>Geburtsdatum: {{ member.geburtsdatum??undefined | datePipe }}</p>
|
<p>Geburtsdatum: {{ member.geburtsdatum | datePipe }}</p>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Kündigun zum</mat-label>
|
<mat-label>Kündigun zum</mat-label>
|
||||||
<input matInput [matDatepicker]="picker" formControlName="kuendigungzum" />
|
<input matInput [matDatepicker]="picker" [field]="form.kuendigungzum" />
|
||||||
<mat-hint>DD.MM.YYYY</mat-hint>
|
<mat-hint>DD.MM.YYYY</mat-hint>
|
||||||
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle
|
||||||
|
matIconSuffix
|
||||||
|
[for]="picker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #picker></mat-datepicker>
|
<mat-datepicker #picker></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button color="primary" type="submit">Speichern</button>
|
<button mat-raised-button color="primary" (click)="submit()">
|
||||||
|
Speichern
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+22
-24
@@ -1,5 +1,5 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
import { Field, form } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatOptionModule } from '@angular/material/core';
|
import { MatOptionModule } from '@angular/material/core';
|
||||||
@@ -9,18 +9,17 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import * as api from '../../generated-api/api';
|
import * as api from '../../generated-api/api';
|
||||||
import { DatePipePipe, dateToLocal } from '../../pipes/date-pipe.pipe.js';
|
import {
|
||||||
|
DatePipePipe,
|
||||||
|
dateToLocal,
|
||||||
|
dateToUTC,
|
||||||
|
} from '../../pipes/date-pipe.pipe.js';
|
||||||
import { EditMemberDialogComponent } from '../edit-member-dialog/edit-member-dialog.component.js';
|
import { EditMemberDialogComponent } from '../edit-member-dialog/edit-member-dialog.component.js';
|
||||||
|
|
||||||
type DeletionForm = {
|
|
||||||
kuendigungzum: FormControl<Date | null>;
|
|
||||||
};
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-delete-member-dialog',
|
selector: 'app-delete-member-dialog',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
ReactiveFormsModule,
|
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
@@ -29,32 +28,31 @@ type DeletionForm = {
|
|||||||
MatOptionModule,
|
MatOptionModule,
|
||||||
MatDatepickerModule,
|
MatDatepickerModule,
|
||||||
DatePipePipe,
|
DatePipePipe,
|
||||||
|
Field,
|
||||||
],
|
],
|
||||||
templateUrl: './delete-member-dialog.component.html',
|
templateUrl: './delete-member-dialog.component.html',
|
||||||
styleUrl: './delete-member-dialog.component.scss',
|
styleUrl: './delete-member-dialog.component.scss',
|
||||||
})
|
})
|
||||||
export class DeleteMemberDialogComponent {
|
export class DeleteMemberDialogComponent {
|
||||||
form: FormGroup<DeletionForm>;
|
private readonly data = inject<{ member: api.MemberDto }>(MAT_DIALOG_DATA);
|
||||||
member: api.MemberDto;
|
private readonly dialogRef = inject(
|
||||||
constructor(
|
MatDialogRef<EditMemberDialogComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: { member: api.MemberDto },
|
);
|
||||||
private dialogRef: MatDialogRef<EditMemberDialogComponent>,
|
private readonly deletionModel = signal({
|
||||||
) {
|
kuendigungzum: this.data.member.kuendigungzum
|
||||||
this.member = data.member;
|
? dateToUTC(this.data.member.kuendigungzum)
|
||||||
this.form = new FormGroup<DeletionForm>({
|
: null,
|
||||||
kuendigungzum: new FormControl(null),
|
|
||||||
});
|
});
|
||||||
}
|
protected readonly form = form(this.deletionModel);
|
||||||
|
protected readonly member = this.data.member;
|
||||||
|
|
||||||
async submit() {
|
protected async submit() {
|
||||||
const date = this.form.controls.kuendigungzum.value;
|
const date = this.deletionModel().kuendigungzum;
|
||||||
if (date) {
|
|
||||||
await api.scheduleDeletion(
|
await api.scheduleDeletion(
|
||||||
this.member.id!,
|
this.member.id,
|
||||||
dateToLocal(date).toISOString(),
|
date ? dateToLocal(date).toISOString() : '',
|
||||||
);
|
);
|
||||||
|
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-17
@@ -1,44 +1,41 @@
|
|||||||
<form [formGroup]="form" (ngSubmit)="submit()">
|
<form>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Vorname</mat-label>
|
<mat-label>Vorname</mat-label>
|
||||||
<input matInput placeholder="Vorname" formControlName="vorname" />
|
<input matInput placeholder="Vorname" [field]="form.vorname" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Nachname</mat-label>
|
<mat-label>Nachname</mat-label>
|
||||||
<input matInput placeholder="Nachname" formControlName="nachname" />
|
<input matInput placeholder="Nachname" [field]="form.nachname" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Geschlecht</mat-label>
|
<mat-label>Geschlecht</mat-label>
|
||||||
<input matInput placeholder="Geschlecht" formControlName="geschlecht" />
|
<input matInput placeholder="Geschlecht" [field]="form.geschlecht" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Passnummer</mat-label>
|
<mat-label>Passnummer</mat-label>
|
||||||
<input matInput placeholder="Passnummer" formControlName="passnummer" />
|
<input matInput placeholder="Passnummer" [field]="form.passnummer" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Geburtsdatum</mat-label>
|
<mat-label>Geburtsdatum</mat-label>
|
||||||
<input matInput [matDatepicker]="picker" formControlName="geburtsdatum" />
|
<input matInput [matDatepicker]="picker" [field]="form.geburtsdatum" />
|
||||||
<mat-hint>DD.MM.YYYY</mat-hint>
|
<mat-hint>DD.MM.YYYY</mat-hint>
|
||||||
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
|
<mat-datepicker-toggle
|
||||||
|
matIconSuffix
|
||||||
|
[for]="picker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #picker></mat-datepicker>
|
<mat-datepicker #picker></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Geburtsort</mat-label>
|
<mat-label>Geburtsort</mat-label>
|
||||||
<input matInput placeholder="Geburtsort" formControlName="geburtsort" />
|
<input matInput placeholder="Geburtsort" [field]="form.geburtsort" />
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field>
|
|
||||||
<mat-label>Unterrichtsvertrag?</mat-label>
|
|
||||||
<mat-select matInput formControlName="uvertrag">
|
|
||||||
<mat-option [value]="true">Ja</mat-option>
|
|
||||||
<mat-option [value]="false">Nein</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Vereinsmitglied?</mat-label>
|
<mat-label>Vereinsmitglied?</mat-label>
|
||||||
<mat-select matInput formControlName="verein">
|
<mat-select matInput [field]="form.verein">
|
||||||
<mat-option [value]="true">Ja</mat-option>
|
<mat-option [value]="true">Ja</mat-option>
|
||||||
<mat-option [value]="false">Nein</mat-option>
|
<mat-option [value]="false">Nein</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button color="primary" type="submit">Speichern</button>
|
<button mat-raised-button color="primary" (click)="submit()">
|
||||||
|
Speichern
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+19
-17
@@ -1,5 +1,5 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
import { FormGroup, ReactiveFormsModule } from '@angular/forms';
|
import { Field, form } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatOptionModule } from '@angular/material/core';
|
import { MatOptionModule } from '@angular/material/core';
|
||||||
@@ -9,13 +9,12 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import * as api from '../../generated-api/api';
|
import * as api from '../../generated-api/api';
|
||||||
import { MemberDtoHelper } from '../../util/member.js';
|
import { MemberDtoHelper, MemberEditForm } from '../../util/member.js';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-edit-member-dialog',
|
selector: 'app-edit-member-dialog',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
ReactiveFormsModule,
|
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
@@ -23,25 +22,28 @@ import { MemberDtoHelper } from '../../util/member.js';
|
|||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatOptionModule,
|
MatOptionModule,
|
||||||
MatDatepickerModule,
|
MatDatepickerModule,
|
||||||
|
Field,
|
||||||
],
|
],
|
||||||
templateUrl: './edit-member-dialog.component.html',
|
templateUrl: './edit-member-dialog.component.html',
|
||||||
styleUrl: './edit-member-dialog.component.scss',
|
styleUrl: './edit-member-dialog.component.scss',
|
||||||
})
|
})
|
||||||
export class EditMemberDialogComponent {
|
export class EditMemberDialogComponent {
|
||||||
form: FormGroup;
|
private readonly data = inject<{ member: api.MemberDto }>(MAT_DIALOG_DATA);
|
||||||
constructor(
|
private readonly memberDtoHelper = inject(MemberDtoHelper);
|
||||||
@Inject(MAT_DIALOG_DATA) public data: { member: api.MemberDto },
|
private readonly dialogRef = inject(
|
||||||
private memberDtoHelper: MemberDtoHelper,
|
MatDialogRef<EditMemberDialogComponent>,
|
||||||
private dialogRef: MatDialogRef<EditMemberDialogComponent>,
|
|
||||||
) {
|
|
||||||
this.form = this.memberDtoHelper.newMemberForm(data.member);
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
|
||||||
const member: api.MemberDto = this.memberDtoHelper.memberFromForm(
|
|
||||||
this.form,
|
|
||||||
);
|
);
|
||||||
api.updateMember(member);
|
|
||||||
|
private readonly memberModel = signal<MemberEditForm>(
|
||||||
|
this.memberDtoHelper.editMemberForm(this.data.member),
|
||||||
|
);
|
||||||
|
protected readonly form = form(this.memberModel);
|
||||||
|
|
||||||
|
protected async submit() {
|
||||||
|
const member: api.MemberDto = this.memberDtoHelper.memberFromSignal(
|
||||||
|
this.memberModel(),
|
||||||
|
);
|
||||||
|
await api.updateMember(member);
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
<h1>Neues Mitglied anlegen</h1>
|
<h1>Neues Mitglied anlegen</h1>
|
||||||
<form [formGroup]="memberForm" (ngSubmit)="onSubmit()">
|
<form>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Vorname</mat-label>
|
<mat-label>Vorname</mat-label>
|
||||||
<input matInput formControlName="vorname" />
|
<input matInput [field]="memberForm.vorname" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Nachname</mat-label>
|
<mat-label>Nachname</mat-label>
|
||||||
<input matInput formControlName="nachname" />
|
<input matInput [field]="memberForm.nachname" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Geschlecht</mat-label>
|
<mat-label>Geschlecht</mat-label>
|
||||||
<input matInput formControlName="geschlecht" />
|
<input matInput [field]="memberForm.geschlecht" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Geburtsdatum</mat-label>
|
<mat-label>Geburtsdatum</mat-label>
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
[matDatepicker]="picker"
|
[matDatepicker]="picker"
|
||||||
formControlName="geburtsdatum" />
|
[field]="memberForm.geburtsdatum" />
|
||||||
<mat-hint>DD.MM.YYYY</mat-hint>
|
<mat-hint>DD.MM.YYYY</mat-hint>
|
||||||
<mat-datepicker-toggle
|
<mat-datepicker-toggle
|
||||||
matIconSuffix
|
matIconSuffix
|
||||||
@@ -26,18 +26,18 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Geburtsort</mat-label>
|
<mat-label>Geburtsort</mat-label>
|
||||||
<input matInput formControlName="geburtsort" />
|
<input matInput [field]="memberForm.geburtsort" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-checkbox [formControl]="memberForm.controls.verein"
|
<mat-checkbox [field]="memberForm.verein">Verein Beigetreten?</mat-checkbox>
|
||||||
>Verein Beigetreten?</mat-checkbox
|
|
||||||
>
|
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Passnummer (falls vorhanden)</mat-label>
|
<mat-label>Passnummer (falls vorhanden)</mat-label>
|
||||||
<input matInput formControlName="passnummer" />
|
<input matInput [field]="memberForm.passnummer" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Kontakt</mat-label>
|
<mat-label>Kontakt</mat-label>
|
||||||
<input matInput formControlName="kontakt" />
|
<input matInput [field]="memberForm.kontakt" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-flat-button color="primary" type="submit">Hinzufügen</button>
|
<button mat-flat-button color="primary" (click)="onSubmit()">
|
||||||
|
Hinzufügen
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { Field, form } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||||
@@ -7,43 +7,49 @@ import { MatDialogRef } from '@angular/material/dialog';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import * as api from '../../generated-api/api.js';
|
import * as api from '../../generated-api/api.js';
|
||||||
import { MemberDtoHelper } from '../../util/member.js';
|
import { MemberCreateForm, MemberDtoHelper } from '../../util/member.js';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-new-member',
|
selector: 'app-new-member',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
providers: [],
|
providers: [],
|
||||||
imports: [
|
imports: [
|
||||||
ReactiveFormsModule,
|
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatDatepickerModule,
|
MatDatepickerModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
|
Field,
|
||||||
],
|
],
|
||||||
templateUrl: './new-member.component.html',
|
templateUrl: './new-member.component.html',
|
||||||
styleUrl: './new-member.component.scss',
|
styleUrl: './new-member.component.scss',
|
||||||
})
|
})
|
||||||
export class NewMemberComponent {
|
export class NewMemberComponent {
|
||||||
private readonly memberDtoHelper = inject(MemberDtoHelper);
|
private readonly memberDtoHelper = inject(MemberDtoHelper);
|
||||||
|
private readonly dialogRef: MatDialogRef<NewMemberComponent> = inject(
|
||||||
constructor() {}
|
|
||||||
memberForm = this.memberDtoHelper.newMemberForm();
|
|
||||||
private dialogRef: MatDialogRef<NewMemberComponent> = inject(
|
|
||||||
MatDialogRef<NewMemberComponent>,
|
MatDialogRef<NewMemberComponent>,
|
||||||
);
|
);
|
||||||
|
|
||||||
onSubmit() {
|
private readonly memberModel = signal<MemberCreateForm>(
|
||||||
const newMember: api.MemberCreateArgs =
|
this.memberDtoHelper.newMemberForm(),
|
||||||
this.memberDtoHelper.newMemberFromForm(this.memberForm);
|
);
|
||||||
|
protected readonly memberForm = form(this.memberModel);
|
||||||
|
|
||||||
api.createMember(newMember)
|
protected async onSubmit(): Promise<void> {
|
||||||
.then(() => {
|
if (!this.memberForm().valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newMember = this.memberDtoHelper.newMemberFromSignal(
|
||||||
|
this.memberModel(),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await api.createMember(newMember);
|
||||||
console.log('Successfully added Member');
|
console.log('Successfully added Member');
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
})
|
} catch (e) {
|
||||||
.catch(e => {
|
|
||||||
console.error('Error adding member', e);
|
console.error('Error adding member', e);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,13 @@
|
|||||||
<div class="filter-container">
|
<div class="filter-container">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<label>Filter:</label>
|
<label>Filter:</label>
|
||||||
<input matInput [formControl]="filterControl" placeholder="Filter" />
|
<input
|
||||||
|
matInput
|
||||||
|
[field]="filterForm.filterString"
|
||||||
|
placeholder="Filter" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<div class="status-filters">
|
<div class="status-filters">
|
||||||
<mat-radio-group [formControl]="statusControl">
|
<mat-radio-group [field]="filterForm.status">
|
||||||
<mat-radio-button [value]="MemberStatusFilter.ACTIVE"
|
<mat-radio-button [value]="MemberStatusFilter.ACTIVE"
|
||||||
>Aktiv</mat-radio-button
|
>Aktiv</mat-radio-button
|
||||||
>
|
>
|
||||||
@@ -30,20 +33,21 @@
|
|||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
[matDatepicker]="picker"
|
[matDatepicker]="picker"
|
||||||
[formControl]="statusDateControl"
|
[field]="filterForm.statusDate"
|
||||||
placeholder="Aktiv bis" />
|
placeholder="Aktiv bis" />
|
||||||
<mat-hint>DD.MM.YYYY</mat-hint>
|
<mat-hint>DD.MM.YYYY</mat-hint>
|
||||||
<mat-datepicker-toggle
|
<mat-datepicker-toggle
|
||||||
matIconSuffix
|
matIconSuffix
|
||||||
[disabled]="statusControl.value===MemberStatusFilter.ALL"
|
[disabled]="statusDateDisabled()"
|
||||||
[for]="picker"></mat-datepicker-toggle>
|
[for]="picker"></mat-datepicker-toggle>
|
||||||
<mat-datepicker #picker></mat-datepicker>
|
<mat-datepicker #picker></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<mat-checkbox [formControl]="onlyWithID">Nur mit Passnummer</mat-checkbox>
|
<mat-checkbox [field]="filterForm.onlyWithID"
|
||||||
|
>Nur mit Passnummer</mat-checkbox
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<!--TODO implement row count, selecting and alternating colors-->
|
|
||||||
<table
|
<table
|
||||||
mat-table
|
mat-table
|
||||||
[dataSource]="dataSource"
|
[dataSource]="dataSource"
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
import { AfterViewInit, Component, viewChild } from '@angular/core';
|
import {
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
AfterViewInit,
|
||||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
computed,
|
||||||
|
effect,
|
||||||
|
inject,
|
||||||
|
signal,
|
||||||
|
viewChild,
|
||||||
|
} from '@angular/core';
|
||||||
|
import { Field, form } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCheckbox } from '@angular/material/checkbox';
|
import { MatCheckbox } from '@angular/material/checkbox';
|
||||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||||
@@ -13,7 +21,6 @@ import { MatSort, MatSortModule } from '@angular/material/sort';
|
|||||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { combineLatest, startWith } from 'rxjs';
|
|
||||||
import * as api from '../../generated-api/api';
|
import * as api from '../../generated-api/api';
|
||||||
import { DatePipePipe } from '../../pipes/date-pipe.pipe.js';
|
import { DatePipePipe } from '../../pipes/date-pipe.pipe.js';
|
||||||
import { NobreakHyphenPipe } from '../../pipes/nobreak-hyphen.pipe.js';
|
import { NobreakHyphenPipe } from '../../pipes/nobreak-hyphen.pipe.js';
|
||||||
@@ -40,25 +47,34 @@ enum MemberStatusFilter {
|
|||||||
RouterModule,
|
RouterModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
DatePipePipe,
|
DatePipePipe,
|
||||||
ReactiveFormsModule,
|
|
||||||
MatDatepickerModule,
|
MatDatepickerModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatCheckbox,
|
MatCheckbox,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatSortModule,
|
MatSortModule,
|
||||||
|
Field,
|
||||||
],
|
],
|
||||||
templateUrl: './view-members.html',
|
templateUrl: './view-members.html',
|
||||||
styleUrl: './view-members.scss',
|
styleUrl: './view-members.scss',
|
||||||
})
|
})
|
||||||
export class ViewMembers implements AfterViewInit {
|
export class ViewMembers implements AfterViewInit {
|
||||||
protected MemberStatusFilter = MemberStatusFilter;
|
private readonly changeDetectorRef = inject(ChangeDetectorRef);
|
||||||
protected readonly filterControl = new FormControl<string>('');
|
|
||||||
protected readonly statusControl = new FormControl<MemberStatusFilter>(
|
protected readonly MemberStatusFilter = MemberStatusFilter;
|
||||||
MemberStatusFilter.ACTIVE,
|
private readonly filterModel = signal({
|
||||||
|
filterString: '',
|
||||||
|
status: MemberStatusFilter.ACTIVE,
|
||||||
|
statusDate: null as Date | null,
|
||||||
|
onlyWithID: false,
|
||||||
|
});
|
||||||
|
protected readonly filterForm = form(this.filterModel);
|
||||||
|
|
||||||
|
protected readonly statusDateDisabled = computed(
|
||||||
|
() => this.filterForm.status().value() === MemberStatusFilter.ALL,
|
||||||
);
|
);
|
||||||
protected readonly statusDateControl = new FormControl<Date | null>(null);
|
|
||||||
protected readonly onlyWithID = new FormControl<boolean>(false);
|
|
||||||
protected dataSource = new MatTableDataSource<api.MemberDto>();
|
protected readonly dataSource = new MatTableDataSource<api.MemberDto>();
|
||||||
private readonly datePipe = new DatePipePipe();
|
private readonly datePipe = new DatePipePipe();
|
||||||
|
|
||||||
protected readonly displayedColumns: string[] = [
|
protected readonly displayedColumns: string[] = [
|
||||||
@@ -159,7 +175,7 @@ export class ViewMembers implements AfterViewInit {
|
|||||||
return originalFilterPredicate(
|
return originalFilterPredicate(
|
||||||
{
|
{
|
||||||
...data,
|
...data,
|
||||||
id: null,
|
id: '',
|
||||||
geburtsdatum: this.datePipe.transform(
|
geburtsdatum: this.datePipe.transform(
|
||||||
data.geburtsdatum ?? undefined,
|
data.geburtsdatum ?? undefined,
|
||||||
),
|
),
|
||||||
@@ -173,41 +189,10 @@ export class ViewMembers implements AfterViewInit {
|
|||||||
filter,
|
filter,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
combineLatest([
|
|
||||||
this.filterControl.valueChanges.pipe(
|
|
||||||
startWith(this.filterControl.value),
|
|
||||||
),
|
|
||||||
this.statusControl.valueChanges.pipe(
|
|
||||||
startWith(this.statusControl.value),
|
|
||||||
),
|
|
||||||
this.statusDateControl.valueChanges.pipe(
|
|
||||||
startWith(this.statusDateControl.value),
|
|
||||||
),
|
|
||||||
this.onlyWithID.valueChanges.pipe(startWith(this.onlyWithID.value)),
|
|
||||||
])
|
|
||||||
// .pipe(takeUntilDestroyed())
|
|
||||||
.subscribe(combined => {
|
|
||||||
const filter = combined[0];
|
|
||||||
const status = combined[1];
|
|
||||||
const date = combined[2];
|
|
||||||
const onlyWithID = combined[3];
|
|
||||||
this.dataSource.filter = `${filter?.replaceAll(';', '') ?? ''};${status};${date?.toISOString()};${onlyWithID}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.statusControl.valueChanges
|
effect(() => {
|
||||||
.pipe(takeUntilDestroyed())
|
const filters = this.filterModel();
|
||||||
.subscribe(value => {
|
this.dataSource.filter = `${filters.filterString?.replaceAll(';', '') ?? ''};${filters.status};${filters.statusDate?.toISOString()};${filters.onlyWithID}`;
|
||||||
if (
|
|
||||||
value === MemberStatusFilter.ALL &&
|
|
||||||
this.statusDateControl.enabled
|
|
||||||
) {
|
|
||||||
return this.statusDateControl.disable();
|
|
||||||
} else if (
|
|
||||||
value !== MemberStatusFilter.ALL &&
|
|
||||||
this.statusDateControl.disabled
|
|
||||||
) {
|
|
||||||
return this.statusDateControl.enable();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.updateData();
|
this.updateData();
|
||||||
@@ -221,5 +206,6 @@ export class ViewMembers implements AfterViewInit {
|
|||||||
private async updateData(): Promise<void> {
|
private async updateData(): Promise<void> {
|
||||||
const members = await api.getMembers();
|
const members = await api.getMembers();
|
||||||
this.dataSource.data = members;
|
this.dataSource.data = members;
|
||||||
|
this.changeDetectorRef.detectChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Inject, Injectable } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
import { FormControl, FormGroup } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
import { MAT_DATE_LOCALE } from '@angular/material/core';
|
import { MAT_DATE_LOCALE } from '@angular/material/core';
|
||||||
import { Locale, parse } from 'date-fns';
|
import { Locale } from 'date-fns';
|
||||||
import { MemberCreateArgs, MemberDto } from '../generated-api/api';
|
import { MemberCreateArgs, MemberDto } from '../generated-api/api';
|
||||||
import { dateToLocal, dateToUTC } from '../pipes/date-pipe.pipe';
|
import { dateToLocal, dateToUTC } from '../pipes/date-pipe.pipe';
|
||||||
|
|
||||||
@@ -21,86 +21,78 @@ interface MemberForm {
|
|||||||
marker: FormControl<boolean | null | undefined>;
|
marker: FormControl<boolean | null | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MemberCreateForm extends Omit<
|
||||||
|
MemberCreateArgs,
|
||||||
|
'geburtsdatum'
|
||||||
|
> {
|
||||||
|
geburtsdatum: Date | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemberEditForm extends Omit<
|
||||||
|
MemberDto,
|
||||||
|
'geburtsdatum' | 'kuendigungzum' | 'letztePruefung'
|
||||||
|
> {
|
||||||
|
geburtsdatum: Date | null;
|
||||||
|
kuendigungzum: Date | null;
|
||||||
|
letztePruefung: Date | null;
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class MemberDtoHelper {
|
export class MemberDtoHelper {
|
||||||
constructor(@Inject(MAT_DATE_LOCALE) private locale: Locale) {}
|
constructor(@Inject(MAT_DATE_LOCALE) private locale: Locale) {}
|
||||||
public newMemberForm(member?: MemberDto): FormGroup<MemberForm> {
|
public newMemberForm(): MemberCreateForm {
|
||||||
const geburtsdatum = member?.geburtsdatum;
|
|
||||||
let enDate: Date | null = null;
|
|
||||||
if (geburtsdatum) {
|
|
||||||
enDate = parse(geburtsdatum, 'dd.MM.yyyy', new Date(), {
|
|
||||||
//TODO get dd.MM.yyyy from MAT_DATE_LOCALE or LOCALE_ID
|
|
||||||
locale: this.locale,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return new FormGroup<MemberForm>({
|
|
||||||
id: new FormControl(member?.id),
|
|
||||||
vorname: new FormControl(member?.vorname),
|
|
||||||
nachname: new FormControl(member?.nachname),
|
|
||||||
geschlecht: new FormControl(member?.geschlecht),
|
|
||||||
geburtsdatum: new FormControl(
|
|
||||||
member?.geburtsdatum ? dateToUTC(member?.geburtsdatum) : null,
|
|
||||||
),
|
|
||||||
geburtsort: new FormControl(member?.geburtsort),
|
|
||||||
passnummer: new FormControl(member?.passnummer),
|
|
||||||
verein: new FormControl(member?.verein),
|
|
||||||
kontakt: new FormControl(member?.kontakt),
|
|
||||||
graduierung: new FormControl(member?.graduierung),
|
|
||||||
kuendigungzum: new FormControl(
|
|
||||||
member?.kuendigungzum ? dateToUTC(member?.kuendigungzum) : null,
|
|
||||||
),
|
|
||||||
letztePruefung: new FormControl(
|
|
||||||
member?.letztePruefung
|
|
||||||
? dateToUTC(member?.letztePruefung)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
marker: new FormControl(false),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
memberFromForm(form: FormGroup<MemberForm>): MemberDto {
|
|
||||||
return {
|
return {
|
||||||
id: form.controls.id.value ?? null,
|
vorname: '',
|
||||||
vorname: form.controls.vorname.value ?? null,
|
nachname: '',
|
||||||
nachname: form.controls.nachname.value ?? null,
|
geschlecht: '',
|
||||||
geschlecht: form.controls.geschlecht.value ?? null,
|
geburtsdatum: null,
|
||||||
geburtsdatum: form.controls.geburtsdatum.value
|
geburtsort: '',
|
||||||
? dateToLocal(form.controls.geburtsdatum.value).toISOString()
|
passnummer: '',
|
||||||
: null,
|
verein: false,
|
||||||
geburtsort: form.controls.geburtsort.value ?? null,
|
kontakt: '',
|
||||||
passnummer: form.controls.passnummer.value ?? null,
|
graduierung: '',
|
||||||
verein: form.controls.verein.value ?? null,
|
marker: false,
|
||||||
kontakt: form.controls.kontakt.value ?? null,
|
|
||||||
graduierung: form.controls.graduierung?.value ?? null,
|
|
||||||
kuendigungzum: form.controls.kuendigungzum.value
|
|
||||||
? dateToLocal(form.controls.kuendigungzum.value).toISOString()
|
|
||||||
: null,
|
|
||||||
letztePruefung: form.controls.letztePruefung.value
|
|
||||||
? dateToLocal(form.controls.letztePruefung.value).toISOString()
|
|
||||||
: null,
|
|
||||||
marker: form.controls.marker.value ?? false,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
newMemberFromForm(form: FormGroup<MemberForm>): MemberCreateArgs {
|
public newMemberFromSignal(sig: MemberCreateForm): MemberCreateArgs {
|
||||||
return {
|
return {
|
||||||
vorname: form.controls.vorname.value ?? null,
|
...sig,
|
||||||
nachname: form.controls.nachname.value ?? null,
|
geburtsdatum: sig.geburtsdatum
|
||||||
geschlecht: form.controls.geschlecht.value ?? null,
|
? dateToLocal(sig.geburtsdatum).toISOString()
|
||||||
geburtsdatum: form.controls.geburtsdatum.value
|
: '',
|
||||||
? dateToLocal(form.controls.geburtsdatum.value).toISOString()
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public editMemberForm(member: MemberDto): MemberEditForm {
|
||||||
|
return {
|
||||||
|
...member,
|
||||||
|
geburtsdatum: member.geburtsdatum
|
||||||
|
? dateToUTC(member.geburtsdatum)
|
||||||
: null,
|
: null,
|
||||||
geburtsort: form.controls.geburtsort.value ?? null,
|
kuendigungzum: member.kuendigungzum
|
||||||
passnummer: form.controls.passnummer.value ?? null,
|
? dateToUTC(member.kuendigungzum)
|
||||||
verein: form.controls.verein.value ?? null,
|
: null,
|
||||||
kontakt: form.controls.kontakt.value ?? null,
|
letztePruefung: member.letztePruefung
|
||||||
graduierung: form.controls.graduierung?.value ?? null,
|
? dateToUTC(member.letztePruefung)
|
||||||
kuendigungzum: null, //TODO not for new member
|
: null,
|
||||||
letztePruefung: null, //TODO not for new member
|
};
|
||||||
marker: form.controls.marker.value ?? false,
|
}
|
||||||
|
|
||||||
|
public memberFromSignal(sig: MemberEditForm): MemberDto {
|
||||||
|
return {
|
||||||
|
...sig,
|
||||||
|
geburtsdatum: sig.geburtsdatum
|
||||||
|
? dateToLocal(sig.geburtsdatum).toISOString()
|
||||||
|
: '',
|
||||||
|
kuendigungzum: sig.kuendigungzum
|
||||||
|
? dateToLocal(sig.kuendigungzum).toISOString()
|
||||||
|
: '',
|
||||||
|
letztePruefung: sig.letztePruefung
|
||||||
|
? dateToLocal(sig.letztePruefung).toISOString()
|
||||||
|
: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user