Bill all platform SMS (including OTP), allow negative balance with manual/auto cutoffs, and support own-panel bypass without wallet debit.
603 lines
19 KiB
TypeScript
603 lines
19 KiB
TypeScript
import { createRouter, createWebHistory } from 'vue-router';
|
|
import type { UserRole } from '@mento/shared';
|
|
import { useAuthStore } from '@/stores/auth';
|
|
import { usePlatformAuthStore } from '@/stores/platform-auth';
|
|
|
|
export const router = createRouter({
|
|
history: createWebHistory(),
|
|
routes: [
|
|
{
|
|
path: '/login',
|
|
name: 'login',
|
|
component: () => import('@/views/LoginView.vue'),
|
|
meta: { public: true },
|
|
},
|
|
{
|
|
path: '/register',
|
|
name: 'register',
|
|
component: () => import('@/views/RegisterView.vue'),
|
|
meta: { public: true },
|
|
},
|
|
{
|
|
path: '/f/:token',
|
|
name: 'public-lead-form',
|
|
component: () => import('@/views/LeadFormPublicView.vue'),
|
|
meta: { public: true },
|
|
},
|
|
{
|
|
path: '/p/:slug',
|
|
name: 'portal',
|
|
component: () => import('@/views/PortalView.vue'),
|
|
meta: { public: true },
|
|
},
|
|
{
|
|
path: '/adm',
|
|
name: 'adm-login',
|
|
component: () => import('@/views/adm/AdmLoginView.vue'),
|
|
meta: { public: true, platformPublic: true },
|
|
},
|
|
{
|
|
path: '/adm',
|
|
component: () => import('@/layouts/AdmLayout.vue'),
|
|
meta: { public: true, platform: true },
|
|
children: [
|
|
{
|
|
path: 'dashboard',
|
|
name: 'adm-dashboard',
|
|
component: () => import('@/views/adm/AdmDashboardView.vue'),
|
|
},
|
|
{
|
|
path: 'organizations',
|
|
name: 'adm-organizations',
|
|
component: () => import('@/views/adm/AdmOrganizationsView.vue'),
|
|
},
|
|
{
|
|
path: 'users',
|
|
name: 'adm-users',
|
|
component: () => import('@/views/adm/AdmUsersView.vue'),
|
|
},
|
|
{
|
|
path: 'admins',
|
|
name: 'adm-admins',
|
|
component: () => import('@/views/adm/AdmAdminsView.vue'),
|
|
},
|
|
{
|
|
path: 'sms',
|
|
name: 'adm-sms',
|
|
component: () => import('@/views/adm/AdmSmsView.vue'),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
path: '/',
|
|
component: () => import('@/layouts/AppLayout.vue'),
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'home',
|
|
component: () => import('@/views/HomeView.vue'),
|
|
},
|
|
{
|
|
path: 'profile',
|
|
name: 'profile',
|
|
component: () => import('@/views/ProfileView.vue'),
|
|
},
|
|
{
|
|
path: 'reports',
|
|
name: 'reports',
|
|
component: () => import('@/views/ReportsView.vue'),
|
|
},
|
|
{
|
|
path: 'behavior/disc',
|
|
name: 'disc-report',
|
|
component: () => import('@/views/DiscReportView.vue'),
|
|
},
|
|
{
|
|
path: 'sales/forecast',
|
|
name: 'sales-forecast',
|
|
component: () => import('@/views/SalesForecastView.vue'),
|
|
},
|
|
{
|
|
path: 'tickets',
|
|
name: 'tickets',
|
|
component: () => import('@/views/TicketsView.vue'),
|
|
},
|
|
{
|
|
path: 'conversations',
|
|
name: 'conversations',
|
|
component: () => import('@/views/ConversationsView.vue'),
|
|
},
|
|
{
|
|
path: 'tickets/new',
|
|
name: 'ticket-new',
|
|
component: () => import('@/views/TicketFormView.vue'),
|
|
},
|
|
{
|
|
path: 'tickets/:id',
|
|
name: 'ticket-detail',
|
|
component: () => import('@/views/TicketFormView.vue'),
|
|
},
|
|
{
|
|
path: 'activities',
|
|
name: 'activities',
|
|
component: () => import('@/views/ActivitiesView.vue'),
|
|
},
|
|
{
|
|
path: 'activities/calendar',
|
|
name: 'activities-calendar',
|
|
component: () => import('@/views/ActivitiesCalendarView.vue'),
|
|
},
|
|
{
|
|
path: 'activities/new',
|
|
name: 'activity-new',
|
|
component: () => import('@/views/ActivityFormView.vue'),
|
|
},
|
|
{
|
|
path: 'activities/:id/edit',
|
|
name: 'activity-edit',
|
|
component: () => import('@/views/ActivityFormView.vue'),
|
|
},
|
|
{
|
|
path: 'activities/:id',
|
|
name: 'activity-detail',
|
|
component: () => import('@/views/ActivityDetailView.vue'),
|
|
},
|
|
{
|
|
path: 'routines',
|
|
component: () => import('@/views/routines/RoutinesShellView.vue'),
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'routines-today',
|
|
component: () => import('@/views/routines/RoutinesTodayView.vue'),
|
|
},
|
|
{
|
|
path: 'overdue',
|
|
name: 'routines-overdue',
|
|
component: () => import('@/views/routines/RoutinesOverdueView.vue'),
|
|
},
|
|
{
|
|
path: 'calendar',
|
|
name: 'routines-calendar',
|
|
component: () => import('@/views/routines/RoutinesCalendarView.vue'),
|
|
},
|
|
{
|
|
path: 'list',
|
|
name: 'routines-list',
|
|
component: () => import('@/views/routines/RoutinesListView.vue'),
|
|
},
|
|
{
|
|
path: 'me',
|
|
name: 'routines-me',
|
|
component: () => import('@/views/routines/RoutinesMyPerformanceView.vue'),
|
|
},
|
|
{
|
|
path: 'team',
|
|
name: 'routines-team',
|
|
component: () => import('@/views/routines/RoutinesTeamView.vue'),
|
|
},
|
|
{
|
|
path: 'manage',
|
|
name: 'routines-manage',
|
|
component: () => import('@/views/routines/RoutinesManageView.vue'),
|
|
},
|
|
{
|
|
path: 'manage/new',
|
|
name: 'routine-new',
|
|
component: () => import('@/views/routines/RoutineFormView.vue'),
|
|
},
|
|
{
|
|
path: 'manage/:id/edit',
|
|
name: 'routine-edit',
|
|
component: () => import('@/views/routines/RoutineFormView.vue'),
|
|
},
|
|
{
|
|
path: 'settings',
|
|
name: 'routines-settings',
|
|
component: () => import('@/views/routines/RoutinesSettingsView.vue'),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
path: 'quotes',
|
|
name: 'quotes',
|
|
component: () => import('@/views/QuotesView.vue'),
|
|
},
|
|
{
|
|
path: 'quotes/new',
|
|
name: 'quote-new',
|
|
component: () => import('@/views/QuoteFormView.vue'),
|
|
},
|
|
{
|
|
path: 'quotes/:id',
|
|
name: 'quote-detail',
|
|
component: () => import('@/views/QuoteFormView.vue'),
|
|
},
|
|
{
|
|
path: 'invoices',
|
|
name: 'invoices',
|
|
component: () => import('@/views/InvoicesView.vue'),
|
|
},
|
|
{
|
|
path: 'invoices/new',
|
|
name: 'invoice-new',
|
|
component: () => import('@/views/InvoiceFormView.vue'),
|
|
},
|
|
{
|
|
path: 'invoices/:id',
|
|
name: 'invoice-detail',
|
|
component: () => import('@/views/InvoiceFormView.vue'),
|
|
},
|
|
{
|
|
path: 'inventory',
|
|
name: 'inventory',
|
|
component: () => import('@/views/InventoryView.vue'),
|
|
},
|
|
{
|
|
path: 'cheques',
|
|
name: 'cheques',
|
|
component: () => import('@/views/ChequesView.vue'),
|
|
},
|
|
{
|
|
path: 'finance',
|
|
name: 'finance',
|
|
component: () => import('@/views/treasury/TreasuryHomeView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/accounts',
|
|
name: 'finance-accounts',
|
|
component: () => import('@/views/treasury/TreasuryAccountsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/accounts/:id',
|
|
name: 'finance-account',
|
|
component: () => import('@/views/treasury/TreasuryAccountView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/incomes',
|
|
name: 'finance-incomes',
|
|
component: () => import('@/views/treasury/TreasuryIncomesView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/expenses',
|
|
name: 'finance-expenses',
|
|
component: () => import('@/views/treasury/TreasuryExpensesView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/receivables',
|
|
name: 'finance-receivables',
|
|
component: () => import('@/views/treasury/TreasuryReceivablesView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/payroll',
|
|
name: 'finance-payroll',
|
|
component: () => import('@/views/treasury/TreasuryPayrollView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/recurring',
|
|
name: 'finance-recurring',
|
|
component: () => import('@/views/treasury/TreasuryRecurringView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/reports',
|
|
name: 'finance-reports',
|
|
component: () => import('@/views/treasury/TreasuryReportsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/audit',
|
|
name: 'finance-audit',
|
|
component: () => import('@/views/treasury/TreasuryAuditView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'finance/categories',
|
|
name: 'finance-categories',
|
|
component: () => import('@/views/treasury/TreasuryCategoriesView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'reservations',
|
|
name: 'reservations',
|
|
component: () => import('@/views/ReservationsView.vue'),
|
|
},
|
|
{
|
|
path: 'commissions',
|
|
name: 'commissions',
|
|
component: () => import('@/views/CommissionsView.vue'),
|
|
},
|
|
{
|
|
path: 'pipeline',
|
|
name: 'pipeline',
|
|
component: () => import('@/views/PipelineBoardView.vue'),
|
|
},
|
|
{
|
|
path: 'leads',
|
|
name: 'leads',
|
|
component: () => import('@/views/LeadsView.vue'),
|
|
},
|
|
{
|
|
path: 'leads/board',
|
|
name: 'leads-board',
|
|
component: () => import('@/views/LeadBoardView.vue'),
|
|
},
|
|
{
|
|
path: 'leads/:id',
|
|
name: 'lead-detail',
|
|
component: () => import('@/views/LeadDetailView.vue'),
|
|
},
|
|
{
|
|
path: 'projects',
|
|
name: 'projects',
|
|
component: () => import('@/views/ProjectBoardView.vue'),
|
|
},
|
|
{
|
|
path: 'project-cards/new',
|
|
name: 'project-card-new',
|
|
component: () => import('@/views/ProjectCardFormView.vue'),
|
|
},
|
|
{
|
|
path: 'project-cards/:id',
|
|
name: 'project-card-detail',
|
|
component: () => import('@/views/ProjectCardFormView.vue'),
|
|
},
|
|
{
|
|
path: 'loyalty',
|
|
name: 'loyalty',
|
|
component: () => import('@/views/LoyaltyClubView.vue'),
|
|
},
|
|
{
|
|
path: 'club',
|
|
name: 'gamification',
|
|
component: () => import('@/views/gamification/GamificationView.vue'),
|
|
},
|
|
{
|
|
path: 'club/admin',
|
|
name: 'gamification-admin',
|
|
component: () => import('@/views/gamification/GamificationAdminView.vue'),
|
|
},
|
|
{
|
|
path: 'deals/new',
|
|
name: 'deal-new',
|
|
component: () => import('@/views/DealFormView.vue'),
|
|
},
|
|
{
|
|
path: 'deals/:id',
|
|
name: 'deal-detail',
|
|
component: () => import('@/views/DealFormView.vue'),
|
|
},
|
|
{
|
|
path: 'contacts',
|
|
name: 'contacts',
|
|
component: () => import('@/views/ContactsView.vue'),
|
|
},
|
|
{
|
|
path: 'notes',
|
|
name: 'notes',
|
|
component: () => import('@/views/NotesView.vue'),
|
|
},
|
|
{
|
|
path: 'attachments',
|
|
name: 'attachments',
|
|
component: () => import('@/views/AttachmentsView.vue'),
|
|
},
|
|
{
|
|
path: 'settings/automations',
|
|
name: 'automations',
|
|
component: () => import('@/views/AutomationsSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/message-automations',
|
|
name: 'message-automations',
|
|
component: () => import('@/views/MessageAutomationsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/lead-stages',
|
|
name: 'lead-stages',
|
|
component: () => import('@/views/LeadStagesSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/pipelines',
|
|
name: 'pipeline-settings',
|
|
component: () => import('@/views/PipelineSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[], module: 'pipeline' },
|
|
},
|
|
{
|
|
path: 'settings/lead-forms',
|
|
name: 'lead-forms',
|
|
component: () => import('@/views/LeadFormsSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/lead-forms/:id',
|
|
name: 'lead-form-builder',
|
|
component: () => import('@/views/LeadFormBuilderView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/team',
|
|
name: 'team-settings',
|
|
component: () => import('@/views/TeamSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/audit-logs',
|
|
name: 'audit-logs',
|
|
component: () => import('@/views/AuditLogsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/deletions',
|
|
name: 'deletion-archives',
|
|
component: () => import('@/views/DeletionArchivesView.vue'),
|
|
meta: { roles: ['owner'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/public-api',
|
|
name: 'public-api',
|
|
component: () => import('@/views/PublicApiSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/sms-campaigns',
|
|
name: 'sms-campaigns',
|
|
component: () => import('@/views/SmsCampaignsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/sms-campaigns/:id/report',
|
|
name: 'sms-campaign-report',
|
|
component: () => import('@/views/SmsCampaignReportView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/custom-fields',
|
|
name: 'custom-fields',
|
|
component: () => import('@/views/CustomFieldsSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/products',
|
|
name: 'products',
|
|
component: () => import('@/views/ProductsSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/products/new',
|
|
name: 'product-new',
|
|
component: () => import('@/views/ProductFormView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/products/:id/edit',
|
|
name: 'product-edit',
|
|
component: () => import('@/views/ProductFormView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/currencies',
|
|
name: 'currencies',
|
|
component: () => import('@/views/CurrencySettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/tahesab',
|
|
name: 'tahesab-settings',
|
|
component: () => import('@/views/TahesabSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/woocommerce',
|
|
name: 'woocommerce-settings',
|
|
component: () => import('@/views/WooCommerceSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/montify',
|
|
name: 'montify-settings',
|
|
component: () => import('@/views/MontifySettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/voip',
|
|
name: 'voip-settings',
|
|
component: () => import('@/views/VoipSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'settings/faq',
|
|
name: 'faq-settings',
|
|
component: () => import('@/views/FaqSettingsView.vue'),
|
|
meta: { roles: ['owner', 'admin'] as UserRole[] },
|
|
},
|
|
{
|
|
path: 'contacts/people/new',
|
|
name: 'person-new',
|
|
component: () => import('@/views/PersonFormView.vue'),
|
|
},
|
|
{
|
|
path: 'contacts/people/:id/edit',
|
|
name: 'person-edit',
|
|
component: () => import('@/views/PersonFormView.vue'),
|
|
},
|
|
{
|
|
path: 'contacts/people/:id',
|
|
name: 'person-detail',
|
|
component: () => import('@/views/PersonProfileView.vue'),
|
|
},
|
|
{
|
|
path: 'contacts/companies/new',
|
|
name: 'company-new',
|
|
component: () => import('@/views/CompanyFormView.vue'),
|
|
},
|
|
{
|
|
path: 'contacts/companies/:id',
|
|
name: 'company-detail',
|
|
component: () => import('@/views/CompanyFormView.vue'),
|
|
},
|
|
],
|
|
},
|
|
],
|
|
});
|
|
|
|
router.beforeEach((to) => {
|
|
if (to.path === '/adm' || to.path.startsWith('/adm/')) {
|
|
const platform = usePlatformAuthStore();
|
|
if (to.meta.platformPublic) {
|
|
if (platform.isAuthenticated) return { name: 'adm-dashboard' };
|
|
return true;
|
|
}
|
|
if (!platform.isAuthenticated) return { name: 'adm-login' };
|
|
return true;
|
|
}
|
|
|
|
const auth = useAuthStore();
|
|
if (!to.meta.public && !auth.isAuthenticated) {
|
|
return { name: 'login', query: { redirect: to.fullPath } };
|
|
}
|
|
if (
|
|
to.meta.public &&
|
|
auth.isAuthenticated &&
|
|
(to.name === 'login' || to.name === 'register')
|
|
) {
|
|
return { name: 'home' };
|
|
}
|
|
if (String(to.path).startsWith('/behavior')) {
|
|
const modules = auth.user?.enabledModules;
|
|
if (modules && !modules.includes('behavior')) return { name: 'home' };
|
|
}
|
|
if (String(to.path).startsWith('/finance')) {
|
|
const modules = auth.user?.enabledModules;
|
|
if (modules && !modules.includes('treasury')) return { name: 'home' };
|
|
}
|
|
const roles = to.meta.roles as UserRole[] | undefined;
|
|
if (roles?.length) {
|
|
const role = auth.user?.role as UserRole | undefined;
|
|
if (role && roles.includes(role)) {
|
|
return true;
|
|
}
|
|
if (to.name === 'team-settings' && auth.user?.viewAs?.canOpenTeamSettings) {
|
|
return true;
|
|
}
|
|
if (String(to.path).startsWith('/finance')) {
|
|
const perms = auth.user?.permissions ?? [];
|
|
const payroll = to.path.startsWith('/finance/payroll');
|
|
if (payroll && perms.includes('treasury_payroll')) return true;
|
|
if (!payroll && (perms.includes('treasury') || perms.includes('treasury_payroll'))) return true;
|
|
}
|
|
return { name: 'home' };
|
|
}
|
|
return true;
|
|
});
|