first commit
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
<header class="page-header">
|
||||
<div>
|
||||
<p class="eyebrow">Finanzen</p>
|
||||
<h1>Kasse</h1>
|
||||
<p>Buchungen erfassen und den vollständigen Verlauf nachvollziehen.</p>
|
||||
</div>
|
||||
<div class="balance">
|
||||
<span>Teamkasse</span>
|
||||
<strong>{{ team()?.balance ?? 0 | currency: 'EUR' }}</strong>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@if (canBook()) {
|
||||
<section class="booking-grid">
|
||||
<mat-card data-testid="player-booking">
|
||||
<mat-card-header>
|
||||
<mat-icon mat-card-avatar>group</mat-icon>
|
||||
<mat-card-title>Mitgliederbuchung</mat-card-title>
|
||||
<mat-card-subtitle>Für eine oder mehrere Personen</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<form [formGroup]="playerForm" (ngSubmit)="submitPlayerBooking()">
|
||||
<mat-form-field appearance="outline" class="wide">
|
||||
<mat-label>Mitglieder</mat-label>
|
||||
<mat-select formControlName="playerIds" multiple>
|
||||
@for (player of activePlayers(); track player.id) {
|
||||
<mat-option [value]="player.id"
|
||||
>{{ player.firstName }} {{ player.lastName }}</mat-option
|
||||
>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Betrag</mat-label>
|
||||
<input
|
||||
matInput
|
||||
formControlName="amount"
|
||||
type="number"
|
||||
min="0.01"
|
||||
max="10000"
|
||||
step="0.01"
|
||||
/>
|
||||
<span matTextSuffix>€</span>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Art</mat-label>
|
||||
<mat-select formControlName="type">
|
||||
@for (type of playerTransactionTypes; track type.id) {
|
||||
<mat-option [value]="type.id">{{ type.label }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Datum</mat-label>
|
||||
<input matInput formControlName="date" type="date" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field appearance="outline" class="wide">
|
||||
<mat-label>Notiz (optional)</mat-label>
|
||||
<input matInput formControlName="note" />
|
||||
</mat-form-field>
|
||||
<mat-checkbox formControlName="total">Betrag gleichmäßig auf alle verteilen</mat-checkbox>
|
||||
<button mat-flat-button type="submit" [disabled]="playerForm.invalid || saving()">
|
||||
<mat-icon>add_card</mat-icon>
|
||||
Buchen
|
||||
</button>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<mat-card data-testid="team-booking">
|
||||
<mat-card-header>
|
||||
<mat-icon mat-card-avatar>account_balance</mat-icon>
|
||||
<mat-card-title>Teambuchung</mat-card-title>
|
||||
<mat-card-subtitle>Einnahme oder Ausgabe der Teamkasse</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<form [formGroup]="teamForm" (ngSubmit)="submitTeamBooking()">
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Betrag</mat-label>
|
||||
<input
|
||||
matInput
|
||||
formControlName="amount"
|
||||
type="number"
|
||||
min="0.01"
|
||||
max="10000"
|
||||
step="0.01"
|
||||
/>
|
||||
<span matTextSuffix>€</span>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Art</mat-label>
|
||||
<mat-select formControlName="type">
|
||||
@for (type of teamTransactionTypes; track type.id) {
|
||||
<mat-option [value]="type.id">{{ type.label }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Datum</mat-label>
|
||||
<input matInput formControlName="date" type="date" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field appearance="outline" class="wide">
|
||||
<mat-label>Notiz (optional)</mat-label>
|
||||
<input matInput formControlName="note" />
|
||||
</mat-form-field>
|
||||
<button mat-flat-button type="submit" [disabled]="teamForm.invalid || saving()">
|
||||
<mat-icon>add_card</mat-icon>
|
||||
Teambuchung speichern
|
||||
</button>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</section>
|
||||
} @else {
|
||||
<mat-card class="info-card">
|
||||
<mat-icon>visibility</mat-icon>
|
||||
<p>
|
||||
Du kannst alle Buchungen sehen. Neue Buchungen sind Kassenwart und Teamleitung vorbehalten.
|
||||
</p>
|
||||
</mat-card>
|
||||
}
|
||||
|
||||
<section class="activity-section">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Journal</p>
|
||||
<h2>Alle Buchungen</h2>
|
||||
</div>
|
||||
<span>{{ activities().length }} Einträge</span>
|
||||
</div>
|
||||
|
||||
@if (loading()) {
|
||||
<div class="state"><mat-spinner diameter="36" /><span>Buchungen werden geladen …</span></div>
|
||||
} @else if (activities().length === 0) {
|
||||
<div class="state">
|
||||
<mat-icon>receipt_long</mat-icon><span>Noch keine Buchungen vorhanden.</span>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="activity-list">
|
||||
@for (activity of activities(); track activity.id) {
|
||||
<article class="activity-item">
|
||||
<div class="activity-icon" [class.team]="activity.isTeamWalletTransaction">
|
||||
<mat-icon>{{
|
||||
activity.isTeamWalletTransaction ? 'account_balance' : 'person'
|
||||
}}</mat-icon>
|
||||
</div>
|
||||
<div class="activity-copy">
|
||||
<strong>{{ activity.playerName || 'Teamkasse' }}</strong>
|
||||
<span>{{ typeLabel(activity.type) }} · {{ activity.date | date: 'dd.MM.yyyy' }}</span>
|
||||
@if (activity.note) {
|
||||
<small>{{ activity.note }}</small>
|
||||
}
|
||||
</div>
|
||||
<strong class="amount">{{ displayAmount(activity) | currency: 'EUR' }}</strong>
|
||||
@if (canReverse(activity)) {
|
||||
<button
|
||||
mat-icon-button
|
||||
data-testid="reverse-booking"
|
||||
aria-label="Buchung stornieren"
|
||||
(click)="reverseBooking(activity)"
|
||||
>
|
||||
<mat-icon>undo</mat-icon>
|
||||
</button>
|
||||
}
|
||||
</article>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
Reference in New Issue
Block a user