import { createRouter, createWebHistory } from 'vue-router' import { isChunkLoadError, reloadForStaleChunk } from '@/lib/chunk-reload' import { useAuthStore } from '@/stores/auth' import { useCompanyStore } from '@/stores/company' import { pinia } from '@/stores/pinia' let brandRefreshPromise: Promise | null = null async function ensureBrandsInitialized(): Promise { const companyStore = useCompanyStore(pinia) if (companyStore.initialized) { return true } if (!brandRefreshPromise) { brandRefreshPromise = companyStore.refreshBrands().finally(() => { brandRefreshPromise = null }) } try { await brandRefreshPromise return true } catch { return false } } const router = createRouter({ history: createWebHistory(), routes: [ { path: '/login', name: 'login', component: () => import('@/views/LoginView.vue'), meta: { titleKey: 'route.login.title', descriptionKey: 'route.login.description', }, }, { path: '/membership-blocked', name: 'membership-blocked', redirect: '/workspace', meta: { requiresAuth: true, }, }, { path: '/onboarding/brand', name: 'brand-onboarding', component: () => import('@/views/BrandOnboardingView.vue'), meta: { requiresAuth: true, onboarding: true, titleKey: 'route.brandOnboarding.title', descriptionKey: 'route.brandOnboarding.description', }, }, { path: '/', component: () => import('@/layouts/AppShell.vue'), meta: { requiresAuth: true, }, children: [ { path: '', redirect: '/workspace', }, { path: 'workspace', name: 'workspace', component: () => import('@/views/WorkspaceView.vue'), meta: { titleKey: 'route.workspace.title', descriptionKey: 'route.workspace.description', navKey: '/workspace', }, }, { path: 'articles/templates', name: 'articles-templates', component: () => import('@/views/TemplatesView.vue'), meta: { titleKey: 'route.templates.title', descriptionKey: 'route.templates.description', navKey: '/articles/templates', }, }, { path: 'articles/wizard', name: 'article-wizard', component: () => import('@/views/TemplateWizardView.vue'), meta: { titleKey: 'route.wizard.title', descriptionKey: 'route.wizard.description', navKey: '/articles/templates', }, }, { path: 'articles/:id/edit', name: 'article-editor', component: () => import('@/views/ArticleEditorView.vue'), meta: { titleKey: 'route.articleEditor.title', descriptionKey: 'route.articleEditor.description', navKey: null, }, }, { path: 'articles/custom', name: 'articles-custom', component: () => import('@/views/CustomGenerateView.vue'), meta: { titleKey: 'route.custom.title', descriptionKey: 'route.custom.description', navKey: '/articles/custom', }, }, { path: 'articles/free-create', name: 'articles-free-create', component: () => import('@/views/FreeCreateView.vue'), meta: { titleKey: 'route.freeCreate.title', descriptionKey: 'route.freeCreate.description', navKey: '/articles/free-create', }, }, { path: 'articles/imitations', name: 'articles-imitations', component: () => import('@/views/ImitationView.vue'), meta: { titleKey: 'route.imitation.title', descriptionKey: 'route.imitation.description', navKey: '/articles/imitations', }, }, { path: 'articles/imitations/create', name: 'article-imitation-create', component: () => import('@/views/ImitationGenerateView.vue'), meta: { titleKey: 'route.imitationCreate.title', descriptionKey: 'route.imitationCreate.description', navKey: '/articles/imitations', }, }, { path: 'media', name: 'media', component: () => import('@/views/MediaView.vue'), meta: { titleKey: 'route.media.title', descriptionKey: 'route.media.description', navKey: '/media', }, }, { path: 'publish-management', name: 'publish-management', component: () => import('@/views/PublishManagementView.vue'), meta: { titleKey: 'route.publishManagement.title', descriptionKey: 'route.publishManagement.description', navKey: '/publish-management', }, }, { path: 'media-supply/resources', name: 'media-supply-resources', component: () => import('@/views/MediaSupplyResourcesView.vue'), meta: { titleKey: 'route.mediaSupplyResources.title', descriptionKey: 'route.mediaSupplyResources.description', navKey: '/media-supply/resources', }, }, { path: 'media-supply/submit', name: 'media-supply-submit', component: () => import('@/views/MediaSupplySubmitView.vue'), meta: { titleKey: 'route.mediaSupplySubmit.title', descriptionKey: 'route.mediaSupplySubmit.description', navKey: '/media-supply/resources', }, }, { path: 'media-supply/orders', name: 'media-supply-orders', component: () => import('@/views/MediaSupplyOrdersView.vue'), meta: { titleKey: 'route.mediaSupplyOrders.title', descriptionKey: 'route.mediaSupplyOrders.description', navKey: '/media-supply/orders', }, }, { path: 'media-supply/favorites', name: 'media-supply-favorites', component: () => import('@/views/MediaSupplyFavoritesView.vue'), meta: { titleKey: 'route.mediaSupplyFavorites.title', descriptionKey: 'route.mediaSupplyFavorites.description', navKey: '/media-supply/favorites', }, }, { path: 'brands', name: 'brands', component: () => import('@/views/BrandsView.vue'), meta: { titleKey: 'route.brands.title', descriptionKey: 'route.brands.description', navKey: '/brands', }, }, { path: 'brands/:brandId/questions/create', name: 'brand-question-create', component: () => import('@/views/BrandQuestionCreateView.vue'), meta: { titleKey: 'route.brandQuestionCreate.title', descriptionKey: 'route.brandQuestionCreate.description', navKey: '/brands', }, }, { path: 'tracking', name: 'tracking', component: () => import('@/views/TrackingView.vue'), meta: { titleKey: 'route.tracking.title', descriptionKey: 'route.tracking.description', navKey: '/tracking', }, }, { path: 'tracking/marked-articles', name: 'tracking-marked-articles', component: () => import('@/views/TrackingMarkedArticlesView.vue'), meta: { titleKey: 'route.trackingMarkedArticles.title', descriptionKey: 'route.trackingMarkedArticles.description', navKey: '/tracking/marked-articles', }, }, { path: 'tracking/questions/:brandId/:questionId', name: 'tracking-question-detail', component: () => import('@/views/TrackingQuestionDetailView.vue'), meta: { titleKey: 'route.trackingQuestion.title', descriptionKey: 'route.trackingQuestion.description', navKey: '/tracking', }, }, { path: 'knowledge', name: 'knowledge', component: () => import('@/views/KnowledgeView.vue'), meta: { titleKey: 'route.knowledge.title', descriptionKey: 'route.knowledge.description', navKey: '/knowledge', }, }, { path: 'images', name: 'images', component: () => import('@/views/ImagesView.vue'), meta: { titleKey: 'route.images.title', descriptionKey: 'route.images.description', navKey: '/images', }, }, { path: 'kol/manage', name: 'kol-manage', component: () => import('@/views/KolManageView.vue'), meta: { titleKey: 'kol.manage.title', navKey: '/kol/manage', requiresKol: true, }, }, { path: 'kol/dashboard', name: 'kol-dashboard', component: () => import('@/views/KolDashboardView.vue'), meta: { titleKey: 'kol.dashboard.title', navKey: '/kol/dashboard', requiresKol: true, }, }, { path: 'kol/profile', name: 'kol-profile', component: () => import('@/views/KolProfileView.vue'), meta: { titleKey: 'kol.profile.title', navKey: '/kol/profile', requiresKol: true, }, }, { path: 'kol/marketplace', name: 'kol-marketplace', component: () => import('@/views/KolMarketplaceView.vue'), meta: { titleKey: 'kol.marketplace.title', navKey: '/kol/marketplace', }, }, { path: 'kol/packages/:id', name: 'kol-package-detail', component: () => import('@/views/KolPackageDetailView.vue'), meta: { titleKey: 'kol.marketplace.title', navKey: '/kol/marketplace', }, }, { path: 'kol/generate/:subscriptionPromptId', name: 'kol-generate', component: () => import('@/views/KolGenerateView.vue'), meta: { titleKey: 'kol.generate.title', navKey: '/articles/templates', }, }, { path: 'account/ai-points', name: 'account-ai-points', component: () => import('@/views/AIPointUsageView.vue'), meta: { titleKey: 'route.aiPoints.title', descriptionKey: 'route.aiPoints.description', navKey: '/account/ai-points', }, }, { path: ':pathMatch(.*)*', name: 'not-found', component: () => import('@/views/NotFoundView.vue'), meta: { titleKey: 'route.notFound.title', descriptionKey: 'route.notFound.description', navKey: null, }, }, ], }, ], }) router.beforeEach(async (to) => { const authStore = useAuthStore(pinia) const companyStore = useCompanyStore(pinia) if (!authStore.initialized) { await authStore.bootstrap() } const requiresAuth = to.matched.some((record) => record.meta.requiresAuth) if (requiresAuth && !authStore.isAuthenticated) { return { name: 'login', query: { redirect: to.fullPath }, } } if (to.name === 'login' && authStore.isAuthenticated) { return { name: 'workspace' } } if (requiresAuth && authStore.isAuthenticated && !authStore.isMembershipBlocked) { const brandsInitialized = await ensureBrandsInitialized() if (brandsInitialized && !companyStore.hasBrands && !to.meta.onboarding) { return { name: 'brand-onboarding' } } if (brandsInitialized && companyStore.hasBrands && to.meta.onboarding) { return { name: 'workspace' } } } if (to.meta.requiresKol && !authStore.isActiveKol) { return { name: 'workspace' } } return true }) router.onError((err) => { if (isChunkLoadError(err)) { reloadForStaleChunk() } }) export { router }