feat: complete multi-platform CMS phases 2-5

Phase 2 - OMS Migration & Integration:
- Fix platform_pages.py to use get_platform_page for marketing pages
- Fix shop_pages.py to pass platform_id to content page service calls

Phase 3 - Admin Interface:
- Add platform management API (app/api/v1/admin/platforms.py)
- Add platforms admin page with stats cards
- Add Platforms menu item to admin sidebar
- Update content pages admin with platform filter and four-tab tier system

Phase 4 - Documentation:
- Add comprehensive architecture docs (docs/architecture/multi-platform-cms.md)
- Update implementation plan with completion status

Phase 5 - Vendor Dashboard:
- Add CMS usage API endpoint with tier limits
- Add usage progress bar to vendor content pages
- Add platform-default/{slug} API for preview
- Add View Default button and modal in page editor

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-19 16:30:31 +01:00
parent fe49008fef
commit 968002630e
19 changed files with 1424 additions and 99 deletions

View File

@@ -41,14 +41,73 @@
<!-- Override Info Banner -->
<div x-show="!loading && isOverride" class="mb-6 bg-purple-50 dark:bg-purple-900/20 border border-purple-200 dark:border-purple-800 rounded-lg p-4">
<div class="flex">
<span x-html="$icon('information-circle', 'w-5 h-5 text-purple-500 mr-3 flex-shrink-0 mt-0.5')"></span>
<div>
<h4 class="text-sm font-medium text-purple-800 dark:text-purple-200">Overriding Platform Default</h4>
<p class="text-sm text-purple-700 dark:text-purple-300 mt-1">
You're customizing the "<span x-text="form.title"></span>" page. Your version will be shown to customers instead of the platform default.
<button @click="deletePage()" class="underline hover:no-underline ml-1">Revert to default</button>
</p>
<div class="flex items-start justify-between">
<div class="flex">
<span x-html="$icon('information-circle', 'w-5 h-5 text-purple-500 mr-3 flex-shrink-0 mt-0.5')"></span>
<div>
<h4 class="text-sm font-medium text-purple-800 dark:text-purple-200">Overriding Platform Default</h4>
<p class="text-sm text-purple-700 dark:text-purple-300 mt-1">
You're customizing the "<span x-text="form.title"></span>" page. Your version will be shown to customers instead of the platform default.
</p>
</div>
</div>
<div class="flex items-center gap-2 ml-4 flex-shrink-0">
<button
@click="showDefaultPreview()"
class="inline-flex items-center px-3 py-1.5 text-xs font-medium text-purple-700 bg-white dark:bg-purple-900/50 dark:text-purple-300 border border-purple-300 dark:border-purple-700 rounded-lg hover:bg-purple-50 dark:hover:bg-purple-900 transition-colors"
>
<span x-html="$icon('eye', 'w-4 h-4 mr-1')"></span>
View Default
</button>
<button
@click="deletePage()"
class="inline-flex items-center px-3 py-1.5 text-xs font-medium text-red-700 bg-white dark:bg-red-900/50 dark:text-red-300 border border-red-300 dark:border-red-700 rounded-lg hover:bg-red-50 dark:hover:bg-red-900 transition-colors"
>
<span x-html="$icon('arrow-uturn-left', 'w-4 h-4 mr-1')"></span>
Revert to Default
</button>
</div>
</div>
</div>
<!-- Default Content Preview Modal -->
<div
x-show="showingDefaultPreview"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-200"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"
@click.self="showingDefaultPreview = false"
>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-3xl w-full mx-4 max-h-[80vh] overflow-hidden">
<div class="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Platform Default Content</h3>
<button @click="showingDefaultPreview = false" class="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">
<span x-html="$icon('x-mark', 'w-6 h-6')"></span>
</button>
</div>
<div class="p-6 overflow-y-auto max-h-[60vh]">
<div x-show="loadingDefault" class="text-center py-8">
<span x-html="$icon('spinner', 'inline w-8 h-8 text-purple-600')"></span>
<p class="mt-2 text-sm text-gray-500">Loading default content...</p>
</div>
<div x-show="!loadingDefault && defaultContent">
<h4 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Title</h4>
<p class="text-lg font-semibold text-gray-900 dark:text-white mb-4" x-text="defaultContent?.title"></p>
<h4 class="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Content</h4>
<div class="prose dark:prose-invert max-w-none bg-gray-50 dark:bg-gray-700 rounded-lg p-4" x-html="defaultContent?.content"></div>
</div>
</div>
<div class="flex justify-end px-6 py-4 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/50">
<button
@click="showingDefaultPreview = false"
class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700"
>
Close
</button>
</div>
</div>
</div>