Skip to main content

Overview

The Customers API manages customer records and their categories with built-in validation, duplicate detection, and bulk import capabilities.

Customer Management

getCustomersFromCache

Retrieves customers from in-memory cache synchronously.
export const getCustomersFromCache = (): Customer[]
customers
Customer[]
Array of customers sorted by creation date (newest first)

fetchAndCacheCustomers

Fetches customers from Firebase and updates caches.
export const fetchAndCacheCustomers = async (): Promise<Customer[]>

addCustomer

Creates a new customer with duplicate detection.
export const addCustomer = async (
  customerData: Omit<Customer, 'id' | 'createdAt'>
): Promise<Customer>
customerData
object
required
customer
Customer
Created customer with:
  • Generated ID (format: CUST-{timestamp}-{random})
  • Creation timestamp
  • Default category if not specified
Duplicate Detection:
  • Checks for existing customers with same phone OR email
  • Throws error if duplicate found: “Ya existe un cliente con ese teléfono o email.”
import { addCustomer } from './services/customerService';

try {
  const customer = await addCustomer({
    name: "Laura Fernández",
    phone: "+5491178901234",
    email: "[email protected]",
    address: "Av. Santa Fe 1234, Buenos Aires"
  });
  
  console.log('Customer created:', customer.id);
} catch (error) {
  console.error('Creation failed:', error.message);
}

updateCustomer

Updates an existing customer with duplicate detection.
export const updateCustomer = async (updatedCustomer: Customer): Promise<Customer>
updatedCustomer
Customer
required
Complete customer object with all fields
customer
Customer
The updated customer
Duplicate Detection:
  • Checks other customers (excluding current one) for phone/email conflicts
  • Throws error if duplicate found
import { updateCustomer } from './services/customerService';

const updated = await updateCustomer({
  id: "CUST-1709876543210-abc67",
  name: "Laura M. Fernández",
  phone: "+5491178901234",
  email: "[email protected]",
  address: "Nueva dirección",
  categoryId: "CUSTCAT-vip-123",
  createdAt: "2024-03-08T10:15:43.210Z"
});

deleteCustomer

Deletes a customer by ID.
export const deleteCustomer = async (customerId: string): Promise<void>
customerId
string
required
The customer ID to delete

importCustomers

Bulk imports customers with validation and category matching.
export const importCustomers = async (
  customersToImport: any[]
): Promise<{ added: number; updated: number; errors: number }>
customersToImport
array
required
Array of customer objects with fields:
  • name (required)
  • phone (required)
  • email (required)
  • address (optional)
  • categoryName (optional, matched to existing categories)
result
object
Validation Rules:
  • Name, phone, and email are required
  • Phone must have at least 10 digits (non-digit characters ignored)
  • Email must match pattern: [email]@[domain].[tld]
  • Category name is matched case-insensitively to existing categories
Matching Logic:
  • Customers matched by phone OR email
  • Existing customers are updated
  • New customers are created
import { importCustomers } from './services/customerService';

const customers = [
  {
    name: "Cliente 1",
    phone: "+5491123456789",
    email: "[email protected]",
    address: "Dirección 1",
    categoryName: "VIP"
  },
  {
    name: "Cliente 2",
    phone: "11-2345-6789",
    email: "[email protected]",
    categoryName: "Regular"
  }
];

const result = await importCustomers(customers);
console.log(`Added: ${result.added}, Updated: ${result.updated}, Errors: ${result.errors}`);

Customer Category Management

getCustomerCategoriesFromCache

Retrieves customer categories from cache.
export const getCustomerCategoriesFromCache = (): CustomerCategory[]
categories
CustomerCategory[]
Array of customer categories sorted alphabetically

fetchAndCacheCustomerCategories

Fetches categories from Firebase.
export const fetchAndCacheCustomerCategories = async (): Promise<CustomerCategory[]>

addCustomerCategory

