Correcao Sidebar Classico e Rail, Correcao Layout, Ajuste de Breakpoint para Tailwind, Ajuste AppTopbar, Ajuste Menu PopOver, Recriado Paleta de Cores, Inserido algumas animações leves, Reajuste Cor items NOVOS da tabela, Drawer Ajuda Corrigido no Logout, Whatsapp, sms, email, recursos extras
This commit is contained in:
+164
-168
@@ -19,64 +19,68 @@
|
||||
// 📦 Importação dos menus base por área
|
||||
// ======================================================
|
||||
|
||||
import adminMenu from './menus/clinic.menu'
|
||||
import therapistMenu from './menus/therapist.menu'
|
||||
import supervisorMenu from './menus/supervisor.menu'
|
||||
import editorMenu from './menus/editor.menu'
|
||||
import portalMenu from './menus/portal.menu'
|
||||
import saasMenu from './menus/saas.menu'
|
||||
import adminMenu from './menus/clinic.menu';
|
||||
import therapistMenu from './menus/therapist.menu';
|
||||
import supervisorMenu from './menus/supervisor.menu';
|
||||
import editorMenu from './menus/editor.menu';
|
||||
import portalMenu from './menus/portal.menu';
|
||||
import saasMenu from './menus/saas.menu';
|
||||
|
||||
import { useSaasHealthStore } from '@/stores/saasHealthStore'
|
||||
import { useTenantFeaturesStore } from '@/stores/tenantFeaturesStore'
|
||||
import { useEntitlementsStore } from '@/stores/entitlementsStore'
|
||||
import { countAtencao } from '@/composables/useDocsHealth'
|
||||
import { useSaasHealthStore } from '@/stores/saasHealthStore';
|
||||
import { useTenantFeaturesStore } from '@/stores/tenantFeaturesStore';
|
||||
import { useEntitlementsStore } from '@/stores/entitlementsStore';
|
||||
import { countAtencao } from '@/composables/useDocsHealth';
|
||||
|
||||
// ======================================================
|
||||
// 🎭 Mapeamento de role → menu base
|
||||
// ======================================================
|
||||
|
||||
const MENUS = {
|
||||
clinic_admin: adminMenu,
|
||||
tenant_admin: adminMenu, // alias
|
||||
therapist: therapistMenu,
|
||||
supervisor: supervisorMenu,
|
||||
editor: editorMenu,
|
||||
patient: portalMenu,
|
||||
portal_user: portalMenu, // alias (globalRole do paciente)
|
||||
saas_admin: saasMenu
|
||||
}
|
||||
clinic_admin: adminMenu,
|
||||
tenant_admin: adminMenu, // alias
|
||||
therapist: therapistMenu,
|
||||
supervisor: supervisorMenu,
|
||||
editor: editorMenu,
|
||||
patient: portalMenu,
|
||||
portal_user: portalMenu, // alias (globalRole do paciente)
|
||||
saas_admin: saasMenu
|
||||
};
|
||||
|
||||
// ======================================================
|
||||
// 🧠 Helpers
|
||||
// ======================================================
|
||||
|
||||
function resolveMenu (builder, ctx) {
|
||||
if (!builder) return []
|
||||
try {
|
||||
return typeof builder === 'function' ? builder(ctx) : builder
|
||||
} catch (e) {
|
||||
// se um builder estourar, não derruba o app: cai no fallback
|
||||
console.warn('[NAV] menu builder error:', e)
|
||||
return []
|
||||
}
|
||||
function resolveMenu(builder, ctx) {
|
||||
if (!builder) return [];
|
||||
try {
|
||||
return typeof builder === 'function' ? builder(ctx) : builder;
|
||||
} catch (e) {
|
||||
// se um builder estourar, não derruba o app: cai no fallback
|
||||
console.warn('[NAV] menu builder error:', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// core menu anti-"sumir"
|
||||
function coreMenu () {
|
||||
return [
|
||||
{
|
||||
label: 'Geral',
|
||||
items: [
|
||||
{ label: 'Início', icon: 'pi pi-home', to: '/' },
|
||||
{ label: 'Assinatura', icon: 'pi pi-credit-card', to: '/billing' },
|
||||
{ label: 'Perfil', icon: 'pi pi-user', to: '/profile' }
|
||||
]
|
||||
}
|
||||
]
|
||||
function coreMenu() {
|
||||
return [
|
||||
{
|
||||
label: 'Geral',
|
||||
items: [
|
||||
{ label: 'Início', icon: 'pi pi-home', to: '/' },
|
||||
{ label: 'Assinatura', icon: 'pi pi-credit-card', to: '/billing' },
|
||||
{ label: 'Perfil', icon: 'pi pi-user', to: '/profile' }
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
function safeHasFeature (fn, key) {
|
||||
try { return !!fn?.(key) } catch { return false }
|
||||
function safeHasFeature(fn, key) {
|
||||
try {
|
||||
return !!fn?.(key);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
@@ -85,43 +89,43 @@ function safeHasFeature (fn, key) {
|
||||
// - Apenas calcula badge PRO dinâmico (com base em entitlements)
|
||||
// ======================================================
|
||||
|
||||
function decorateMenu (menu, hasFeature) {
|
||||
const arr = Array.isArray(menu) ? menu : []
|
||||
return arr.map((group) => {
|
||||
if (group?.items && Array.isArray(group.items)) {
|
||||
return { ...group, items: decorateItems(group.items, hasFeature) }
|
||||
}
|
||||
return group
|
||||
})
|
||||
function decorateMenu(menu, hasFeature) {
|
||||
const arr = Array.isArray(menu) ? menu : [];
|
||||
return arr.map((group) => {
|
||||
if (group?.items && Array.isArray(group.items)) {
|
||||
return { ...group, items: decorateItems(group.items, hasFeature) };
|
||||
}
|
||||
return group;
|
||||
});
|
||||
}
|
||||
|
||||
function decorateItems (items, hasFeature) {
|
||||
return (items || []).map((it) => {
|
||||
if (it?.items && Array.isArray(it.items)) {
|
||||
return { ...it, items: decorateItems(it.items, hasFeature) }
|
||||
}
|
||||
function decorateItems(items, hasFeature) {
|
||||
return (items || []).map((it) => {
|
||||
if (it?.items && Array.isArray(it.items)) {
|
||||
return { ...it, items: decorateItems(it.items, hasFeature) };
|
||||
}
|
||||
|
||||
const featureKey = it?.feature ? String(it.feature) : null
|
||||
const showPro = !!it?.proBadge && !!featureKey && !safeHasFeature(hasFeature, featureKey)
|
||||
const featureKey = it?.feature ? String(it.feature) : null;
|
||||
const showPro = !!it?.proBadge && !!featureKey && !safeHasFeature(hasFeature, featureKey);
|
||||
|
||||
return { ...it, __showProBadge: showPro }
|
||||
})
|
||||
return { ...it, __showProBadge: showPro };
|
||||
});
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
// ✅ Normalização de role (evita menu vazio)
|
||||
// ======================================================
|
||||
|
||||
function normalizeRole (role) {
|
||||
const r = String(role || '').trim()
|
||||
if (!r) return null
|
||||
function normalizeRole(role) {
|
||||
const r = String(role || '').trim();
|
||||
if (!r) return null;
|
||||
|
||||
// aliases comuns (blindagem)
|
||||
if (r === 'tenant_admin') return 'clinic_admin'
|
||||
if (r === 'admin') return 'clinic_admin'
|
||||
if (r === 'clinic') return 'clinic_admin'
|
||||
// aliases comuns (blindagem)
|
||||
if (r === 'tenant_admin') return 'clinic_admin';
|
||||
if (r === 'admin') return 'clinic_admin';
|
||||
if (r === 'clinic') return 'clinic_admin';
|
||||
|
||||
return r
|
||||
return r;
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
@@ -130,129 +134,121 @@ function normalizeRole (role) {
|
||||
// - Senão tenta deduzir do store com vários formatos comuns
|
||||
// ======================================================
|
||||
|
||||
function buildHasFeature (sessionCtx, entitlementsStore) {
|
||||
// 1) se já veio pronto, usa
|
||||
if (typeof sessionCtx?.hasFeature === 'function') return sessionCtx.hasFeature
|
||||
function buildHasFeature(sessionCtx, entitlementsStore) {
|
||||
// 1) se já veio pronto, usa
|
||||
if (typeof sessionCtx?.hasFeature === 'function') return sessionCtx.hasFeature;
|
||||
|
||||
// 2) se veio entitlements como objeto { key: true }
|
||||
if (sessionCtx?.entitlements && typeof sessionCtx.entitlements === 'object') {
|
||||
const bag = sessionCtx.entitlements
|
||||
return (k) => !!bag[String(k || '').trim()]
|
||||
}
|
||||
|
||||
// 3) se veio allowedFeatures como array ou Set
|
||||
if (sessionCtx?.allowedFeatures) {
|
||||
const af = sessionCtx.allowedFeatures
|
||||
if (Array.isArray(af)) {
|
||||
const s = new Set(af.map((x) => String(x).trim()).filter(Boolean))
|
||||
return (k) => s.has(String(k || '').trim())
|
||||
// 2) se veio entitlements como objeto { key: true }
|
||||
if (sessionCtx?.entitlements && typeof sessionCtx.entitlements === 'object') {
|
||||
const bag = sessionCtx.entitlements;
|
||||
return (k) => !!bag[String(k || '').trim()];
|
||||
}
|
||||
if (af instanceof Set) {
|
||||
return (k) => af.has(String(k || '').trim())
|
||||
}
|
||||
}
|
||||
|
||||
// 4) fallback no store
|
||||
return (featureKey) => {
|
||||
const k = String(featureKey || '').trim()
|
||||
if (!k) return false
|
||||
|
||||
try {
|
||||
if (typeof entitlementsStore?.hasFeature === 'function') return !!entitlementsStore.hasFeature(k)
|
||||
if (typeof entitlementsStore?.has === 'function') return !!entitlementsStore.has(k)
|
||||
|
||||
// formatos comuns:
|
||||
// - entitlements: { key: true }
|
||||
// - entitlements: Set([...])
|
||||
// - entitlements: Array([...])
|
||||
// - byOwner: { [ownerId]: { key: true } }
|
||||
const bag =
|
||||
entitlementsStore?.entitlements ||
|
||||
entitlementsStore?.features ||
|
||||
entitlementsStore?.data ||
|
||||
entitlementsStore?.state
|
||||
|
||||
if (bag instanceof Set) return bag.has(k)
|
||||
if (Array.isArray(bag)) return bag.includes(k)
|
||||
if (bag && typeof bag === 'object') {
|
||||
// tenta direto
|
||||
if (Object.prototype.hasOwnProperty.call(bag, k)) return !!bag[k]
|
||||
|
||||
// tenta byOwner (caso exista)
|
||||
const ownerId = sessionCtx?.ownerId || sessionCtx?.activeTenantId || sessionCtx?.tenantId
|
||||
if (ownerId && bag[ownerId] && typeof bag[ownerId] === 'object') {
|
||||
return !!bag[ownerId][k]
|
||||
// 3) se veio allowedFeatures como array ou Set
|
||||
if (sessionCtx?.allowedFeatures) {
|
||||
const af = sessionCtx.allowedFeatures;
|
||||
if (Array.isArray(af)) {
|
||||
const s = new Set(af.map((x) => String(x).trim()).filter(Boolean));
|
||||
return (k) => s.has(String(k || '').trim());
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
if (af instanceof Set) {
|
||||
return (k) => af.has(String(k || '').trim());
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
// 4) fallback no store
|
||||
return (featureKey) => {
|
||||
const k = String(featureKey || '').trim();
|
||||
if (!k) return false;
|
||||
|
||||
try {
|
||||
if (typeof entitlementsStore?.hasFeature === 'function') return !!entitlementsStore.hasFeature(k);
|
||||
if (typeof entitlementsStore?.has === 'function') return !!entitlementsStore.has(k);
|
||||
|
||||
// formatos comuns:
|
||||
// - entitlements: { key: true }
|
||||
// - entitlements: Set([...])
|
||||
// - entitlements: Array([...])
|
||||
// - byOwner: { [ownerId]: { key: true } }
|
||||
const bag = entitlementsStore?.entitlements || entitlementsStore?.features || entitlementsStore?.data || entitlementsStore?.state;
|
||||
|
||||
if (bag instanceof Set) return bag.has(k);
|
||||
if (Array.isArray(bag)) return bag.includes(k);
|
||||
if (bag && typeof bag === 'object') {
|
||||
// tenta direto
|
||||
if (Object.prototype.hasOwnProperty.call(bag, k)) return !!bag[k];
|
||||
|
||||
// tenta byOwner (caso exista)
|
||||
const ownerId = sessionCtx?.ownerId || sessionCtx?.activeTenantId || sessionCtx?.tenantId;
|
||||
if (ownerId && bag[ownerId] && typeof bag[ownerId] === 'object') {
|
||||
return !!bag[ownerId][k];
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
// 🎯 getMenuByRole
|
||||
// ======================================================
|
||||
|
||||
export function getMenuByRole (role, sessionCtx = {}) {
|
||||
const saasHealthStore = useSaasHealthStore()
|
||||
const mismatchCount = saasHealthStore?.mismatchCount || 0
|
||||
export function getMenuByRole(role, sessionCtx = {}) {
|
||||
const saasHealthStore = useSaasHealthStore();
|
||||
const mismatchCount = saasHealthStore?.mismatchCount || 0;
|
||||
|
||||
const tenantFeaturesStore = useTenantFeaturesStore()
|
||||
const entitlementsStore = useEntitlementsStore()
|
||||
const tenantFeaturesStore = useTenantFeaturesStore();
|
||||
const entitlementsStore = useEntitlementsStore();
|
||||
|
||||
const isSaas = sessionCtx?.isSaasAdmin === true
|
||||
const isSaas = sessionCtx?.isSaasAdmin === true;
|
||||
|
||||
const tenantFeatureEnabled =
|
||||
typeof sessionCtx?.tenantFeatureEnabled === 'function'
|
||||
? sessionCtx.tenantFeatureEnabled
|
||||
: (key) => {
|
||||
try { return !!tenantFeaturesStore?.isEnabled?.(key) } catch { return false }
|
||||
}
|
||||
const tenantFeatureEnabled =
|
||||
typeof sessionCtx?.tenantFeatureEnabled === 'function'
|
||||
? sessionCtx.tenantFeatureEnabled
|
||||
: (key) => {
|
||||
try {
|
||||
return !!tenantFeaturesStore?.isEnabled?.(key);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const tenantLoading =
|
||||
typeof sessionCtx?.tenantLoading === 'function'
|
||||
? sessionCtx.tenantLoading
|
||||
: () => false
|
||||
const tenantLoading = typeof sessionCtx?.tenantLoading === 'function' ? sessionCtx.tenantLoading : () => false;
|
||||
|
||||
const tenantFeaturesLoading =
|
||||
typeof sessionCtx?.tenantFeaturesLoading === 'function'
|
||||
? sessionCtx.tenantFeaturesLoading
|
||||
: () => false
|
||||
const tenantFeaturesLoading = typeof sessionCtx?.tenantFeaturesLoading === 'function' ? sessionCtx.tenantFeaturesLoading : () => false;
|
||||
|
||||
const hasFeature = buildHasFeature(sessionCtx, entitlementsStore)
|
||||
const hasFeature = buildHasFeature(sessionCtx, entitlementsStore);
|
||||
|
||||
const ctx = {
|
||||
...sessionCtx,
|
||||
mismatchCount,
|
||||
tenantFeaturesStore,
|
||||
tenantFeatureEnabled,
|
||||
tenantLoading,
|
||||
tenantFeaturesLoading,
|
||||
entitlementsStore,
|
||||
hasFeature
|
||||
}
|
||||
const ctx = {
|
||||
...sessionCtx,
|
||||
mismatchCount,
|
||||
tenantFeaturesStore,
|
||||
tenantFeatureEnabled,
|
||||
tenantLoading,
|
||||
tenantFeaturesLoading,
|
||||
entitlementsStore,
|
||||
hasFeature
|
||||
};
|
||||
|
||||
// ✅ role normalizado
|
||||
const r = normalizeRole(role)
|
||||
// ✅ role normalizado
|
||||
const r = normalizeRole(role);
|
||||
|
||||
const baseRaw = resolveMenu(MENUS[r], ctx)
|
||||
const base = decorateMenu(baseRaw, hasFeature)
|
||||
const baseRaw = resolveMenu(MENUS[r], ctx);
|
||||
const base = decorateMenu(baseRaw, hasFeature);
|
||||
|
||||
const saasRaw = typeof saasMenu === 'function'
|
||||
? saasMenu(ctx, { mismatchCount, docsAtencaoCount: countAtencao.value })
|
||||
: saasMenu
|
||||
const saas = decorateMenu(saasRaw, hasFeature)
|
||||
const saasRaw = typeof saasMenu === 'function' ? saasMenu(ctx, { mismatchCount, docsAtencaoCount: countAtencao.value }) : saasMenu;
|
||||
const saas = decorateMenu(saasRaw, hasFeature);
|
||||
|
||||
// 🔒 SaaS master: somente área SaaS
|
||||
if (isSaas) {
|
||||
return saas.length ? saas : coreMenu()
|
||||
}
|
||||
// 🔒 SaaS master: somente área SaaS
|
||||
if (isSaas) {
|
||||
return saas.length ? saas : coreMenu();
|
||||
}
|
||||
|
||||
// ✅ fallback: nunca retorna vazio
|
||||
if (!base || !base.length) {
|
||||
return coreMenu()
|
||||
}
|
||||
// ✅ fallback: nunca retorna vazio
|
||||
if (!base || !base.length) {
|
||||
return coreMenu();
|
||||
}
|
||||
|
||||
return [...base]
|
||||
}
|
||||
return [...base];
|
||||
}
|
||||
|
||||
@@ -14,107 +14,105 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
export default function adminMenu (ctx = {}) {
|
||||
const menu = [
|
||||
{
|
||||
label: 'Clínica',
|
||||
items: [
|
||||
// ✅ usar name real da rota (evita /admin cair em redirect estranho)
|
||||
{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: { name: 'admin.dashboard' } },
|
||||
|
||||
export default function adminMenu(ctx = {}) {
|
||||
const menu = [
|
||||
{
|
||||
label: 'Agenda da Clínica',
|
||||
icon: 'pi pi-fw pi-calendar',
|
||||
to: { name: 'admin-agenda-clinica' },
|
||||
feature: 'agenda.view',
|
||||
badgeKey: 'agendaHoje'
|
||||
label: 'Clínica',
|
||||
items: [
|
||||
// ✅ usar name real da rota (evita /admin cair em redirect estranho)
|
||||
{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: { name: 'admin.dashboard' } },
|
||||
|
||||
{
|
||||
label: 'Agenda da Clínica',
|
||||
icon: 'pi pi-fw pi-calendar',
|
||||
to: { name: 'admin-agenda-clinica' },
|
||||
feature: 'agenda.view',
|
||||
badgeKey: 'agendaHoje'
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Recorrências',
|
||||
icon: 'pi pi-fw pi-refresh',
|
||||
to: { name: 'admin-agenda-recorrencias' },
|
||||
feature: 'agenda.view'
|
||||
},
|
||||
|
||||
// ✅ Compromissos determinísticos (tipos)
|
||||
{
|
||||
label: 'Compromissos',
|
||||
icon: 'pi pi-fw pi-clock',
|
||||
to: { name: 'admin-agenda-compromissos' },
|
||||
feature: 'agenda.view'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// ✅ SEM IF: sempre existe, só fica visível quando a feature estiver ligada
|
||||
{
|
||||
label: 'Pacientes',
|
||||
visible: () => {
|
||||
// 1) enquanto tenant/features estão carregando, NÃO some (evita piscar ao trocar de aba)
|
||||
if (ctx?.tenantLoading?.()) return true;
|
||||
if (ctx?.tenantFeaturesLoading?.()) return true;
|
||||
|
||||
// 2) quando estabilizou, aí sim decide pela feature
|
||||
return !!ctx?.tenantFeatureEnabled?.('patients');
|
||||
},
|
||||
items: [
|
||||
// ✅ usar name real das rotas (você já tem todas no routes.clinic.js)
|
||||
{ label: 'Lista de Pacientes', icon: 'pi pi-fw pi-users', to: { name: 'admin-pacientes' }, quickCreate: true, quickCreateRoute: 'admin-pacientes-cadastro', quickCreateLinkTo: { name: 'admin-pacientes-link-externo' } },
|
||||
{ label: 'Grupos', icon: 'pi pi-fw pi-sitemap', to: { name: 'admin-pacientes-grupos' } },
|
||||
{ label: 'Tags', icon: 'pi pi-fw pi-tags', to: { name: 'admin-pacientes-tags' } },
|
||||
{ label: 'Link Externo', icon: 'pi pi-fw pi-link', to: { name: 'admin-pacientes-link-externo' } },
|
||||
{ label: 'Cadastros recebidos', icon: 'pi pi-inbox', to: { name: 'admin-pacientes-recebidos' }, badgeKey: 'cadastrosRecebidos' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Recorrências',
|
||||
icon: 'pi pi-fw pi-refresh',
|
||||
to: { name: 'admin-agenda-recorrencias' },
|
||||
feature: 'agenda.view'
|
||||
label: 'Gestão',
|
||||
items: [
|
||||
{ label: 'Profissionais', icon: 'pi pi-fw pi-id-card', to: { name: 'admin-clinic-professionals' } },
|
||||
{
|
||||
label: 'Tipos de Clínicas',
|
||||
icon: 'pi pi-fw pi-sliders-h',
|
||||
to: { name: 'admin-clinic-features' },
|
||||
visible: () => {
|
||||
if (ctx?.tenantLoading?.()) return true; // ← true durante loading (evita piscar)
|
||||
const role = ctx?.role?.();
|
||||
return role === 'clinic_admin'; // tenant_admin normaliza para clinic_admin
|
||||
}
|
||||
},
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: { name: 'admin-meu-plano' } }
|
||||
]
|
||||
},
|
||||
|
||||
// ✅ Compromissos determinísticos (tipos)
|
||||
{
|
||||
label: 'Compromissos',
|
||||
icon: 'pi pi-fw pi-clock',
|
||||
to: { name: 'admin-agenda-compromissos' },
|
||||
feature: 'agenda.view'
|
||||
label: 'Financeiro',
|
||||
items: [{ label: 'Cobranças', icon: 'pi pi-fw pi-wallet', to: { name: 'admin-financeiro' } }]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Sistema',
|
||||
items: [
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: { name: 'admin-settings-security' } },
|
||||
{
|
||||
label: 'Agendamento Online (PRO)',
|
||||
icon: 'pi pi-fw pi-calendar-plus',
|
||||
to: { name: 'admin-online-scheduling' },
|
||||
feature: 'online_scheduling.manage',
|
||||
proBadge: true
|
||||
},
|
||||
{
|
||||
label: 'Agendamentos Recebidos',
|
||||
icon: 'pi pi-fw pi-inbox',
|
||||
to: { name: 'admin-agendamentos-recebidos' },
|
||||
feature: 'online_scheduling.manage',
|
||||
proBadge: true,
|
||||
badgeKey: 'agendamentosRecebidos'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
// ✅ SEM IF: sempre existe, só fica visível quando a feature estiver ligada
|
||||
{
|
||||
label: 'Pacientes',
|
||||
visible: () => {
|
||||
// 1) enquanto tenant/features estão carregando, NÃO some (evita piscar ao trocar de aba)
|
||||
if (ctx?.tenantLoading?.()) return true
|
||||
if (ctx?.tenantFeaturesLoading?.()) return true
|
||||
|
||||
// 2) quando estabilizou, aí sim decide pela feature
|
||||
return !!ctx?.tenantFeatureEnabled?.('patients')
|
||||
},
|
||||
items: [
|
||||
// ✅ usar name real das rotas (você já tem todas no routes.clinic.js)
|
||||
{ label: 'Lista de Pacientes', icon: 'pi pi-fw pi-users', to: { name: 'admin-pacientes' }, quickCreate: true, quickCreateRoute: 'admin-pacientes-cadastro', quickCreateLinkTo: { name: 'admin-pacientes-link-externo' } },
|
||||
{ label: 'Grupos', icon: 'pi pi-fw pi-sitemap', to: { name: 'admin-pacientes-grupos' } },
|
||||
{ label: 'Tags', icon: 'pi pi-fw pi-tags', to: { name: 'admin-pacientes-tags' } },
|
||||
{ label: 'Link Externo', icon: 'pi pi-fw pi-link', to: { name: 'admin-pacientes-link-externo' } },
|
||||
{ label: 'Cadastros recebidos', icon: 'pi pi-inbox', to: { name: 'admin-pacientes-recebidos' }, badgeKey: 'cadastrosRecebidos' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Gestão',
|
||||
items: [
|
||||
{ label: 'Profissionais', icon: 'pi pi-fw pi-id-card', to: { name: 'admin-clinic-professionals' } },
|
||||
{
|
||||
label: 'Tipos de Clínicas',
|
||||
icon: 'pi pi-fw pi-sliders-h',
|
||||
to: { name: 'admin-clinic-features' },
|
||||
visible: () => {
|
||||
if (ctx?.tenantLoading?.()) return true // ← true durante loading (evita piscar)
|
||||
const role = ctx?.role?.()
|
||||
return role === 'clinic_admin' // tenant_admin normaliza para clinic_admin
|
||||
}
|
||||
},
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: { name: 'admin-meu-plano' } }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Financeiro',
|
||||
items: [
|
||||
{ label: 'Cobranças', icon: 'pi pi-fw pi-wallet', to: { name: 'admin-financeiro' } }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Sistema',
|
||||
items: [
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: { name: 'admin-settings-security' } },
|
||||
{
|
||||
label: 'Agendamento Online (PRO)',
|
||||
icon: 'pi pi-fw pi-calendar-plus',
|
||||
to: { name: 'admin-online-scheduling' },
|
||||
feature: 'online_scheduling.manage',
|
||||
proBadge: true
|
||||
},
|
||||
{
|
||||
label: 'Agendamentos Recebidos',
|
||||
icon: 'pi pi-fw pi-inbox',
|
||||
to: { name: 'admin-agendamentos-recebidos' },
|
||||
feature: 'online_scheduling.manage',
|
||||
proBadge: true,
|
||||
badgeKey: 'agendamentosRecebidos'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
return menu
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
@@ -21,28 +21,26 @@
|
||||
//
|
||||
|
||||
export default [
|
||||
{
|
||||
label: 'Início',
|
||||
items: [
|
||||
{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/editor' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Início',
|
||||
items: [{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/editor' }]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Conteúdo',
|
||||
items: [
|
||||
{ label: 'Cursos', icon: 'pi pi-fw pi-book', to: '/editor/cursos' },
|
||||
{ label: 'Módulos', icon: 'pi pi-fw pi-th-large', to: '/editor/modulos' },
|
||||
{ label: 'Publicados', icon: 'pi pi-fw pi-check-circle', to: '/editor/publicados' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Conteúdo',
|
||||
items: [
|
||||
{ label: 'Cursos', icon: 'pi pi-fw pi-book', to: '/editor/cursos' },
|
||||
{ label: 'Módulos', icon: 'pi pi-fw pi-th-large', to: '/editor/modulos' },
|
||||
{ label: 'Publicados', icon: 'pi pi-fw pi-check-circle', to: '/editor/publicados' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Conta',
|
||||
items: [
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: '/editor/meu-plano' },
|
||||
{ label: 'Meu Perfil', icon: 'pi pi-fw pi-user', to: '/account/profile' },
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: '/account/security' }
|
||||
]
|
||||
}
|
||||
]
|
||||
{
|
||||
label: 'Conta',
|
||||
items: [
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: '/editor/meu-plano' },
|
||||
{ label: 'Meu Perfil', icon: 'pi pi-fw pi-user', to: '/account/profile' },
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: '/account/security' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -16,26 +16,22 @@
|
||||
*/
|
||||
|
||||
export default [
|
||||
{
|
||||
label: 'Início',
|
||||
items: [
|
||||
{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/portal' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Início',
|
||||
items: [{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/portal' }]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Minhas sessões',
|
||||
items: [
|
||||
{ label: 'Sessões', icon: 'pi pi-fw pi-calendar', to: '/portal/sessoes' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Minhas sessões',
|
||||
items: [{ label: 'Sessões', icon: 'pi pi-fw pi-calendar', to: '/portal/sessoes' }]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Conta',
|
||||
items: [
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: '/portal/meu-plano' },
|
||||
{ label: 'Minha Conta', icon: 'pi pi-fw pi-user', to: '/account/profile' },
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: '/account/security' }
|
||||
]
|
||||
}
|
||||
]
|
||||
{
|
||||
label: 'Conta',
|
||||
items: [
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: '/portal/meu-plano' },
|
||||
{ label: 'Minha Conta', icon: 'pi pi-fw pi-user', to: '/account/profile' },
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: '/account/security' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -15,77 +15,80 @@
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export default function saasMenu (sessionCtx, opts = {}) {
|
||||
if (!sessionCtx?.isSaasAdmin) return []
|
||||
export default function saasMenu(sessionCtx, opts = {}) {
|
||||
if (!sessionCtx?.isSaasAdmin) return [];
|
||||
|
||||
const mismatchCount = Number(opts?.mismatchCount || 0)
|
||||
const docsAtencaoCount = Number(opts?.docsAtencaoCount || 0)
|
||||
const mismatchCount = Number(opts?.mismatchCount || 0);
|
||||
const docsAtencaoCount = Number(opts?.docsAtencaoCount || 0);
|
||||
|
||||
const mismatchBadge = mismatchCount > 0
|
||||
? { badge: String(mismatchCount), badgeClass: 'p-badge p-badge-danger' }
|
||||
: {}
|
||||
const mismatchBadge = mismatchCount > 0 ? { badge: String(mismatchCount), badgeClass: 'p-badge p-badge-danger' } : {};
|
||||
|
||||
const docsBadge = docsAtencaoCount > 0
|
||||
? { badge: String(docsAtencaoCount), badgeClass: 'p-badge p-badge-danger' }
|
||||
: {}
|
||||
const docsBadge = docsAtencaoCount > 0 ? { badge: String(docsAtencaoCount), badgeClass: 'p-badge p-badge-danger' } : {};
|
||||
|
||||
return [
|
||||
{
|
||||
label: 'Início',
|
||||
items: [
|
||||
{ label: 'Dashboard', icon: 'pi pi-fw pi-chart-bar', to: '/saas' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Planos',
|
||||
items: [
|
||||
{ label: 'Planos e Preços', icon: 'pi pi-fw pi-list', to: '/saas/plans' },
|
||||
{ label: 'Vitrine Pública', icon: 'pi pi-fw pi-megaphone', to: '/saas/plans-public' },
|
||||
{ label: 'Recursos', icon: 'pi pi-fw pi-bolt', to: '/saas/features' },
|
||||
{ label: 'Controle de Recursos',icon: 'pi pi-fw pi-th-large', to: '/saas/plan-features' },
|
||||
{ label: 'Limites por Plano', icon: 'pi pi-fw pi-sliders-h', to: '/saas/plan-limits' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Assinaturas',
|
||||
items: [
|
||||
{ label: 'Listagem', icon: 'pi pi-fw pi-list', to: '/saas/subscriptions' },
|
||||
{ label: 'Intenções', icon: 'pi pi-fw pi-inbox', to: '/saas/subscription-intents' },
|
||||
{ label: 'Histórico', icon: 'pi pi-fw pi-history', to: '/saas/subscription-events' },
|
||||
return [
|
||||
{
|
||||
label: 'Saúde das Assinaturas',
|
||||
icon: 'pi pi-fw pi-shield',
|
||||
to: '/saas/subscription-health',
|
||||
...mismatchBadge
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Operações',
|
||||
items: [
|
||||
{ label: 'Clínicas (Tenants)', icon: 'pi pi-fw pi-users', to: '/saas/tenants' },
|
||||
{ label: 'Feriados', icon: 'pi pi-fw pi-star', to: '/saas/feriados' },
|
||||
{ label: 'Suporte Técnico', icon: 'pi pi-fw pi-headphones', to: '/saas/support' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Conteúdo',
|
||||
items: [
|
||||
{
|
||||
label: 'Documentação',
|
||||
icon: 'pi pi-fw pi-question-circle',
|
||||
to: '/saas/docs',
|
||||
...docsBadge
|
||||
label: 'Início',
|
||||
items: [{ label: 'Dashboard', icon: 'pi pi-fw pi-chart-bar', to: '/saas' }]
|
||||
},
|
||||
{ label: 'FAQ', icon: 'pi pi-fw pi-comments', to: '/saas/faq' },
|
||||
{ label: 'Carrossel Login', icon: 'pi pi-fw pi-images', to: '/saas/login-carousel' },
|
||||
{ label: 'Avisos Globais', icon: 'pi pi-fw pi-megaphone', to: '/saas/global-notices' },
|
||||
{ label: 'Templates de E-mail', icon: 'pi pi-fw pi-envelope', to: '/saas/email-templates' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
{
|
||||
label: 'Planos',
|
||||
items: [
|
||||
{ label: 'Planos e Preços', icon: 'pi pi-fw pi-list', to: '/saas/plans' },
|
||||
{ label: 'Vitrine Pública', icon: 'pi pi-fw pi-megaphone', to: '/saas/plans-public' },
|
||||
{ label: 'Recursos', icon: 'pi pi-fw pi-bolt', to: '/saas/features' },
|
||||
{ label: 'Controle de Recursos', icon: 'pi pi-fw pi-th-large', to: '/saas/plan-features' },
|
||||
{ label: 'Limites por Plano', icon: 'pi pi-fw pi-sliders-h', to: '/saas/plan-limits' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Assinaturas',
|
||||
items: [
|
||||
{ label: 'Listagem', icon: 'pi pi-fw pi-list', to: '/saas/subscriptions' },
|
||||
{ label: 'Intenções', icon: 'pi pi-fw pi-inbox', to: '/saas/subscription-intents' },
|
||||
{ label: 'Histórico', icon: 'pi pi-fw pi-history', to: '/saas/subscription-events' },
|
||||
{
|
||||
label: 'Saúde das Assinaturas',
|
||||
icon: 'pi pi-fw pi-shield',
|
||||
to: '/saas/subscription-health',
|
||||
...mismatchBadge
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Operações',
|
||||
items: [
|
||||
{ label: 'Clínicas (Tenants)', icon: 'pi pi-fw pi-users', to: '/saas/tenants' },
|
||||
{ label: 'Feriados', icon: 'pi pi-fw pi-star', to: '/saas/feriados' },
|
||||
{ label: 'Suporte Técnico', icon: 'pi pi-fw pi-headphones', to: '/saas/support' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Canais',
|
||||
items: [
|
||||
{ label: 'WhatsApp', icon: 'pi pi-fw pi-whatsapp', to: '/saas/whatsapp' },
|
||||
{ label: 'Templates WhatsApp/SMS', icon: 'pi pi-fw pi-comment', to: '/saas/notification-templates' },
|
||||
{ label: 'Add-ons / Créditos SMS', icon: 'pi pi-fw pi-box', to: '/saas/addons' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Conteúdo',
|
||||
items: [
|
||||
{
|
||||
label: 'Documentação',
|
||||
icon: 'pi pi-fw pi-question-circle',
|
||||
to: '/saas/docs',
|
||||
...docsBadge
|
||||
},
|
||||
{ label: 'FAQ', icon: 'pi pi-fw pi-comments', to: '/saas/faq' },
|
||||
{ label: 'Carrossel Login', icon: 'pi pi-fw pi-images', to: '/saas/login-carousel' },
|
||||
{ label: 'Avisos Globais', icon: 'pi pi-fw pi-megaphone', to: '/saas/global-notices' },
|
||||
{ label: 'Templates de E-mail', icon: 'pi pi-fw pi-envelope', to: '/saas/email-templates' }
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -16,31 +16,29 @@
|
||||
*/
|
||||
|
||||
export default [
|
||||
{
|
||||
label: 'Início',
|
||||
items: [
|
||||
{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/supervisor' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Início',
|
||||
items: [{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/supervisor' }]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Supervisão',
|
||||
items: [
|
||||
{
|
||||
label: 'Sala de Supervisão',
|
||||
icon: 'pi pi-fw pi-users',
|
||||
to: '/supervisor/sala',
|
||||
feature: 'supervisor.access'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Supervisão',
|
||||
items: [
|
||||
{
|
||||
label: 'Sala de Supervisão',
|
||||
icon: 'pi pi-fw pi-users',
|
||||
to: '/supervisor/sala',
|
||||
feature: 'supervisor.access'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Conta',
|
||||
items: [
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: '/supervisor/meu-plano' },
|
||||
{ label: 'Meu Perfil', icon: 'pi pi-fw pi-user', to: '/account/profile' },
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: '/account/security' }
|
||||
]
|
||||
}
|
||||
]
|
||||
{
|
||||
label: 'Conta',
|
||||
items: [
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: '/supervisor/meu-plano' },
|
||||
{ label: 'Meu Perfil', icon: 'pi pi-fw pi-user', to: '/account/profile' },
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: '/account/security' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@@ -16,75 +16,71 @@
|
||||
*/
|
||||
|
||||
export default [
|
||||
{
|
||||
label: 'Início',
|
||||
items: [
|
||||
{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/therapist' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Início',
|
||||
items: [{ label: 'Dashboard', icon: 'pi pi-fw pi-home', to: '/therapist' }]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Agenda',
|
||||
items: [
|
||||
{ label: 'Agenda', icon: 'pi pi-fw pi-calendar', to: '/therapist/agenda', feature: 'agenda.view', proBadge: true, badgeKey: 'agendaHoje' },
|
||||
{ label: 'Recorrências', icon: 'pi pi-fw pi-refresh', to: '/therapist/agenda/recorrencias', feature: 'agenda.view', proBadge: true },
|
||||
{ label: 'Compromissos', icon: 'pi pi-fw pi-clock', to: '/therapist/agenda/compromissos', feature: 'agenda.view', proBadge: true }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Agenda',
|
||||
items: [
|
||||
{ label: 'Agenda', icon: 'pi pi-fw pi-calendar', to: '/therapist/agenda', feature: 'agenda.view', proBadge: true, badgeKey: 'agendaHoje' },
|
||||
{ label: 'Recorrências', icon: 'pi pi-fw pi-refresh', to: '/therapist/agenda/recorrencias', feature: 'agenda.view', proBadge: true },
|
||||
{ label: 'Compromissos', icon: 'pi pi-fw pi-clock', to: '/therapist/agenda/compromissos', feature: 'agenda.view', proBadge: true }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Pacientes',
|
||||
items: [
|
||||
{ label: 'Meus pacientes', icon: 'pi pi-list', to: '/therapist/patients', quickCreate: true, quickCreateRoute: 'therapist-patients-cadastro', quickCreateLinkTo: '/therapist/patients/link-externo' },
|
||||
{ label: 'Grupo de pacientes', icon: 'pi pi-fw pi-users', to: '/therapist/patients/grupos' },
|
||||
{ label: 'Tags', icon: 'pi pi-tags', to: '/therapist/patients/tags' },
|
||||
{ label: 'Meu link de cadastro', icon: 'pi pi-link', to: '/therapist/patients/link-externo' },
|
||||
{ label: 'Cadastros recebidos', icon: 'pi pi-inbox', to: '/therapist/patients/cadastro/recebidos', badgeKey: 'cadastrosRecebidos' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Pacientes',
|
||||
items: [
|
||||
{ label: 'Meus pacientes', icon: 'pi pi-list', to: '/therapist/patients', quickCreate: true, quickCreateRoute: 'therapist-patients-cadastro', quickCreateLinkTo: '/therapist/patients/link-externo' },
|
||||
{ label: 'Grupo de pacientes', icon: 'pi pi-fw pi-users', to: '/therapist/patients/grupos' },
|
||||
{ label: 'Tags', icon: 'pi pi-tags', to: '/therapist/patients/tags' },
|
||||
{ label: 'Meu link de cadastro', icon: 'pi pi-link', to: '/therapist/patients/link-externo' },
|
||||
{ label: 'Cadastros recebidos', icon: 'pi pi-inbox', to: '/therapist/patients/cadastro/recebidos', badgeKey: 'cadastrosRecebidos' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Agendamento Online',
|
||||
items: [
|
||||
{
|
||||
label: 'Configurar página',
|
||||
icon: 'pi pi-fw pi-globe',
|
||||
to: '/therapist/online-scheduling',
|
||||
feature: 'online_scheduling.manage',
|
||||
proBadge: true
|
||||
},
|
||||
{
|
||||
label: 'Agendamentos Recebidos',
|
||||
icon: 'pi pi-fw pi-inbox',
|
||||
to: '/therapist/agendamentos-recebidos',
|
||||
feature: 'online_scheduling.manage',
|
||||
proBadge: true,
|
||||
badgeKey: 'agendamentosRecebidos'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Agendamento Online',
|
||||
items: [
|
||||
{
|
||||
label: 'Configurar página',
|
||||
icon: 'pi pi-fw pi-globe',
|
||||
to: '/therapist/online-scheduling',
|
||||
feature: 'online_scheduling.manage',
|
||||
proBadge: true
|
||||
},
|
||||
{
|
||||
label: 'Agendamentos Recebidos',
|
||||
icon: 'pi pi-fw pi-inbox',
|
||||
to: '/therapist/agendamentos-recebidos',
|
||||
feature: 'online_scheduling.manage',
|
||||
proBadge: true,
|
||||
badgeKey: 'agendamentosRecebidos'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Financeiro',
|
||||
items: [
|
||||
{ label: 'Cobranças', icon: 'pi pi-fw pi-wallet', to: '/therapist/financeiro' },
|
||||
{ label: 'Lançamentos', icon: 'pi pi-fw pi-list', to: '/therapist/financeiro/lancamentos' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Financeiro',
|
||||
items: [
|
||||
{ label: 'Cobranças', icon: 'pi pi-fw pi-wallet', to: '/therapist/financeiro' },
|
||||
{ label: 'Lançamentos', icon: 'pi pi-fw pi-list', to: '/therapist/financeiro/lancamentos' }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Relatórios',
|
||||
items: [
|
||||
{ label: 'Relatórios', icon: 'pi pi-fw pi-chart-bar', to: '/therapist/relatorios', feature: 'agenda.view' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Relatórios',
|
||||
items: [{ label: 'Relatórios', icon: 'pi pi-fw pi-chart-bar', to: '/therapist/relatorios', feature: 'agenda.view' }]
|
||||
},
|
||||
|
||||
{
|
||||
label: 'Conta',
|
||||
items: [
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: '/therapist/meu-plano' },
|
||||
{ label: 'Meu Perfil', icon: 'pi pi-fw pi-user', to: '/account/profile' },
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: '/account/security' }
|
||||
]
|
||||
}
|
||||
]
|
||||
{
|
||||
label: 'Conta',
|
||||
items: [
|
||||
{ label: 'Meu plano', icon: 'pi pi-fw pi-credit-card', to: '/therapist/meu-plano' },
|
||||
{ label: 'Meu Perfil', icon: 'pi pi-fw pi-user', to: '/account/profile' },
|
||||
{ label: 'Segurança', icon: 'pi pi-fw pi-shield', to: '/account/security' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user