| Server IP : 173.209.174.21 / Your IP : 216.73.216.89 Web Server : Apache/2.4.58 (Ubuntu) System : Linux wcfs-server 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64 User : nodor ( 1000) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/wcfs/NAOPOS/src/lib/ |
Upload File : |
import { defaultProducts, Product } from "@/data/products";
import { ReportCategory } from "@/types/sales";
const API_BASE = (import.meta.env.VITE_POS_API_BASE_URL || "/api").replace(
/\/$/,
"",
);
export interface CatalogProduct extends Product {
reportCategory: ReportCategory;
taxable: boolean;
}
export interface CatalogSaveResult {
ok: boolean;
error?: string;
}
export function normalizeCatalogProduct(
product: Partial<CatalogProduct>,
index = 0,
): CatalogProduct {
const fallback = defaultProducts[index] || defaultProducts[0];
const taxable =
typeof product.taxable === "boolean"
? product.taxable
: Boolean(product.taxRate);
return {
id: product.id || fallback.id || `product-${index + 1}`,
name: product.name || fallback.name || "Item",
price:
typeof product.price === "number" && !Number.isNaN(product.price)
? product.price
: fallback.price || 0,
category: product.category || fallback.category || "General",
emoji: product.emoji || fallback.emoji || "ITEM",
imageUrl: product.imageUrl || fallback.imageUrl,
taxable,
taxRate: taxable
? typeof product.taxRate === "number" && !Number.isNaN(product.taxRate)
? product.taxRate
: 0
: undefined,
reportCategory: (product.reportCategory || "Non-Taxable") as ReportCategory,
};
}
export function defaultCatalog(): CatalogProduct[] {
return defaultProducts.map((product, index) =>
normalizeCatalogProduct(
{
...product,
taxable: false,
reportCategory: "Non-Taxable",
},
index,
),
);
}
export function deriveCategories(products: CatalogProduct[]): string[] {
const list = Array.from(
new Set(products.map((product) => product.category.trim()).filter(Boolean)),
).sort((a, b) => a.localeCompare(b));
return ["All", ...list];
}
export async function loadCatalog(): Promise<CatalogProduct[] | null> {
try {
const response = await fetch(`${API_BASE}/catalog.php`);
if (!response.ok) return null;
const payload = (await response.json()) as {
products?: Partial<CatalogProduct>[];
};
if (!payload.products) return [];
return payload.products.map((product, index) =>
normalizeCatalogProduct(product, index),
);
} catch (error) {
console.error("Failed to load catalog", error);
return null;
}
}
export async function saveCatalog(products: CatalogProduct[]): Promise<boolean> {
try {
const response = await fetch(`${API_BASE}/catalog.php`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ products }),
});
return response.ok;
} catch (error) {
console.error("Failed to save catalog", error);
return false;
}
}
export async function saveCatalogDetailed(
products: CatalogProduct[],
): Promise<CatalogSaveResult> {
try {
const response = await fetch(`${API_BASE}/catalog.php`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ products }),
});
if (response.ok) {
return { ok: true };
}
const text = await response.text();
try {
const payload = JSON.parse(text) as { error?: string };
return {
ok: false,
error: payload.error || `Catalog save failed (${response.status})`,
};
} catch {
return {
ok: false,
error: text || `Catalog save failed (${response.status})`,
};
}
} catch (error) {
console.error("Failed to save catalog", error);
return {
ok: false,
error: error instanceof Error ? error.message : "Catalog save failed",
};
}
}