Changelog - 30/04/2026
Dia muito pesado: 27 PRs no base + 8 PRs no core. O core foi quase todo dedicado a expandir o @cactus-agents/i18n para alimentar a leva grande de novas variants do base (mobile bottom nav, footer-stacked, quick-access menu, side sheets, tournament detail, FTD offer/cashback). No base, o destaque foi a reformulação completa do MobileBottomNav com 4 variantes tipadas, novo primitive CtaButton, footer-stacked do 7k-bet-br e revamp da página de detalhe de torneios.
i18n / Internacionalização
@cactus-agents/i18nrecebeu 4 PRs de chaves novas no mesmo dia (#157, #158, #159, #160), todas em pt-br (autoritativo) + pt + es + en. Cada PR cobre um surface novo do base:mobile_nav.*para variantes de bottom nav,tournaments.*para a tela de detalhe, quick-access menu + side sheets, e footer-stacked.mobile_navexpandido (PR #157, core): dehome/casino/sports/deposit/menupara 13 intents —tournaments,missions,promotions,rewards,referral,wallet,profile,store,slots,withdraw,casino_live,sports_live. Suporta os 4 variants novos doMobileBottomNav(flat, trail-cta, fab-center, illustrated) sem brand precisar declarar namespace próprio.tournaments.*na gamification (PR #158, core): 5 chaves para a revamp da tournament detail —information(título do stats carousel),show_more/show_less(collapse/expand das descrições e tabs),no_players/no_prizes(empty states de ranking e prêmios).- Quick-access menu + side sheets (PR #159, core): chaves nos namespaces
layout,casinoegamificationpara o novo widget+no header e os painéis laterais de Favoritos, Recentes e Notificações usados em 7k-bet-br e cl-bet7k-com. - Footer-stacked (PR #160, core): 14 chaves por locale para o novo variant —
col_doubts,col_vip_games,vip_*,payment_label,download_app_label,back_to_top_cta,central_atendimento. Antes os textos viviam na pastaoverrides/7k-bet-br/app/localese bloqueavam o uso compartilhado entre brands. ftd_offereftd_cashbackno namespacepayments(PRs #152 e #155, core): chaves para o modal de oferta FTD e o fluxo de cashback FTD (D0) —first_modal.*eprize_modal.*. PT-BR neutra e brand-agnostic; PT, ES, EN traduzidos.favorites.empty_*erecently_played.empty_*(PR #153, core): chaves para oEmptyRowPlaceholderquando o usuário tem favoritos/recentes vazios — labels de scroll, aria-labels do botão e variantes com sugestões ao lado.casino:show_filters/hide_filters(PR #438, base via bump i18n ^0.78.0): chaves para o toggle de filtros recolhíveis nas páginas de games.- Normalização "Casino" → "Cassino" para BRA (PR #432, base): hook
useCasinoNomenclatureaplica regex whole-word só quandocountryCode === "BRA"— corrige o fato do BFF retornarnomenclature_for_casino_games = "Casino"(com um 's') que vencia o i18n correto via fallback||. Workaround temporário enquanto o@cactus-agents/brand.transformFeatures()está congelado; outros países (pt-PT, es-ES, en-GB) passam direto porque "Casino" é gramaticalmente correto neles.
Gamificação
- Tournament detail revamp completo (PR #441): a rota
vip/tournaments.$id.tsxpassou de 304 linhas monolíticas para uma composição de 11 componentes novos emapp/components/gamification/tournament-detail/—TournamentHero,RegistrationCTA,TournamentDescription(comshow_more/show_less),TournamentDetailTabs,TournamentStatsCarousel+TournamentStatCard,TournamentPrizesList+PrizeRow,TournamentRankingList, e helpers utilitários. - Sizing dos cards de missão e torneio é configurável por brand via
app/types/mission-card.tseapp/types/tournament-card.tsnovos. Brands 7k-bet-br, cl-bet7k-com declararam owidgets/mission-card.ts+widgets/tournament-card.tspróprios. MissionCardClassic/StackedeTournamentCardClassic/Stackedagora usam o novo primitiveCtaButtonem vez de implementar botão próprio — convergência visual entre cards e signature header.
UI e Componentes
- Novo primitive
CtaButton(PR #431,app/components/ui/cta-button/): substitui implementações ad-hoc de botão CTA emLoginModal,RegisterModal,GameCardClassic,GameIframe,DepositForm,HeaderUserAreae nos cards de missão/torneio. Vem em 2 variants —flat(botão sólido tradicional) esignature(estilo do botão "Depositar" do header 7k com brilho/gradient). Configurável por brand viaapp/config/widgets/cta-button.ts. Cobertura completa de tests (CtaButton.test.tsx,CtaButton.config.test.tsx). MobileBottomNavreescrito do zero como sistema de variants tipado (PR #430): o componente legado (app/components/layout/MobileBottomNav.tsx, 204 linhas) foi removido. Substituído por dispatcher + 4 variants emapp/layouts/variants/mobile-bottom-nav/—MobileBottomNavFlat(5 tiles iguais),MobileBottomNavTrailCta(4 tiles + CTA destacado à direita),MobileBottomNavFabCenter(FAB no centro estilo Material),MobileBottomNavIllustrated(tiles com ilustração). Catálogo de intents typed (intents.ts), resolver com fallback (resolve.ts), specials (specials.ts), handlers compartilhados, plus shared shells (BottomNavShell,CtaPill,FabButton,NavTile,RotatingLabel). Cobertura:resolve.test.ts(102 linhas) +variants.test.tsx(213 linhas).- CTA de depósito alinhado entre header / mobile-nav / game fullscreen (PR #439): o
CtaPilldo mobile-bottom-nav e o overlay doGameIframeagora reaproveitam o variantsignaturedoCtaButton, evitando 3 implementações divergentes do mesmo botão "Depositar". - Filtros do cassino recolhíveis (PR #438): aplicado em
/games,/games/live,/games/category/:sluge/games/providers/:slug. Novo ícone de filtro à esquerda da busca expande/recolhe o bloco de categorias e providers in-place. Mobile e desktop começam com filtros escondidos. - Breadcrumb do detalhe de jogo (PR #434): adicionada etapa "Início" como primeiro link e listagem do provider antes do nome do jogo (
Início > Provider > Jogo).app/components/layout/InternalNavBar.tsxeapp/routes/games/$provider.$game.tsx. StoriesCirclesganha overlay de badge "NEW" (PR #453): novo campobadgeemStoriesConfigcontrolaenabled, asset e índices 1-based dos circles que recebem o ribbon. Asset padrão/assets/stories/new-badge.pngé trocado pelo overrideoverrides/<brand>/public/assets/stories/new-badge.png. Os 14 brand overrides ganharam o blocobadgepreparado (enabled: false); ativado para 7k-bet-br (pt-br) e cl-bet7k-com (es) com items[1, 2].FavoriteButtoneLastGameFloatingWidget(PR #442): correção de SVG fill handling no botão de favoritar e ajustes de layout no widget flutuante de "última jogada".- Quick-access menu + side sheets (PR #445): novo widget
+no header de 7k-bet-br e cl-bet7k-com abre painéis laterais para Favoritos, Recentes e Notificações. Adicionadowidgets/quick-access-menu.tsno override do cl-bet7k-com; rotas e flags propagadas em todos os 14 brand overrides.
Cassino
- Sidebar não roteia mais "Mines" e "Aviator" pro provider errado (PR #437): ambos estavam apontando para o provider Spribe, mas a curadoria desses jogos no catálogo Cactus é via Banana Games. Correção em
app/config/layout/sidebar.tse nos 11 brand overrides afetados. - Item permanente "Mini Games Diários" na sidebar do 7k-bet-br (PR #440): adicionado ao
sidebar-buttonsconfig do 7k. Doc operacional nova emdocs/features/strategy/overview.mdcobrindo a feature. - Rows pessoais (Favoritos / Jogados Recentemente) escondidas quando vazias (PR #436): novo flag
hidePersonalRowsWhenEmptyemfeatures.ts. Quando ativo,FavoritesRoweRecentlyPlayedRowsomem da home se o usuário não tem dado em vez de mostrar empty state. Defaultfalseem todos os 14 overrides; ativado só no 7k-bet-br. Hook novouseRecentlyPlayedSlugsemapp/hooks/.
Pagamentos
- Allow-list de métodos de pagamento por brand + agrupamento de Pix providers (PR #435):
app/config/payments/methods.tseapp/types/payments-config.tsnovos. Brand declara quais métodos aceita; múltiplos providers de Pix são agrupados visualmente noDepositForm. HookusePaymentsganhou +83 linhas para resolver a lista permitida e o agrupamento. - Withdraw "Valor máximo" mostra cap da casa, não saldo do usuário (PR #450): a célula "Máximo" no
WithdrawFormestava puxandoavailableBalancedo user. Trocado para o teto que a casa permite por transação — fim das confusões em saques limitados pela política do operador.
Auth
- Kill-switch front-end
disableSocialAuth(PR #457): nova flag emapp/config/features/auth.ts(type emapp/types/auth-features.ts). Quando ligada, oRegisterModalesconde os botões "Continuar com Google/Facebook" e oSocialAccountsSectionda área de Segurança fica oculto. Propagada para os 14 brand overrides com defaultfalse.
Sports
- Header secundário pode ser renderizado dentro do header sticky em páginas de esportes (PR #469): novo flag em
LayoutConfig+ suporte nos shellsHeaderTopShelleSplitShell. AdicionadosecondaryHeader.stickyInsideHeaderao type. Ativado nooverrides/7k-bet-br/app/config/layout/composition.ts. useSportsAvailableHeightcomResizeObserver(PR #470): substitui o cálculo viauseEffect+window.resizepor observação contínua do header — o iframe do sportsbook se reajusta dinamicamente quando o header secundário muda de altura (ex: quando colapsa em scroll).- SEO copy do sports-seo do 7k removido (PR #466): conteúdo grande de copy SEO comentado em
overrides/7k-bet-br/app/config/seo/sports-seo.tspara revisão futura. Rota de sports continua respondendo, só sem o bloco.
Layout / Footer
- Novo variant
footer-stackedpara 7k-bet-br (PR #454): footer reorganizado em 6 partes empilhadas —FooterStackedMain(com 4 colunas: VIP games, dúvidas, downloads, central de atendimento),FooterStackedHeartRow,FooterStackedSeals,FooterStackedSponsors,FooterStackedPaymentBar,FooterStackedBottomBar,FooterStackedLegal. Inclui novo assetpublic/assets/seals/google-play.png. Config novaapp/config/widgets/footer-socials.tspermite brand declarar quais redes sociais aparecem no footer. topbarNotificationagora é configurável viaLayoutConfig(PR #455): adicionado emoverrides/7k-bet-br/app/config/layout/composition.tspara deixar a barra de notificações controlada pelo composition em vez de hardcoded no shell.- Logo da sidebar do 7k-bet-br (PR #452): redimensionada para 52x24 e alinhada à esquerda.
Brand Overrides
- 7k-bet-br absorveu o grosso do dia:
MobileBottomNavvariant configurada, sidebar-buttons com novo intentstore(item "Loja" como 5º), footer-stacked ligado, topbarNotification no composition, sports header sticky com secondary nav inside, novowidgets/strategy/strategy.tspara o item permanente "Mini Games Diários", logo da sidebar shrunk, stories badge ativado em items[1, 2],hidePersonalRowsWhenEmpty: true,widgets/footer-socials.tsdeclarado. - cl-bet7k-com (chile, es): quick-access menu + side sheets ligados,
widgets/quick-access-menu.tsadicionado, stories badge ativado em items[1, 2],widgets/cta-button.ts,widgets/mission-card.tsewidgets/tournament-card.tsdeclarados. - Propagação file-replacement em todos os 14 overrides (regra dura do brandOverridesPlugin):
hidePersonalRowsWhenEmpty: false,notificationsSheet: { enabled: true },disableSocialAuth: false,widgets/stories.tscombadge.enabled: false, novos paths emroutes/paths.ts,widgets/cta-button.tsopcionais. PR #436 documenta o resolve de conflict entrehidePersonalRowsWhenEmpty(PR atual) enotificationsSheet(stage) em todos os overrides. - Sidebar do cassino corrigida em 11 overrides (
7k-bet-br,betpontobet-bet-br,cassino-bet-br,ng-7k-bet,pb-bet,ph-state77-com,pt-state77-com,rj-bet,state77-com,vera-bet-br,x2b-bet): "Mines" e "Aviator" agora apontam para Banana Games em vez de Spribe. sidebar-buttonsdo 7k-bet-br ganhou intentstoreapontando para a rota canônicagamification.storecom íconeShoppingBag.SidebarButtonIntentvirou união backwards-compatível — outros brands não precisam fazer nada.
Segurança
- Bloqueio de leak cross-user de saldo via cache classification (PR #428): bump de
@cactus-agents/platform-cachepara0.12.0+ 85 linhas novas de classificação noworkers/middleware.ts. Endpoints sensíveis a usuário (saldo, KYC status, transações) agora são marcados explicitamente para nunca atravessar o cache compartilhado da Cloudflare Cache API; só o cache scopado por user-key passa. Resolve incident report do dia anterior onde um usuário viu saldo de outro depois de um cache hit equivocado. - Suporte ao chat Zendesk abre instantâneo (PR #465): removido o
setTimeout(..., 5000)legado douseLiveSupportque segurava o widget por 5s "esperando o script carregar". O script já tem promise própria de ready — o delay extra era redundante e quebrava o UX em sessões de suporte urgentes.
Strategy / Campaigns
strategy-campaign-api.clientrefatorado (PR #448): cliente de Campaign API trocou de fluxo imperativo (init→fetch→dispatch) para uma promise única que devolve user state + campaign manifest.app/store/strategy.tsfica mais enxuto (-26 linhas), tipos simplificados emapp/types/strategy.ts.CampaignWidget.tsxconsome o novo shape direto. Tests atualizados (strategy-campaign-api.client.test.ts: 192 linhas;strategy.test.ts: 71 linhas).
Core / SDK
8 PRs no front-cactus-core no mesmo dia — uma das maiores levas dos últimos 30 dias.
@cactus-agents/i18nganhou 4 PRs consecutivos (#157 → 0.75.0, #158 → 0.78.x, #159 → 0.8x.0, #160 → 0.81.0). Todas as 4 keys-libraries seguem o pattern: pt-br autoritativo, pt + es + en como traduções equivalentes, brand-agnostic. As surfaces cobertas (mobile_nav expandido, tournaments detail, quick-access menu, footer-stacked) liberaram o base para parar de injetar traduções viaapp/locales/overrides/(cumprindo a regra dura do AGENTS.md: traduções novas vão no core, não no base).@cactus-agents/paymentslocales (PRs #152 e #155): namespacesftd_offer.*(4 locales × 15 keys = 60 keys) eftd_cashback.{first_modal,prize_modal}.*adicionados aopackages/i18n/locales/{pt-br,pt,es,en}/payments.json. Alimentam o modal de oferta FTD e o fluxo de cashback FTD (D0) que o base vai shipar nos próximos dias.@cactus-agents/i18ncom chaves de empty state pra Favoritos / Recentes (PR #153):casino.favorites.empty_scroll_label,empty_scroll_label2,empty_scroll_aria,empty_casino_aria+casino.recently_played.empty_scroll_aria. Suporta oEmptyRowPlaceholderdo base nos modos com sugestões ao lado e variant botão.@cactus-agents/brandcom guards de OTP frequente e KYC integration (PR #156):transform/features.tsganhou +50 linhas e bateria de tests (94 linhas embrand.test.ts). A funçãotransformFeaturesagora valida e gateia módulos de OTP frequente e integração KYC vindos do BFF antes de expô-los ao base — evita que feature flag mal-configurada do admin estoure UI no front.
Infra / CI / Deploy
- Deploy
prod-7k-bet-bragora sai da branchmain-7k(PR #458, base): correção em.github/workflows/ci-deploy.yml— antes apontava paramain, o que casava com o staging unificado mas não com o pipeline de produção do 7k que vive numa branch separada. Sem isso, hotfixes do 7k vinham com bundle errado.