Files
marketplaces/src/app/app.routes.ts
sdarbinyan 20442eb93c feat(admin): Seller Management Phase 1 UI - Partners section, empty state, request/learn-more dialogs
No backend, no CRUD, no API, no business logic - production-quality
UI only, built entirely from existing shared components (app-dialog,
app-empty-state, app-button, app-form-field, app-input, app-icon,
app-badge). Gated per ADR-011: reads
modules.sellerManagement.enabled from bootstrap (always false today,
no backend sets it) rather than hardcoding disabled state.

New:
- AdminSellerManagementPageComponent (features/admin/seller-management/
  pages/) - renders the specified empty state (title/description/
  Request Access + Learn More buttons) using existing shared/ui
  primitives only, no new UI infrastructure.
- Request Access dialog: Company/Email/Message form via
  app-form-field + app-input + a plain textarea (no dedicated
  textarea component exists yet, styled to match app-input's own
  tokens exactly). Submission is mocked (setTimeout), no API call.
  On submit: closes and opens a success dialog ("Thank you...").
- Learn More dialog: 6 capability bullets (seller dashboards,
  storefronts, permissions, analytics, product ownership, marketplace
  administration) under a "Coming Soon" badge.
- New admin nav group "Partners" > "Seller Management" link
  (admin-nav.model.ts), new route /backoffice/partners/seller-management
  (app.routes.ts), using the same loadComponent/breadcrumb pattern as
  every other admin route.

Translations: full en/ru/hy coverage, zero hardcoded strings - new
adminShell.nav.{partnersGroup,sellerManagement},
adminShell.pages.sellerManagement, and a new adminSellerManagement.*
namespace (emptyState/requestDialog/requestSuccessDialog/
learnMoreDialog) added to translations.ts (types) and all three
locale files.

Accessibility: inherited from app-dialog (role="dialog",
aria-modal, focus trap on Tab/Shift+Tab, Escape to close, focus
restored to trigger on close) - no new a11y code needed, reused as-is.

Responsive: existing --space-*/--font-size-* tokens throughout,
flex-wrap on button row, mobile breakpoint stacks actions full-width.

Verified live (ru locale, devBypassAdmin): nav group/link render
correctly, breadcrumb shows "Управление продавцами", empty state
copy matches spec exactly, Request Access dialog opens with all 3
fields + Cancel/Send Request, filled + submitted -> success dialog
with exact spec copy, Learn More dialog shows all 6 bullets + Coming
Soon badge, no console errors, verified again at 375px mobile
viewport. tsc --noEmit clean, ng build clean (pre-existing bundle-
budget warning only), arch:check (boundaries + cycles) clean.
2026-07-26 20:47:18 +04:00

324 lines
14 KiB
TypeScript

