diff --git a/src/app/features/content-management/components/static-pages-editor.component.ts b/src/app/features/content-management/components/static-pages-editor.component.ts index 7b36343..b4a723c 100644 --- a/src/app/features/content-management/components/static-pages-editor.component.ts +++ b/src/app/features/content-management/components/static-pages-editor.component.ts @@ -156,8 +156,28 @@ export class StaticPagesEditorComponent { this.mediaPickerOpen = false; } + /** + * Appends `-2`, `-3`, ... to `candidate` until it's not in `existing`. + * createPage()/duplicatePage() both used to derive slugs/routes from array + * length or a fixed "-copy" suffix, which reproducibly collides with an + * existing page (create, delete, create again; or duplicate the same page + * twice) - the duplicate then trips the duplicate-slug/route validator + * on a page the user never touched. + */ + private uniqueValue(candidate: string, existing: Set): string { + if (!existing.has(candidate)) { + return candidate; + } + let suffix = 2; + while (existing.has(`${candidate}-${suffix}`)) { + suffix++; + } + return `${candidate}-${suffix}`; + } + createPage(): void { - const slug = `custom-page-${this.allPages().length + 1}`; + const existingSlugs = new Set(this.allPages().map(page => page.slug)); + const slug = this.uniqueValue(`custom-page-${this.allPages().length + 1}`, existingSlugs); const page: ContentPage = { id: `page-${Date.now()}`, slug, @@ -189,11 +209,13 @@ export class StaticPagesEditorComponent { if (!source) { return; } + const existingSlugs = new Set(this.allPages().map(page => page.slug)); + const existingRoutes = new Set(this.allPages().map(page => page.route)); const clone: ContentPage = { ...source, id: `page-${Date.now()}`, - slug: `${source.slug}-copy`, - route: `${source.route}-copy`, + slug: this.uniqueValue(`${source.slug}-copy`, existingSlugs), + route: this.uniqueValue(`${source.route}-copy`, existingRoutes), order: this.allPages().length + 1, status: 'draft', translations: Object.fromEntries(Object.entries(source.translations).map(([locale, t]) => [locale, { ...t }])),