231 lines
11 KiB
HTML
231 lines
11 KiB
HTML
<div class="oe">
|
||
<div class="oe__inner">
|
||
<header class="oe__head">
|
||
<span class="oe__eyebrow">River of Life · Offering</span>
|
||
<h1 class="oe__title">主日奉獻錄入 <span>Sunday Offering Entry</span></h1>
|
||
<div class="oe__date">{{ sessionDate | date:'EEE, MMM d, y' }}</div>
|
||
<div class="oe__status" [class.is-on]="connected">
|
||
<span class="oe__dot"></span>
|
||
{{ connected ? '即時同步中 · Live' : '連線中… · Connecting' }}
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Today's running tally (live across phones) -->
|
||
<div class="oe__tally">
|
||
<div class="oe__tally-item">
|
||
<span class="oe__tally-num">{{ lineCount }}</span>
|
||
<span class="oe__tally-label">今日筆數 · Lines</span>
|
||
</div>
|
||
<div class="oe__tally-divider"></div>
|
||
<button type="button" class="oe__tally-item oe__tally-item--btn" (click)="openTotals()">
|
||
<span class="oe__tally-num">{{ systemTotal | currency }}</span>
|
||
<span class="oe__tally-label">今日總額 · Total <span class="oe__tally-hint">›</span></span>
|
||
</button>
|
||
<div class="oe__tally-divider"></div>
|
||
<!-- Day-level paper proof (the whole session's count sheet / envelopes), not
|
||
any single line — lives here, beside the running tally, on purpose. -->
|
||
<button type="button" class="oe__tally-item oe__tally-item--btn oe__tally-item--proof"
|
||
[class.is-attached]="hasProof" (click)="openPaperProof()">
|
||
<span class="oe__tally-num oe__tally-icon">{{ hasProof ? '📎' : '+' }}</span>
|
||
<span class="oe__tally-label">紙本證明 · Proof</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Entry form -->
|
||
<section class="oe__card">
|
||
<div class="oe__field">
|
||
<label class="oe__label">奉獻人 · Giver</label>
|
||
<kendo-combobox *ngIf="!entry.isAnonymous"
|
||
class="oe__control"
|
||
[data]="memberResults" textField="displayName" valueField="id" [valuePrimitive]="true"
|
||
[filterable]="true" (filterChange)="onMemberFilter($event)"
|
||
[(ngModel)]="selectedMemberId" (valueChange)="onMemberSelected($event)"
|
||
size="large" placeholder="輸入姓名搜尋 · Search by name"></kendo-combobox>
|
||
|
||
<div *ngIf="entry.isAnonymous" class="oe__anon">
|
||
<span class="oe__anon-chip">匿名 · Anonymous</span>
|
||
<button kendoButton fillMode="flat" themeColor="primary" size="large"
|
||
(click)="clearAnonymous()">改回填寫 · Clear</button>
|
||
</div>
|
||
|
||
<div *ngIf="!entry.isAnonymous" class="oe__giver-actions">
|
||
<button kendoButton fillMode="outline" size="large"
|
||
(click)="openQuickAdd()">+ 快速新增 · Quick add</button>
|
||
<button kendoButton fillMode="outline" size="large"
|
||
(click)="markAnonymous()">設為匿名 · Anonymous</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="oe__field">
|
||
<label class="oe__label">類別 · Type</label>
|
||
<kendo-dropdownlist class="oe__control"
|
||
[data]="categories" textField="label" valueField="id" [valuePrimitive]="true"
|
||
[(ngModel)]="entry.givingCategoryId" size="large"></kendo-dropdownlist>
|
||
</div>
|
||
|
||
<div class="oe__field">
|
||
<label class="oe__label">付款方式 · Method</label>
|
||
<kendo-dropdownlist class="oe__control"
|
||
[data]="paymentMethods" textField="label" valueField="value" [valuePrimitive]="true"
|
||
[(ngModel)]="entry.paymentMethod" size="large"></kendo-dropdownlist>
|
||
</div>
|
||
|
||
<div class="oe__field" *ngIf="entry.paymentMethod === 'Check'">
|
||
<label class="oe__label">支票號碼 · Check #</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="entry.checkNumber" size="large"></kendo-textbox>
|
||
</div>
|
||
<div class="oe__field" *ngIf="entry.paymentMethod === 'Zelle'">
|
||
<label class="oe__label">Zelle 參考碼 · Reference</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="entry.zelleReferenceCode" size="large"></kendo-textbox>
|
||
</div>
|
||
<div class="oe__field" *ngIf="entry.paymentMethod === 'PayPal'">
|
||
<label class="oe__label">PayPal 交易編號 · Txn ID</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="entry.payPalTransactionId" size="large"></kendo-textbox>
|
||
</div>
|
||
|
||
<div class="oe__field">
|
||
<label class="oe__label">金額 · Amount</label>
|
||
<kendo-numerictextbox class="oe__control"
|
||
[(ngModel)]="entry.amount" [min]="0" [format]="'c2'" size="large"></kendo-numerictextbox>
|
||
</div>
|
||
|
||
<div class="oe__field">
|
||
<label class="oe__label">備註 · Notes</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="entry.notes" size="large"></kendo-textbox>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
<!-- Sticky submit bar -->
|
||
<div class="oe__submit">
|
||
<button kendoButton themeColor="primary" size="large" class="oe__submit-btn"
|
||
[disabled]="!canSubmit" (click)="submit()">
|
||
{{ submitting ? '送出中… · Submitting' : '送出 · Submit' }}
|
||
</button>
|
||
</div>
|
||
|
||
<div *ngIf="toast" class="oe__toast">{{ toast }}</div>
|
||
|
||
<!-- Quick-add member -->
|
||
<kendo-dialog *ngIf="showQuickAdd" title="快速新增會友 · Quick add member"
|
||
(close)="cancelQuickAdd()" [minWidth]="280" [width]="'95vw'" [maxWidth]="360">
|
||
<div class="oe__qa">
|
||
<div class="oe__field">
|
||
<label class="oe__label">英文名 · Legal first name *</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="quickAdd.firstName_en" size="large"></kendo-textbox>
|
||
</div>
|
||
<div class="oe__field">
|
||
<label class="oe__label">英文姓 · Last name *</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="quickAdd.lastName_en" size="large"></kendo-textbox>
|
||
</div>
|
||
<div class="oe__field">
|
||
<label class="oe__label">暱稱 · Nick name</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="quickAdd.nickName" size="large"></kendo-textbox>
|
||
</div>
|
||
<div class="oe__field">
|
||
<label class="oe__label">中文名 · Chinese first name</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="quickAdd.firstName_zh" size="large"></kendo-textbox>
|
||
</div>
|
||
<div class="oe__field">
|
||
<label class="oe__label">中文姓 · Chinese last name</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="quickAdd.lastName_zh" size="large"></kendo-textbox>
|
||
</div>
|
||
<div class="oe__field">
|
||
<label class="oe__label">手機 · Cell phone</label>
|
||
<kendo-textbox class="oe__control" [(ngModel)]="quickAdd.phoneCell" size="large"></kendo-textbox>
|
||
</div>
|
||
</div>
|
||
<kendo-dialog-actions>
|
||
<button kendoButton (click)="cancelQuickAdd()">取消 · Cancel</button>
|
||
<button kendoButton themeColor="primary" [disabled]="!canSaveQuickAdd" (click)="saveQuickAdd()">
|
||
{{ quickAddSaving ? '新增中… · Saving' : '新增 · Add' }}
|
||
</button>
|
||
</kendo-dialog-actions>
|
||
</kendo-dialog>
|
||
|
||
<!-- Today's totals: payment-method breakdown + per-check detail -->
|
||
<kendo-dialog *ngIf="showTotals" title="今日總計 · Today's Totals"
|
||
(close)="closeTotals()" [minWidth]="280" [width]="'95vw'" [maxWidth]="360">
|
||
<div class="oe__qa">
|
||
<p *ngIf="totalsLoading" class="oe__totals-loading">載入中… · Loading</p>
|
||
|
||
<ng-container *ngIf="!totalsLoading">
|
||
<!-- By payment method -->
|
||
<div class="oe__totals-section">
|
||
<h3 class="oe__totals-heading">各付款方式 · By method</h3>
|
||
<ul class="oe__totals-list">
|
||
<li *ngFor="let row of methodSubtotals" class="oe__totals-row">
|
||
<span class="oe__totals-name">{{ row.label }}</span>
|
||
<span class="oe__totals-amount">{{ row.total | currency }}</span>
|
||
</li>
|
||
<li *ngIf="!methodSubtotals.length" class="oe__totals-empty">今日尚無紀錄 · No entries yet</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Per-check detail -->
|
||
<div class="oe__totals-section">
|
||
<h3 class="oe__totals-heading">各支票 · Checks</h3>
|
||
<ul class="oe__totals-list">
|
||
<li *ngFor="let check of checkLines" class="oe__totals-row">
|
||
<span class="oe__totals-name"># {{ check.checkNumber || '(無號碼 · no #)' }}</span>
|
||
<span class="oe__totals-amount">{{ check.amount | currency }}</span>
|
||
</li>
|
||
<li *ngIf="!checkLines.length" class="oe__totals-empty">今日無支票 · No checks</li>
|
||
</ul>
|
||
<div *ngIf="checkLines.length" class="oe__totals-row oe__totals-row--subtotal">
|
||
<span class="oe__totals-name">支票合計 · Check total</span>
|
||
<span class="oe__totals-amount">{{ checkTotal | currency }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Grand total -->
|
||
<div class="oe__totals-row oe__totals-row--grand">
|
||
<span class="oe__totals-name">今日總計 · Total</span>
|
||
<span class="oe__totals-amount">{{ grandTotal | currency }}</span>
|
||
</div>
|
||
</ng-container>
|
||
</div>
|
||
<kendo-dialog-actions>
|
||
<button kendoButton themeColor="primary" (click)="closeTotals()">關閉 · Close</button>
|
||
</kendo-dialog-actions>
|
||
</kendo-dialog>
|
||
|
||
<!-- Add paper proof: capture photos / pick files → compress + merge to one PDF -->
|
||
<kendo-dialog *ngIf="showPaperProof" title="新增 Paper Proof · 紙本證明"
|
||
(close)="cancelPaperProof()" [minWidth]="280" [width]="'95vw'" [maxWidth]="360">
|
||
<div class="oe__qa">
|
||
<p class="oe__proof-hint">附上點算單/信封的照片或 PDF · Photo or PDF of the count sheet / envelopes</p>
|
||
|
||
<!-- Hidden native inputs, driven by the buttons below. -->
|
||
<input #cameraInput type="file" hidden accept="image/*" capture="environment"
|
||
(change)="onProofFilesSelected($event)" />
|
||
<input #libraryInput type="file" hidden multiple accept="image/*,application/pdf"
|
||
(change)="onProofFilesSelected($event)" />
|
||
|
||
<div class="oe__proof-actions">
|
||
<button kendoButton fillMode="outline" size="large" (click)="cameraInput.click()">
|
||
📷 拍照 · Camera
|
||
</button>
|
||
<button kendoButton fillMode="outline" size="large" (click)="libraryInput.click()">
|
||
🖼️ 相簿/檔案 · Library
|
||
</button>
|
||
</div>
|
||
|
||
<ul *ngIf="paperProofFiles.length" class="oe__proof-list">
|
||
<li *ngFor="let file of paperProofFiles; let i = index" class="oe__proof-item">
|
||
<span class="oe__proof-name">{{ file.name }}</span>
|
||
<button kendoButton fillMode="flat" size="small" (click)="removeProofFile(i)">×</button>
|
||
</li>
|
||
</ul>
|
||
|
||
<p *ngIf="hasProof" class="oe__proof-merge">將與現有證明合併 · Will be merged with the existing proof</p>
|
||
</div>
|
||
<kendo-dialog-actions>
|
||
<button kendoButton (click)="cancelPaperProof()">取消 · Cancel</button>
|
||
<button kendoButton themeColor="primary" [disabled]="!canSavePaperProof" (click)="savePaperProof()">
|
||
{{ paperProofSaving ? '處理中… · Saving' : '附加 · Attach' }}
|
||
</button>
|
||
</kendo-dialog-actions>
|
||
</kendo-dialog>
|
||
</div>
|