Skip to main content
The customer profile section covers several authenticated routes where customers manage their account information, shipping addresses, notification preferences, and view personal statistics. All routes require authentication and are wrapped in <ProtectedRoute>.

Routes

RouteComponentDescription
/profileProfileEdit name, phone, WhatsApp, birthdate
/addressesAddressesManage shipping and billing addresses
/notificationsNotificationsNotification center and preferences
/statsStatsPersonal purchase statistics

Updating Profile Data

updateProfile() from auth.service.ts performs a Supabase upsert on the customer_profiles table:
export async function updateProfile(
    userId: string,
    data: {
        full_name?: string;
        phone?: string;
        whatsapp?: string;
        birthdate?: string;    // ISO date string, e.g. "1995-08-15"
        avatar_url?: string;   // Supabase Storage URL
        ia_context?: IAContext;
    }
): Promise<void>
The Profile page (src/pages/Profile.tsx) accesses the current profile via useAuth().profile and submits changes through a controlled form that calls updateProfile(user.id, formData).

Address Management

Addresses are stored in the addresses table with a one-to-many relationship to customer_profiles.

Address Interface

interface Address {
    id: string;
    customer_id: string;            // Foreign key to customer_profiles.id
    type: 'shipping' | 'billing';
    street: string;
    city: string;
    state: string;
    zip_code: string;
    is_default: boolean;
}

CRUD Operations

All address operations are in src/services/addresses.service.ts:

getAddresses(customerId)

Returns all addresses for the authenticated customer. Used by useAddresses() hook with query key ['addresses'].

createAddress(data)

Inserts a new address. If is_default: true, the service first clears the default flag on all other addresses of the same type.

updateAddress(id, data)

Partial update on an existing address row.

deleteAddress(id)

Deletes the address. The Addresses page shows a confirmation dialog before deletion.
setDefault(addressId, customerId, type) — Sets a specific address as the default for its type ('shipping' or 'billing'), clearing all other defaults for that type.

useAddresses() Hook

import { useAddresses } from '@/hooks/useAddresses';

const { data: addresses, isLoading } = useAddresses();
// Query key: ['addresses']
// Reads customer ID internally from useAuth().user.id

Loyalty Tier Badges

The Profile page prominently displays the customer’s current loyalty tier using the LoyaltyBadge component (src/components/loyalty/LoyaltyBadge.tsx).

Tier Definitions

TierMinimum SpentBadge ColorBenefits
bronze$0 MXNCopperBase earn rate
silver$5,000 MXNSilver5% discount, free shipping above $1,000
gold$20,000 MXNGold10% discount, free shipping always
platinum$50,000 MXNPlatinum15% discount, express shipping, VIP access
// The tier field from CustomerProfile (src/types/customer.ts):
tier: 'bronze' | 'silver' | 'gold' | 'platinum';
Tier thresholds are configurable from the admin panel via store_settings and the loyalty_config JSON field. The defaults are defined in src/lib/domain/loyalty.ts as LOYALTY_TIERS.
Progress toward the next tier is calculated by getProgressToNextTier(totalSpent) from loyalty.service.ts, which returns:
{
    currentTier: Tier;
    nextTier: Tier;
    progress: number;      // 0–100 percentage
    remaining: number;     // MXN amount remaining to next tier
}

Personal Statistics (/stats)

The Stats page (src/pages/Stats.tsx) displays aggregated purchase statistics for the authenticated customer.
import { useStats } from '@/hooks/useStats';

const { data: stats, isLoading } = useStats();
// Query key: ['stats']
// Backed by stats.service.ts which queries customer order history
Typical stats shown include total orders, total amount spent, average order value, most purchased products, and purchase frequency.

Notifications (/notifications)

The Notifications page (src/pages/user/Notifications.tsx) renders the in-app notification history from the Zustand notifications.store.ts:
interface NotificationsState {
    notifications: Notification[];  // Max 50, LIFO order
    addNotification(n: Notification): void;
    removeNotification(id: string): void;
    markAsRead(id: string): void;
    markAllAsRead(): void;
    clearAll(): void;
}
Accessed via useNotification() hook (src/hooks/useNotification.ts). Notifications are in-memory only — they reset on page refresh.

Build docs developers (and LLMs) love