From b05421325c5608655c7cb702f4c2433bf47e999c Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Tue, 18 Nov 2025 06:02:13 +0000 Subject: [PATCH] Refactor Site Management Components and Update URL Parameters - Changed `siteId` to `id` in `useParams` across multiple site-related components for consistency. - Removed "Sites" from the sidebar settings menu. - Updated navigation links in `SiteDashboard` to reflect new paths for integrations and deployments. - Enhanced `SiteList` component with improved site management features, including modals for site creation and sector configuration. - Added functionality to handle industry and sector selection for sites, with validation for maximum selections. - Improved UI elements and alerts for better user experience in site management. --- backend/celerybeat-schedule | Bin 16384 -> 16384 bytes frontend/src/layout/AppSidebar.tsx | 1 - frontend/src/pages/Sites/Content.tsx | 2 +- frontend/src/pages/Sites/Dashboard.tsx | 14 +- .../src/pages/Sites/EXPECTED-PAGES-LIST.md | 61 ++ frontend/src/pages/Sites/Editor.tsx | 2 +- frontend/src/pages/Sites/FIXES-SUMMARY.md | 92 +++ frontend/src/pages/Sites/List.tsx | 689 +++++++++++++++--- frontend/src/pages/Sites/Manage.tsx | 25 +- frontend/src/pages/Sites/PageManager.tsx | 2 +- frontend/src/pages/Sites/PostEditor.tsx | 2 +- frontend/src/pages/Sites/Preview.tsx | 2 +- frontend/src/pages/Sites/Settings.tsx | 2 +- 13 files changed, 787 insertions(+), 107 deletions(-) create mode 100644 frontend/src/pages/Sites/EXPECTED-PAGES-LIST.md create mode 100644 frontend/src/pages/Sites/FIXES-SUMMARY.md diff --git a/backend/celerybeat-schedule b/backend/celerybeat-schedule index 4f12d06baddc571157f649531616b3baea09e223..f7b27e357bf4be784a02f5a2665a0e4a74233ff6 100644 GIT binary patch delta 30 mcmZo@U~Fh$+@NT}&uY%Vz~DF~L$qy5&=l`En+;4Za038`XbFA* delta 30 lcmZo@U~Fh$+@NT}&mzLWz)& { subItems: [ { name: "General", path: "/settings" }, { name: "Plans", path: "/settings/plans" }, - { name: "Sites", path: "/settings/sites" }, { name: "Integration", path: "/settings/integration" }, { name: "Publishing", path: "/settings/publishing" }, { name: "Import / Export", path: "/settings/import-export" }, diff --git a/frontend/src/pages/Sites/Content.tsx b/frontend/src/pages/Sites/Content.tsx index d1f13a58..5f3c458a 100644 --- a/frontend/src/pages/Sites/Content.tsx +++ b/frontend/src/pages/Sites/Content.tsx @@ -28,7 +28,7 @@ interface ContentItem { } export default function SiteContentManager() { - const { siteId } = useParams<{ siteId: string }>(); + const { id: siteId } = useParams<{ id: string }>(); const navigate = useNavigate(); const toast = useToast(); const [content, setContent] = useState([]); diff --git a/frontend/src/pages/Sites/Dashboard.tsx b/frontend/src/pages/Sites/Dashboard.tsx index 07c594df..feb73f83 100644 --- a/frontend/src/pages/Sites/Dashboard.tsx +++ b/frontend/src/pages/Sites/Dashboard.tsx @@ -46,7 +46,7 @@ interface SiteStats { } export default function SiteDashboard() { - const { siteId } = useParams<{ siteId: string }>(); + const { id: siteId } = useParams<{ id: string }>(); const navigate = useNavigate(); const toast = useToast(); const [site, setSite] = useState(null); @@ -152,14 +152,14 @@ export default function SiteDashboard() { value: stats?.integrations_count || 0, icon: , color: 'purple', - link: `/sites/${siteId}/integrations`, + link: `/sites/${siteId}/settings?tab=integrations`, }, { label: 'Deployments', value: stats?.deployments_count || 0, icon: , color: 'teal', - link: `/sites/${siteId}/deployments`, + link: `/sites/${siteId}/preview`, }, { label: 'Total Content', @@ -256,7 +256,7 @@ export default function SiteDashboard() { diff --git a/frontend/src/pages/Sites/EXPECTED-PAGES-LIST.md b/frontend/src/pages/Sites/EXPECTED-PAGES-LIST.md new file mode 100644 index 00000000..d4ca5536 --- /dev/null +++ b/frontend/src/pages/Sites/EXPECTED-PAGES-LIST.md @@ -0,0 +1,61 @@ +# Expected Frontend Pages - Sites Module + +## Currently Available Pages (4) + +1. **Site List** (`/sites`) - Basic list with filters +2. **Site Builder** (`/sites/builder`) - Placeholder only +3. **Blueprints** (`/sites/blueprints`) - Placeholder only +4. **Sites Management** (`/settings/sites`) - Should be merged into Site List + +## Expected Pages (16 Total) + +### Site Management Pages (12) + +| Page | Route | Status | Description | +|------|-------|--------|-------------| +| **All Sites** | `/sites` | ✅ Exists | Site list with filters, search, type badges | +| **Site Dashboard** | `/sites/:id` | ✅ Exists | Individual site dashboard with stats | +| **Site Content** | `/sites/:id/content` | ✅ Exists | Content list for a site | +| **Site Editor** | `/sites/:id/editor` | ✅ Exists | Site content editor | +| **Page Manager** | `/sites/:id/pages` | ✅ Exists | Manage pages for a site | +| **New Page** | `/sites/:id/pages/new` | ✅ Exists | Create new page | +| **Edit Page** | `/sites/:id/pages/:pageId/edit` | ✅ Exists | Edit existing page | +| **Post Editor** | `/sites/:id/posts/:postId` | ✅ Exists | View/edit post | +| **Edit Post** | `/sites/:id/posts/:postId/edit` | ✅ Exists | Edit post | +| **Site Preview** | `/sites/:id/preview` | ✅ Exists | Preview site | +| **Site Settings** | `/sites/:id/settings` | ✅ Exists | Site settings (General, SEO, OG, Schema, Integrations) | +| **Site Management** | `/sites/manage` | ✅ Exists | Site management dashboard | + +### Site Builder Pages (3) + +| Page | Route | Status | Description | +|------|-------|--------|-------------| +| **Site Builder Wizard** | `/sites/builder` | ⚠️ Placeholder | AI-powered site creation wizard (needs migration) | +| **Site Builder Preview** | `/sites/builder/preview` | ⚠️ Placeholder | Preview site during building (needs migration) | +| **Blueprints** | `/sites/blueprints` | ⚠️ Placeholder | View and manage all site blueprints (needs migration) | + +### Settings Pages (1) + +| Page | Route | Status | Description | +|------|-------|--------|-------------| +| **Sites Settings** | `/settings/sites` | ❌ Should be removed | Site configuration (should be merged into Site List) | + +## Issues to Fix + +1. **Sites in Settings dropdown** - Broken UX, should be removed +2. **Site management features** - Should be merged into Site List page +3. **Wizard is placeholder** - Needs full migration from site-builder container +4. **Pages incomplete** - Many pages exist but lack full functionality + +## Required Features for Site List + +- Create new site (modal) +- Edit site (modal) +- Delete site (with confirmation) +- Toggle site active/inactive +- Configure sectors for site (modal) +- View site details +- Site cards with all information +- Industry/sector badges +- Status indicators + diff --git a/frontend/src/pages/Sites/Editor.tsx b/frontend/src/pages/Sites/Editor.tsx index d32ea3fa..fd9f0cbd 100644 --- a/frontend/src/pages/Sites/Editor.tsx +++ b/frontend/src/pages/Sites/Editor.tsx @@ -30,7 +30,7 @@ interface SiteBlueprint { } export default function SiteContentEditor() { - const { siteId } = useParams<{ siteId: string }>(); + const { id: siteId } = useParams<{ id: string }>(); const navigate = useNavigate(); const toast = useToast(); const [blueprints, setBlueprints] = useState([]); diff --git a/frontend/src/pages/Sites/FIXES-SUMMARY.md b/frontend/src/pages/Sites/FIXES-SUMMARY.md new file mode 100644 index 00000000..392a50ca --- /dev/null +++ b/frontend/src/pages/Sites/FIXES-SUMMARY.md @@ -0,0 +1,92 @@ +# Sites Module Fixes Summary + +## ✅ Completed Fixes + +### 1. Removed Sites from Settings Dropdown +- **File**: `frontend/src/layout/AppSidebar.tsx` +- **Change**: Removed "Sites" from Settings submenu +- **Result**: Sites now only accessible from main "Sites" menu in WORKFLOWS section + +### 2. Merged Site Management into Site List Page +- **File**: `frontend/src/pages/Sites/List.tsx` +- **Changes**: + - Added all site management functionality from Settings/Sites.tsx + - Added create/edit site modals + - Added sectors configuration modal + - Added site details/edit modal with delete option + - Added toggle switch for active/inactive status + - Updated site cards to match Settings/Sites.tsx style + - Added industry/sector badges + - Added site type badges + - Added integration count badges + - Added "Create with Builder" button alongside "Add Site" + - Added info alert about site configuration + +### 3. Updated Site Cards +- **Features Added**: + - Site icon + - Site description display + - Domain display + - Industry name badge + - Sector count badge (X / 5 Sectors) + - Integration count badge + - Site type badge (Site Builder / WordPress) + - Active/Inactive status indicator with colored circle + - Settings button (opens sectors modal) + - Details button (opens edit modal) + - Toggle switch for active/inactive + +## ⚠️ Still Needs Work + +### 1. Site Builder Wizard Migration +- **Current Status**: Placeholder only (`/sites/builder`) +- **Needs**: Full migration from `site-builder` container +- **Files to Migrate**: + - `site-builder/src/pages/wizard/WizardPage.tsx` + - `site-builder/src/pages/wizard/steps/*.tsx` (4 step components) + - `site-builder/src/state/builderStore.ts` + - `site-builder/src/api/builder.api.ts` + - `site-builder/src/types/siteBuilder.ts` +- **Target Location**: `frontend/src/pages/Sites/Builder/Wizard.tsx` + +### 2. Blueprints Page +- **Current Status**: Placeholder only (`/sites/blueprints`) +- **Needs**: Full implementation to list and manage site blueprints + +### 3. Site Builder Preview +- **Current Status**: Placeholder only (`/sites/builder/preview`) +- **Needs**: Full preview canvas implementation + +### 4. Other Site Pages +- Many pages exist but may need complete functionality: + - Site Dashboard (`/sites/:id`) + - Site Content (`/sites/:id/content`) + - Site Editor (`/sites/:id/editor`) + - Page Manager (`/sites/:id/pages`) + - Post Editor (`/sites/:id/posts/:postId`) + - Site Preview (`/sites/:id/preview`) + - Site Settings (`/sites/:id/settings`) + +## 📋 Expected Pages List + +See `EXPECTED-PAGES-LIST.md` for complete list of all expected frontend pages. + +## 🎯 Next Steps + +1. **Priority 1**: Migrate Site Builder Wizard + - Copy wizard components from site-builder container + - Adapt to main app structure + - Ensure API calls work correctly + - Test full wizard flow + +2. **Priority 2**: Implement Blueprints Page + - List all site blueprints + - Show blueprint status + - Allow editing/deleting blueprints + - Link to wizard for creating new blueprints + +3. **Priority 3**: Verify Other Pages + - Check each page has complete functionality + - Add missing features + - Ensure proper navigation between pages + diff --git a/frontend/src/pages/Sites/List.tsx b/frontend/src/pages/Sites/List.tsx index 89a95ed2..c039ea26 100644 --- a/frontend/src/pages/Sites/List.tsx +++ b/frontend/src/pages/Sites/List.tsx @@ -5,7 +5,7 @@ */ import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { PlusIcon, EditIcon, SettingsIcon, EyeIcon, TrashIcon, FilterIcon, SearchIcon, PlugIcon } from 'lucide-react'; +import { PlusIcon, EditIcon, SettingsIcon, EyeIcon, TrashIcon, FilterIcon, SearchIcon, PlugIcon, FileTextIcon } from 'lucide-react'; import PageMeta from '../../components/common/PageMeta'; import { Card } from '../../components/ui/card'; import Button from '../../components/ui/button/Button'; @@ -14,20 +14,30 @@ import { useToast } from '../../components/ui/toast/ToastContainer'; import { fetchAPI } from '../../services/api'; import SiteTypeBadge from '../../components/sites/SiteTypeBadge'; import Badge from '../../components/ui/badge/Badge'; +import FormModal, { FormField } from '../../components/common/FormModal'; +import Alert from '../../components/ui/alert/Alert'; +import Switch from '../../components/form/switch/Switch'; +import { + fetchSites, + createSite, + updateSite, + deleteSite, + setActiveSite, + selectSectorsForSite, + fetchIndustries, + fetchSiteSectors, + Site as SiteType, + Industry, +} from '../../services/api'; -interface Site { - id: number; - name: string; - slug: string; - site_type: string; - hosting_type: string; - status: string; - is_active: boolean; - created_at: string; - updated_at: string; +interface Site extends SiteType { page_count?: number; integration_count?: number; has_wordpress_integration?: boolean; + domain?: string; + description?: string; + industry_name?: string; + active_sectors_count?: number; } export default function SiteList() { @@ -37,6 +47,26 @@ export default function SiteList() { const [filteredSites, setFilteredSites] = useState([]); const [loading, setLoading] = useState(true); + // Site Management Modals + const [selectedSite, setSelectedSite] = useState(null); + const [showSiteModal, setShowSiteModal] = useState(false); + const [showSectorsModal, setShowSectorsModal] = useState(false); + const [showDetailsModal, setShowDetailsModal] = useState(false); + const [isSaving, setIsSaving] = useState(false); + const [togglingSiteId, setTogglingSiteId] = useState(null); + const [industries, setIndustries] = useState([]); + const [selectedIndustry, setSelectedIndustry] = useState(''); + const [selectedSectors, setSelectedSectors] = useState([]); + const [isSelectingSectors, setIsSelectingSectors] = useState(false); + + // Form state for site creation/editing + const [formData, setFormData] = useState({ + name: '', + domain: '', + description: '', + is_active: true, + }); + // Filters const [searchTerm, setSearchTerm] = useState(''); const [siteTypeFilter, setSiteTypeFilter] = useState(''); @@ -46,6 +76,7 @@ export default function SiteList() { useEffect(() => { loadSites(); + loadIndustries(); }, []); useEffect(() => { @@ -55,8 +86,9 @@ export default function SiteList() { const loadSites = async () => { try { setLoading(true); - const data = await fetchAPI('/v1/auth/sites/'); - if (data && Array.isArray(data)) { + const response = await fetchSites(); + const data = response.results || response || []; + if (Array.isArray(data)) { // Check for WordPress integrations const sitesWithIntegrations = await Promise.all( data.map(async (site: Site) => { @@ -83,6 +115,15 @@ export default function SiteList() { } }; + const loadIndustries = async () => { + try { + const response = await fetchIndustries(); + setIndustries(response.industries || []); + } catch (error: any) { + console.error('Failed to load industries:', error); + } + }; + const applyFilters = () => { let filtered = [...sites]; @@ -127,7 +168,14 @@ export default function SiteList() { }; const handleCreateSite = () => { - navigate('/sites/builder'); + setSelectedSite(null); + setFormData({ + name: '', + domain: '', + description: '', + is_active: true, + }); + setShowSiteModal(true); }; const handleIntegration = (siteId: number) => { @@ -135,11 +183,250 @@ export default function SiteList() { }; const handleEdit = (siteId: number) => { - navigate(`/sites/${siteId}/edit`); + const site = sites.find(s => s.id === siteId); + if (site) { + handleEditSite(site); + } + }; + + const handleEditSite = (site: Site) => { + setSelectedSite(site); + setFormData({ + name: site.name || '', + domain: site.domain || '', + description: site.description || '', + is_active: site.is_active || false, + }); + setShowSiteModal(true); }; const handleSettings = (siteId: number) => { - navigate(`/sites/${siteId}/settings`); + const site = sites.find(s => s.id === siteId); + if (site) { + setSelectedSite(site); + setShowSectorsModal(true); + loadSiteSectors(site); + } + }; + + const handleToggle = async (siteId: number, enabled: boolean) => { + if (togglingSiteId !== null) { + toast.error('Please wait for the current operation to complete'); + return; + } + + try { + setTogglingSiteId(siteId); + if (enabled) { + await setActiveSite(siteId); + toast.success('Site activated successfully'); + } else { + const site = sites.find(s => s.id === siteId); + if (site) { + await updateSite(siteId, { is_active: false }); + toast.success('Site deactivated successfully'); + } + } + await loadSites(); + } catch (error: any) { + toast.error(`Failed to update site: ${error.message}`); + } finally { + setTogglingSiteId(null); + } + }; + + const loadSiteSectors = async (site: Site) => { + try { + const sectors = await fetchSiteSectors(site.id); + const sectorSlugs = sectors.map((s: any) => s.slug); + setSelectedSectors(sectorSlugs); + + if (site.industry_slug) { + setSelectedIndustry(site.industry_slug); + } else { + for (const industry of industries) { + const matchingSectors = industry.sectors.filter(s => sectorSlugs.includes(s.slug)); + if (matchingSectors.length > 0) { + setSelectedIndustry(industry.slug); + break; + } + } + } + } catch (error: any) { + console.error('Failed to load site sectors:', error); + } + }; + + const handleDetails = (site: Site) => { + setSelectedSite(site); + setFormData({ + name: site.name || '', + domain: site.domain || '', + description: site.description || '', + is_active: site.is_active || false, + }); + setShowDetailsModal(true); + }; + + const handleSaveDetails = async () => { + if (!selectedSite) return; + + try { + setIsSaving(true); + const normalizedFormData = { + ...formData, + domain: formData.domain ? normalizeDomain(formData.domain) : formData.domain, + }; + await updateSite(selectedSite.id, normalizedFormData); + toast.success('Site updated successfully'); + setShowDetailsModal(false); + await loadSites(); + } catch (error: any) { + toast.error(`Failed to update site: ${error.message}`); + } finally { + setIsSaving(false); + } + }; + + const normalizeDomain = (domain: string): string => { + if (!domain || !domain.trim()) return domain; + const trimmed = domain.trim(); + if (trimmed.startsWith('https://')) return trimmed; + if (trimmed.startsWith('http://')) return trimmed.replace('http://', 'https://'); + return `https://${trimmed}`; + }; + + const handleSaveSite = async () => { + try { + setIsSaving(true); + const normalizedFormData = { + ...formData, + domain: formData.domain ? normalizeDomain(formData.domain) : formData.domain, + }; + + if (selectedSite) { + await updateSite(selectedSite.id, normalizedFormData); + toast.success('Site updated successfully'); + } else { + const newSite = await createSite({ + ...normalizedFormData, + is_active: normalizedFormData.is_active || false, + }); + toast.success('Site created successfully'); + + if (sites.length === 0 || normalizedFormData.is_active) { + await setActiveSite(newSite.id); + } + } + setShowSiteModal(false); + setSelectedSite(null); + setFormData({ + name: '', + domain: '', + description: '', + is_active: false, + }); + await loadSites(); + } catch (error: any) { + toast.error(`Failed to save site: ${error.message}`); + } finally { + setIsSaving(false); + } + }; + + const handleSelectSectors = async () => { + if (!selectedSite || !selectedIndustry || selectedSectors.length === 0) { + toast.error('Please select an industry and at least one sector'); + return; + } + + if (selectedSectors.length > 5) { + toast.error('Maximum 5 sectors allowed per site'); + return; + } + + try { + setIsSelectingSectors(true); + await selectSectorsForSite( + selectedSite.id, + selectedIndustry, + selectedSectors + ); + toast.success('Sectors selected successfully'); + setShowSectorsModal(false); + await loadSites(); + } catch (error: any) { + toast.error(`Failed to select sectors: ${error.message}`); + } finally { + setIsSelectingSectors(false); + } + }; + + const handleDeleteSite = async (site: Site) => { + if (!window.confirm(`Are you sure you want to delete "${site.name}"? This action cannot be undone.`)) { + return; + } + + try { + await deleteSite(site.id); + toast.success('Site deleted successfully'); + await loadSites(); + if (showDetailsModal) { + setShowDetailsModal(false); + setSelectedSite(null); + } + } catch (error: any) { + toast.error(`Failed to delete site: ${error.message}`); + } + }; + + const getSiteFormFields = (): FormField[] => [ + { + key: 'name', + label: 'Site Name', + type: 'text', + value: formData.name, + onChange: (value: any) => setFormData({ ...formData, name: value }), + required: true, + placeholder: 'Enter site name', + }, + { + key: 'domain', + label: 'Domain', + type: 'text', + value: formData.domain, + onChange: (value: any) => setFormData({ ...formData, domain: value }), + required: false, + placeholder: 'example.com (https:// will be added automatically)', + }, + { + key: 'description', + label: 'Description', + type: 'textarea', + value: formData.description, + onChange: (value: any) => setFormData({ ...formData, description: value }), + required: false, + placeholder: 'Enter site description', + rows: 4, + }, + { + key: 'is_active', + label: 'Set as Active Site', + type: 'select', + value: formData.is_active ? 'true' : 'false', + onChange: (value: any) => setFormData({ ...formData, is_active: value === 'true' }), + required: false, + options: [ + { value: 'true', label: 'Active' }, + { value: 'false', label: 'Inactive' }, + ], + }, + ]; + + const getIndustrySectors = () => { + if (!selectedIndustry) return []; + const industry = industries.find(i => i.slug === selectedIndustry); + return industry?.sectors || []; }; const handleView = (siteId: number) => { @@ -215,21 +502,40 @@ export default function SiteList() { return (
- + -
-
-

- Site List -

-

- View and manage all your sites with advanced filtering -

+
+
+
+

+ Sites Management +

+

+ Manage your sites, configure industries, and select sectors. Multiple sites can be active simultaneously. +

+
+
+ + + +
- + + {/* Info Alert */} +
{/* Filters */} @@ -341,88 +647,297 @@ export default function SiteList() { )} ) : ( -
+
{filteredSites.map((site) => ( - -
-
-
-

- {site.name} -

-

- {site.slug} -

-
- - {site.is_active ? 'Active' : 'Inactive'} - + +
+
+ + + + +
- -
- - {site.site_type} - - - {site.hosting_type} - +

+ {site.name} +

+

+ {site.description || 'No description'} +

+ {site.domain && ( +

+ {site.domain} +

+ )} +
+ + {site.industry_name && ( + + {site.industry_name} + + )} + + {site.active_sectors_count || 0} / 5 Sectors + {site.integration_count && site.integration_count > 0 && ( - + {site.integration_count} integration{site.integration_count > 1 ? 's' : ''} - + )}
- -
-
- {site.page_count || 0} pages -
+ {/* Status Text and Circle - Same row */} +
+ + {site.is_active ? 'Active' : 'Inactive'} + +
+
+
+
+ {/* Quick Actions */} +
+ + + +
+ + {/* Secondary Actions */} +
- -
+ handleToggle(site.id, enabled)} + disabled={togglingSiteId === site.id} + />
))}
)} + + {/* Create/Edit Site Modal */} + { + setShowSiteModal(false); + setSelectedSite(null); + setFormData({ + name: '', + domain: '', + description: '', + is_active: false, + }); + }} + onSubmit={handleSaveSite} + title={selectedSite ? 'Edit Site' : 'Create New Site'} + submitLabel={selectedSite ? 'Update Site' : 'Create Site'} + fields={getSiteFormFields()} + isLoading={isSaving} + /> + + {/* Sectors Selection Modal */} + setShowSectorsModal(false)} + onSubmit={handleSelectSectors} + title={selectedSite ? `Configure Sectors for ${selectedSite.name}` : 'Configure Sectors'} + submitLabel={isSelectingSectors ? 'Saving...' : 'Save Sectors'} + cancelLabel="Cancel" + isLoading={isSelectingSectors} + className="max-w-2xl" + customBody={ +
+
+ + + {selectedIndustry && ( +

+ {industries.find(i => i.slug === selectedIndustry)?.description} +

+ )} +
+ + {selectedIndustry && ( +
+ +
+ {getIndustrySectors().map((sector) => ( + + ))} +
+

+ Selected: {selectedSectors.length} / 5 sectors +

+
+ )} +
+ } + customFooter={ +
+ + +
+ } + /> + + {/* Site Details Modal - Editable */} + {selectedSite && ( + { + setShowDetailsModal(false); + setSelectedSite(null); + }} + onSubmit={handleSaveDetails} + title={`Edit Site: ${selectedSite.name}`} + submitLabel="Save Changes" + fields={getSiteFormFields()} + isLoading={isSaving} + customFooter={ +
+ +
+ + +
+
+ } + /> + )}
); } diff --git a/frontend/src/pages/Sites/Manage.tsx b/frontend/src/pages/Sites/Manage.tsx index 8fe5de78..31a0d46b 100644 --- a/frontend/src/pages/Sites/Manage.tsx +++ b/frontend/src/pages/Sites/Manage.tsx @@ -167,15 +167,28 @@ export default function SiteManagement() {
-
- +
+ + {site.site_type} - - - {site.hosting_type} - +
+ {/* WordPress Integration Button */} + {site.hosting_type === 'wordpress' && ( +
+ +
+ )} +
{site.page_count || 0} pages diff --git a/frontend/src/pages/Sites/PageManager.tsx b/frontend/src/pages/Sites/PageManager.tsx index 14df37c7..1de80e69 100644 --- a/frontend/src/pages/Sites/PageManager.tsx +++ b/frontend/src/pages/Sites/PageManager.tsx @@ -98,7 +98,7 @@ const DraggablePageItem: React.FC<{ }; export default function PageManager() { - const { siteId } = useParams<{ siteId: string }>(); + const { id: siteId } = useParams<{ id: string }>(); const navigate = useNavigate(); const toast = useToast(); const [pages, setPages] = useState([]); diff --git a/frontend/src/pages/Sites/PostEditor.tsx b/frontend/src/pages/Sites/PostEditor.tsx index 6a53f49d..29cd8138 100644 --- a/frontend/src/pages/Sites/PostEditor.tsx +++ b/frontend/src/pages/Sites/PostEditor.tsx @@ -35,7 +35,7 @@ interface Content { } export default function PostEditor() { - const { siteId, postId } = useParams<{ siteId: string; postId?: string }>(); + const { id: siteId, postId } = useParams<{ id: string; postId?: string }>(); const navigate = useNavigate(); const toast = useToast(); const [loading, setLoading] = useState(true); diff --git a/frontend/src/pages/Sites/Preview.tsx b/frontend/src/pages/Sites/Preview.tsx index 09f7eeda..52f9d74d 100644 --- a/frontend/src/pages/Sites/Preview.tsx +++ b/frontend/src/pages/Sites/Preview.tsx @@ -13,7 +13,7 @@ import { useToast } from '../../components/ui/toast/ToastContainer'; import { fetchAPI } from '../../services/api'; export default function SitePreview() { - const { siteId } = useParams<{ siteId: string }>(); + const { id: siteId } = useParams<{ id: string }>(); const toast = useToast(); const [loading, setLoading] = useState(true); const [previewUrl, setPreviewUrl] = useState(null); diff --git a/frontend/src/pages/Sites/Settings.tsx b/frontend/src/pages/Sites/Settings.tsx index fd0240af..0b910ab8 100644 --- a/frontend/src/pages/Sites/Settings.tsx +++ b/frontend/src/pages/Sites/Settings.tsx @@ -20,7 +20,7 @@ import WordPressIntegrationModal, { WordPressIntegrationFormData } from '../../c import { integrationApi, SiteIntegration } from '../../services/integration.api'; export default function SiteSettings() { - const { siteId } = useParams<{ siteId: string }>(); + const { id: siteId } = useParams<{ id: string }>(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const toast = useToast();