Wallet
Carteira, bonus, cashback, rollover e historico de transacoes no template.
:::danger @cactus-agents/wallet nao existe mais
O pacote foi deletado (core 452450e, 2026-04-17) e unificado em @cactus-agents/accounts, junto com auth e user. Nenhum import … from "@cactus-agents/wallet" resolve.
- Tipos e transforms (
Wallet,RealWallet,BonusWallet,CashbackWallet,Rollover,Transaction,TransactionFilter) →@cactus-agents/accounts - Estado e hooks React (
useAccountsStore,useWallet,useRollover,useTransactions, …) →@cactus-agents/accounts/react
Ver SDK — accounts. :::
Onde vive o estado
Nao existe app/store/wallet.ts, app/hooks/useWallet.ts nem app/utils/walletRefresh.client.ts no template. Todo o estado de carteira e owned pelo core, em useAccountsStore:
// campos relevantes de AccountsState (@cactus-agents/accounts/react)
interface AccountsState {
wallet: WalletData | null;
isLoading: boolean;
error: Error | null;
transactions: Transaction[];
transactionsRaw: TransactionResponseRaw | null;
transactionsMeta: TransactionsMeta | null;
transactionsLoading: boolean;
transactionsFilter: TransactionFilter;
// moedas (brands dual-currency)
activeCoinId: CoinId | null;
coinBalances: Record<CoinId, number> | null;
// actions
setWallet(data: WalletData | null): void;
refetchWallet(opts?: { force?: boolean }): Promise<void>;
fetchTransactions(filter?: TransactionFilter): Promise<void>;
transferBonus(): Promise<void>;
transferCashback(): Promise<void>;
}
O que o base possui e apenas o estado de UI dos modais:
// app/store/walletModal.ts
export type WalletModalType = "bonus-withdraw" | "bonus-rules" | "cashback-redeem" | null;
export const useWalletModalStore = create<WalletModalState>((set) => ({
walletModal: null,
openWalletModal: (modal) => set({ walletModal: modal }),
closeWalletModal: () => set({ walletModal: null }),
}));
Hooks (@cactus-agents/accounts/react)
| Hook | Retorno |
|---|---|
useWallet() | { wallet, isLoading, error, refetch } |
useRealBalance() / useBonusBalance() / useCashbackBalance() | { balance, isLoading, error, refetch } — balance ja formatado |
useWalletFlags() | { hasReal, hasBonus, hasCashback, hasFirstDeposit } |
useRollover() | { rollover, accomplished, isLoading } |
useTransactions() | { transactions, meta, isLoading, filter, fetch, raw } |
useTransferBonus() / useTransferCashback() | { transfer, isLoading, error } |
useRefreshWallet() | (opts?: { force?: boolean }) => Promise<void> |
useWithdrawReceipt(withdrawId) | { receipt, isLoading, error } — PDF base64, auto-fetch |
useFormatMoney() | (value: number) => string |
Exemplo real, da propria pagina de carteira:
import {
useFormatMoney,
useRefreshWallet,
useRollover,
useTransactions,
useWallet,
} from "@cactus-agents/accounts/react";
import { useWalletModalStore } from "~/store/walletModal";
const { wallet, isLoading: walletLoading } = useWallet();
const { rollover, accomplished: rolloverAccomplished } = useRollover();
const formatMoney = useFormatMoney();
const updateWallet = useRefreshWallet();
const { transactions, filter: txFilter, fetch: fetchTx } = useTransactions();
const openWalletModal = useWalletModalStore((s) => s.openWalletModal);
:::tip Formate dinheiro so com useFormatMoney()
Ele resolve locale + currency + displayDecimalDigits (0 pra NGN/CLP, 2 pras demais) a partir da config do accounts, e reage a troca de moeda nas brands dual-currency. Nao use Intl.NumberFormat({ style: "currency" }) a mao nem ~/utils/money em componentes React.
useTransactions() ja devolve amountFormatted (valor absoluto formatado) em cada transacao — use amount apenas pra logica de sinal.
:::
useRefreshWallet() e o TTL
O refresh aplica memoize de 2s + dedup de in-flight. Chamadas passivas (botao de reload, listeners, hooks de mount) devem omitir opcoes, pra que gatilhos quase simultaneos colapsem numa unica chamada ao BFF.
Passe { force: true } depois de uma mutacao que mudou o estado da carteira: deposito, saque, aposta, transferencia de bonus/cashback.
API Routes
| Rota | Descricao |
|---|---|
api/wallet/refresh | Refresh completo (saldo + rollover) |
api/wallet/transactions | Transacoes paginadas com filtros |
api/wallet/action | Transfer bonus/cashback |
api/wallet/receipt | Comprovante de saque |
Os adapters HTTP default do accounts apontam pra essas rotas; a brand pode sobrescrever via AccountsConfig na inicializacao. Erros seguem proxyErrorResponse() + unauthorizedNoToken() — ver Services.
Paginas
| Chave | Path padrao | Descricao |
|---|---|---|
user.wallet | /user/wallet | Cards de saldo + rollover + atividade recente |
user.history | /user/history | Historico unificado: transacoes e login, com filtro e paginacao |
:::warning Nao existe /user/wallet/transactions
O historico de transacoes foi unificado com o historico de login em user.history (routes/user/history.tsx). Os filtros disponiveis hoje sao deposit, withdraw, sports, casino, coupon, bonus, cashback, login e full.
:::
A store de transacoes e unica e compartilhada entre /user/wallet e /user/history. A pagina de carteira compara o filter do ultimo fetch (exposto pelo hook) com a query dela mesma antes de renderizar o bloco de atividade recente — sem isso, remontar a pagina esconderia o bloco a cada navegacao.
Componentes
Em app/components/user/wallet/ — lista viva, consulte o diretorio.
Cards de saldo
RealWalletCard— saldo real com botao de depositoBonusWalletCard— saldo bonus + progresso do rolloverCashbackWalletCard— saldo cashback com botao de resgate
Historico
WalletRecentActivity— bloco de atividade recente na pagina de carteiraTransactionCard/TransactionCardSkeleton(emapp/components/user/) — item de transacaoPagination— navegacao de paginasLoginCardSkeleton(emapp/components/user/) — skeleton do historico de login
Modais
BonusWithdrawModal— confirmacao de transferencia bonus → realBonusRulesModal— regras do bonus ativoCashbackRedeemModal— confirmacao de resgate de cashbackWithdrawDetailsModal— comprovante de saque (usauseWithdrawReceipt)
Outros
WalletInitializer(app/components/user/WalletInitializer.tsx) — busca a carteira uma vez quando o usuario esta autenticado (login ou reload). Nao renderiza nadaCountdownTimer— timer regressivo (ex.: expiracao de bonus)ProgressBar— barra de progresso do rollover
WalletInitializer — implementacao
import { useAccountsStore, useRefreshWallet } from "@cactus-agents/accounts/react";
export function WalletInitializer() {
const hydrated = useAccountsStore((s) => s.authHydrated);
const isAuthenticated = useAccountsStore((s) => s.isAuthenticated);
const refreshWallet = useRefreshWallet();
// efeito dispara uma vez por sessao autenticada; reseta no logout
}
Ele e montado lazy pelo DefaultLayout e le auth da store, nao de loaderData — o doc SSR e auth-agnostico. Ver State Management.
Restricao de conta
A pagina de carteira consulta useAccountRestriction() (app/hooks/useAccountRestriction.ts, que empacota isAccountRestricted / getAccountRestriction de @cactus-agents/accounts) pra esconder acoes indisponiveis quando a conta esta restrita. Ver User Account.