diff --git a/marketplace/src/pages/Cart.tsx b/marketplace/src/pages/Cart.tsx
index a2b9019..81cd0a3 100644
--- a/marketplace/src/pages/Cart.tsx
+++ b/marketplace/src/pages/Cart.tsx
@@ -2,7 +2,17 @@ import { ShoppingBasket } from 'lucide-react'
import { Link } from 'react-router-dom'
import { Shell } from '../layouts/Shell'
import { selectGroupedCart, selectCartSummary, useCartStore } from '../stores/cartStore'
-import { formatCurrency } from '../utils/format'
+import { formatCents } from '../utils/format'
+
+// Debug logging for price values
+const logPrice = (label: string, value: number | undefined) => {
+ console.log(`%c🛒 [Cart] ${label}:`, 'color: #10B981; font-weight: bold', {
+ rawValue: value,
+ inCents: value,
+ inReais: value ? (value / 100).toFixed(2) : '0.00',
+ formatted: value ? formatCents(value) : 'N/A'
+ })
+}
export function CartPage() {
const items = useCartStore((state) => state.items)
@@ -27,7 +37,9 @@ export function CartPage() {
{!isEmpty && (
Itens: {summary.totalItems}
-
R$ {formatCurrency(summary.totalValue)}
+ {/* Log total value */}
+ {(() => { logPrice('Total do carrinho', summary.totalValue); return null })()}
+
{formatCents(summary.totalValue)}
)}
@@ -81,7 +93,9 @@ export function CartPage() {
Preço
-
R$ {formatCurrency(item.unitPrice)}
+ {/* Log unit price */}
+ {(() => { logPrice(`Preço unitário ${item.name}`, item.unitPrice); return null })()}
+
{formatCents(item.unitPrice)}
Subtotal
+ {/* Log subtotal */}
+ {(() => { logPrice(`Subtotal ${item.name} (${item.quantity}x)`, item.quantity * item.unitPrice); return null })()}
- R$ {formatCurrency(item.quantity * item.unitPrice)}
+ {formatCents(item.quantity * item.unitPrice)}
diff --git a/marketplace/src/stores/cartStore.test.ts b/marketplace/src/stores/cartStore.test.ts
index 7161cef..77ebab2 100644
--- a/marketplace/src/stores/cartStore.test.ts
+++ b/marketplace/src/stores/cartStore.test.ts
@@ -198,3 +198,129 @@ describe('selectors', () => {
})
})
})
+
+/**
+ * PRICE CONVERSION TESTS
+ * These tests verify that prices are handled correctly in CENTS
+ * The API returns price_cents (e.g., 819 = R$ 8,19)
+ */
+describe('price conversion (cents)', () => {
+ const mockItemCents: Omit = {
+ id: 'prod-cents-1',
+ name: 'Paracetamol 750mg',
+ activeIngredient: 'Paracetamol',
+ lab: 'EMS',
+ batch: 'L2025840',
+ expiry: '2027-09-15',
+ vendorId: 'vendor-anapolis',
+ vendorName: 'Anápolis/GO',
+ unitPrice: 819 // 819 cents = R$ 8,19
+ }
+
+ const mockItemCents2: Omit = {
+ id: 'prod-cents-2',
+ name: 'Dipirona 500mg',
+ activeIngredient: 'Dipirona',
+ lab: 'Medley',
+ batch: 'L2025123',
+ expiry: '2026-06-30',
+ vendorId: 'vendor-anapolis',
+ vendorName: 'Anápolis/GO',
+ unitPrice: 1299 // 1299 cents = R$ 12,99
+ }
+
+ beforeEach(() => {
+ useCartStore.setState({ items: [] })
+ })
+
+ describe('storing prices in cents', () => {
+ it('should store unitPrice as cents (819 = R$ 8,19)', () => {
+ useCartStore.getState().addItem(mockItemCents)
+
+ const state = useCartStore.getState()
+ expect(state.items[0].unitPrice).toBe(819)
+ // Verify it's NOT stored as reais (8.19)
+ expect(state.items[0].unitPrice).not.toBe(8.19)
+ })
+
+ it('should preserve cents precision for subtotal calculation', () => {
+ useCartStore.getState().addItem(mockItemCents, 3)
+
+ const state = useCartStore.getState()
+ const item = state.items[0]
+ const subtotal = item.quantity * item.unitPrice
+
+ // 3 * 819 = 2457 cents = R$ 24,57
+ expect(subtotal).toBe(2457)
+ expect(subtotal / 100).toBe(24.57)
+ })
+ })
+
+ describe('cents calculations in selectors', () => {
+ it('should calculate vendor total in cents', () => {
+ // 819 cents * 2 = 1638 cents
+ useCartStore.getState().addItem(mockItemCents, 2)
+ // 1299 cents * 1 = 1299 cents
+ useCartStore.getState().addItem(mockItemCents2, 1)
+
+ const state = useCartStore.getState()
+ const groups = selectGroupedCart(state)
+
+ // Total: 1638 + 1299 = 2937 cents = R$ 29,37
+ expect(groups['vendor-anapolis'].total).toBe(2937)
+ expect(groups['vendor-anapolis'].total / 100).toBeCloseTo(29.37)
+ })
+
+ it('should calculate cart summary total in cents', () => {
+ useCartStore.getState().addItem(mockItemCents, 2) // 1638 cents
+ useCartStore.getState().addItem(mockItemCents2, 1) // 1299 cents
+
+ const state = useCartStore.getState()
+ const summary = selectCartSummary(state)
+
+ expect(summary.totalItems).toBe(3)
+ expect(summary.totalValue).toBe(2937) // cents
+ expect(summary.totalValue / 100).toBeCloseTo(29.37) // reais
+ })
+ })
+
+ describe('edge cases for cents', () => {
+ it('should handle single unit correctly', () => {
+ useCartStore.getState().addItem(mockItemCents, 1)
+
+ const state = useCartStore.getState()
+ const summary = selectCartSummary(state)
+
+ expect(summary.totalValue).toBe(819)
+ expect(summary.totalValue / 100).toBe(8.19)
+ })
+
+ it('should handle large quantities without overflow', () => {
+ useCartStore.getState().addItem(mockItemCents, 1000)
+
+ const state = useCartStore.getState()
+ const summary = selectCartSummary(state)
+
+ // 819 * 1000 = 819000 cents = R$ 8,190.00
+ expect(summary.totalValue).toBe(819000)
+ expect(summary.totalValue / 100).toBe(8190)
+ })
+
+ it('should handle small cent values (R$ 0,01)', () => {
+ const cheapItem: Omit = {
+ ...mockItemCents,
+ id: 'cheap-1',
+ unitPrice: 1 // 1 cent = R$ 0,01
+ }
+
+ useCartStore.getState().addItem(cheapItem, 10)
+
+ const state = useCartStore.getState()
+ const summary = selectCartSummary(state)
+
+ expect(summary.totalValue).toBe(10) // 10 cents
+ expect(summary.totalValue / 100).toBe(0.10)
+ })
+ })
+})
+
diff --git a/marketplace/src/stores/cartStore.ts b/marketplace/src/stores/cartStore.ts
index bea9d87..73a4194 100644
--- a/marketplace/src/stores/cartStore.ts
+++ b/marketplace/src/stores/cartStore.ts
@@ -10,7 +10,7 @@ export interface CartItem {
expiry: string
vendorId: string
vendorName: string
- unitPrice: number
+ unitPrice: number // Price in CENTS (e.g., 819 = R$ 8,19)
quantity: number
}
@@ -23,14 +23,31 @@ interface CartState {
clearAll: () => void
}
+// Debug logging for cart operations
+const logCartOp = (operation: string, data: Record) => {
+ console.log(`%c🛒 [CartStore] ${operation}`, 'color: #8B5CF6; font-weight: bold', data)
+}
+
export const useCartStore = create()(
persist(
(set, get) => ({
items: [],
addItem: (item, quantity = 1) => {
+ // Log the incoming item with price details
+ logCartOp('addItem', {
+ id: item.id,
+ name: item.name,
+ unitPrice: item.unitPrice,
+ unitPriceInReais: (item.unitPrice / 100).toFixed(2),
+ quantity,
+ subtotalCents: item.unitPrice * quantity,
+ subtotalReais: ((item.unitPrice * quantity) / 100).toFixed(2)
+ })
+
set((state) => {
const exists = state.items.find((i) => i.id === item.id)
if (exists) {
+ logCartOp('addItem - updating existing', { existingQty: exists.quantity, newQty: exists.quantity + quantity })
return {
items: state.items.map((i) =>
i.id === item.id ? { ...i, quantity: i.quantity + quantity } : i
@@ -40,14 +57,24 @@ export const useCartStore = create()(
return { items: [...state.items, { ...item, quantity }] }
})
},
- updateQuantity: (id, quantity) =>
+ updateQuantity: (id, quantity) => {
+ logCartOp('updateQuantity', { id, newQuantity: quantity })
set((state) => ({
items: state.items.map((i) => (i.id === id ? { ...i, quantity } : i))
- })),
- removeItem: (id) => set((state) => ({ items: state.items.filter((i) => i.id !== id) })),
- clearVendor: (vendorId) =>
- set((state) => ({ items: state.items.filter((i) => i.vendorId !== vendorId) })),
- clearAll: () => set({ items: [] })
+ }))
+ },
+ removeItem: (id) => {
+ logCartOp('removeItem', { id })
+ set((state) => ({ items: state.items.filter((i) => i.id !== id) }))
+ },
+ clearVendor: (vendorId) => {
+ logCartOp('clearVendor', { vendorId })
+ set((state) => ({ items: state.items.filter((i) => i.vendorId !== vendorId) }))
+ },
+ clearAll: () => {
+ logCartOp('clearAll', {})
+ set({ items: [] })
+ }
}),
{
name: 'mp-cart-storage',