feat: integrate barcode scanning functionality and enhance Appwrite setup
- Added a new `barcode_products` collection to the Appwrite setup for managing barcode data. - Implemented barcode scanning feature with a dedicated modal for scanning and adding products. - Introduced new components for barcode product preview and management. - Updated the setup script to seed verified barcode products from a JSON file. - Enhanced the application state management to handle barcode-related actions and user interactions.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { normalizeBarcode } from "./barcodeLookup";
|
||||
import type { BarcodeProductDraft, UserBarcodeMapping } from "../types";
|
||||
|
||||
const STORAGE_PREFIX = "red-bull-barcode-mappings:v1";
|
||||
|
||||
export function loadUserBarcodeMappings(userId: string) {
|
||||
const raw = localStorage.getItem(storageKey(userId));
|
||||
if (!raw) return [];
|
||||
|
||||
try {
|
||||
const parsed: unknown = JSON.parse(raw);
|
||||
if (!Array.isArray(parsed)) return [];
|
||||
return parsed.filter(isUserBarcodeMapping);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function saveUserBarcodeMappings(userId: string, mappings: UserBarcodeMapping[]) {
|
||||
localStorage.setItem(storageKey(userId), JSON.stringify(mappings));
|
||||
}
|
||||
|
||||
export function upsertUserBarcodeMapping(
|
||||
userId: string,
|
||||
barcodeValue: string,
|
||||
product: BarcodeProductDraft,
|
||||
) {
|
||||
const barcode = normalizeBarcode(barcodeValue);
|
||||
const now = new Date().toISOString();
|
||||
const mappings = loadUserBarcodeMappings(userId);
|
||||
const existing = mappings.find((mapping) => mapping.barcode === barcode);
|
||||
const nextMapping: UserBarcodeMapping = {
|
||||
...product,
|
||||
barcode,
|
||||
createdAt: existing?.createdAt ?? now,
|
||||
updatedAt: now,
|
||||
};
|
||||
const nextMappings = existing
|
||||
? mappings.map((mapping) => (mapping.barcode === barcode ? nextMapping : mapping))
|
||||
: [...mappings, nextMapping];
|
||||
|
||||
saveUserBarcodeMappings(userId, nextMappings);
|
||||
return nextMapping;
|
||||
}
|
||||
|
||||
function storageKey(userId: string) {
|
||||
return `${STORAGE_PREFIX}:${userId}`;
|
||||
}
|
||||
|
||||
function isUserBarcodeMapping(value: unknown): value is UserBarcodeMapping {
|
||||
if (!value || typeof value !== "object") return false;
|
||||
const mapping = value as Partial<UserBarcodeMapping>;
|
||||
return (
|
||||
typeof mapping.barcode === "string" &&
|
||||
typeof mapping.flavourName === "string" &&
|
||||
typeof mapping.sizeMl === "number" &&
|
||||
typeof mapping.pricePerCan === "number" &&
|
||||
typeof mapping.createdAt === "string" &&
|
||||
typeof mapping.updatedAt === "string" &&
|
||||
(mapping.sugarFree === undefined || typeof mapping.sugarFree === "boolean") &&
|
||||
(mapping.caffeineMgPerCan === undefined || typeof mapping.caffeineMgPerCan === "number")
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user