WIP
This commit is contained in:
+122
-72
@@ -1,92 +1,142 @@
|
||||
<div class="page">
|
||||
<header class="page-header">
|
||||
<h2>Sunday Offering Entry / 主日奉獻錄入</h2>
|
||||
<label>Date
|
||||
<kendo-datepicker [(ngModel)]="sessionDate" (valueChange)="checkDate()" [disabled]="editingSessionId != null"></kendo-datepicker>
|
||||
</label>
|
||||
</header>
|
||||
<!-- Card A — Session header -->
|
||||
<section class="card">
|
||||
<header class="page-header">
|
||||
<h2 style="margin:0">Sunday Offering Entry / 主日奉獻錄入</h2>
|
||||
<label class="flex flex-col gap-1">Date
|
||||
<kendo-datepicker [(ngModel)]="sessionDate" (valueChange)="checkDate()"
|
||||
[disabled]="editingSessionId != null"></kendo-datepicker>
|
||||
</label>
|
||||
</header>
|
||||
|
||||
<div *ngIf="editingSessionId != null" class="edit-banner">
|
||||
Editing submitted session — make changes and click "Update Session".
|
||||
<button kendoButton fillMode="flat" (click)="cancelEdit()">Cancel edit</button>
|
||||
</div>
|
||||
<div *ngIf="editingSessionId != null" class="edit-banner">
|
||||
<span class="badge badge--draft">Editing</span>
|
||||
Editing session — make changes and click "Update Session".
|
||||
<button kendoButton fillMode="flat" (click)="cancelEdit()">Cancel edit</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="dateConflict && editingSessionId == null" class="warn">
|
||||
An offering session for this date already exists. Pick another date, or reopen the existing session to edit.
|
||||
</div>
|
||||
|
||||
<section class="entry-row">
|
||||
<label *ngIf="!entry.isAnonymous">Giver
|
||||
<kendo-dropdownlist [data]="memberResults" textField="displayName" valueField="id"
|
||||
[valuePrimitive]="true" [filterable]="true"
|
||||
(filterChange)="onMemberFilter($event)" [(ngModel)]="selectedMemberId"
|
||||
(valueChange)="onMemberSelected($event)" placeholder="Search by name"></kendo-dropdownlist>
|
||||
</label>
|
||||
<span *ngIf="entry.isAnonymous" class="anon-chip">Anonymous</span>
|
||||
|
||||
<label>Type
|
||||
<kendo-dropdownlist [data]="categories" textField="name_en" valueField="id"
|
||||
[valuePrimitive]="true" [(ngModel)]="entry.givingCategoryId"></kendo-dropdownlist>
|
||||
</label>
|
||||
<label>Method
|
||||
<kendo-dropdownlist [data]="paymentMethods" [(ngModel)]="entry.paymentMethod"></kendo-dropdownlist>
|
||||
</label>
|
||||
<label *ngIf="entry.paymentMethod === 'Check'">Check #<kendo-textbox [(ngModel)]="entry.checkNumber"></kendo-textbox></label>
|
||||
<label>Amount
|
||||
<kendo-numerictextbox [(ngModel)]="entry.amount" [min]="0" [format]="'c2'" (keydown.enter)="addLine()"></kendo-numerictextbox>
|
||||
</label>
|
||||
<label>Notes<kendo-textbox [(ngModel)]="entry.notes" (keydown.enter)="addLine()"></kendo-textbox></label>
|
||||
|
||||
<div class="entry-actions">
|
||||
<button kendoButton (click)="markAnonymous()">Anonymous</button>
|
||||
<button kendoButton (click)="showQuickAdd = true">+ Quick add member</button>
|
||||
<button kendoButton themeColor="primary" (click)="addLine()">+ Add (Enter)</button>
|
||||
<div *ngIf="dateConflict && editingSessionId == null" class="warn">
|
||||
An offering session for this date already exists. Pick another date, or reopen the existing session to edit.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<kendo-grid [data]="buffer">
|
||||
<kendo-grid-column title="Giver">
|
||||
<ng-template kendoGridCellTemplate let-l>{{ l.isAnonymous ? '(Anonymous)' : l.memberName }}</ng-template>
|
||||
</kendo-grid-column>
|
||||
<kendo-grid-column field="categoryName" title="Type"></kendo-grid-column>
|
||||
<kendo-grid-column field="paymentMethod" title="Method" [width]="90"></kendo-grid-column>
|
||||
<kendo-grid-column field="checkNumber" title="Check #" [width]="90"></kendo-grid-column>
|
||||
<kendo-grid-column field="amount" title="Amount" [width]="110" format="c2"></kendo-grid-column>
|
||||
<kendo-grid-column title="" [width]="120">
|
||||
<ng-template kendoGridCellTemplate let-l let-i="rowIndex">
|
||||
<button kendoButton fillMode="flat" (click)="editLine(i)">Edit</button>
|
||||
<button kendoButton fillMode="flat" (click)="removeLine(i)">×</button>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
</kendo-grid>
|
||||
<!-- Card B — Add giving -->
|
||||
<section class="card">
|
||||
<h3 class="section-title">Add Giving / 錄入奉獻</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-x-4 gap-y-3">
|
||||
<label class="flex flex-col gap-1 md:col-span-2">Giver
|
||||
<kendo-dropdownlist *ngIf="!entry.isAnonymous" [data]="memberResults" textField="displayName" valueField="id"
|
||||
[valuePrimitive]="true" [filterable]="true" (filterChange)="onMemberFilter($event)"
|
||||
[(ngModel)]="selectedMemberId" (valueChange)="onMemberSelected($event)"
|
||||
placeholder="Search by name"></kendo-dropdownlist>
|
||||
<span *ngIf="entry.isAnonymous" class="flex items-center gap-2">
|
||||
<span class="anon-chip">Anonymous</span>
|
||||
<button kendoButton fillMode="flat" size="small" (click)="clearAnonymous()">Clear</button>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<section class="reconcile">
|
||||
<div>Lines: {{ buffer.length }} | System total: {{ systemTotal | currency }}</div>
|
||||
<label>Cash counted<kendo-numerictextbox [(ngModel)]="cashTotal" [min]="0" [format]="'c2'"></kendo-numerictextbox></label>
|
||||
<label>Check counted<kendo-numerictextbox [(ngModel)]="checkTotal" [min]="0" [format]="'c2'"></kendo-numerictextbox></label>
|
||||
<div [class.ok]="difference === 0" [class.bad]="difference !== 0">Difference: {{ difference | currency }}</div>
|
||||
<button kendoButton themeColor="primary"
|
||||
[disabled]="buffer.length === 0 || (editingSessionId == null && dateConflict) || submitting"
|
||||
(click)="submit()">{{ editingSessionId != null ? 'Update Session' : 'Submit' }}</button>
|
||||
<label class="flex flex-col gap-1">Type
|
||||
<kendo-dropdownlist [data]="categories" textField="name_en" valueField="id" [valuePrimitive]="true"
|
||||
[(ngModel)]="entry.givingCategoryId"></kendo-dropdownlist>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1">Method
|
||||
<kendo-dropdownlist [data]="paymentMethods" [(ngModel)]="entry.paymentMethod"></kendo-dropdownlist>
|
||||
</label>
|
||||
|
||||
<label *ngIf="entry.paymentMethod === 'Check'" class="flex flex-col gap-1">Check #
|
||||
<kendo-textbox [(ngModel)]="entry.checkNumber"></kendo-textbox>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1">Amount
|
||||
<kendo-numerictextbox [(ngModel)]="entry.amount" [min]="0" [format]="'c2'"
|
||||
(keydown.enter)="addLine()"></kendo-numerictextbox>
|
||||
</label>
|
||||
|
||||
<label class="flex flex-col gap-1 md:col-span-2">Notes
|
||||
<kendo-textbox [(ngModel)]="entry.notes" (keydown.enter)="addLine()"></kendo-textbox>
|
||||
</label>
|
||||
|
||||
<div class="flex flex-wrap gap-2 md:col-span-2">
|
||||
<button kendoButton (click)="markAnonymous()">Anonymous</button>
|
||||
<button kendoButton (click)="showQuickAdd = true">+ Quick add member</button>
|
||||
<button kendoButton themeColor="primary" (click)="addLine()">{{ editingIndex !== null ? 'Update line' : '+ Add
|
||||
(Enter)' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sessions-list">
|
||||
<h3>Recent Sessions</h3>
|
||||
<!-- Card C — Lines -->
|
||||
<section class="card">
|
||||
<h3 class="section-title">Lines / 已加入明細</h3>
|
||||
<div *ngIf="buffer.length === 0" class="empty">No lines yet — add givings above.</div>
|
||||
<kendo-grid *ngIf="buffer.length > 0" [data]="buffer">
|
||||
<kendo-grid-column title="Giver">
|
||||
<ng-template kendoGridCellTemplate let-l>{{ l.isAnonymous ? '(Anonymous)' : l.memberName }}</ng-template>
|
||||
</kendo-grid-column>
|
||||
<kendo-grid-column field="categoryName" title="Type"></kendo-grid-column>
|
||||
<kendo-grid-column field="paymentMethod" title="Method" [width]="90"></kendo-grid-column>
|
||||
<kendo-grid-column field="checkNumber" title="Check #" [width]="90"></kendo-grid-column>
|
||||
<kendo-grid-column field="amount" title="Amount" [width]="110" format="c2"></kendo-grid-column>
|
||||
<kendo-grid-column title="" [width]="120">
|
||||
<ng-template kendoGridCellTemplate let-l let-i="rowIndex">
|
||||
<button kendoButton fillMode="flat" (click)="editLine(i)">Edit</button>
|
||||
<button kendoButton fillMode="flat" (click)="removeLine(i)">×</button>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
</kendo-grid>
|
||||
<div *ngIf="buffer.length > 0" class="lines-footer">Lines: {{ buffer.length }} · System total: {{ systemTotal |
|
||||
currency }}</div>
|
||||
</section>
|
||||
|
||||
<!-- Card D — Reconcile & submit -->
|
||||
<section class="card">
|
||||
<h3 class="section-title">Reconcile & Submit / 對帳</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-3">
|
||||
<label class="flex flex-col gap-1">Cash counted
|
||||
<kendo-numerictextbox [(ngModel)]="cashTotal" [min]="0" [format]="'c2'"></kendo-numerictextbox>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1">Check counted
|
||||
<kendo-numerictextbox [(ngModel)]="checkTotal" [min]="0" [format]="'c2'"></kendo-numerictextbox>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1 md:col-span-2">Session notes
|
||||
<kendo-textarea [(ngModel)]="notes" [rows]="2"></kendo-textarea>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-4 mt-4">
|
||||
<span>System total: {{ systemTotal | currency }}</span>
|
||||
<span [class.ok]="difference === 0" [class.bad]="difference !== 0">Difference: {{ difference | currency }}</span>
|
||||
<button kendoButton themeColor="primary"
|
||||
[disabled]="buffer.length === 0 || (editingSessionId == null && dateConflict) || submitting"
|
||||
(click)="submit()">{{ editingSessionId != null ? 'Update Session' : 'Submit' }}</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Card E — Recent sessions -->
|
||||
<section class="card">
|
||||
<h3 class="section-title">Recent Sessions</h3>
|
||||
<kendo-grid [data]="sessions">
|
||||
<kendo-grid-column field="sessionDate" title="Date" [width]="120"></kendo-grid-column>
|
||||
<kendo-grid-column field="status" title="Status" [width]="110"></kendo-grid-column>
|
||||
<kendo-grid-column title="Status" [width]="120">
|
||||
<ng-template kendoGridCellTemplate let-s>
|
||||
<span class="badge" [class.badge--draft]="s.status === 'Draft'"
|
||||
[class.badge--submitted]="s.status === 'Submitted'" [class.badge--reconciled]="s.status === 'Reconciled'">{{
|
||||
s.status }}</span>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
<kendo-grid-column field="lineCount" title="Lines" [width]="80"></kendo-grid-column>
|
||||
<kendo-grid-column field="systemTotal" title="System" [width]="110" format="c2"></kendo-grid-column>
|
||||
<kendo-grid-column field="difference" title="Diff" [width]="100" format="c2"></kendo-grid-column>
|
||||
<kendo-grid-column title="" [width]="140">
|
||||
<kendo-grid-column title="" [width]="150">
|
||||
<ng-template kendoGridCellTemplate let-s>
|
||||
<button kendoButton fillMode="flat" *ngIf="s.status === 'Submitted'" (click)="reopenAndEdit(s)">Reopen & Edit</button>
|
||||
<button kendoButton fillMode="flat" *ngIf="s.status === 'Submitted'" (click)="reopenAndEdit(s)">Reopen &
|
||||
Edit</button>
|
||||
<button kendoButton fillMode="flat" *ngIf="s.status === 'Draft'" (click)="continueEditDraft(s)">Continue
|
||||
editing</button>
|
||||
</ng-template>
|
||||
</kendo-grid-column>
|
||||
</kendo-grid>
|
||||
</section>
|
||||
|
||||
<app-member-quick-add-dialog *ngIf="showQuickAdd"
|
||||
(created)="onMemberQuickCreated($event)"
|
||||
(cancelled)="showQuickAdd = false"></app-member-quick-add-dialog>
|
||||
</div>
|
||||
<app-member-quick-add-dialog *ngIf="showQuickAdd" (created)="onMemberQuickCreated($event)"
|
||||
(cancelled)="showQuickAdd = false"></app-member-quick-add-dialog>
|
||||
</div>
|
||||
Reference in New Issue
Block a user