import { Routes } from '@angular/router';
import { languageGuard } from './guards/language.guard';
import { projectEditorDirtyGuard } from './features/project-editor/guards/project-editor-dirty.guard';
import { adminAuthGuard } from './core/admin-auth/admin-auth.guard';
import { authRoutes } from './core/auth/auth.routes';
import { adminCategoryDirtyGuard } from './features/admin/categories/guards/admin-category-dirty.guard';
import { adminProductDirtyGuard } from './features/admin/products/guards/admin-product-dirty.guard';
import { environment } from '../environments/environment';
// Core routes (same across all brands)
const coreRoutes: Routes = [
{
path: '',
loadComponent: () => import('./pages/home/home.component').then(m => m.HomeComponent)
},
{
path: 'catalog',
loadComponent: () => import('./features/website/catalog/containers/catalog-container.component').then(m => m.CatalogContainerComponent)
},
{
path: 'catalog/:id',
loadComponent: () => import('./features/website/catalog/containers/catalog-container.component').then(m => m.CatalogContainerComponent)
},
{
path: 'category/:id',
redirectTo: 'catalog/:id',
pathMatch: 'full'
},
{
path: 'category/:id/items',
redirectTo: 'catalog/:id',
pathMatch: 'full'
},
{
path: 'product/:id',
loadComponent: () => import('./features/website/product/containers/product-details-container.component').then(m => m.ProductDetailsContainerComponent)
},
{
path: 'item/:id',
redirectTo: 'product/:id',
pathMatch: 'full'
},
{
path: 'search',
loadComponent: () => import('./features/website/catalog/containers/catalog-container.component').then(m => m.CatalogContainerComponent)
},
{
path: 'edit',
canActivate: [adminAuthGuard],
loadComponent: () => import('./features/project-editor/pages/builder-overview-page.component').then(m => m.BuilderOverviewPageComponent)
},
{
path: 'edit/:section',
canActivate: [adminAuthGuard],
loadComponent: () => import('./features/project-editor/pages/project-editor-page.component').then(m => m.ProjectEditorPageComponent),
canDeactivate: [projectEditorDirtyGuard]
},
{
path: 'backoffice',
canActivate: [adminAuthGuard],
loadComponent: () => import('./features/admin/shell/admin-layout.component').then(m => m.AdminLayoutComponent),
children: [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{
path: 'dashboard',
loadComponent: () => import('./features/admin/dashboard/pages/admin-dashboard-page.component').then(m => m.AdminDashboardPageComponent),
data: {
titleKey: 'adminShell.pages.dashboard.title',
descriptionKey: 'adminShell.pages.dashboard.description',
breadcrumb: [{ labelKey: 'adminShell.pages.dashboard.title' }]
}
},
{
path: 'products',
loadComponent: () => import('./features/admin/products/pages/admin-products-list-page.component').then(m => m.AdminProductsListPageComponent),
data: {
titleKey: 'adminShell.pages.products.title',
descriptionKey: 'adminShell.pages.products.description',
breadcrumb: [{ labelKey: 'adminShell.nav.products' }]
}
},
{
path: 'products/create',
loadComponent: () => import('./features/admin/products/pages/admin-product-editor-page.component').then(m => m.AdminProductEditorPageComponent),
canDeactivate: [adminProductDirtyGuard],
data: {
titleKey: 'adminShell.pages.productCreate.title',
descriptionKey: 'adminShell.pages.productCreate.description',
breadcrumb: [{ labelKey: 'adminShell.nav.products', path: ['products'] }, { labelKey: 'adminShell.pages.productCreate.title' }]
}
},
{
path: 'products/:id/edit',
loadComponent: () => import('./features/admin/products/pages/admin-product-editor-page.component').then(m => m.AdminProductEditorPageComponent),
canDeactivate: [adminProductDirtyGuard],
data: {
titleKey: 'adminShell.pages.productEdit.title',
descriptionKey: 'adminShell.pages.productEdit.description',
breadcrumb: [{ labelKey: 'adminShell.nav.products', path: ['products'] }, { labelKey: 'adminShell.pages.productEdit.title' }]
}
},
{
path: 'products/:id/duplicate',
loadComponent: () => import('./features/admin/products/pages/admin-product-editor-page.component').then(m => m.AdminProductEditorPageComponent),
canDeactivate: [adminProductDirtyGuard],
data: {
titleKey: 'adminShell.pages.productDuplicate.title',
descriptionKey: 'adminShell.pages.productDuplicate.description',
breadcrumb: [{ labelKey: 'adminShell.nav.products', path: ['products'] }, { labelKey: 'adminShell.pages.productDuplicate.title' }]
}
},
{
path: 'categories',
loadComponent: () => import('./features/admin/categories/pages/admin-categories-list-page.component').then(m => m.AdminCategoriesListPageComponent),
data: {
titleKey: 'adminShell.pages.categories.title',
descriptionKey: 'adminShell.pages.categories.description',
breadcrumb: [{ labelKey: 'adminShell.nav.categories' }]
}
},
{
path: 'categories/create',
loadComponent: () => import('./features/admin/categories/pages/admin-category-editor-page.component').then(m => m.AdminCategoryEditorPageComponent),
canDeactivate: [adminCategoryDirtyGuard],
data: {
titleKey: 'adminShell.pages.categoryCreate.title',
descriptionKey: 'adminShell.pages.categoryCreate.description',
breadcrumb: [{ labelKey: 'adminShell.nav.categories', path: ['categories'] }, { labelKey: 'adminShell.pages.categoryCreate.title' }]
}
},
{
path: 'categories/:id/edit',
loadComponent: () => import('./features/admin/categories/pages/admin-category-editor-page.component').then(m => m.AdminCategoryEditorPageComponent),
canDeactivate: [adminCategoryDirtyGuard],
data: {
titleKey: 'adminShell.pages.categoryEdit.title',
descriptionKey: 'adminShell.pages.categoryEdit.description',
breadcrumb: [{ labelKey: 'adminShell.nav.categories', path: ['categories'] }, { labelKey: 'adminShell.pages.categoryEdit.title' }]
}
},
{
// Static Pages is a first-class Project Editor module (Sprint X+2), not a
// separate backoffice CRUD surface - redirect here rather than build a
// second UI over the same bootstrap.staticPages data.
path: 'static-pages',
redirectTo: '/edit/static-pages',
pathMatch: 'full'
},
{
path: 'transactions',
loadComponent: () => import('./features/admin/transactions/pages/admin-transactions-list-page.component').then(m => m.AdminTransactionsListPageComponent),
data: {
titleKey: 'adminShell.pages.transactions.title',
descriptionKey: 'adminShell.pages.transactions.description',
breadcrumb: [{ labelKey: 'adminShell.nav.transactions' }]
}
},
{
path: 'orders',
loadComponent: () => import('./features/admin/orders/pages/admin-orders-list-page.component').then(m => m.AdminOrdersListPageComponent),
data: {
titleKey: 'adminShell.pages.orders.title',
descriptionKey: 'adminShell.pages.orders.description',
breadcrumb: [{ labelKey: 'adminShell.nav.orders' }]
}
},
{
path: 'orders/:id',
loadComponent: () => import('./features/admin/orders/pages/admin-order-detail-page.component').then(m => m.AdminOrderDetailPageComponent),
data: {
titleKey: 'adminShell.pages.orderDetail.title',
descriptionKey: 'adminShell.pages.orderDetail.description',
breadcrumb: [{ labelKey: 'adminShell.nav.orders', path: ['orders'] }, { labelKey: 'adminShell.pages.orderDetail.title' }]
}
},
{
path: 'customers',
loadComponent: () => import('./features/admin/customers/pages/admin-customers-list-page.component').then(m => m.AdminCustomersListPageComponent),
data: {
titleKey: 'adminShell.pages.customers.title',
descriptionKey: 'adminShell.pages.customers.description',
breadcrumb: [{ labelKey: 'adminShell.nav.customers' }]
}
},
{
path: 'customers/:email',
loadComponent: () => import('./features/admin/customers/pages/admin-customer-detail-page.component').then(m => m.AdminCustomerDetailPageComponent),
data: {
titleKey: 'adminShell.pages.customerDetail.title',
descriptionKey: 'adminShell.pages.customerDetail.description',
breadcrumb: [{ labelKey: 'adminShell.nav.customers', path: ['customers'] }, { labelKey: 'adminShell.pages.customerDetail.title' }]
}
},
{
path: 'moderation',
loadComponent: () => import('./features/admin/moderation/pages/admin-reviews-list-page.component').then(m => m.AdminReviewsListPageComponent),
data: {
titleKey: 'adminShell.pages.moderation.title',
descriptionKey: 'adminShell.pages.moderation.description',
breadcrumb: [{ labelKey: 'adminShell.nav.moderation' }]
}
},
{
path: 'moderation/reports',
loadComponent: () => import('./features/admin/moderation/pages/admin-reports-list-page.component').then(m => m.AdminReportsListPageComponent),
data: {
titleKey: 'adminShell.pages.reportsQueue.title',
descriptionKey: 'adminShell.pages.reportsQueue.description',
breadcrumb: [{ labelKey: 'adminShell.nav.moderation', path: ['moderation'] }, { labelKey: 'adminShell.pages.reportsQueue.title' }]
}
},
{
path: 'moderation/:id',
loadComponent: () => import('./features/admin/moderation/pages/admin-review-detail-page.component').then(m => m.AdminReviewDetailPageComponent),
data: {
titleKey: 'adminShell.pages.reviewDetail.title',
descriptionKey: 'adminShell.pages.reviewDetail.description',
breadcrumb: [{ labelKey: 'adminShell.nav.moderation', path: ['moderation'] }, { labelKey: 'adminShell.pages.reviewDetail.title' }]
}
},
{
path: 'media',
loadComponent: () => import('./features/backoffice/media/media-library-page.component').then(m => m.MediaLibraryPageComponent),
data: {
titleKey: 'adminShell.pages.media.title',
descriptionKey: 'adminShell.pages.media.description',
breadcrumb: [{ labelKey: 'adminShell.nav.mediaLibrary' }]
}
},
{
path: 'users',
loadComponent: () => import('./features/admin/users/pages/admin-users-page.component').then(m => m.AdminUsersPageComponent),
data: {
titleKey: 'adminShell.pages.users.title',
descriptionKey: 'adminShell.pages.users.description',
breadcrumb: [{ labelKey: 'adminShell.nav.users' }]
}
},
{
path: 'monitoring',
loadComponent: () => import('./features/admin/monitoring/pages/admin-monitoring-page.component').then(m => m.AdminMonitoringPageComponent),
data: {
titleKey: 'adminShell.pages.monitoring.title',
descriptionKey: 'adminShell.pages.monitoring.description',
breadcrumb: [{ labelKey: 'adminShell.nav.monitoring' }]
}
},
{
path: 'analytics',
loadComponent: () => import('./features/admin/analytics/pages/admin-analytics-page.component').then(m => m.AdminAnalyticsPageComponent),
data: {
titleKey: 'adminShell.pages.analytics.title',
descriptionKey: 'adminShell.pages.analytics.description',
breadcrumb: [{ labelKey: 'adminShell.nav.analytics' }]
}
},
{
path: 'partners/seller-management',
loadComponent: () => import('./features/admin/seller-management/pages/admin-seller-management-page.component').then(m => m.AdminSellerManagementPageComponent),
data: {
titleKey: 'adminShell.pages.sellerManagement.title',
descriptionKey: 'adminShell.pages.sellerManagement.description',
breadcrumb: [{ labelKey: 'adminShell.nav.sellerManagement' }]
}
},
{ path: '**', redirectTo: 'dashboard' }
]
},
{
path: 'builder',
redirectTo: 'edit',
pathMatch: 'full'
},
{
path: 'project-editor',
redirectTo: 'edit',
pathMatch: 'full'
},
{
path: 'wishlist',
loadComponent: () => import('./features/website/user-experience/wishlist/containers/wishlist-page.component').then(m => m.WishlistPageComponent)
},
{
path: 'compare',
loadComponent: () => import('./features/website/user-experience/compare/containers/compare-page.component').then(m => m.ComparePageComponent)
},
{
path: 'cart',
loadComponent: () => import('./pages/cart/cart.component').then(m => m.CartComponent)
},
{
path: 'page/:key',
loadComponent: () => import('./pages/static-page/static-page.component').then(m => m.StaticPageComponent)
},
{
path: ':staticPath',
loadComponent: () => import('./pages/static-page/static-page.component').then(m => m.StaticPageComponent)
}
];
// TODO(CMS): Resolve informational/legal pages from backend content configuration here.
// Disabled hardcoded pages: about, contacts, faq, delivery, guarantee,
// company-details, payment-terms, return-policy, public-offer, privacy-policy.
const cmsContentRoutes: Routes = [];
// All routes sit under a :lang prefix (e.g. /ru/cart, /en/product/5)
export const routes: Routes = [
...(environment.production ? [] : [{
path: '__diagnostics',
loadComponent: () => import('./features/diagnostics/components/diagnostics-page.component').then(m => m.DiagnosticsPageComponent)
}]),
...authRoutes,
{
path: ':lang',
canActivate: [languageGuard],
children: [
...coreRoutes,
...cmsContentRoutes,
{ path: '**', redirectTo: '' }
]
},
// URLs without a language prefix → redirect to default language
{ path: '**', redirectTo: 'ru' }
];