From 89c06e279922569bb872be07a77636cb0ca47c1a Mon Sep 17 00:00:00 2001 From: Knee Cola Date: Sun, 23 Nov 2025 08:25:06 +0100 Subject: [PATCH] Refactor: Complete barcodeImage to hub3aText migration across codebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Database & Types: - Added hub3aText field to Bill interface in db-types.ts - Marked barcodeImage as @deprecated legacy field Server Actions: - Updated billActions to read/write hub3aText instead of barcodeImage - Commented out legacy barcodeImage code with migration notes Barcode Decoder: - Renamed image2canvas to file2canvas for clarity - Added new image2canvas function for base64 encoded images (migration support) - Added hub3aText to DecodeResult type - Exported decodeFromImage function for legacy data migration - Updated decoding logic to extract and return hub3aText UI Components: - Refactored Pdf417Barcode to accept hub3aText string instead of PaymentParams - Removed EncodePayment call from Pdf417Barcode (now expects pre-encoded text) - Updated ViewLocationCard to encode payment params before passing to Pdf417Barcode This completes the refactoring from storing bitmap images to storing decoded HUB-3A payment strings, providing more efficient storage and easier data manipulation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/lib/actions/billActions.ts | 15 +++++++---- app/lib/db-types.ts | 7 ++++- app/lib/pdf/barcodeDecoder.ts | 47 +++++++++++++++++++++++++++++++--- app/ui/Pdf417Barcode.tsx | 6 ++--- app/ui/ViewLocationCard.tsx | 6 +++-- 5 files changed, 65 insertions(+), 16 deletions(-) diff --git a/app/lib/actions/billActions.ts b/app/lib/actions/billActions.ts index 1a26d48..f2d3617 100644 --- a/app/lib/actions/billActions.ts +++ b/app/lib/actions/billActions.ts @@ -146,7 +146,8 @@ export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationI const billPaid = formData.get('billPaid') === 'on'; const billedTo = (formData.get('billedTo') as BilledTo) ?? BilledTo.Tenant; - const barcodeImage = formData.get('barcodeImage')?.valueOf() as string; + // const barcodeImage = formData.get('barcodeImage')?.valueOf() as string; // LEGACY FIELD - not used anymore + const hub3aText = formData.get('hub3aText')?.valueOf() as string; // update the bill in the mongodb const dbClient = await getDbClient(); @@ -164,7 +165,8 @@ export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationI "bills.$[elem].attachment": billAttachment, "bills.$[elem].notes": billNotes, "bills.$[elem].payedAmount": payedAmount, - "bills.$[elem].barcodeImage": barcodeImage, + // "bills.$[elem].barcodeImage": barcodeImage, // LEGACY FIELD - not used anymore + "bills.$[elem].hub3aText": hub3aText, }: { "bills.$[elem].name": billName, @@ -172,7 +174,8 @@ export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationI "bills.$[elem].billedTo": billedTo, "bills.$[elem].notes": billNotes, "bills.$[elem].payedAmount": payedAmount, - "bills.$[elem].barcodeImage": barcodeImage, + // "bills.$[elem].barcodeImage": barcodeImage, // LEGACY FIELD - not used anymore + "bills.$[elem].hub3aText": hub3aText, }; // find a location with the given locationID @@ -198,7 +201,8 @@ export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationI attachment: billAttachment, notes: billNotes, payedAmount, - barcodeImage, + // barcodeImage, // LEGACY FIELD - not used anymore + hub3aText, }; // Add to current location @@ -262,7 +266,8 @@ export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationI attachment: null, // No attachment for subsequent months notes: billNotes, payedAmount: null, - barcodeImage: undefined, + // barcodeImage: undefined, // LEGACY FIELD - not used anymore + hub3aText: undefined, } } } diff --git a/app/lib/db-types.ts b/app/lib/db-types.ts index 5c67800..7d8bebb 100644 --- a/app/lib/db-types.ts +++ b/app/lib/db-types.ts @@ -98,6 +98,11 @@ export interface Bill { hasAttachment?: boolean; /** (optional) notes */ notes?: string|null; - /** (optional) image data containing PDF471 bar code */ + /** + * (optional) image data containing PDF471 bar code + * @deprecated LEGACY FIELD - use hub3aText instead + * */ barcodeImage?:string; + /** (optional) HUB-3A text for generating PDF417 bar code */ + hub3aText?:string; }; \ No newline at end of file diff --git a/app/lib/pdf/barcodeDecoder.ts b/app/lib/pdf/barcodeDecoder.ts index 401f871..595f303 100644 --- a/app/lib/pdf/barcodeDecoder.ts +++ b/app/lib/pdf/barcodeDecoder.ts @@ -93,7 +93,7 @@ const parseHubText = (text: string):BillInfo => { * @param {File} imageFile - a file containing an image * @return {Promise} the canvas with the image rendered onto it */ -const image2canvas = async function (imageFile:File): Promise { +const file2canvas = async function (imageFile:File): Promise { const reader = new FileReader(); @@ -127,9 +127,40 @@ const image2canvas = async function (imageFile:File): Promise }); return(canvas); - } +/** + * Render an image from onto a canvas. + * @param {String} image - base64 encoded image string + * @return {Promise} the canvas with the image rendered onto it + */ +const image2canvas = async function (imageBase64:string): Promise { + + const canvas = await new Promise((resolve, reject) => { + const img = new Image(); + + img.onload = () => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + canvas.width = img.width; + canvas.height = img.height; + + if(!ctx) { + reject("Context is not set") + return; + } + + ctx.drawImage(img, 0, 0); + + resolve(canvas); + }; + + img.src = imageBase64; + }); + + return(canvas); +}; + /** * Render the first page of a PDF document onto a new canvas. * @param {File} pdfFile - a file containing a PDF document @@ -173,6 +204,7 @@ const pdf2canvas = async function (pdfFile:File): Promise => { + return(await decodeFromCanvas( await image2canvas(imageBase64) )); +} + /** Finds PDF417 code within a file and decodes it */ const decodeFromFile = async (file:File): Promise => { switch(file.type) { case 'image/png': case 'image/jpeg': - return(await decodeFromCanvas( await image2canvas(file) )); + return(await decodeFromCanvas( await file2canvas(file) )); case 'application/pdf': const pageCanvas = await pdf2canvas(file); // go through each page of the PDF and decode the PDF417 codes diff --git a/app/ui/Pdf417Barcode.tsx b/app/ui/Pdf417Barcode.tsx index 8743f0c..27ac0c4 100644 --- a/app/ui/Pdf417Barcode.tsx +++ b/app/ui/Pdf417Barcode.tsx @@ -5,16 +5,14 @@ import { generateBarcode } from '../lib/pdf/pdf417'; import { renderBarcode } from '../lib/pdf/renderBarcode'; import { EncodePayment, PaymentParams } from 'hub-3a-payment-encoder'; -export const Pdf417Barcode:FC<{paymentParams:PaymentParams}> = ({paymentParams}) => { +export const Pdf417Barcode:FC<{hub3aText:string}> = ({hub3aText: hub3a_text}) => { const [bitmapData, setBitmapData] = useState(undefined); useEffect(() => { - const hub3a_text = EncodePayment(paymentParams); - const barcodeMatrix = generateBarcode(hub3a_text); const bitmap = renderBarcode(barcodeMatrix, 2, 2); setBitmapData(bitmap); - }, [paymentParams]); + }, [hub3a_text]); // Don't render until bitmap is generated (prevents hydration mismatch) if (!bitmapData) { diff --git a/app/ui/ViewLocationCard.tsx b/app/ui/ViewLocationCard.tsx index d77fed0..ab8682e 100644 --- a/app/ui/ViewLocationCard.tsx +++ b/app/ui/ViewLocationCard.tsx @@ -7,7 +7,7 @@ import { formatCurrency } from "../lib/formatStrings"; import { useTranslations } from "next-intl"; import { ViewBillBadge } from "./ViewBillBadge"; import { Pdf417Barcode } from "./Pdf417Barcode"; -import { PaymentParams } from "hub-3a-payment-encoder"; +import { EncodePayment, PaymentParams } from "hub-3a-payment-encoder"; import Link from "next/link"; import { DocumentIcon } from "@heroicons/react/24/outline"; import { uploadUtilBillsProofOfPayment } from "../lib/actions/locationActions"; @@ -87,6 +87,8 @@ export const ViewLocationCard:FC = ({location, userSettin OpisPlacanja: `Režije-${locationNameTrimmed_max20}-${formatYearMonth(yearMonth)}`, // max length 35 = "Režije-" (7) + locationName (20) + "-" (1) + "YYYY-MM" (7) }; + const hub3a_text = EncodePayment(paymentParams); + return(
@@ -118,7 +120,7 @@ export const ViewLocationCard:FC = ({location, userSettin
  • {t("payment-reference-label")}
    {paymentParams.PozivNaBroj}
  • {t("payment-purpose-code-label")}
    {paymentParams.SifraNamjene}
  • - + : null }