Refactor: Complete barcodeImage to hub3aText migration across codebase

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 <noreply@anthropic.com>
This commit is contained in:
Knee Cola
2025-11-23 08:25:06 +01:00
parent 278976b75b
commit 89c06e2799
5 changed files with 65 additions and 16 deletions

View File

@@ -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,
}
}
}

View File

@@ -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;
};

View File

@@ -93,7 +93,7 @@ const parseHubText = (text: string):BillInfo => {
* @param {File} imageFile - a file containing an image
* @return {Promise<HTMLCanvasElement>} the canvas with the image rendered onto it
*/
const image2canvas = async function (imageFile:File): Promise<HTMLCanvasElement> {
const file2canvas = async function (imageFile:File): Promise<HTMLCanvasElement> {
const reader = new FileReader();
@@ -127,9 +127,40 @@ const image2canvas = async function (imageFile:File): Promise<HTMLCanvasElement>
});
return(canvas);
}
/**
* Render an image from onto a canvas.
* @param {String} image - base64 encoded image string
* @return {Promise<HTMLCanvasElement>} the canvas with the image rendered onto it
*/
const image2canvas = async function (imageBase64:string): Promise<HTMLCanvasElement> {
const canvas = await new Promise<HTMLCanvasElement>((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<Array<HTMLCanvasElemen
}
export type DecodeResult = {
hub3aText: string,
billInfo: BillInfo,
barcodeImage: string,
};
@@ -240,10 +272,12 @@ const decodeFromCanvas = async (canvas:HTMLCanvasElement): Promise<Array<DecodeR
const result = await codeReader.decodeFromCanvas(sectionCanvas);
const hub3aText = result.getText()
if (result) {
codesFoundInSection.push({
billInfo: parseHubText(result.getText()),
hub3aText,
billInfo: parseHubText(hub3aText),
barcodeImage: copyBarcodeImage(sectionCanvas, result)
});
}
@@ -329,12 +363,17 @@ const copyBarcodeImage = (canvas:HTMLCanvasElement, decoderResult:Result):string
return(dataURL);
}
/** Finds PDF417 code within a base64 encoded image and decodes it */
export const decodeFromImage = async (imageBase64:string): Promise<DecodeResult[]|null> => {
return(await decodeFromCanvas( await image2canvas(imageBase64) ));
}
/** Finds PDF417 code within a file and decodes it */
const decodeFromFile = async (file:File): Promise<DecodeResult[]|null> => {
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