Milestone 7 of the Static Pages Module sprint.
- app.routes.ts: /backoffice/static-pages now redirects to /edit/static-pages
(absolute redirectTo) instead of rendering BackofficeComingSoonPageComponent
- Static Pages is a first-class Project Editor module, not a second CRUD
surface over the same bootstrap.staticPages data.
- New docs/StaticPages.md: full field reference (General/Localization/SEO/
Media/Publishing), the enabled+status storefront-gating story and its
backward-compat default (existing/legacy data normalizes to
enabled+published so nothing gets silently un-published; only new pages
default to draft), CRUD/search/filter/bulk, the "mutate from the
unfiltered list" implementation note, rich-text/HTML-mode contract
(pointer to EDITOR.md), nav integration, and the export/import/draft/
publish compatibility statement.
- docs/EDITOR.md: Static Pages row in the Sections table (was previously
absent - the row lived implicitly in Footer's description), HTML editor
section updated with the Sprint X+2 toolbar additions + validation
contract, redirect noted near the route line. `docs/Project-Editor.md`
(named in the original brief) no longer exists - superseded by EDITOR.md
per that file's own header; documentation went there + the new file
instead.
- docs/PROJECT.md: doc index entry for StaticPages.md.
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
188 lines
7.1 KiB
TypeScript
188 lines
7.1 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 { adminCategoryDirtyGuard } from './features/admin/categories/guards/admin-category-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/:section',
|
|
loadComponent: () => import('./features/project-editor/pages/project-editor-page.component').then(m => m.ProjectEditorPageComponent),
|
|
canDeactivate: [projectEditorDirtyGuard]
|
|
},
|
|
{
|
|
path: 'backoffice',
|
|
canActivate: [adminAuthGuard],
|
|
children: [
|
|
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
|
|
{
|
|
path: 'dashboard',
|
|
loadComponent: () => import('./features/admin/dashboard/pages/admin-dashboard-page.component').then(m => m.AdminDashboardPageComponent)
|
|
},
|
|
{
|
|
path: 'products',
|
|
loadComponent: () => import('./features/admin/products/pages/admin-products-list-page.component').then(m => m.AdminProductsListPageComponent)
|
|
},
|
|
{
|
|
path: 'products/create',
|
|
loadComponent: () => import('./features/admin/products/pages/admin-product-editor-page.component').then(m => m.AdminProductEditorPageComponent)
|
|
},
|
|
{
|
|
path: 'products/:id/edit',
|
|
loadComponent: () => import('./features/admin/products/pages/admin-product-editor-page.component').then(m => m.AdminProductEditorPageComponent)
|
|
},
|
|
{
|
|
path: 'products/:id/duplicate',
|
|
loadComponent: () => import('./features/admin/products/pages/admin-product-editor-page.component').then(m => m.AdminProductEditorPageComponent)
|
|
},
|
|
{
|
|
path: 'categories',
|
|
loadComponent: () => import('./features/admin/categories/pages/admin-categories-list-page.component').then(m => m.AdminCategoriesListPageComponent)
|
|
},
|
|
{
|
|
path: 'categories/create',
|
|
loadComponent: () => import('./features/admin/categories/pages/admin-category-editor-page.component').then(m => m.AdminCategoryEditorPageComponent),
|
|
canDeactivate: [adminCategoryDirtyGuard]
|
|
},
|
|
{
|
|
path: 'categories/:id/edit',
|
|
loadComponent: () => import('./features/admin/categories/pages/admin-category-editor-page.component').then(m => m.AdminCategoryEditorPageComponent),
|
|
canDeactivate: [adminCategoryDirtyGuard]
|
|
},
|
|
{
|
|
// 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)
|
|
},
|
|
{
|
|
path: 'orders',
|
|
loadComponent: () => import('./features/admin/orders/pages/admin-orders-list-page.component').then(m => m.AdminOrdersListPageComponent)
|
|
},
|
|
{
|
|
path: 'orders/:id',
|
|
loadComponent: () => import('./features/admin/orders/pages/admin-order-detail-page.component').then(m => m.AdminOrderDetailPageComponent)
|
|
},
|
|
{
|
|
path: 'media',
|
|
loadComponent: () => import('./features/backoffice/media/media-library-page.component').then(m => m.MediaLibraryPageComponent),
|
|
data: { titleKey: 'dashboard.actionMediaLibrary' }
|
|
},
|
|
{
|
|
path: 'users',
|
|
loadComponent: () => import('./features/admin/users/pages/admin-users-page.component').then(m => m.AdminUsersPageComponent)
|
|
},
|
|
{
|
|
path: 'monitoring',
|
|
loadComponent: () => import('./features/admin/monitoring/pages/admin-monitoring-page.component').then(m => m.AdminMonitoringPageComponent)
|
|
},
|
|
{
|
|
path: 'analytics',
|
|
loadComponent: () => import('./features/admin/analytics/pages/admin-analytics-page.component').then(m => m.AdminAnalyticsPageComponent)
|
|
},
|
|
{ path: '**', redirectTo: 'dashboard' }
|
|
]
|
|
},
|
|
{
|
|
path: 'edit',
|
|
redirectTo: 'edit/general',
|
|
pathMatch: 'full'
|
|
},
|
|
{
|
|
path: 'builder',
|
|
redirectTo: 'edit/general',
|
|
pathMatch: 'full'
|
|
},
|
|
{
|
|
path: 'project-editor',
|
|
redirectTo: 'edit/general',
|
|
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)
|
|
}]),
|
|
{
|
|
path: ':lang',
|
|
canActivate: [languageGuard],
|
|
children: [
|
|
...coreRoutes,
|
|
...cmsContentRoutes,
|
|
{ path: '**', redirectTo: '' }
|
|
]
|
|
},
|
|
// URLs without a language prefix → redirect to default language
|
|
{ path: '**', redirectTo: 'ru' }
|
|
]; |