Refactor image upload handling across items and receipts routes to include validation for uploaded images, enhancing error handling and user feedback. Consolidate parsing functions by importing from a shared module, improving code maintainability. Update server hooks to ensure consistent cookie handling and error logging.
CI / build (push) Has been skipped
CI / deploy (push) Successful in 1m33s

This commit is contained in:
eewing
2026-02-26 09:45:37 -06:00
parent 47625259ba
commit 455b762eef
11 changed files with 143 additions and 65 deletions
+19
View File
@@ -0,0 +1,19 @@
/**
* Parse form values. Shared by items and receipts server actions.
*/
export function parseNum(val: unknown): number | undefined {
if (val === "" || val === null || val === undefined) return undefined;
const n = Number(val);
return Number.isFinite(n) ? n : undefined;
}
/** Like parseNum but return a number (default when empty/invalid). */
export function parseNumWithDefault(val: unknown, defaultVal: number): number {
const n = parseNum(val);
return n ?? defaultVal;
}
export function parseBool(val: unknown): boolean {
return val === "on" || val === "true" || val === true;
}
+33
View File
@@ -0,0 +1,33 @@
/** Allowed MIME types for receipt/item image uploads (server-side check). */
const ALLOWED_IMAGE_TYPES = new Set([
"image/jpeg",
"image/png",
"image/webp",
"image/heic",
"image/heif",
]);
/** Max size 10MB. */
const MAX_IMAGE_BYTES = 10 * 1024 * 1024;
/**
* Validates an image file for upload. Returns an error message if invalid, or null if valid/no file.
* Use in form actions before sending the file to PocketBase.
*/
export function validateImageUpload(file: File | null): string | null {
if (!file || file.size === 0) return null;
const type = (file.type ?? "").toLowerCase();
const name = file.name.toLowerCase();
const isHeic =
type === "image/heic" ||
type === "image/heif" ||
name.endsWith(".heic") ||
name.endsWith(".heif");
if (!isHeic && !ALLOWED_IMAGE_TYPES.has(type)) {
return "Invalid image type. Use JPEG, PNG, WebP, or HEIC.";
}
if (file.size > MAX_IMAGE_BYTES) {
return `Image must be under ${MAX_IMAGE_BYTES / 1024 / 1024}MB.`;
}
return null;
}