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:
@@ -35,16 +35,16 @@
|
||||
* Obs: 'admin' é role GLOBAL (profiles.role). Aqui é guard de tenant,
|
||||
* mas mantemos um fallback seguro para legado.
|
||||
*/
|
||||
export function roleHomePath (role) {
|
||||
// ✅ clínica: aceita nomes canônicos e legado
|
||||
if (role === 'clinic_admin' || role === 'tenant_admin') return '/admin'
|
||||
if (role === 'therapist') return '/therapist'
|
||||
if (role === 'patient') return '/portal'
|
||||
export function roleHomePath(role) {
|
||||
// ✅ clínica: aceita nomes canônicos e legado
|
||||
if (role === 'clinic_admin' || role === 'tenant_admin') return '/admin';
|
||||
if (role === 'therapist') return '/therapist';
|
||||
if (role === 'patient') return '/portal';
|
||||
|
||||
// ✅ fallback (não deveria acontecer em tenant)
|
||||
if (role === 'admin') return '/admin'
|
||||
// ✅ fallback (não deveria acontecer em tenant)
|
||||
if (role === 'admin') return '/admin';
|
||||
|
||||
return '/'
|
||||
return '/';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,19 +55,19 @@ export function roleHomePath (role) {
|
||||
* - use403 = true → sempre /pages/access (recomendado para clareza)
|
||||
* - use403 = false → home do papel (útil quando você quer "auto-corrigir" navegação)
|
||||
*/
|
||||
export function denyByRole ({ to, currentRole, use403 = true } = {}) {
|
||||
// ✅ padrão forte: 403 (não é caso de upgrade)
|
||||
if (use403) return { path: '/pages/access' }
|
||||
export function denyByRole({ to, currentRole, use403 = true } = {}) {
|
||||
// ✅ padrão forte: 403 (não é caso de upgrade)
|
||||
if (use403) return { path: '/pages/access' };
|
||||
|
||||
// modo "suave": manda pra home do papel
|
||||
const fallback = roleHomePath(currentRole)
|
||||
// modo "suave": manda pra home do papel
|
||||
const fallback = roleHomePath(currentRole);
|
||||
|
||||
// evita loop: se já está no fallback, manda pra página de acesso negado
|
||||
if (to?.path && to.path === fallback) {
|
||||
return { path: '/pages/access' }
|
||||
}
|
||||
// evita loop: se já está no fallback, manda pra página de acesso negado
|
||||
if (to?.path && to.path === fallback) {
|
||||
return { path: '/pages/access' };
|
||||
}
|
||||
|
||||
return { path: fallback }
|
||||
return { path: fallback };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,12 +75,12 @@ export function denyByRole ({ to, currentRole, use403 = true } = {}) {
|
||||
* missingFeature: feature key (ex: 'online_scheduling.manage')
|
||||
* redirectTo: para onde voltar após upgrade
|
||||
*/
|
||||
export function denyByPlan ({ to, missingFeature, redirectTo } = {}) {
|
||||
return {
|
||||
path: '/upgrade',
|
||||
query: {
|
||||
feature: missingFeature || '',
|
||||
redirectTo: redirectTo || to?.fullPath || '/'
|
||||
}
|
||||
}
|
||||
}
|
||||
export function denyByPlan({ to, missingFeature, redirectTo } = {}) {
|
||||
return {
|
||||
path: '/upgrade',
|
||||
query: {
|
||||
feature: missingFeature || '',
|
||||
redirectTo: redirectTo || to?.fullPath || '/'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+826
-839
File diff suppressed because it is too large
Load Diff
+28
-25
@@ -30,24 +30,24 @@ import supervisorRoutes from './routes.supervisor';
|
||||
import editorRoutes from './routes.editor';
|
||||
import featuresRoutes from './routes.features';
|
||||
|
||||
import { pinia } from '@/plugins/pinia' // ← singleton compartilhado
|
||||
import { supportGuard } from '@/support/supportGuard'
|
||||
import { pinia } from '@/plugins/pinia'; // ← singleton compartilhado
|
||||
import { supportGuard } from '@/support/supportGuard';
|
||||
import { applyGuards } from './guards';
|
||||
|
||||
const routes = [
|
||||
...(Array.isArray(publicRoutes) ? publicRoutes : [publicRoutes]),
|
||||
...(Array.isArray(authRoutes) ? authRoutes : [authRoutes]),
|
||||
...(Array.isArray(miscRoutes) ? miscRoutes : [miscRoutes]),
|
||||
...(Array.isArray(billingRoutes) ? billingRoutes : [billingRoutes]),
|
||||
...(Array.isArray(saasRoutes) ? saasRoutes : [saasRoutes]),
|
||||
...(Array.isArray(meRoutes) ? meRoutes : [meRoutes]),
|
||||
...(Array.isArray(adminRoutes) ? adminRoutes : [adminRoutes]),
|
||||
...(Array.isArray(therapistRoutes) ? therapistRoutes : [therapistRoutes]),
|
||||
...(Array.isArray(supervisorRoutes) ? supervisorRoutes : [supervisorRoutes]),
|
||||
...(Array.isArray(editorRoutes) ? editorRoutes : [editorRoutes]),
|
||||
...(Array.isArray(portalRoutes) ? portalRoutes : [portalRoutes]),
|
||||
...(Array.isArray(configuracoesRoutes) ? configuracoesRoutes : [configuracoesRoutes]),
|
||||
...(Array.isArray(featuresRoutes) ? featuresRoutes : [featuresRoutes]),
|
||||
...(Array.isArray(publicRoutes) ? publicRoutes : [publicRoutes]),
|
||||
...(Array.isArray(authRoutes) ? authRoutes : [authRoutes]),
|
||||
...(Array.isArray(miscRoutes) ? miscRoutes : [miscRoutes]),
|
||||
...(Array.isArray(billingRoutes) ? billingRoutes : [billingRoutes]),
|
||||
...(Array.isArray(saasRoutes) ? saasRoutes : [saasRoutes]),
|
||||
...(Array.isArray(meRoutes) ? meRoutes : [meRoutes]),
|
||||
...(Array.isArray(adminRoutes) ? adminRoutes : [adminRoutes]),
|
||||
...(Array.isArray(therapistRoutes) ? therapistRoutes : [therapistRoutes]),
|
||||
...(Array.isArray(supervisorRoutes) ? supervisorRoutes : [supervisorRoutes]),
|
||||
...(Array.isArray(editorRoutes) ? editorRoutes : [editorRoutes]),
|
||||
...(Array.isArray(portalRoutes) ? portalRoutes : [portalRoutes]),
|
||||
...(Array.isArray(configuracoesRoutes) ? configuracoesRoutes : [configuracoesRoutes]),
|
||||
...(Array.isArray(featuresRoutes) ? featuresRoutes : [featuresRoutes]),
|
||||
|
||||
// ✅ compat: rota antiga /login → /auth/login
|
||||
{
|
||||
@@ -56,7 +56,7 @@ const routes = [
|
||||
path: '/auth/login',
|
||||
query: to.query || {}
|
||||
})
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
@@ -71,7 +71,10 @@ const router = createRouter({
|
||||
/* 🔎 DEBUG: listar todas as rotas registradas */
|
||||
console.log(
|
||||
'[ROUTES]',
|
||||
router.getRoutes().map((r) => r.path).sort()
|
||||
router
|
||||
.getRoutes()
|
||||
.map((r) => r.path)
|
||||
.sort()
|
||||
);
|
||||
|
||||
// ===== DEBUG NAV + TRACE (remover depois) =====
|
||||
@@ -80,9 +83,9 @@ router.push = async (loc) => {
|
||||
console.log('[router.push]', loc);
|
||||
console.trace('[push caller]');
|
||||
const res = await _push(loc);
|
||||
if (isNavigationFailure(res, NavigationFailureType.duplicated)) console.warn('[NAV FAIL] duplicated', res);
|
||||
else if (isNavigationFailure(res, NavigationFailureType.cancelled)) console.warn('[NAV FAIL] cancelled', res);
|
||||
else if (isNavigationFailure(res, NavigationFailureType.aborted)) console.warn('[NAV FAIL] aborted', res);
|
||||
if (isNavigationFailure(res, NavigationFailureType.duplicated)) console.warn('[NAV FAIL] duplicated', res);
|
||||
else if (isNavigationFailure(res, NavigationFailureType.cancelled)) console.warn('[NAV FAIL] cancelled', res);
|
||||
else if (isNavigationFailure(res, NavigationFailureType.aborted)) console.warn('[NAV FAIL] aborted', res);
|
||||
else if (isNavigationFailure(res, NavigationFailureType.redirected)) console.warn('[NAV FAIL] redirected', res);
|
||||
return res;
|
||||
};
|
||||
@@ -92,8 +95,8 @@ router.replace = async (loc) => {
|
||||
console.log('[router.replace]', loc);
|
||||
console.trace('[replace caller]');
|
||||
const res = await _replace(loc);
|
||||
if (isNavigationFailure(res, NavigationFailureType.cancelled)) console.warn('[NAV FAIL replace] cancelled', res);
|
||||
else if (isNavigationFailure(res, NavigationFailureType.aborted)) console.warn('[NAV FAIL replace] aborted', res);
|
||||
if (isNavigationFailure(res, NavigationFailureType.cancelled)) console.warn('[NAV FAIL replace] cancelled', res);
|
||||
else if (isNavigationFailure(res, NavigationFailureType.aborted)) console.warn('[NAV FAIL replace] aborted', res);
|
||||
else if (isNavigationFailure(res, NavigationFailureType.redirected)) console.warn('[NAV FAIL replace] redirected', res);
|
||||
return res;
|
||||
};
|
||||
@@ -102,8 +105,8 @@ router.onError((e) => console.error('[router.onError]', e));
|
||||
|
||||
// ✅ support guard — passa pinia para garantir acesso ao store antes do app.use(pinia)
|
||||
router.beforeEach(async (to) => {
|
||||
await supportGuard(to, pinia)
|
||||
})
|
||||
await supportGuard(to, pinia);
|
||||
});
|
||||
|
||||
router.beforeEach((to, from) => {
|
||||
console.log('[beforeEach]', from.fullPath, '->', to.fullPath);
|
||||
@@ -118,4 +121,4 @@ router.afterEach((to, from, failure) => {
|
||||
|
||||
applyGuards(router);
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
||||
@@ -14,26 +14,26 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
export default {
|
||||
path: '/account',
|
||||
component: AppLayout,
|
||||
meta: { requiresAuth: true, area: 'account' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirect: { name: 'account-profile' }
|
||||
},
|
||||
{
|
||||
path: 'profile',
|
||||
name: 'account-profile',
|
||||
component: () => import('@/views/pages/account/ProfilePage.vue')
|
||||
},
|
||||
{
|
||||
path: 'security',
|
||||
name: 'account-security',
|
||||
component: () => import('@/views/pages/auth/SecurityPage.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
path: '/account',
|
||||
component: AppLayout,
|
||||
meta: { requiresAuth: true, area: 'account' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirect: { name: 'account-profile' }
|
||||
},
|
||||
{
|
||||
path: 'profile',
|
||||
name: 'account-profile',
|
||||
component: () => import('@/views/pages/account/ProfilePage.vue')
|
||||
},
|
||||
{
|
||||
path: 'security',
|
||||
name: 'account-security',
|
||||
component: () => import('@/views/pages/auth/SecurityPage.vue')
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
+41
-41
@@ -15,47 +15,47 @@
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
export default {
|
||||
path: '/auth',
|
||||
children: [
|
||||
{
|
||||
path: 'login',
|
||||
name: 'login',
|
||||
component: () => import('@/views/pages/auth/Login.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
path: '/auth',
|
||||
children: [
|
||||
{
|
||||
path: 'login',
|
||||
name: 'login',
|
||||
component: () => import('@/views/pages/auth/Login.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
|
||||
// ✅ Signup público, mas com URL /auth/signup
|
||||
{
|
||||
path: 'signup',
|
||||
name: 'signup',
|
||||
component: () => import('@/views/pages/public/Signup.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
{
|
||||
path: 'welcome',
|
||||
name: 'auth.welcome',
|
||||
component: () => import('@/views/pages/auth/Welcome.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
{
|
||||
path: 'reset-password',
|
||||
name: 'resetPassword',
|
||||
component: () => import('@/views/pages/auth/ResetPasswordPage.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
// ✅ Signup público, mas com URL /auth/signup
|
||||
{
|
||||
path: 'signup',
|
||||
name: 'signup',
|
||||
component: () => import('@/views/pages/public/Signup.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
{
|
||||
path: 'welcome',
|
||||
name: 'auth.welcome',
|
||||
component: () => import('@/views/pages/auth/Welcome.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
{
|
||||
path: 'reset-password',
|
||||
name: 'resetPassword',
|
||||
component: () => import('@/views/pages/auth/ResetPasswordPage.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
|
||||
{
|
||||
path: 'access',
|
||||
name: 'accessDenied',
|
||||
component: () => import('@/views/pages/auth/Access.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
{
|
||||
path: 'access',
|
||||
name: 'accessDenied',
|
||||
component: () => import('@/views/pages/auth/Access.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
|
||||
{
|
||||
path: 'error',
|
||||
name: 'error',
|
||||
component: () => import('@/views/pages/auth/Error.vue'),
|
||||
meta: { public: true }
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
path: 'error',
|
||||
name: 'error',
|
||||
component: () => import('@/views/pages/auth/Error.vue'),
|
||||
meta: { public: true }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -14,17 +14,17 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
export default {
|
||||
path: '/upgrade',
|
||||
component: AppLayout,
|
||||
meta: { requiresAuth: true },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'upgrade',
|
||||
component: () => import('@/views/pages/billing/UpgradePage.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
path: '/upgrade',
|
||||
component: AppLayout,
|
||||
meta: { requiresAuth: true },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'upgrade',
|
||||
component: () => import('@/views/pages/billing/UpgradePage.vue')
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
+199
-199
@@ -14,225 +14,225 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
export default [
|
||||
// ======================================================
|
||||
// 🚀 SETUP WIZARD — fora do AppLayout (fullscreen)
|
||||
// ======================================================
|
||||
{
|
||||
path: '/admin/setup',
|
||||
name: 'admin.setup',
|
||||
component: () => import('@/features/setup/SetupWizardPage.vue'),
|
||||
meta: { area: 'admin', requiresAuth: true, roles: ['clinic_admin'], fullscreen: true },
|
||||
},
|
||||
|
||||
{
|
||||
path: '/admin',
|
||||
component: AppLayout,
|
||||
|
||||
meta: {
|
||||
// 🔐 Tudo aqui dentro exige login
|
||||
area: 'admin',
|
||||
requiresAuth: true,
|
||||
|
||||
// 👤 Perfil de acesso (tenant-level)
|
||||
// tenantStore normaliza tenant_admin -> clinic_admin, mas mantemos compatibilidade
|
||||
roles: ['clinic_admin']
|
||||
},
|
||||
children: [
|
||||
|
||||
// ======================================================
|
||||
// 📊 DASHBOARD
|
||||
// ======================================================
|
||||
{ path: '', name: 'admin.dashboard', component: () => import('@/views/pages/clinic/ClinicDashboard.vue') },
|
||||
|
||||
// ======================================================
|
||||
// 🧩 CLÍNICA — MÓDULOS (tenant_features)
|
||||
// 🚀 SETUP WIZARD — fora do AppLayout (fullscreen)
|
||||
// ======================================================
|
||||
{
|
||||
path: 'clinic/features',
|
||||
name: 'admin-clinic-features',
|
||||
component: () => import('@/views/pages/clinic/clinic/ClinicFeaturesPage.vue'),
|
||||
meta: {
|
||||
// opcional: restringir apenas para admin canônico
|
||||
roles: ['clinic_admin', 'tenant_admin']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'clinic/professionals',
|
||||
name: 'admin-clinic-professionals',
|
||||
component: () => import('@/views/pages/clinic/clinic/ClinicProfessionalsPage.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
roles: ['clinic_admin', 'tenant_admin']
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'admin-meu-plano',
|
||||
component: () => import('@/views/pages/billing/ClinicMeuPlanoPage.vue')
|
||||
path: '/admin/setup',
|
||||
name: 'admin.setup',
|
||||
component: () => import('@/features/setup/SetupWizardPage.vue'),
|
||||
meta: { area: 'admin', requiresAuth: true, roles: ['clinic_admin'], fullscreen: true }
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 📅 AGENDA DA CLÍNICA
|
||||
// ======================================================
|
||||
|
||||
{
|
||||
path: 'agenda/clinica',
|
||||
name: 'admin-agenda-clinica',
|
||||
component: () => import('@/features/agenda/pages/AgendaClinicaPage.vue'),
|
||||
meta: {
|
||||
feature: 'agenda.view',
|
||||
roles: ['clinic_admin', 'tenant_admin']
|
||||
}
|
||||
},
|
||||
path: '/admin',
|
||||
component: AppLayout,
|
||||
|
||||
// Recorrências
|
||||
{
|
||||
path: 'agenda/recorrencias',
|
||||
name: 'admin-agenda-recorrencias',
|
||||
component: () => import('@/features/agenda/pages/AgendaRecorrenciasPage.vue'),
|
||||
meta: { feature: 'agenda.view', roles: ['clinic_admin', 'tenant_admin'], mode: 'clinic' }
|
||||
},
|
||||
meta: {
|
||||
// 🔐 Tudo aqui dentro exige login
|
||||
area: 'admin',
|
||||
requiresAuth: true,
|
||||
|
||||
// ✅ NOVO: Compromissos determinísticos (tipos)
|
||||
{
|
||||
path: 'agenda/compromissos',
|
||||
name: 'admin-agenda-compromissos',
|
||||
component: () => import('@/features/agenda/pages/CompromissosDeterminados.vue'),
|
||||
meta: {
|
||||
feature: 'agenda.view',
|
||||
roles: ['clinic_admin', 'tenant_admin']
|
||||
// ✅ sem tenantScope: a área /admin já está no tenant da clínica pelo fluxo normal
|
||||
}
|
||||
},
|
||||
// 👤 Perfil de acesso (tenant-level)
|
||||
// tenantStore normaliza tenant_admin -> clinic_admin, mas mantemos compatibilidade
|
||||
roles: ['clinic_admin']
|
||||
},
|
||||
children: [
|
||||
// ======================================================
|
||||
// 📊 DASHBOARD
|
||||
// ======================================================
|
||||
{ path: '', name: 'admin.dashboard', component: () => import('@/views/pages/clinic/ClinicDashboard.vue') },
|
||||
|
||||
// ======================================================
|
||||
// 👥 PACIENTES (módulo ativável por clínica)
|
||||
// ======================================================
|
||||
// ======================================================
|
||||
// 🧩 CLÍNICA — MÓDULOS (tenant_features)
|
||||
// ======================================================
|
||||
{
|
||||
path: 'clinic/features',
|
||||
name: 'admin-clinic-features',
|
||||
component: () => import('@/views/pages/clinic/clinic/ClinicFeaturesPage.vue'),
|
||||
meta: {
|
||||
// opcional: restringir apenas para admin canônico
|
||||
roles: ['clinic_admin', 'tenant_admin']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'clinic/professionals',
|
||||
name: 'admin-clinic-professionals',
|
||||
component: () => import('@/views/pages/clinic/clinic/ClinicProfessionalsPage.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
roles: ['clinic_admin', 'tenant_admin']
|
||||
}
|
||||
},
|
||||
|
||||
// 📋 Lista de pacientes
|
||||
{
|
||||
path: 'pacientes',
|
||||
name: 'admin-pacientes',
|
||||
component: () => import('@/features/patients/PatientsListPage.vue'),
|
||||
meta: {
|
||||
// ✅ depende do tenant_features.patients
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'admin-meu-plano',
|
||||
component: () => import('@/views/pages/billing/ClinicMeuPlanoPage.vue')
|
||||
},
|
||||
|
||||
// ➕ Cadastro de paciente (novo)
|
||||
{
|
||||
path: 'pacientes/cadastro',
|
||||
name: 'admin-pacientes-cadastro',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
// ======================================================
|
||||
// 📅 AGENDA DA CLÍNICA
|
||||
// ======================================================
|
||||
|
||||
// ✏️ Editar paciente
|
||||
{
|
||||
path: 'pacientes/cadastro/:id',
|
||||
name: 'admin-pacientes-cadastro-edit',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue'),
|
||||
props: true,
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'agenda/clinica',
|
||||
name: 'admin-agenda-clinica',
|
||||
component: () => import('@/features/agenda/pages/AgendaClinicaPage.vue'),
|
||||
meta: {
|
||||
feature: 'agenda.view',
|
||||
roles: ['clinic_admin', 'tenant_admin']
|
||||
}
|
||||
},
|
||||
|
||||
// 👥 Grupos de pacientes
|
||||
{
|
||||
path: 'pacientes/grupos',
|
||||
name: 'admin-pacientes-grupos',
|
||||
component: () => import('@/features/patients/grupos/GruposPacientesPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
// Recorrências
|
||||
{
|
||||
path: 'agenda/recorrencias',
|
||||
name: 'admin-agenda-recorrencias',
|
||||
component: () => import('@/features/agenda/pages/AgendaRecorrenciasPage.vue'),
|
||||
meta: { feature: 'agenda.view', roles: ['clinic_admin', 'tenant_admin'], mode: 'clinic' }
|
||||
},
|
||||
|
||||
// 🏷️ Tags de pacientes
|
||||
{
|
||||
path: 'pacientes/tags',
|
||||
name: 'admin-pacientes-tags',
|
||||
component: () => import('@/features/patients/tags/TagsPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
// ✅ NOVO: Compromissos determinísticos (tipos)
|
||||
{
|
||||
path: 'agenda/compromissos',
|
||||
name: 'admin-agenda-compromissos',
|
||||
component: () => import('@/features/agenda/pages/CompromissosDeterminados.vue'),
|
||||
meta: {
|
||||
feature: 'agenda.view',
|
||||
roles: ['clinic_admin', 'tenant_admin']
|
||||
// ✅ sem tenantScope: a área /admin já está no tenant da clínica pelo fluxo normal
|
||||
}
|
||||
},
|
||||
|
||||
// 🔗 Link externo para cadastro
|
||||
{
|
||||
path: 'pacientes/link-externo',
|
||||
name: 'admin-pacientes-link-externo',
|
||||
component: () => import('@/features/patients/cadastro/PatientsExternalLinkPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
// ======================================================
|
||||
// 👥 PACIENTES (módulo ativável por clínica)
|
||||
// ======================================================
|
||||
|
||||
// 📥 Cadastros recebidos via link externo
|
||||
{
|
||||
path: 'pacientes/cadastro/recebidos',
|
||||
name: 'admin-pacientes-recebidos',
|
||||
component: () => import('@/features/patients/cadastro/recebidos/CadastrosRecebidosPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
// 📋 Lista de pacientes
|
||||
{
|
||||
path: 'pacientes',
|
||||
name: 'admin-pacientes',
|
||||
component: () => import('@/features/patients/PatientsListPage.vue'),
|
||||
meta: {
|
||||
// ✅ depende do tenant_features.patients
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔐 SEGURANÇA
|
||||
// ======================================================
|
||||
{
|
||||
path: 'settings/security',
|
||||
name: 'admin-settings-security',
|
||||
component: () => import('@/views/pages/auth/SecurityPage.vue')
|
||||
},
|
||||
// ➕ Cadastro de paciente (novo)
|
||||
{
|
||||
path: 'pacientes/cadastro',
|
||||
name: 'admin-pacientes-cadastro',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔒 MÓDULO PRO — Online Scheduling
|
||||
// ======================================================
|
||||
{
|
||||
path: 'online-scheduling',
|
||||
name: 'admin-online-scheduling',
|
||||
component: () => import('@/views/pages/clinic/OnlineSchedulingAdminPage.vue'),
|
||||
meta: {
|
||||
feature: 'online_scheduling.manage'
|
||||
}
|
||||
},
|
||||
// ✏️ Editar paciente
|
||||
{
|
||||
path: 'pacientes/cadastro/:id',
|
||||
name: 'admin-pacientes-cadastro-edit',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue'),
|
||||
props: true,
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔒 PRO — Agendamentos Recebidos
|
||||
// ======================================================
|
||||
{
|
||||
path: 'agendamentos-recebidos',
|
||||
name: 'admin-agendamentos-recebidos',
|
||||
component: () => import('@/features/agenda/pages/AgendamentosRecebidosPage.vue'),
|
||||
meta: {
|
||||
feature: 'online_scheduling.manage'
|
||||
}
|
||||
},
|
||||
// 👥 Grupos de pacientes
|
||||
{
|
||||
path: 'pacientes/grupos',
|
||||
name: 'admin-pacientes-grupos',
|
||||
component: () => import('@/features/patients/grupos/GruposPacientesPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 💰 FINANCEIRO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'financeiro',
|
||||
name: 'admin-financeiro',
|
||||
component: () => import('@/features/financeiro/pages/FinanceiroDashboardPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'financeiro/lancamentos',
|
||||
name: 'admin-financeiro-lancamentos',
|
||||
component: () => import('@/features/financeiro/pages/FinanceiroPage.vue')
|
||||
// 🏷️ Tags de pacientes
|
||||
{
|
||||
path: 'pacientes/tags',
|
||||
name: 'admin-pacientes-tags',
|
||||
component: () => import('@/features/patients/tags/TagsPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
|
||||
// 🔗 Link externo para cadastro
|
||||
{
|
||||
path: 'pacientes/link-externo',
|
||||
name: 'admin-pacientes-link-externo',
|
||||
component: () => import('@/features/patients/cadastro/PatientsExternalLinkPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
|
||||
// 📥 Cadastros recebidos via link externo
|
||||
{
|
||||
path: 'pacientes/cadastro/recebidos',
|
||||
name: 'admin-pacientes-recebidos',
|
||||
component: () => import('@/features/patients/cadastro/recebidos/CadastrosRecebidosPage.vue'),
|
||||
meta: {
|
||||
tenantFeature: 'patients'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔐 SEGURANÇA
|
||||
// ======================================================
|
||||
{
|
||||
path: 'settings/security',
|
||||
name: 'admin-settings-security',
|
||||
component: () => import('@/views/pages/auth/SecurityPage.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔒 MÓDULO PRO — Online Scheduling
|
||||
// ======================================================
|
||||
{
|
||||
path: 'online-scheduling',
|
||||
name: 'admin-online-scheduling',
|
||||
component: () => import('@/views/pages/clinic/OnlineSchedulingAdminPage.vue'),
|
||||
meta: {
|
||||
feature: 'online_scheduling.manage'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔒 PRO — Agendamentos Recebidos
|
||||
// ======================================================
|
||||
{
|
||||
path: 'agendamentos-recebidos',
|
||||
name: 'admin-agendamentos-recebidos',
|
||||
component: () => import('@/features/agenda/pages/AgendamentosRecebidosPage.vue'),
|
||||
meta: {
|
||||
feature: 'online_scheduling.manage'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 💰 FINANCEIRO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'financeiro',
|
||||
name: 'admin-financeiro',
|
||||
component: () => import('@/features/financeiro/pages/FinanceiroDashboardPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'financeiro/lancamentos',
|
||||
name: 'admin-financeiro-lancamentos',
|
||||
component: () => import('@/features/financeiro/pages/FinanceiroPage.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
];
|
||||
|
||||
@@ -14,78 +14,102 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
const configuracoesRoutes = {
|
||||
path: '/configuracoes',
|
||||
component: AppLayout,
|
||||
path: '/configuracoes',
|
||||
component: AppLayout,
|
||||
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
roles: ['admin', 'tenant_admin', 'therapist']
|
||||
},
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
roles: ['admin', 'tenant_admin', 'therapist']
|
||||
},
|
||||
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/layout/ConfiguracoesPage.vue'),
|
||||
redirect: { name: 'ConfiguracoesAgenda' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/layout/ConfiguracoesPage.vue'),
|
||||
redirect: { name: 'ConfiguracoesAgenda' },
|
||||
|
||||
children: [
|
||||
{
|
||||
path: 'agenda',
|
||||
name: 'ConfiguracoesAgenda',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesAgendaPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'bloqueios',
|
||||
name: 'ConfiguracoesBloqueios',
|
||||
component: () => import('@/layout/configuracoes/BloqueiosPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'agendador',
|
||||
name: 'ConfiguracoesAgendador',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesAgendadorPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'pagamento',
|
||||
name: 'ConfiguracoesPagamento',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesPagamentoPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'precificacao',
|
||||
name: 'ConfiguracoesPrecificacao',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesPrecificacaoPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'descontos',
|
||||
name: 'ConfiguracoesDescontos',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesDescontosPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'excecoes-financeiras',
|
||||
name: 'ConfiguracoesExcecoesFinanceiras',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesExcecoesFinanceirasPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'convenios',
|
||||
name: 'ConfiguracoesConvenios',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesConveniosPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'email-templates',
|
||||
name: 'ConfiguracoesEmailTemplates',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesEmailTemplatesPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'empresa',
|
||||
name: 'ConfiguracoesMinhaEmpresa',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesMinhaEmpresaPage.vue')
|
||||
children: [
|
||||
{
|
||||
path: 'agenda',
|
||||
name: 'ConfiguracoesAgenda',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesAgendaPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'bloqueios',
|
||||
name: 'ConfiguracoesBloqueios',
|
||||
component: () => import('@/layout/configuracoes/BloqueiosPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'agendador',
|
||||
name: 'ConfiguracoesAgendador',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesAgendadorPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'pagamento',
|
||||
name: 'ConfiguracoesPagamento',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesPagamentoPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'precificacao',
|
||||
name: 'ConfiguracoesPrecificacao',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesPrecificacaoPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'descontos',
|
||||
name: 'ConfiguracoesDescontos',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesDescontosPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'excecoes-financeiras',
|
||||
name: 'ConfiguracoesExcecoesFinanceiras',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesExcecoesFinanceirasPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'convenios',
|
||||
name: 'ConfiguracoesConvenios',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesConveniosPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'email-templates',
|
||||
name: 'ConfiguracoesEmailTemplates',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesEmailTemplatesPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'empresa',
|
||||
name: 'ConfiguracoesMinhaEmpresa',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesMinhaEmpresaPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'canais',
|
||||
name: 'ConfiguracoesCanais',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesCanaisPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'whatsapp',
|
||||
name: 'ConfiguracoesWhatsapp',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesWhatsappPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'sms',
|
||||
name: 'ConfiguracoesSms',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesSmsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'sms-canal',
|
||||
name: 'ConfiguracoesSmsCanal',
|
||||
component: () => import('@/views/pages/notifications/SmsChannelSetupPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'recursos-extras',
|
||||
name: 'ConfiguracoesRecursosExtras',
|
||||
component: () => import('@/layout/configuracoes/ConfiguracoesRecursosExtrasPage.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export default configuracoesRoutes
|
||||
]
|
||||
};
|
||||
|
||||
export default configuracoesRoutes;
|
||||
|
||||
+50
-50
@@ -18,61 +18,61 @@
|
||||
// Acesso controlado por `platform_roles` no guard (não por tenant role).
|
||||
// meta.editorArea: true sinaliza ao guard que use a verificação de plataforma.
|
||||
//
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
export default {
|
||||
path: '/editor',
|
||||
component: AppLayout,
|
||||
path: '/editor',
|
||||
component: AppLayout,
|
||||
|
||||
meta: { area: 'editor', requiresAuth: true, editorArea: true },
|
||||
meta: { area: 'editor', requiresAuth: true, editorArea: true },
|
||||
|
||||
children: [
|
||||
// ======================================================
|
||||
// 📊 DASHBOARD
|
||||
// ======================================================
|
||||
{
|
||||
path: '',
|
||||
name: 'editor.dashboard',
|
||||
component: () => import('@/views/pages/editor/EditorDashboard.vue')
|
||||
},
|
||||
children: [
|
||||
// ======================================================
|
||||
// 📊 DASHBOARD
|
||||
// ======================================================
|
||||
{
|
||||
path: '',
|
||||
name: 'editor.dashboard',
|
||||
component: () => import('@/views/pages/editor/EditorDashboard.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 📚 CURSOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'cursos',
|
||||
name: 'editor-cursos',
|
||||
// placeholder — módulo de microlearning a implementar
|
||||
component: () => import('@/views/pages/editor/EditorDashboard.vue')
|
||||
},
|
||||
// ======================================================
|
||||
// 📚 CURSOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'cursos',
|
||||
name: 'editor-cursos',
|
||||
// placeholder — módulo de microlearning a implementar
|
||||
component: () => import('@/views/pages/editor/EditorDashboard.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 📦 MÓDULOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'modulos',
|
||||
name: 'editor-modulos',
|
||||
// placeholder
|
||||
component: () => import('@/views/pages/editor/EditorDashboard.vue')
|
||||
},
|
||||
// ======================================================
|
||||
// 📦 MÓDULOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'modulos',
|
||||
name: 'editor-modulos',
|
||||
// placeholder
|
||||
component: () => import('@/views/pages/editor/EditorDashboard.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// ✅ PUBLICADOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'publicados',
|
||||
name: 'editor-publicados',
|
||||
// placeholder
|
||||
component: () => import('@/views/pages/editor/EditorDashboard.vue')
|
||||
},
|
||||
// ======================================================
|
||||
// ✅ PUBLICADOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'publicados',
|
||||
name: 'editor-publicados',
|
||||
// placeholder
|
||||
component: () => import('@/views/pages/editor/EditorDashboard.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO (assinatura pessoal do editor)
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'editor-meu-plano',
|
||||
component: () => import('@/views/pages/billing/TherapistMeuPlanoPage.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO (assinatura pessoal do editor)
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'editor-meu-plano',
|
||||
component: () => import('@/views/pages/billing/TherapistMeuPlanoPage.vue')
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -14,28 +14,28 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
export default {
|
||||
path: '/features',
|
||||
component: AppLayout,
|
||||
meta: { requiresAuth: true }, // roles: se você quiser travar aqui também
|
||||
children: [
|
||||
// Patients
|
||||
{
|
||||
path: 'patients',
|
||||
name: 'features.patients.list',
|
||||
component: () => import('@/features/patients/PatientsListPage.vue') // ajuste se seu arquivo tiver outro nome
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro',
|
||||
name: 'features.patients.create',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro/:id',
|
||||
name: 'features.patients.edit',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
path: '/features',
|
||||
component: AppLayout,
|
||||
meta: { requiresAuth: true }, // roles: se você quiser travar aqui também
|
||||
children: [
|
||||
// Patients
|
||||
{
|
||||
path: 'patients',
|
||||
name: 'features.patients.list',
|
||||
component: () => import('@/features/patients/PatientsListPage.vue') // ajuste se seu arquivo tiver outro nome
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro',
|
||||
name: 'features.patients.create',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro/:id',
|
||||
name: 'features.patients.edit',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue')
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
+29
-29
@@ -15,35 +15,35 @@
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
export default {
|
||||
path: '/',
|
||||
children: [
|
||||
{
|
||||
path: 'landing',
|
||||
name: 'landing',
|
||||
component: () => import('@/views/pages/Landing.vue')
|
||||
},
|
||||
path: '/',
|
||||
children: [
|
||||
{
|
||||
path: 'landing',
|
||||
name: 'landing',
|
||||
component: () => import('@/views/pages/Landing.vue')
|
||||
},
|
||||
|
||||
// 404
|
||||
{
|
||||
path: 'pages/notfound',
|
||||
name: 'notfound',
|
||||
component: () => import('@/views/pages/NotFound.vue')
|
||||
},
|
||||
// 404
|
||||
{
|
||||
path: 'pages/notfound',
|
||||
name: 'notfound',
|
||||
component: () => import('@/views/pages/NotFound.vue')
|
||||
},
|
||||
|
||||
// 403 (Acesso negado - RBAC)
|
||||
{
|
||||
path: 'pages/access', // ❗ SEM barra inicial aqui
|
||||
name: 'AccessDenied',
|
||||
component: () => import('@/views/pages/misc/AccessDeniedPage.vue'),
|
||||
meta: {
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
// 403 (Acesso negado - RBAC)
|
||||
{
|
||||
path: 'pages/access', // ❗ SEM barra inicial aqui
|
||||
name: 'AccessDenied',
|
||||
component: () => import('@/views/pages/misc/AccessDeniedPage.vue'),
|
||||
meta: {
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
|
||||
// Catch-all (SEMPRE o último)
|
||||
{
|
||||
path: ':pathMatch(.*)*',
|
||||
redirect: { name: 'notfound' }
|
||||
}
|
||||
]
|
||||
}
|
||||
// Catch-all (SEMPRE o último)
|
||||
{
|
||||
path: ':pathMatch(.*)*',
|
||||
redirect: { name: 'notfound' }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
+21
-21
@@ -14,27 +14,27 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
export default {
|
||||
path: '/portal',
|
||||
component: AppLayout,
|
||||
meta: { area: 'portal', requiresAuth: true, profileRole: 'portal_user' },
|
||||
children: [
|
||||
{ path: '', name: 'portal.dashboard', component: () => import('@/views/pages/portal/PortalDashboard.vue') },
|
||||
{
|
||||
path: 'sessoes',
|
||||
name: 'portal-sessoes',
|
||||
component: () => import('@/views/pages/portal/MinhasSessoes.vue')
|
||||
},
|
||||
path: '/portal',
|
||||
component: AppLayout,
|
||||
meta: { area: 'portal', requiresAuth: true, profileRole: 'portal_user' },
|
||||
children: [
|
||||
{ path: '', name: 'portal.dashboard', component: () => import('@/views/pages/portal/PortalDashboard.vue') },
|
||||
{
|
||||
path: 'sessoes',
|
||||
name: 'portal-sessoes',
|
||||
component: () => import('@/views/pages/portal/MinhasSessoes.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO (assinatura pessoal do paciente)
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'portal-meu-plano',
|
||||
component: () => import('@/views/pages/billing/TherapistMeuPlanoPage.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO (assinatura pessoal do paciente)
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'portal-meu-plano',
|
||||
component: () => import('@/views/pages/billing/TherapistMeuPlanoPage.vue')
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
+11
-11
@@ -38,19 +38,19 @@ export default {
|
||||
component: () => import('@/views/pages/public/CadastroPacienteExterno.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
// ✅ convite de clinicas
|
||||
{
|
||||
path: '/accept-invite',
|
||||
name: 'accept-invite',
|
||||
component: () => import('@/views/pages/public/AcceptInvitePage.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
// ✅ convite de clinicas
|
||||
{
|
||||
path: '/accept-invite',
|
||||
name: 'accept-invite',
|
||||
component: () => import('@/views/pages/public/AcceptInvitePage.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
// ✅ agendador online público
|
||||
{
|
||||
path: '/agendar/:slug',
|
||||
name: 'agendador.publico',
|
||||
component: () => import('@/views/pages/public/AgendadorPublicoPage.vue'),
|
||||
meta: { public: true }
|
||||
path: '/agendar/:slug',
|
||||
name: 'agendador.publico',
|
||||
component: () => import('@/views/pages/public/AgendadorPublicoPage.vue'),
|
||||
meta: { public: true }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
+119
-101
@@ -14,106 +14,124 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
export default {
|
||||
path: '/saas',
|
||||
component: AppLayout,
|
||||
meta: { requiresAuth: true, saasAdmin: true },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'saas-dashboard',
|
||||
component: () => import('@/views/pages/saas/SaasDashboard.vue')
|
||||
},
|
||||
{
|
||||
path: 'plans',
|
||||
name: 'saas-plans',
|
||||
component: () => import('@/views/pages/saas/SaasPlansPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'plans-public',
|
||||
name: 'saas-plans-public',
|
||||
component: () => import('@/views/pages/saas/SaasPlansPublicPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'features',
|
||||
name: 'saas-features',
|
||||
component: () => import('@/views/pages/saas/SaasFeaturesPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'plan-features',
|
||||
name: 'saas-plan-features',
|
||||
component: () => import('@/views/pages/saas/SaasPlanFeaturesMatrixPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'plan-limits',
|
||||
name: 'saas-plan-limits',
|
||||
component: () => import('@/views/pages/saas/SaasPlanLimitsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'subscriptions',
|
||||
name: 'saas-subscriptions',
|
||||
component: () => import('@/views/pages/saas/SaasSubscriptionsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'subscription-events',
|
||||
name: 'saas-subscription-events',
|
||||
component: () => import('@/views/pages/saas/SaasSubscriptionEventsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'subscription-health',
|
||||
name: 'saas-subscription-health',
|
||||
component: () => import('@/views/pages/saas/SaasSubscriptionHealthPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'subscription-intents',
|
||||
name: 'saas.subscriptionIntents',
|
||||
component: () => import('@/views/pages/saas/SubscriptionIntentsPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'tenants',
|
||||
name: 'saas-tenants',
|
||||
component: () => import('@/views/pages/saas/SaasPlaceholder.vue')
|
||||
},
|
||||
{
|
||||
path: 'feriados',
|
||||
name: 'saas-feriados',
|
||||
component: () => import('@/views/pages/saas/SaasFeriadosPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'docs',
|
||||
name: 'saas-docs',
|
||||
component: () => import('@/views/pages/saas/SaasDocsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'faq',
|
||||
name: 'saas-faq',
|
||||
component: () => import('@/views/pages/saas/SaasFaqPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'support',
|
||||
name: 'saas-support',
|
||||
component: () => import('@/views/pages/saas/SaasSupportPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'login-carousel',
|
||||
name: 'saas-login-carousel',
|
||||
component: () => import('@/views/pages/saas/SaasLoginCarousel.vue')
|
||||
},
|
||||
{
|
||||
path: 'global-notices',
|
||||
name: 'saas-global-notices',
|
||||
component: () => import('@/views/pages/saas/SaasGlobalNoticesPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'email-templates',
|
||||
name: 'saas-email-templates',
|
||||
component: () => import('@/views/pages/saas/SaasEmailTemplatesPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
}
|
||||
]
|
||||
}
|
||||
path: '/saas',
|
||||
component: AppLayout,
|
||||
meta: { requiresAuth: true, saasAdmin: true },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'saas-dashboard',
|
||||
component: () => import('@/views/pages/saas/SaasDashboard.vue')
|
||||
},
|
||||
{
|
||||
path: 'plans',
|
||||
name: 'saas-plans',
|
||||
component: () => import('@/views/pages/saas/SaasPlansPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'plans-public',
|
||||
name: 'saas-plans-public',
|
||||
component: () => import('@/views/pages/saas/SaasPlansPublicPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'features',
|
||||
name: 'saas-features',
|
||||
component: () => import('@/views/pages/saas/SaasFeaturesPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'plan-features',
|
||||
name: 'saas-plan-features',
|
||||
component: () => import('@/views/pages/saas/SaasPlanFeaturesMatrixPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'plan-limits',
|
||||
name: 'saas-plan-limits',
|
||||
component: () => import('@/views/pages/saas/SaasPlanLimitsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'subscriptions',
|
||||
name: 'saas-subscriptions',
|
||||
component: () => import('@/views/pages/saas/SaasSubscriptionsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'subscription-events',
|
||||
name: 'saas-subscription-events',
|
||||
component: () => import('@/views/pages/saas/SaasSubscriptionEventsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'subscription-health',
|
||||
name: 'saas-subscription-health',
|
||||
component: () => import('@/views/pages/saas/SaasSubscriptionHealthPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'subscription-intents',
|
||||
name: 'saas.subscriptionIntents',
|
||||
component: () => import('@/views/pages/saas/SubscriptionIntentsPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'tenants',
|
||||
name: 'saas-tenants',
|
||||
component: () => import('@/views/pages/saas/SaasPlaceholder.vue')
|
||||
},
|
||||
{
|
||||
path: 'feriados',
|
||||
name: 'saas-feriados',
|
||||
component: () => import('@/views/pages/saas/SaasFeriadosPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'docs',
|
||||
name: 'saas-docs',
|
||||
component: () => import('@/views/pages/saas/SaasDocsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'faq',
|
||||
name: 'saas-faq',
|
||||
component: () => import('@/views/pages/saas/SaasFaqPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'support',
|
||||
name: 'saas-support',
|
||||
component: () => import('@/views/pages/saas/SaasSupportPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'login-carousel',
|
||||
name: 'saas-login-carousel',
|
||||
component: () => import('@/views/pages/saas/SaasLoginCarousel.vue')
|
||||
},
|
||||
{
|
||||
path: 'global-notices',
|
||||
name: 'saas-global-notices',
|
||||
component: () => import('@/views/pages/saas/SaasGlobalNoticesPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'email-templates',
|
||||
name: 'saas-email-templates',
|
||||
component: () => import('@/views/pages/saas/SaasEmailTemplatesPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'notification-templates',
|
||||
name: 'saas-notification-templates',
|
||||
component: () => import('@/views/pages/saas/SaasNotificationTemplatesPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'whatsapp',
|
||||
name: 'saas-whatsapp',
|
||||
component: () => import('@/views/pages/saas/SaasWhatsappPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'addons',
|
||||
name: 'saas-addons',
|
||||
component: () => import('@/views/pages/saas/SaasAddonsPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -14,48 +14,48 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
export default {
|
||||
path: '/supervisor',
|
||||
component: AppLayout,
|
||||
path: '/supervisor',
|
||||
component: AppLayout,
|
||||
|
||||
// tenantScope: 'supervisor' → o guard troca automaticamente para o tenant
|
||||
// com kind='supervisor' quando o usuário navega para esta área.
|
||||
meta: {
|
||||
area: 'supervisor',
|
||||
requiresAuth: true,
|
||||
roles: ['supervisor'],
|
||||
tenantScope: 'supervisor'
|
||||
},
|
||||
|
||||
children: [
|
||||
// ======================================================
|
||||
// 📊 DASHBOARD
|
||||
// ======================================================
|
||||
{
|
||||
path: '',
|
||||
name: 'supervisor.dashboard',
|
||||
component: () => import('@/views/pages/supervisor/SupervisorDashboard.vue')
|
||||
// tenantScope: 'supervisor' → o guard troca automaticamente para o tenant
|
||||
// com kind='supervisor' quando o usuário navega para esta área.
|
||||
meta: {
|
||||
area: 'supervisor',
|
||||
requiresAuth: true,
|
||||
roles: ['supervisor'],
|
||||
tenantScope: 'supervisor'
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🎓 SALA DE SUPERVISÃO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'sala',
|
||||
name: 'supervisor.sala',
|
||||
component: () => import('@/views/pages/supervisor/SupervisaoSalaPage.vue'),
|
||||
meta: { feature: 'supervisor.access' }
|
||||
},
|
||||
children: [
|
||||
// ======================================================
|
||||
// 📊 DASHBOARD
|
||||
// ======================================================
|
||||
{
|
||||
path: '',
|
||||
name: 'supervisor.dashboard',
|
||||
component: () => import('@/views/pages/supervisor/SupervisorDashboard.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'supervisor.meu-plano',
|
||||
component: () => import('@/views/pages/billing/TherapistMeuPlanoPage.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
// ======================================================
|
||||
// 🎓 SALA DE SUPERVISÃO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'sala',
|
||||
name: 'supervisor.sala',
|
||||
component: () => import('@/views/pages/supervisor/SupervisaoSalaPage.vue'),
|
||||
meta: { feature: 'supervisor.access' }
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'supervisor.meu-plano',
|
||||
component: () => import('@/views/pages/billing/TherapistMeuPlanoPage.vue')
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
+153
-153
@@ -14,173 +14,173 @@
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
import AppLayout from '@/layout/AppLayout.vue'
|
||||
import AppLayout from '@/layout/AppLayout.vue';
|
||||
|
||||
export default [
|
||||
// ======================================================
|
||||
// 🚀 SETUP WIZARD — fora do AppLayout (fullscreen)
|
||||
// ======================================================
|
||||
{
|
||||
path: '/therapist/setup',
|
||||
name: 'therapist.setup',
|
||||
component: () => import('@/features/setup/SetupWizardPage.vue'),
|
||||
meta: { area: 'therapist', requiresAuth: true, roles: ['therapist'], fullscreen: true },
|
||||
},
|
||||
|
||||
{
|
||||
path: '/therapist',
|
||||
component: AppLayout,
|
||||
|
||||
meta: { area: 'therapist', requiresAuth: true, roles: ['therapist'] },
|
||||
|
||||
children: [
|
||||
|
||||
// ======================================================
|
||||
// 📊 DASHBOARD
|
||||
// ======================================================
|
||||
{ path: '', name: 'therapist.dashboard', component: () => import('@/views/pages/therapist/TherapistDashboard.vue') },
|
||||
|
||||
// ======================================================
|
||||
// 📅 AGENDA
|
||||
// 🚀 SETUP WIZARD — fora do AppLayout (fullscreen)
|
||||
// ======================================================
|
||||
{
|
||||
path: 'agenda',
|
||||
name: 'therapist-agenda',
|
||||
component: () => import('@/features/agenda/pages/AgendaTerapeutaPage.vue'),
|
||||
meta: {
|
||||
feature: 'agenda.view'
|
||||
}
|
||||
path: '/therapist/setup',
|
||||
name: 'therapist.setup',
|
||||
component: () => import('@/features/setup/SetupWizardPage.vue'),
|
||||
meta: { area: 'therapist', requiresAuth: true, roles: ['therapist'], fullscreen: true }
|
||||
},
|
||||
|
||||
// Recorrências
|
||||
{
|
||||
path: 'agenda/recorrencias',
|
||||
name: 'therapist-agenda-recorrencias',
|
||||
component: () => import('@/features/agenda/pages/AgendaRecorrenciasPage.vue'),
|
||||
meta: { feature: 'agenda.view', mode: 'therapist' }
|
||||
},
|
||||
path: '/therapist',
|
||||
component: AppLayout,
|
||||
|
||||
// ✅ Compromissos determinísticos
|
||||
{
|
||||
path: 'agenda/compromissos',
|
||||
name: 'therapist-agenda-compromissos',
|
||||
component: () => import('@/features/agenda/pages/CompromissosDeterminados.vue'),
|
||||
meta: {
|
||||
feature: 'agenda.view',
|
||||
roles: ['therapist']
|
||||
// ✅ sem tenantScope
|
||||
}
|
||||
},
|
||||
meta: { area: 'therapist', requiresAuth: true, roles: ['therapist'] },
|
||||
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'therapist-meu-plano',
|
||||
component: () => import('@/views/pages/billing/TherapistMeuPlanoPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'upgrade',
|
||||
name: 'therapist-upgrade',
|
||||
component: () => import('@/views/pages/billing/TherapistUpgradePage.vue')
|
||||
},
|
||||
children: [
|
||||
// ======================================================
|
||||
// 📊 DASHBOARD
|
||||
// ======================================================
|
||||
{ path: '', name: 'therapist.dashboard', component: () => import('@/views/pages/therapist/TherapistDashboard.vue') },
|
||||
|
||||
// ======================================================
|
||||
// 👥 PATIENTS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'patients',
|
||||
name: 'therapist-patients',
|
||||
component: () => import('@/features/patients/PatientsListPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro',
|
||||
name: 'therapist-patients-create',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro/:id',
|
||||
name: 'therapist-patients-edit',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue'),
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: 'patients/grupos',
|
||||
name: 'therapist-patients-groups',
|
||||
component: () => import('@/features/patients/grupos/GruposPacientesPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/tags',
|
||||
name: 'therapist-patients-tags',
|
||||
component: () => import('@/features/patients/tags/TagsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/link-externo',
|
||||
name: 'therapist-patients-link-externo',
|
||||
component: () => import('@/features/patients/cadastro/PatientsExternalLinkPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro/recebidos',
|
||||
name: 'therapist-patients-recebidos',
|
||||
component: () => import('@/features/patients/cadastro/recebidos/CadastrosRecebidosPage.vue')
|
||||
},
|
||||
// ======================================================
|
||||
// 📅 AGENDA
|
||||
// ======================================================
|
||||
{
|
||||
path: 'agenda',
|
||||
name: 'therapist-agenda',
|
||||
component: () => import('@/features/agenda/pages/AgendaTerapeutaPage.vue'),
|
||||
meta: {
|
||||
feature: 'agenda.view'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔒 PRO — Online Scheduling
|
||||
// ======================================================
|
||||
{
|
||||
path: 'online-scheduling',
|
||||
name: 'therapist-online-scheduling',
|
||||
component: () => import('@/views/pages/therapist/OnlineSchedulingPage.vue'),
|
||||
meta: {
|
||||
feature: 'online_scheduling.manage'
|
||||
}
|
||||
},
|
||||
// Recorrências
|
||||
{
|
||||
path: 'agenda/recorrencias',
|
||||
name: 'therapist-agenda-recorrencias',
|
||||
component: () => import('@/features/agenda/pages/AgendaRecorrenciasPage.vue'),
|
||||
meta: { feature: 'agenda.view', mode: 'therapist' }
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔒 PRO — Agendamentos Recebidos
|
||||
// ======================================================
|
||||
{
|
||||
path: 'agendamentos-recebidos',
|
||||
name: 'therapist-agendamentos-recebidos',
|
||||
component: () => import('@/features/agenda/pages/AgendamentosRecebidosPage.vue'),
|
||||
meta: {
|
||||
feature: 'online_scheduling.manage'
|
||||
}
|
||||
},
|
||||
// ✅ Compromissos determinísticos
|
||||
{
|
||||
path: 'agenda/compromissos',
|
||||
name: 'therapist-agenda-compromissos',
|
||||
component: () => import('@/features/agenda/pages/CompromissosDeterminados.vue'),
|
||||
meta: {
|
||||
feature: 'agenda.view',
|
||||
roles: ['therapist']
|
||||
// ✅ sem tenantScope
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 💰 FINANCEIRO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'financeiro',
|
||||
name: 'therapist-financeiro',
|
||||
component: () => import('@/features/financeiro/pages/FinanceiroDashboardPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'financeiro/lancamentos',
|
||||
name: 'therapist-financeiro-lancamentos',
|
||||
component: () => import('@/features/financeiro/pages/FinanceiroPage.vue')
|
||||
},
|
||||
// ======================================================
|
||||
// 💳 MEU PLANO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'meu-plano',
|
||||
name: 'therapist-meu-plano',
|
||||
component: () => import('@/views/pages/billing/TherapistMeuPlanoPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'upgrade',
|
||||
name: 'therapist-upgrade',
|
||||
component: () => import('@/views/pages/billing/TherapistUpgradePage.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 📈 RELATÓRIOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'relatorios',
|
||||
name: 'therapist-relatorios',
|
||||
component: () => import('@/views/pages/therapist/RelatoriosPage.vue'),
|
||||
meta: { feature: 'agenda.view' }
|
||||
},
|
||||
// ======================================================
|
||||
// 👥 PATIENTS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'patients',
|
||||
name: 'therapist-patients',
|
||||
component: () => import('@/features/patients/PatientsListPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro',
|
||||
name: 'therapist-patients-create',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro/:id',
|
||||
name: 'therapist-patients-edit',
|
||||
component: () => import('@/features/patients/cadastro/PatientsCadastroPage.vue'),
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: 'patients/grupos',
|
||||
name: 'therapist-patients-groups',
|
||||
component: () => import('@/features/patients/grupos/GruposPacientesPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/tags',
|
||||
name: 'therapist-patients-tags',
|
||||
component: () => import('@/features/patients/tags/TagsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/link-externo',
|
||||
name: 'therapist-patients-link-externo',
|
||||
component: () => import('@/features/patients/cadastro/PatientsExternalLinkPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/cadastro/recebidos',
|
||||
name: 'therapist-patients-recebidos',
|
||||
component: () => import('@/features/patients/cadastro/recebidos/CadastrosRecebidosPage.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔐 SECURITY
|
||||
// ======================================================
|
||||
{
|
||||
path: 'settings/security',
|
||||
name: 'therapist-settings-security',
|
||||
component: () => import('@/views/pages/auth/SecurityPage.vue')
|
||||
// ======================================================
|
||||
// 🔒 PRO — Online Scheduling
|
||||
// ======================================================
|
||||
{
|
||||
path: 'online-scheduling',
|
||||
name: 'therapist-online-scheduling',
|
||||
component: () => import('@/views/pages/therapist/OnlineSchedulingPage.vue'),
|
||||
meta: {
|
||||
feature: 'online_scheduling.manage'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔒 PRO — Agendamentos Recebidos
|
||||
// ======================================================
|
||||
{
|
||||
path: 'agendamentos-recebidos',
|
||||
name: 'therapist-agendamentos-recebidos',
|
||||
component: () => import('@/features/agenda/pages/AgendamentosRecebidosPage.vue'),
|
||||
meta: {
|
||||
feature: 'online_scheduling.manage'
|
||||
}
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 💰 FINANCEIRO
|
||||
// ======================================================
|
||||
{
|
||||
path: 'financeiro',
|
||||
name: 'therapist-financeiro',
|
||||
component: () => import('@/features/financeiro/pages/FinanceiroDashboardPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'financeiro/lancamentos',
|
||||
name: 'therapist-financeiro-lancamentos',
|
||||
component: () => import('@/features/financeiro/pages/FinanceiroPage.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 📈 RELATÓRIOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'relatorios',
|
||||
name: 'therapist-relatorios',
|
||||
component: () => import('@/views/pages/therapist/RelatoriosPage.vue'),
|
||||
meta: { feature: 'agenda.view' }
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔐 SECURITY
|
||||
// ======================================================
|
||||
{
|
||||
path: 'settings/security',
|
||||
name: 'therapist-settings-security',
|
||||
component: () => import('@/views/pages/auth/SecurityPage.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user