Pular para o conteúdo principal

Gamification Module

O template integra o SDK @cactus-agents/gamification com Smartico como provider de gamificação. A abordagem é híbrida: UI nativa (React) para listagens e detalhes, widgets overlay do Smartico para interações que não justificam UI própria.

Configuração

gamification.config.ts

Arquivo principal de configuração client-side:

export const gamificationConfig: GamificationConfig = {
enabled: true,
provider: 'smartico',
smartico: {
libraryUrl: 'https://libs.smartico.ai/...',
labelKey: '',
brandKey: '',
visitorLabelKey: '',
visitorBrandKey: '',
allowLocalhost: true,
enableDebug: false,
requestPush: false,
},
naming: { programName: 'VIP', coinsName: 'coins' },
modules: {
missions: { enabled: true, native: true },
tournaments: { enabled: true, native: true },
store: { enabled: true, native: true },
miniGames: { enabled: true, native: true },
levels: { enabled: true, native: true },
profile: { enabled: true },
notifications: { enabled: true, native: true },
badges: { enabled: true, native: true },
bonuses: { enabled: true, native: true },
jackpots: { enabled: true, native: true },
raffles: { enabled: true, native: true },
},
};

O hook useGamificationConfig() vive em app/hooks/useGamificationConfig.ts e usa o config estático (base ou override da brand):

import { useGamificationConfig } from '~/hooks/useGamificationConfig';

const config = useGamificationConfig();

O hook verifica se as keys obrigatórias do Smartico estão configuradas (labelKey ou visitorLabelKey). Se não estiverem, enabled é forçado para false — impedindo que o SDK carregue e que a UI renderize elementos de gamificação.

O hook useGamificationEnabled() também vive no mesmo arquivo:

import { useGamificationEnabled } from '~/hooks/useGamificationConfig';

const enabled = useGamificationEnabled(); // true se config.enabled && keys configuradas

Os arquivos podem ser sobrescritos por brand em:

  • overrides/<brand-key>/app/config/gamification/gamification.ts
  • overrides/<brand-key>/app/config/gamification/gamification.server.ts

<brand-key> vem de ORIGIN_DOMAIN normalizado.

gamification.server.config.ts

Configuração server-side para geração do hash de autenticação. Exporta o objeto smarticoHashConfig:

import { smarticoHashConfig } from '~/config/gamification.server.config';

// smarticoHashConfig.saltKey — usado apenas como fallback
cuidado

A saltKey é um segredo server-side e não deve ser commitada nos arquivos de override. Em vez disso, use a variável de ambiente SMARTICO_SALT_KEY.

Prioridade de resolução da saltKey:

  1. SMARTICO_SALT_KEY via env var da Cloudflare (secret)
  2. SMARTICO_SALT_KEY via process.env (dev local / .dev.vars)
  3. smarticoHashConfig.saltKey do config file (fallback — normalmente vazio)

Inicialização

O componente SmarticoInitializer é montado no layout e gerencia todo o ciclo de vida:

SmarticoInitializer
├── 1. Carrega script Smartico dinamicamente
├── 2. Inicializa SDK com labelKey/brandKey
├── 3. Aguarda sdkReady + auth.hydrated
├── 4a. Autenticado:
│ ├── Identifica via hash MD5 (do loader)
│ ├── Carrega: profile, missions, badges, tournaments,
│ │ storeItems, miniGames, levels, currentLevel,
│ │ bonuses, jackpots, raffles, inboxUnread, translations
│ └── Aplica resolveTranslations (i18n Smartico)
└── 4b. Visitante:
├── Inicializa via vapi()
├── Carrega: missions, tournaments, storeItems, miniGames,
│ levels, jackpots, raffles, translations
└── Aplica resolveTranslations

Hash server-side

No _layout.tsx loader, o hash é gerado e passado ao client. O cf (Cloudflare env) é passado para que a função priorize a env var SMARTICO_SALT_KEY:

const cf = context?.cloudflare?.env;
// ...
const smarticoHash = generateSmarticoUserHash(String(auth.user.id), cf);
// Passado via loaderData para SmarticoInitializer

Internamente, generateSmarticoUserHash resolve a saltKey com prioridade:

  1. cf.SMARTICO_SALT_KEY — env var Cloudflare
  2. process.env.SMARTICO_SALT_KEY — env var Node (.dev.vars)
  3. smarticoHashConfig.saltKey — config file (fallback)

Módulos (enabled / native)

Cada módulo pode ser controlado via flags:

  • enabled: false — módulo completamente desativado (sem botão, sem página)
  • enabled: true, native: true — UI React própria (páginas de gamificação, modais)
  • enabled: true, native: false — widget overlay Smartico (dp:gf_*)

Comportamento na sidebar

  • native: true → botão navega via routeHref("gamification.missions"), routeHref("gamification.tournaments"), etc.
  • native: false → botão abre window._smartico.dp(WidgetAction.MISSIONS) diretamente

Comportamento no user menu

Mesma lógica: native: true navega, native: false abre widget.

Modo visitante

Páginas de listagem funcionam sem login (dados via vapi). Ao tentar abrir detalhe de uma missão ou torneio, redireciona para modal de login.

Rotas

Os paths abaixo são os defaults — configuráveis via Route Registry (~/config/routes.paths). Use routeHref() para gerar links.

ChavePath padrãoDescrição
gamification/vipHub de gamificação
gamification.missions/vip/missionsListagem de missões com filtros
gamification.tournaments/vip/tournamentsListagem de torneios com filtros
gamification.tournament/vip/tournaments/:idDetalhe de torneio (leaderboard, prêmios)
gamification.store/vip/storeLoja com filtros
gamification.miniGames/vip/mini-gamesListagem de mini-games
gamification.levels/vip/levelsTimeline de progresso com perfil lateral
gamification.badges/vip/badgesListagem de badges
gamification.bonuses/vip/bonusesListagem de bônus
user.notifications/user/notificationsInbox nativo (mensagens expandidas, marcar lidas)

Todas registradas em routes.config.ts via routePattern().

Componentes

Layout

  • SmarticoInitializer — inicialização do SDK (montado no layout)
  • SidebarVipButtons — botões highlight no topo da sidebar (torneios, missões)
  • HeaderUserArea — menu VIP no dropdown do usuário (perfil, avatar, coins, nível)

Sections

  • GamificationSection — seção genérica (título + grid + skeleton + empty state)
  • GamificationFilters — tabs + busca para páginas VIP
  • MissionsSection / TournamentsSection / MiniGamesSection — listagens específicas
  • InboxSection — notificações com corpos expandidos, status (lida/não lida), ações

Cards

TournamentCard, MissionCard, MiniGameCard, StoreItemCard, BadgeCard, JackpotCard, etc.

Modais

  • MissionDetailModal — detalhe de missão com opt-in

Habilitando/desabilitando

Para desativar um módulo, basta alterar o flag em gamification.config.ts:

modules: {
missions: { enabled: true, native: true },
tournaments: { enabled: false }, // desativado
// ...
}