update view.
ci-cd-vm / ci-cd (push) Successful in 1m59s

This commit is contained in:
Chris Chen
2026-06-25 21:55:16 -07:00
parent d987ddea0e
commit 773d38d838
2 changed files with 134 additions and 22 deletions
@@ -30,20 +30,24 @@
</div>
</div>
<!-- Main grid -->
<!-- Desktop grid -->
<div class="hidden md:block">
<div class="hint-text-sm mb-2">Right-click a row for actions / 右鍵顯示動作</div>
<kendo-grid [data]="{ data: rows, total: total }" [loading]="loading" [pageable]="true" [skip]="skip"
[pageSize]="pageSize" (pageChange)="onPageChange($event)">
[pageSize]="pageSize" (pageChange)="onPageChange($event)" (cellClick)="onCellClick($event)">
<kendo-grid-column field="expenseDate" title="Date" [width]="110"></kendo-grid-column>
<!-- <kendo-grid-column field="type" title="Type" [width]="140"></kendo-grid-column> -->
<kendo-grid-column field="ministryName" title="Ministry" [width]="280"></kendo-grid-column>
<kendo-grid-column title="Category" [width]="360">
<kendo-grid-column title="Ministry / Category" [width]="240">
<ng-template kendoGridCellTemplate let-dataItem>
{{ dataItem.primaryCategoryName }}<span *ngIf="dataItem.lineCount > 1" class="text-gray-500"> +{{ dataItem.lineCount - 1 }}</span>
<div>{{ dataItem.ministryName }}</div>
<div class="text-gray-500 text-xs">
{{ dataItem.primaryCategoryName }}<span *ngIf="dataItem.lineCount > 1"> +{{ dataItem.lineCount - 1 }}</span>
</div>
</ng-template>
</kendo-grid-column>
@@ -81,19 +85,75 @@
</ng-template>
</kendo-grid-column>
<kendo-grid-column title="Actions" [width]="160">
<ng-template kendoGridCellTemplate let-dataItem>
<button *ngIf="canEdit(dataItem)" kendoButton fillMode="flat" (click)="openEdit(dataItem)">Edit</button>
<button *ngIf="canApproveOrReject(dataItem)" kendoButton themeColor="primary" fillMode="flat"
(click)="openReview(dataItem)">Review</button>
<button *ngIf="canPay(dataItem)" kendoButton themeColor="primary" fillMode="flat"
(click)="openPay(dataItem)">Pay</button>
<button *ngIf="dataItem.hasReceipt" kendoButton fillMode="flat" (click)="openReceipt(dataItem.id)"
class="receipt-link">Receipt</button>
</ng-template>
</kendo-grid-column>
</kendo-grid>
<kendo-contextmenu #rowMenu [items]="rowMenuItems" (select)="onRowMenuSelect($event)"></kendo-contextmenu>
</div>
<!-- Mobile cards -->
<div class="md:hidden flex flex-col gap-3">
<div *ngFor="let dataItem of rows" class="rounded border p-3 flex flex-col gap-2">
<div class="flex justify-between items-start gap-2">
<div class="text-sm text-gray-500">{{ dataItem.expenseDate }}</div>
<div class="font-semibold">{{ dataItem.amount | currency }}</div>
</div>
<div>
<div class="font-medium">{{ dataItem.ministryName }}</div>
<div class="text-gray-500 text-xs">
{{ dataItem.primaryCategoryName }}<span *ngIf="dataItem.lineCount > 1"> +{{ dataItem.lineCount - 1 }}</span>
</div>
</div>
<div *ngIf="dataItem.description" class="text-sm">{{ dataItem.description }}</div>
<div class="text-sm flex justify-between gap-2">
<span class="text-gray-500">Payee / 收款人</span>
<span class="text-right">
<ng-container *ngIf="dataItem.vendorName; else mobileMemberPayee">{{ dataItem.vendorName }}</ng-container>
<ng-template #mobileMemberPayee>
<ng-container *ngIf="dataItem.memberName; else mobileDash">
<span *ngIf="dataItem.memberNickName">{{ dataItem.memberNickName }} </span>
<span [class.text-gray-500]="dataItem.memberNickName">{{ dataItem.memberName }}</span>
</ng-container>
<ng-template #mobileDash></ng-template>
</ng-template>
</span>
</div>
<div *ngIf="dataItem.status === 'Paid' && dataItem.checkNumber" class="text-sm flex justify-between gap-2">
<span class="text-gray-500">Check # / 支票號</span>
<span>{{ dataItem.checkNumber }}</span>
</div>
<div>
<span [class]="statusClass(dataItem.status)">{{ dataItem.status }}</span>
<div *ngIf="dataItem.reviewedByName && (dataItem.status === 'Approved' || dataItem.status === 'Paid')"
class="review-meta">✓ Approved by {{ dataItem.reviewedByName }}<br>{{ dataItem.reviewedAt | date:'yyyy-MM-dd HH:mm' }}</div>
<div *ngIf="dataItem.reviewedByName && dataItem.status === 'Rejected'" class="review-meta review-meta-reject">
✗ Rejected by {{ dataItem.reviewedByName }}<br>{{ dataItem.reviewedAt | date:'yyyy-MM-dd HH:mm' }}
<div *ngIf="dataItem.reviewNotes" class="review-reason">{{ dataItem.reviewNotes }}</div>
</div>
</div>
<div class="flex flex-wrap gap-2 pt-1">
<button *ngIf="canEdit(dataItem)" kendoButton size="small" (click)="openEdit(dataItem)">Edit</button>
<button *ngIf="canApproveOrReject(dataItem)" kendoButton size="small" themeColor="primary"
(click)="openReview(dataItem)">Review</button>
<button *ngIf="canPay(dataItem)" kendoButton size="small" themeColor="primary"
(click)="openPay(dataItem)">Pay</button>
<button *ngIf="dataItem.hasReceipt" kendoButton size="small" fillMode="outline"
(click)="openReceipt(dataItem.id)">Receipt</button>
</div>
</div>
<div *ngIf="!loading && rows.length === 0" class="text-center text-gray-500 py-6">No expenses / 無支出資料</div>
<div *ngIf="rows.length > 0" class="flex items-center justify-between gap-2 pt-1">
<button kendoButton size="small" [disabled]="page <= 1" (click)="prevPage()"> Prev</button>
<span class="text-sm text-gray-500">{{ page }} / {{ totalPages }}</span>
<button kendoButton size="small" [disabled]="page >= totalPages" (click)="nextPage()">Next </button>
</div>
</div>
<!-- Vendor Payment dialog -->
<app-expense-form-dialog *ngIf="vendorDialogOpen" mode="vendor" title="Vendor Payment" (save)="onVendorSave($event)"