Creates a new customer category.
export const addCustomerCategory = async (
  categoryData: Omit<CustomerCategory, 'id'>
): Promise<CustomerCategory>
categoryData
object
required
category
CustomerCategory
Created category with generated ID
import { addCustomerCategory } from './services/customerCategoryService';

const category = await addCustomerCategory({
  name: "Premium",
  color: "#9C27B0"
});

updateCustomerCategory

Updates an existing customer category.
export const updateCustomerCategory = async (
  updatedCategory: CustomerCategory
): Promise<CustomerCategory>

deleteCustomerCategory

Deletes a customer category with automatic customer reassignment.
export const deleteCustomerCategory = async (categoryId: string): Promise<void>
categoryId
string
required
The category ID to delete
Protected Categories:
  • Cannot delete the “Nuevo” (New) category
  • Throws error: “La categoría ‘Nuevo’ no se puede eliminar.”
Automatic Reassignment:
  • All customers in deleted category are automatically reassigned to “Nuevo” category
  • Uses Firebase batch write for atomicity
import { deleteCustomerCategory } from './services/customerCategoryService';

try {
  await deleteCustomerCategory("CUSTCAT-old-category");
  console.log('Category deleted, customers reassigned');
} catch (error) {
  console.error('Cannot delete:', error.message);
}

getDefaultNewCustomerCategory

Gets the default “Nuevo” category.
export const getDefaultNewCustomerCategory = (): CustomerCategory | undefined
category
CustomerCategory | undefined
The “Nuevo” category or undefined if not found

reassignCustomersFromCategory

Reassigns all customers from one category to the default category.
export const reassignCustomersFromCategory = async (deletedCategoryId: string): Promise<void>
deletedCategoryId
string
required
Category ID to reassign customers from
This function is automatically called by deleteCustomerCategory. You typically don’t need to call it directly.

TypeScript Types

Customer Interface

interface Customer {
  id: string;
  name: string;
  phone?: string;
  email?: string;
  address?: string;
  categoryId: string;
  createdAt: string; // ISO timestamp
}

CustomerCategory Interface

interface CustomerCategory {
  id: string;
  name: string;
  color: string; // Hex color code
}

Default Categories

The system initializes with three default customer categories:
NameColorPurpose
Nuevo#4CAF50 (Green)Default for new customers
Regular#2196F3 (Blue)Repeat customers
VIP#FFC107 (Amber)Premium customers
The “Nuevo” category is protected and cannot be deleted. It serves as the fallback category for all customer operations.

Complete Example

Customer Lifecycle Management

import {
  addCustomer,
  updateCustomer,
  getCustomersFromCache,
  addCustomerCategory,
  getCustomerCategoriesFromCache
} from './services/customerService';
import { getDefaultNewCustomerCategory } from './services/customerCategoryService';

// 1. Create new customer with validation
try {
  const customer = await addCustomer({
    name: "Roberto Sánchez",
    phone: "+5491189012345",
    email: "[email protected]",
    address: "Calle Falsa 123"
  });
  
  console.log('Customer created with default category:', customer.categoryId);
  
  // 2. After a few successful orders, upgrade to Regular
  const regularCategory = getCustomerCategoriesFromCache()
    .find(c => c.name === 'Regular');
  
  if (regularCategory) {
    const updated = await updateCustomer({
      ...customer,
      categoryId: regularCategory.id
    });
    console.log('Upgraded to Regular customer');
  }
  
  // 3. Create custom VIP category for high-value customers
  const vipCategory = await addCustomerCategory({
    name: "Gold VIP",
    color: "#FFD700"
  });
  
  // 4. Promote to Gold VIP
  const vipCustomer = await updateCustomer({
    ...updated,
    categoryId: vipCategory.id
  });
  
  console.log('Customer is now Gold VIP!');
  
} catch (error) {
  if (error.message.includes('Ya existe un cliente')) {
    console.log('Customer already exists in system');
  } else {
    console.error('Error:', error.message);
  }
}

Build docs developers (and LLMs) love