The SansiStore shopping cart provides a persistent, real-time purchasing flow that works for both guest and authenticated buyers. Guest items are stored inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/ProcesosAgilesUMSS/sansistore/llms.txt
Use this file to discover all available pages before exploring further.
localStorage; upon sign-in they are automatically synced to Firestore. The cart page at /carrito lists all items, shows live price and stock changes, allows quantity edits and item removal, and guides the buyer through a multi-step checkout ending in order creation.
Checkout Flow
View Cart
Navigate to
/carrito. The <CartView> component loads itemsWithProducts from the CartContext, which reads the authenticated user’s users/{uid}/cartItems subcollection (or localStorage for guests) and enriches each item with live product and inventory data.Review Items
Each
<CartItemRow> shows the product image, name, unit price (with a strikethrough of the original price-at-add if the price changed), stock-aware quantity controls (+/−), and a remove button. The payment summary sidebar animates the running total with <AnimatedAmount>.Confirm Order (Login Gate)
Clicking Confirmar pedido checks authentication. Unauthenticated users see
<LoginModal> prompting them to sign in before continuing. Only users with the comprador role can proceed.Select Delivery Location
<LocationSelectorModal> subscribes to users/{uid}/locations in real time via subscribeToUserLocations(). The buyer selects a saved address; if none exist, a link to /ubicaciones is shown to add one. The default location is pre-selected.Confirm Payment
<PaymentConfirmModal> shows the selected location, the final total, and asks the buyer to confirm. The payment method is initialized as cash_on_delivery at order creation and updated later by the seller.Cart State Management
Cart state is managed with Nanostores (src/features/cart/store/cartStore.ts). Two atoms drive the cart badge in the navbar:
CartContext (src/features/cart/components/CartContext.tsx) provides the full cart state and actions to all React components below the <CartProvider> boundary:
Firestore Cart Structure
Cart items for authenticated users live in theusers/{uid}/cartItems subcollection. Each document ID equals the productId.
Key Firestore Operations
localStorage cart is merged with any existing Firestore cart and the result is written back to Firestore atomically.
Real-Time Price and Stock Checks
CartView uses getUserCartItems() which re-fetches the live products and inventory documents for each cart item on every load. It computes:
Price Change
When the live price differs from
priceAtAdd, a warning banner reads “N producto(s) cambió de precio. Revisa el total antes de confirmar.” The summary shows both the old (strikethrough) and new prices.Out of Stock
When
stockAvailable drops to zero between cart add and checkout, the row shows “Sin stock disponible.” and the Confirmar pedido button is disabled until the item is removed.Product Inactive
If
product.active === false or inventory.enabled === false, the availability message reads “El producto ya no está activo.” or “El producto no está disponible para venta.”Invalid Price
If the computed
unitPrice is 0 or negative, the message is “El producto no tiene un precio válido.”Order Creation
createOrder() (src/features/cart/services/orderService.ts) performs all writes in a single Firestore writeBatch:
orders/{orderId}— the order document (see field reference below)orders/{orderId}/orderItems/{itemId}— one document per included cart iteminventory/{productId}—stockReserved += quantityfor each itempayments/{paymentCode}— initial payment record withstatus: 'PENDIENTE'
Order ID Format
Order IDs are generated as{uuidv4}_{zBase32Label}:
secret field is a 4-digit shuffled PIN generated client-side, used to allow anonymous order status lookups without requiring sign-in.
Firestore Data Model
users/{uid}/cartItems subcollection
| Field | Type | Description |
|---|---|---|
cartItemId | string | Same as productId (document ID) |
userId | string | Firebase Auth UID of the cart owner |
productId | string | Reference to products collection |
quantity | number | Integer ≥ 1 |
updatedAt | Timestamp | serverTimestamp() on every upsert |
priceAtAdd | number? | Price captured when item was added; used for price-change detection |
payments collection
| Field | Type | Description |
|---|---|---|
paymentId | string | Same as orderId |
orderId | string | Reference to the order |
amount | number | Order total in Bolivianos |
method | string | cash_on_delivery (default); seller updates to final method |
status | string | PENDIENTE → PAGADO after seller validation |
registeredBy | string | Buyer’s uid |
registeredAt | Timestamp | Creation time |
Payment methods recognized by the system include EFECTIVO (cash on delivery), QR, TRANSFERENCIA, and TARJETA. The method is recorded in the
payments document when the seller validates payment.End-to-End Tests
Cart behavior is covered by Playwright tests intests/cart/cart.spec.ts: