Pular para o conteúdo principal

Gamification Module

O template integra o SDK @cactus-agents/lotus-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
// ...
}