Cart (Carrinho)
Componentes de carrinho de compras e cupom. Requerem CartProvider.
CartProvider
Envolva a árvore que usa Cart, Coupon ou TicketQuantityController com CartProvider. O estado do cupom é mantido aqui e usado pelo Cart para calcular descontos.
- Props:
initialCoupon: CouponProps | null– obrigatório. Cupom inicial; usenullquando não houver cupom (ex.: início da compra).
<CartProvider initialCoupon={null}>
<Cart platformFee={platformFee} feeType="DIGITAL">
{({ totalPrice, items, clearCart }) => (
// ...
)}
</Cart>
</CartProvider>Cart
Carrinho de compras com cálculos automáticos de preços, taxas e descontos. Requer CartProvider.
💡 Importante: O componente
Cartcalcula automaticamente todos os valores financeiros do carrinho. Você não precisa fazer cálculos manualmente — apenas use os valores retornados nas render props.
import { Cart, CartProvider } from '@meaple-com/react-headless-components';
function ShoppingCart({ platformFee }: { platformFee?: PlatformFeeData }) {
return (
<CartProvider initialCoupon={null}>
<Cart platformFee={platformFee} feeType="DIGITAL">
{({ totalPrice, totalAmount, items, clearCart }) => (
<div>
<h2>Carrinho</h2>
<p>Itens: {totalAmount}</p>
<p>Total: R$ {totalPrice.toFixed(2)}</p>
{items.map(item => (
<div key={item.id}>
{item.name} - {item.amount}x R$ {item.price}
</div>
))}
<button onClick={clearCart}>Limpar</button>
</div>
)}
</Cart>
</CartProvider>
);
}- Props:
feeType?: 'POS' | 'DIGITAL'– tipo de taxa (padrão:'DIGITAL').platformFee?: PlatformFeeData– configuração de taxas da plataforma (opcional; se omitido,totalFeeerawFeeAmountserão 0).
Render props (todos os valores são calculados automaticamente):
items: ItemProps[]– itens no carrinho (ingressos/produtos).totalAmount: number– quantidade total de itens no carrinho (soma de todas as quantidades).rawPrice: number– preço bruto (soma depreço × quantidadede cada item, sem taxas ou descontos).totalDiscount: number– desconto total aplicado (calculado automaticamente com base nos cupons e regras de desconto).rawFeeAmount: number– taxa bruta calculada (antes de aplicar mínimos e thresholds).totalFee: number– taxa final da plataforma (consideraminFeeAmountethresholdAmountse configurados).totalPrice: number– preço final a pagar (rawPrice - totalDiscount + totalFee).clearCart(): void– limpa o carrinho.
Coupon
Aplicar cupom de desconto. Requer CartProvider.
import { Coupon, CartProvider } from '@meaple-com/react-headless-components';
function CouponSection({ eventId }: { eventId: string }) {
return (
<CartProvider initialCoupon={null}>
<Coupon eventId={eventId}>
{({
coupon,
applyCoupon,
clearCoupon,
isCheckingCoupon,
couponError,
isCouponValid,
checkCoupon,
currentCouponCode,
setCouponCode
}) => (
<div>
{coupon ? (
<div className="bg-green-100 p-4 rounded">
<p className="font-semibold">Cupom aplicado: {coupon.code}</p>
<p>Desconto: {coupon.type === 'PERCENTAGE' ? `${coupon.value}%` : `R$ ${coupon.value.toFixed(2)}`}</p>
<button
onClick={clearCoupon}
className="mt-2 px-3 py-1 bg-red-500 text-white rounded"
>
Remover
</button>
</div>
) : (
<div className="space-y-2">
<input
type="text"
value={currentCouponCode || ''}
onChange={e => setCouponCode(e.target.value)}
placeholder="Código do cupom"
className="border rounded px-3 py-2 w-full"
onKeyPress={e => {
if (e.key === 'Enter') {
checkCoupon(currentCouponCode || '');
}
}}
/>
<button
onClick={() => checkCoupon(currentCouponCode || '')}
disabled={isCheckingCoupon || !currentCouponCode}
className="px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
>
{isCheckingCoupon ? 'Verificando...' : 'Aplicar Cupom'}
</button>
{couponError && (
<p className="text-red-500 text-sm">
{couponError.message || 'Cupom inválido'}
</p>
)}
</div>
)}
</div>
)}
</Coupon>
</CartProvider>
);
}- Props:
eventId: string– ID do evento (para validar o cupom na API).options?– opções do hookuseCheckCoupon(React Query).
Render props:
- coupon?: CouponProps – cupom aplicado (contém
code,value,type,ticketIds, etc.). - isCheckingCoupon: boolean – estado de verificação.
- couponError?: Error – erro ao validar o cupom.
- isCouponValid: boolean – indica se o cupom atual é válido.
- currentCouponCode: string | undefined – código digitado.
- setCouponCode(code: string) – atualiza o código digitado.
- checkCoupon(code: string) – verifica o cupom na API e aplica ao carrinho em caso de sucesso.
- applyCoupon(coupon: CouponProps | null) – define o cupom no carrinho (uso avançado).
- clearCoupon() – remove o cupom.
Método Core: coupon.check — veja o exemplo de resposta no Core.
TicketQuantityController
Controla quantidade de ingressos no carrinho. Recebe o objeto do ingresso (ex.: retornado por ListEventTickets).
import { TicketQuantityController, CartProvider } from '@meaple-com/react-headless-components';
import type { TicketProps } from '@meaple-com/types';
function TicketSelector({ ticket }: { ticket: TicketProps }) {
return (
<CartProvider initialCoupon={null}>
<TicketQuantityController ticket={ticket}>
{({ amount, increment, decrement, isMaxLimitReached, disabled }) => (
<div>
<button onClick={decrement} disabled={amount === 0 || disabled}>-</button>
<span>{amount}</span>
<button onClick={increment} disabled={isMaxLimitReached}>+</button>
</div>
)}
</TicketQuantityController>
</CartProvider>
);
}- Props:
ticket– objeto do ingresso comid,name,price,type,minBuy?,maxBuy?,availableAmount(TicketProps).disabled?: boolean– desabilita incremento/decremento.onSoldOut?: () => void– callback quando atinge o limite disponível ao incrementar.
Render props:
- amount: number – quantidade atual no carrinho.
- increment: () => void – incrementa a quantidade (respeita
minBuy). - decrement: () => void – decrementa a quantidade.
- isMaxLimitReached: boolean – se o limite máximo (maxBuy/availableAmount) foi atingido.
- disabled: boolean – se o controle está desabilitado (ex.: sem estoque).