Overview
The Products API manages menu items and their categories, including pricing, descriptions, and bulk operations. It implements a cache-first architecture with Firebase sync.
Product Management
getProductsFromCache
Retrieves products from the in-memory cache synchronously.
export const getProductsFromCache = () : Product [] => Product []
Returns immediately - No async operation, uses in-memory cache.
import { getProductsFromCache } from './services/productService' ;
const products = getProductsFromCache ();
console . log ( `Found ${ products . length } products` );
fetchAndCacheProducts
Fetches products from Firebase and updates all caches.
export const fetchAndCacheProducts = async () : Promise < Product []>
Array of all products from Firebase
Behavior:
Fetches from Firebase Firestore Products collection
Updates in-memory and localStorage caches
If Firebase is empty but local cache exists, seeds Firebase from local data
Falls back to cache on network errors
import { fetchAndCacheProducts } from './services/productService' ;
try {
const products = await fetchAndCacheProducts ();
console . log ( 'Products synced:' , products . length );
} catch ( error ) {
console . error ( 'Sync failed:' , error );
}
addProduct
Creates a new product and saves it to Firebase.
export const addProduct = async (
productData : Omit < Product , 'id' >
): Promise < Product >
Product data without ID Product description or ingredients
Price as string (e.g., “9200”)
Optional product image URL
The created product with generated ID
import { addProduct } from './services/productService' ;
const newProduct = await addProduct ({
category: "Pizzas" ,
name: "Napolitana" ,
description: "Muzzarella, salsa, ajies, orégano y aceitunas verdes" ,
price: "9700"
});
console . log ( 'Created product:' , newProduct . id );
Error Handling:
Throws error with user-friendly message in Spanish on Firebase failures
Updates cache immediately on success
updateProduct
Updates an existing product.
export const updateProduct = async ( updatedProduct : Product ) : Promise < Product >
Complete product object with all fields including ID
import { updateProduct } from './services/productService' ;
const updated = await updateProduct ({
id: "PROD-1709876543210-xyz789" ,
category: "Pizzas" ,
name: "Napolitana Especial" ,
description: "Con extra queso" ,
price: "10500"
});
deleteProduct
Deletes a product by ID.
export const deleteProduct = async ( productId : string ) : Promise < void >
import { deleteProduct } from './services/productService' ;
await deleteProduct ( "PROD-1709876543210-xyz789" );
console . log ( 'Product deleted' );
adjustProductPrices
Bulk price adjustment with rounding options.
export const adjustProductPrices = async (
targetCategory : string ,
percentage : number ,
rounding : 'none' | 'integer' | '10' | '50' | '100'
): Promise < void >
Category name or “all” for all products
Percentage increase/decrease (e.g., 10 for +10%, -5 for -5%)
rounding
'none' | 'integer' | '10' | '50' | '100'
required
Rounding strategy:
none - No rounding (2 decimals)
integer - Round to nearest integer
10 - Round to nearest 10
50 - Round to nearest 50
100 - Round to nearest 100
import { adjustProductPrices } from './services/productService' ;
// Increase all pizza prices by 15%, round to nearest 50
await adjustProductPrices ( "Pizzas" , 15 , "50" );
// Decrease all prices by 10%, round to integer
await adjustProductPrices ( "all" , - 10 , "integer" );
Implementation:
Uses Firebase batch write for atomicity
Updates all matching products in single transaction
Price calculation: newPrice = currentPrice * (1 + percentage/100)
importProducts
Bulk import products from array.
export const importProducts = async (
productsToImport : Omit < Product , 'id' | 'imageUrl' >[]
): Promise < { added: number ; updated : number ; errors : number } >
Array of product objects without ID or imageUrl
Import statistics Number of new products created
Number of existing products updated
Number of products that failed validation
import { importProducts } from './services/productService' ;
const result = await importProducts ([
{ name: "Pizza 1" , category: "Pizzas" , price: "9000" },
{ name: "Pizza 2" , category: "Pizzas" , price: "9500" }
]);
console . log ( `Added: ${ result . added } , Updated: ${ result . updated } , Errors: ${ result . errors } ` );
Matching Logic:
Products are matched by name (case-insensitive) and category
Existing products are updated, new ones are created
Validates required fields: name, category, price
Category Management
getCategoriesFromCache
Retrieves categories from in-memory cache.
export const getCategoriesFromCache = () : Category []
Array of categories sorted alphabetically by name
fetchAndCacheCategories
Fetches categories from Firebase and updates caches.
export const fetchAndCacheCategories = async () : Promise < Category []>
addCategory
Creates a new product category.
export const addCategory = async (
categoryData : Omit < Category , 'id' >
): Promise < Category >
Hex color code (e.g., “#E53935”)
import { addCategory } from './services/categoryService' ;
const category = await addCategory ({
name: "Bebidas" ,
imageUrl: "https://example.com/drinks.jpg" ,
color: "#2196F3"
});
updateCategory
Updates an existing category.
export const updateCategory = async ( updatedCategory : Category ) : Promise < Category >
deleteCategory
Deletes a category by ID.
export const deleteCategory = async ( categoryId : string ) : Promise < void >
TypeScript Types
Product
interface Product {
id : string ;
category : string ;
name : string ;
description ?: string ;
price : string ;
imageUrl ?: string ;
}
Category
interface Category {
id : string ;
name : string ;
imageUrl ?: string ;
color ?: string ;
}
interface MenuItem {
name : string ;
price : string ;
description ?: string ;
imageUrl ?: string ;
}