Implement per-bill proof of payment and update field names

Frontend changes:
- Added ViewBillCard proof of payment upload for per-bill mode
  - Conditional rendering based on proofOfPaymentType
  - File upload with PDF validation and loading states
  - Download link to /share/proof-of-payment/per-bill/
- Updated LocationCard to use new utilBillsProofOfPayment field structure

Backend changes:
- Updated locationActions with improved file validation
  - File size validation using MAX_PROOF_OF_PAYMENT_UPLOAD_SIZE_KB
  - PDF type validation before database operations
  - Enhanced serializeAttachment with FileAttachment type
  - Updated database projections for optimized queries
- Updated monthActions to use consolidated field name
- Updated proof-of-payment download route with new field names

Data structure migration:
- Replaced utilBillsProofOfPaymentAttachment + utilBillsProofOfPaymentUploadedAt
  with single utilBillsProofOfPayment object containing uploadedAt
- Consistent use of FileAttachment type across all upload functions

Translations:
- Added upload-proof-of-payment-legend and upload-proof-of-payment-label
  to bill-edit-form section in both English and Croatian

This completes the proof of payment feature implementation for both
combined (location-level) and per-bill modes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Knee Cola
2025-12-07 13:11:17 +01:00
parent 0facc9c257
commit aa573c68a3
7 changed files with 172 additions and 114 deletions

View File

@@ -24,7 +24,7 @@ export const LocationCard: FC<LocationCardProps> = ({ location, currency }) => {
bills,
seenByTenantAt,
// NOTE: only the fileName is projected from the DB to reduce data transfer
utilBillsProofOfPaymentUploadedAt
utilBillsProofOfPayment,
} = location;
const t = useTranslations("home-page.location-card");
@@ -64,7 +64,7 @@ export const LocationCard: FC<LocationCardProps> = ({ location, currency }) => {
</Link>
<ShareIcon className="h-[1em] w-[1em] cursor-pointer text-2xl inline hover:text-red-500" title="create sharable link" onClick={handleCopyLinkClick} />
</div>
{ monthlyExpense > 0 || seenByTenantAt || utilBillsProofOfPaymentUploadedAt ?
{ monthlyExpense > 0 || seenByTenantAt || utilBillsProofOfPayment?.uploadedAt ?
<>
<div className="flex ml-1">
<div className="divider divider-horizontal p-0 m-0"></div>
@@ -89,7 +89,7 @@ export const LocationCard: FC<LocationCardProps> = ({ location, currency }) => {
</span>
</div>
)}
{utilBillsProofOfPaymentUploadedAt && (
{utilBillsProofOfPayment?.uploadedAt && (
<Link
href={`/share/proof-of-payment/${_id}/`}
target="_blank"