Appearance
Dashboard
Visão Geral
A Dashboard (/dashboard) consolida KPIs de membros, finanças, minhas escalas e aniversariantes. Renderizada por DashboardController@index → resources/js/pages/Dashboard.vue.
Gate por Permissão (Opção B)
Cada widget é condicionado a uma permissão Spatie. Usuários recém-cadastrados (sem role atribuída) veem apenas um estado de boas-vindas. Isto é importante porque o auto-cadastro não atribui papéis — os administradores definem a função depois.
| Widget | Permissão | Fonte dos dados |
|---|---|---|
| Membros ativos, Membros por situação, Aniversariantes da semana | member.view | Member::count, query agrupada, GetBirthdayMembersAction |
| Receitas/Despesas/Saldo/Dízimos, Chart Receitas vs Despesas, Top 5 Despesas | finance.view | Transaction |
| Minhas Escalas | próprio membro | ScheduleItem filtrado por member_id do usuário logado |
| Engajamento | feature member_insights_basic + permission member_insights.view_full | MemberEngagementScore |
Estratégia
DashboardController@indexcalcula$canViewMembers/$canViewFinancevia$user->can('...').- Só executa as queries quando a permissão existe — economiza DB round-trips e evita leaks de dados agregados.
- Passa flags (
canViewMembers,canViewFinance) para o Inertia + props na view. Dashboard.vueusav-if="canViewMembers"ev-if="canViewFinance"em cada bloco.- Se usuário não tem nenhuma permissão, nenhum schedule e nenhum engagementWidget, exibe card "Bem-vindo(a) — aguarde sua função ser atribuída".
Avatar no widget de aniversariantes
DashboardController envia avatar_url do membro via getFirstMediaUrl('foto') (collection foto, não avatar). Ver Módulo Membros.
Arquivos
app/Http/Controllers/DashboardController.phpresources/js/pages/Dashboard.vue
Estender
Para adicionar um novo widget gated:
- Definir/reutilizar a permissão em
database/seeders/Production/RoleAndPermissionSeeder.php. - No controller, guardar o cálculo dentro de
if ($user?->can('nova.permission')) { ... }. - Passar a flag no
Inertia::render. - Na view:
<div v-if="canNovaPermissao">...</div>. - Incluir a nova permissão no
hasAnyWidgetcomputed para o empty state não aparecer indevidamente.