Skip to main content

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
Product[]
Array of cached products
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[]>
products
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>
productData
object
required
Product data without ID
product
Product
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>
updatedProduct
Product
required
Complete product object with all fields including ID
product
Product
The updated product
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>
productId
string
required
The product ID to delete
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>
targetCategory
string
required
Category name or “all” for all products
percentage
number
required
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 }>
productsToImport
array
required
Array of product objects without ID or imageUrl
result
object
Import statistics
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[]
categories
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>
categoryData
object
required
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;
}

Build docs developers (and LLMs) love