Update WorkflowGuide component to include industry and sector selection; enhance site creation process with new state management and validation. Refactor SelectDropdown for improved styling and functionality. Add HomepageSiteSelector for better site management in Dashboard.
This commit is contained in:
338
HOMEPAGE_RESTRUCTURE_PLAN.md
Normal file
338
HOMEPAGE_RESTRUCTURE_PLAN.md
Normal file
@@ -0,0 +1,338 @@
|
||||
# Homepage Restructure Plan
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### Current Homepage Structure (in order):
|
||||
1. **PageHeader** - Title, last updated, refresh button
|
||||
2. **WorkflowGuide** - Welcome screen with site addition form (conditional)
|
||||
3. **Hero Section** - Large banner with title, description, and 2 action buttons
|
||||
4. **Your Content Creation Workflow** - 4-step workflow cards
|
||||
5. **Key Metrics** - 4 metric cards (Keywords, Content, Images, Completion)
|
||||
6. **Platform Modules** - 4 module cards (Planner, Writer, Thinker, Automation)
|
||||
7. **Activity Chart & Recent Activity** - Chart and activity list
|
||||
8. **How It Works** - 7-step detailed workflow pipeline
|
||||
9. **Quick Actions** - 4 action cards (Add Keywords, Create Content, Setup Automation, Manage Prompts)
|
||||
10. **Credit Balance & Usage** - Widgets at bottom
|
||||
|
||||
### Identified Issues:
|
||||
|
||||
#### 1. Duplicates & Redundancies:
|
||||
- **Hero Section** vs **WorkflowGuide**: Both serve as welcome/intro sections
|
||||
- **"Your Content Creation Workflow"** (4 steps) vs **"How It Works"** (7 steps): Duplicate workflow explanations
|
||||
- **Quick Actions** duplicates workflow steps and module navigation
|
||||
- **Platform Modules** duplicates sidebar navigation
|
||||
- **Activity Chart** shows dummy data (hardcoded)
|
||||
|
||||
#### 2. Site Management Issues:
|
||||
- Site addition only in WorkflowGuide (hidden when dismissed)
|
||||
- No clear trigger for multi-site users to add sites
|
||||
- Site selector not present on homepage (but should be for multi-site users)
|
||||
- Sector selector not needed on homepage (as per user requirement)
|
||||
|
||||
#### 3. Layout Issues:
|
||||
- Hero banner is too large and has action buttons (should be simpler, at top)
|
||||
- Banner appears after welcome screen (should be at top)
|
||||
- Too much content, overwhelming for new users
|
||||
|
||||
---
|
||||
|
||||
## Proposed Restructure Plan
|
||||
|
||||
### New Homepage Structure:
|
||||
|
||||
```
|
||||
1. PageHeader (with conditional Site Selector for multi-site users)
|
||||
└─ Site Selector: "All Sites" | "Site Name" dropdown (only if user has 2+ sites)
|
||||
|
||||
2. Simplified Banner (moved to top, minimal content, no buttons)
|
||||
└─ Title: "AI-Powered Content Creation Workflow"
|
||||
└─ Subtitle: Brief description
|
||||
└─ No action buttons (removed)
|
||||
|
||||
3. Welcome Screen / Site Addition (conditional)
|
||||
└─ Show WorkflowGuide if:
|
||||
- No sites exist, OR
|
||||
- User manually triggers "Add Site" button
|
||||
└─ For multi-site users: Show compact "Add Site" button/trigger
|
||||
|
||||
4. Key Metrics (4 cards)
|
||||
└─ Data filtered by selected site or "All Sites"
|
||||
|
||||
5. Your Content Creation Workflow (4 steps - keep this one)
|
||||
└─ Remove "How It Works" (7 steps) - redundant
|
||||
|
||||
6. Platform Modules (keep but make more compact)
|
||||
└─ Or consider removing if sidebar navigation is sufficient
|
||||
|
||||
7. Activity Overview (chart + recent activity)
|
||||
└─ Use real data, not dummy data
|
||||
|
||||
8. Quick Actions (simplified - remove duplicates)
|
||||
└─ Keep only unique actions not covered elsewhere
|
||||
|
||||
9. Credit Balance & Usage (keep at bottom)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Detailed Changes
|
||||
|
||||
### 1. PageHeader Enhancement
|
||||
**Location**: Top of page, after PageMeta
|
||||
|
||||
**Changes**:
|
||||
- Add conditional **Site Selector** dropdown (right side of header)
|
||||
- Only show if user has 2+ active sites
|
||||
- Options: "All Sites" | Individual site names
|
||||
- When "All Sites" selected: Show aggregated data
|
||||
- When specific site selected: Show filtered data for that site
|
||||
- **Hide sector selector** on homepage (as per requirement)
|
||||
|
||||
**Implementation**:
|
||||
```tsx
|
||||
<PageHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1>Dashboard</h1>
|
||||
<p>Last updated: {time}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
{sites.length > 1 && (
|
||||
<SiteSelector
|
||||
value={selectedSiteFilter}
|
||||
onChange={handleSiteFilterChange}
|
||||
options={[
|
||||
{ value: 'all', label: 'All Sites' },
|
||||
...sites.map(s => ({ value: s.id, label: s.name }))
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
<RefreshButton />
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Simplified Banner (Move to Top)
|
||||
**Location**: Immediately after PageHeader
|
||||
|
||||
**Changes**:
|
||||
- Move from current position (after WorkflowGuide) to top
|
||||
- Remove action buttons ("Get Started", "Configure Automation")
|
||||
- Reduce padding and content
|
||||
- Keep gradient background and title
|
||||
- Make it more compact (p-6 instead of p-8 md:p-12)
|
||||
|
||||
**New Structure**:
|
||||
```tsx
|
||||
<div className="bg-gradient-to-r from-brand-500 to-purple-600 rounded-2xl p-6 text-white">
|
||||
<h1 className="text-3xl md:text-4xl font-bold mb-2">
|
||||
AI-Powered Content Creation Workflow
|
||||
</h1>
|
||||
<p className="text-lg text-white/90">
|
||||
Transform keywords into published content with intelligent automation.
|
||||
</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Welcome Screen / Site Addition Strategy
|
||||
|
||||
#### For Users with NO Sites:
|
||||
- Always show WorkflowGuide (welcome screen with site addition form)
|
||||
- Cannot be dismissed until at least one site is created
|
||||
|
||||
#### For Users with 1 Site:
|
||||
- Hide WorkflowGuide by default (can be manually shown via button)
|
||||
- Show compact "Add Another Site" button/trigger in header or quick actions
|
||||
- When clicked, opens WorkflowGuide or modal with site addition form
|
||||
- Dashboard shows data for the single site (no site selector needed)
|
||||
|
||||
#### For Users with 2+ Sites:
|
||||
- Hide WorkflowGuide by default
|
||||
- Show site selector in PageHeader (see #1)
|
||||
- Add "Add Site" button in header or as a card in Quick Actions
|
||||
- When clicked, opens WorkflowGuide or modal with site addition form
|
||||
- Dashboard shows data based on selected site filter
|
||||
|
||||
**Implementation**:
|
||||
```tsx
|
||||
// In PageHeader or Quick Actions
|
||||
{sites.length > 0 && (
|
||||
<Button
|
||||
onClick={() => setShowAddSite(true)}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
<PlusIcon /> Add Site
|
||||
</Button>
|
||||
)}
|
||||
|
||||
// Conditional WorkflowGuide
|
||||
{(!hasSites || showAddSite) && (
|
||||
<WorkflowGuide
|
||||
onSiteAdded={() => {
|
||||
setShowAddSite(false);
|
||||
refreshDashboard();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Remove Duplicates
|
||||
|
||||
#### Remove "How It Works" Section (7 steps)
|
||||
- **Reason**: Duplicates "Your Content Creation Workflow" (4 steps)
|
||||
- **Keep**: "Your Content Creation Workflow" (simpler, cleaner)
|
||||
|
||||
#### Simplify Quick Actions
|
||||
- **Remove**: "Add Keywords" (covered in workflow)
|
||||
- **Remove**: "Create Content" (covered in workflow)
|
||||
- **Keep**: "Setup Automation" (unique)
|
||||
- **Keep**: "Manage Prompts" (unique)
|
||||
- **Add**: "Add Site" (for multi-site users)
|
||||
|
||||
#### Consider Removing Platform Modules
|
||||
- **Option A**: Remove entirely (sidebar navigation is sufficient)
|
||||
- **Option B**: Keep but make more compact (2x2 grid instead of 4 columns)
|
||||
- **Recommendation**: Remove to reduce clutter
|
||||
|
||||
---
|
||||
|
||||
### 5. Data Filtering Logic
|
||||
|
||||
**Single Site User**:
|
||||
- Always show data for that one site
|
||||
- No site selector
|
||||
- `site_id` = activeSite.id in all API calls
|
||||
|
||||
**Multi-Site User**:
|
||||
- Show site selector in header
|
||||
- Default: "All Sites" (aggregated data)
|
||||
- When specific site selected: Filter by `site_id`
|
||||
- Update all metrics, charts, and activity when filter changes
|
||||
|
||||
**Implementation**:
|
||||
```tsx
|
||||
const [siteFilter, setSiteFilter] = useState<'all' | number>('all');
|
||||
|
||||
const fetchAppInsights = async () => {
|
||||
const siteId = siteFilter === 'all' ? undefined : siteFilter;
|
||||
|
||||
const [keywordsRes, clustersRes, ...] = await Promise.all([
|
||||
fetchKeywords({ page_size: 1, site_id: siteId }),
|
||||
fetchClusters({ page_size: 1, site_id: siteId }),
|
||||
// ... other calls
|
||||
]);
|
||||
|
||||
// Update insights state
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. Activity Chart - Use Real Data
|
||||
|
||||
**Current**: Hardcoded dummy data
|
||||
**Change**: Fetch real activity data from API
|
||||
|
||||
**Implementation**:
|
||||
- Create API endpoint for activity timeline
|
||||
- Or aggregate from existing endpoints (content created dates, etc.)
|
||||
- Show actual trends over past 7 days
|
||||
|
||||
---
|
||||
|
||||
## Final Proposed Structure
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ PageHeader │
|
||||
│ - Title: Dashboard │
|
||||
│ - Site Selector (if 2+ sites) │
|
||||
│ - Refresh Button │
|
||||
└─────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Simplified Banner (compact, no buttons) │
|
||||
│ - Title + Subtitle only │
|
||||
└─────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────┐
|
||||
│ WorkflowGuide (conditional) │
|
||||
│ - Show if: no sites OR manually opened │
|
||||
│ - Contains site addition form │
|
||||
└─────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Key Metrics (4 cards) │
|
||||
│ - Filtered by site selection │
|
||||
└─────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Your Content Creation Workflow (4 steps)│
|
||||
│ - Keep this, remove "How It Works" │
|
||||
└─────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Activity Overview │
|
||||
│ - Chart (real data) + Recent Activity │
|
||||
└─────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Quick Actions (2-3 unique actions) │
|
||||
│ - Setup Automation │
|
||||
│ - Manage Prompts │
|
||||
│ - Add Site (if multi-site user) │
|
||||
└─────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Credit Balance & Usage │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Priority
|
||||
|
||||
### Phase 1: Core Restructure
|
||||
1. ✅ Move banner to top, simplify it
|
||||
2. ✅ Add site selector to PageHeader (conditional)
|
||||
3. ✅ Implement data filtering logic
|
||||
4. ✅ Update WorkflowGuide visibility logic
|
||||
|
||||
### Phase 2: Remove Duplicates
|
||||
5. ✅ Remove "How It Works" section
|
||||
6. ✅ Simplify Quick Actions
|
||||
7. ✅ Consider removing Platform Modules
|
||||
|
||||
### Phase 3: Enhancements
|
||||
8. ✅ Add "Add Site" trigger for existing users
|
||||
9. ✅ Replace dummy activity data with real data
|
||||
10. ✅ Test single vs multi-site scenarios
|
||||
|
||||
---
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Cleaner UI**: Removed redundant sections
|
||||
2. **Better UX**: Clear site management for multi-site users
|
||||
3. **Focused Content**: Less overwhelming for new users
|
||||
4. **Proper Data**: Real activity data, filtered by site
|
||||
5. **Flexible**: Works for both single and multi-site users
|
||||
6. **Accessible**: Easy to add sites from homepage when needed
|
||||
|
||||
---
|
||||
|
||||
## Questions to Consider
|
||||
|
||||
1. Should Platform Modules be removed entirely or kept compact?
|
||||
2. Should "Add Site" be a button in header or a card in Quick Actions?
|
||||
3. Should WorkflowGuide be a modal or inline component when triggered?
|
||||
4. Do we need a separate "All Sites" view or just individual site filtering?
|
||||
|
||||
Binary file not shown.
@@ -102,7 +102,9 @@ const SelectDropdown: React.FC<SelectDropdownProps> = ({
|
||||
onClick={() => !disabled && setIsOpen(!isOpen)}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
className={`igny8-select-styled h-9 w-full appearance-none rounded-lg border border-gray-300 bg-transparent px-3 py-2 pr-10 text-sm shadow-theme-xs focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:focus:border-brand-800 ${
|
||||
className={`igny8-select-styled w-full appearance-none rounded-lg border border-gray-300 bg-transparent px-3 pr-10 shadow-theme-xs focus:border-brand-300 focus:outline-hidden focus:ring-3 focus:ring-brand-500/10 dark:border-gray-700 dark:bg-gray-900 dark:focus:border-brand-800 ${
|
||||
className.includes('text-base') ? 'h-11 py-2.5 text-base' : 'h-9 py-2 text-sm'
|
||||
} ${
|
||||
isPlaceholder
|
||||
? "text-gray-400 dark:text-gray-400"
|
||||
: "text-gray-800 dark:text-white/90"
|
||||
@@ -140,7 +142,9 @@ const SelectDropdown: React.FC<SelectDropdownProps> = ({
|
||||
// Pass the normalized optionValue to ensure consistency
|
||||
handleSelect(optionValue);
|
||||
}}
|
||||
className={`w-full text-left px-3 py-2 text-sm transition-colors flex items-center gap-2 ${
|
||||
className={`w-full text-left px-3 py-2 transition-colors flex items-center gap-2 ${
|
||||
className.includes('text-base') ? 'text-base' : 'text-sm'
|
||||
} ${
|
||||
isSelected
|
||||
? "bg-brand-500 text-white"
|
||||
: "text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800"
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
/**
|
||||
* WorkflowGuide Component
|
||||
* Inline welcome/guide screen for new users
|
||||
* Shows complete workflow explainer with visual flow maps and progress tracking
|
||||
* Shows site creation form with industry and sector selection
|
||||
*/
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Card } from '../ui/card';
|
||||
import Button from '../ui/button/Button';
|
||||
import Badge from '../ui/badge/Badge';
|
||||
import { ProgressBar } from '../ui/progress';
|
||||
import Checkbox from '../form/input/Checkbox';
|
||||
import {
|
||||
CloseIcon,
|
||||
ArrowRightIcon,
|
||||
@@ -24,33 +22,32 @@ import {
|
||||
} from '../../icons';
|
||||
import { useOnboardingStore } from '../../store/onboardingStore';
|
||||
import { useSiteStore } from '../../store/siteStore';
|
||||
import { fetchSites, fetchKeywords, fetchClusters, fetchContent } from '../../services/api';
|
||||
import { fetchSites, fetchIndustries, Industry, Sector, createSite, selectSectorsForSite, setActiveSite } from '../../services/api';
|
||||
import { useAuthStore } from '../../store/authStore';
|
||||
import SelectDropdown from '../form/SelectDropdown';
|
||||
import { useToast } from '../ui/toast/ToastContainer';
|
||||
import Alert from '../ui/alert/Alert';
|
||||
|
||||
interface WorkflowProgress {
|
||||
hasSite: boolean;
|
||||
keywordsCount: number;
|
||||
clustersCount: number;
|
||||
contentCount: number;
|
||||
publishedCount: number;
|
||||
completionPercentage: number;
|
||||
interface WorkflowGuideProps {
|
||||
onSiteAdded?: () => void;
|
||||
}
|
||||
|
||||
export default function WorkflowGuide() {
|
||||
export default function WorkflowGuide({ onSiteAdded }: WorkflowGuideProps) {
|
||||
const navigate = useNavigate();
|
||||
const toast = useToast();
|
||||
const { isGuideVisible, dismissGuide, loadFromBackend } = useOnboardingStore();
|
||||
const { activeSite } = useSiteStore();
|
||||
const { activeSite, loadActiveSite } = useSiteStore();
|
||||
const { isAuthenticated } = useAuthStore();
|
||||
const [progress, setProgress] = useState<WorkflowProgress>({
|
||||
hasSite: false,
|
||||
keywordsCount: 0,
|
||||
clustersCount: 0,
|
||||
contentCount: 0,
|
||||
publishedCount: 0,
|
||||
completionPercentage: 0,
|
||||
});
|
||||
const [loadingProgress, setLoadingProgress] = useState(true);
|
||||
const [dontShowAgain, setDontShowAgain] = useState(false);
|
||||
|
||||
// Industry and Sector selection state
|
||||
const [industries, setIndustries] = useState<Industry[]>([]);
|
||||
const [selectedIndustry, setSelectedIndustry] = useState<Industry | null>(null);
|
||||
const [selectedSectors, setSelectedSectors] = useState<string[]>([]);
|
||||
const [loadingIndustries, setLoadingIndustries] = useState(false);
|
||||
const [isWordPressExpanded, setIsWordPressExpanded] = useState(false);
|
||||
const [isCreatingSite, setIsCreatingSite] = useState(false);
|
||||
const [siteName, setSiteName] = useState('');
|
||||
const [websiteAddress, setWebsiteAddress] = useState('');
|
||||
|
||||
// Load dismissal state from backend on mount
|
||||
useEffect(() => {
|
||||
@@ -61,56 +58,137 @@ export default function WorkflowGuide() {
|
||||
}
|
||||
}, [isAuthenticated, loadFromBackend]);
|
||||
|
||||
// Load progress data
|
||||
// Load industries on mount
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated || !isGuideVisible) return;
|
||||
|
||||
const loadProgress = async () => {
|
||||
|
||||
const loadIndustries = async () => {
|
||||
try {
|
||||
setLoadingProgress(true);
|
||||
const [sitesRes, keywordsRes, clustersRes, contentRes] = await Promise.all([
|
||||
fetchSites().catch(() => ({ results: [], count: 0 })),
|
||||
fetchKeywords({ page_size: 1 }).catch(() => ({ count: 0 })),
|
||||
fetchClusters({ page_size: 1 }).catch(() => ({ count: 0 })),
|
||||
fetchContent({ page_size: 1 }).catch(() => ({ count: 0 })),
|
||||
]);
|
||||
|
||||
const sitesCount = sitesRes.results?.filter((s: any) => s.is_active).length || 0;
|
||||
const keywordsCount = keywordsRes.count || 0;
|
||||
const clustersCount = clustersRes.count || 0;
|
||||
const contentCount = contentRes.count || 0;
|
||||
const publishedCount = 0; // TODO: Add published content count when API is available
|
||||
|
||||
// Calculate completion percentage
|
||||
// Milestones: Site (20%), Keywords (20%), Clusters (20%), Content (20%), Published (20%)
|
||||
let completion = 0;
|
||||
if (sitesCount > 0) completion += 20;
|
||||
if (keywordsCount > 0) completion += 20;
|
||||
if (clustersCount > 0) completion += 20;
|
||||
if (contentCount > 0) completion += 20;
|
||||
if (publishedCount > 0) completion += 20;
|
||||
|
||||
setProgress({
|
||||
hasSite: sitesCount > 0,
|
||||
keywordsCount,
|
||||
clustersCount,
|
||||
contentCount,
|
||||
publishedCount,
|
||||
completionPercentage: completion,
|
||||
});
|
||||
setLoadingIndustries(true);
|
||||
const response = await fetchIndustries();
|
||||
setIndustries(response.industries || []);
|
||||
} catch (error) {
|
||||
console.error('Failed to load progress:', error);
|
||||
console.error('Failed to load industries:', error);
|
||||
} finally {
|
||||
setLoadingProgress(false);
|
||||
setLoadingIndustries(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadProgress();
|
||||
|
||||
loadIndustries();
|
||||
}, [isAuthenticated, isGuideVisible]);
|
||||
|
||||
if (!isGuideVisible) return null;
|
||||
// Get available sectors for selected industry
|
||||
const availableSectors = useMemo(() => {
|
||||
if (!selectedIndustry) return [];
|
||||
return selectedIndustry.sectors || [];
|
||||
}, [selectedIndustry]);
|
||||
|
||||
const { hasSite, keywordsCount, clustersCount, contentCount, publishedCount, completionPercentage } = progress;
|
||||
// Handle industry selection
|
||||
const handleIndustrySelect = (industry: Industry) => {
|
||||
setSelectedIndustry(industry);
|
||||
setSelectedSectors([]); // Reset sectors when industry changes
|
||||
};
|
||||
|
||||
// Handle sector toggle
|
||||
const handleSectorToggle = (sectorSlug: string) => {
|
||||
setSelectedSectors(prev =>
|
||||
prev.includes(sectorSlug)
|
||||
? prev.filter(s => s !== sectorSlug)
|
||||
: [...prev, sectorSlug]
|
||||
);
|
||||
};
|
||||
|
||||
// Handle WordPress card click - expand to show industry/sector selection
|
||||
const handleWordPressCardClick = () => {
|
||||
setIsWordPressExpanded(!isWordPressExpanded);
|
||||
if (!isWordPressExpanded && industries.length === 0) {
|
||||
// Load industries if not already loaded
|
||||
const loadIndustries = async () => {
|
||||
try {
|
||||
setLoadingIndustries(true);
|
||||
const response = await fetchIndustries();
|
||||
setIndustries(response.industries || []);
|
||||
} catch (error) {
|
||||
console.error('Failed to load industries:', error);
|
||||
} finally {
|
||||
setLoadingIndustries(false);
|
||||
}
|
||||
};
|
||||
loadIndustries();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle Add Site button click
|
||||
const handleAddSite = async () => {
|
||||
if (!siteName || !siteName.trim()) {
|
||||
toast.error('Please enter a site name');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedIndustry) {
|
||||
toast.error('Please select an industry first');
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedSectors.length === 0) {
|
||||
toast.error('Please select at least one sector');
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedSectors.length > 5) {
|
||||
toast.error('Maximum 5 sectors allowed per site');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsCreatingSite(true);
|
||||
|
||||
// Create site with user-provided name and domain
|
||||
const newSite = await createSite({
|
||||
name: siteName.trim(),
|
||||
domain: websiteAddress.trim() || undefined,
|
||||
is_active: true,
|
||||
hosting_type: 'wordpress',
|
||||
});
|
||||
|
||||
// Set industry for the site (if API supports it during creation, otherwise update)
|
||||
// For now, we'll set it via selectSectorsForSite which also sets industry
|
||||
|
||||
// Select sectors for the site (this also sets the industry)
|
||||
await selectSectorsForSite(
|
||||
newSite.id,
|
||||
selectedIndustry.slug,
|
||||
selectedSectors
|
||||
);
|
||||
|
||||
// Set as active site if it's the first site
|
||||
const sitesRes = await fetchSites();
|
||||
if (sitesRes.results.length === 1) {
|
||||
await setActiveSite(newSite.id);
|
||||
}
|
||||
|
||||
const siteNameTrimmed = siteName.trim();
|
||||
toast.success(`Site "${siteNameTrimmed}" created successfully with ${selectedSectors.length} sector${selectedSectors.length !== 1 ? 's' : ''}!`);
|
||||
|
||||
// Reload sites in store
|
||||
await loadActiveSite();
|
||||
|
||||
// Call callback if provided (before navigation)
|
||||
if (onSiteAdded) {
|
||||
onSiteAdded();
|
||||
}
|
||||
|
||||
// Dismiss guide and redirect to site settings with integrations tab
|
||||
await dismissGuide();
|
||||
navigate(`/sites/${newSite.id}/settings?tab=integrations`);
|
||||
} catch (error: any) {
|
||||
toast.error(`Failed to create site: ${error.message}`);
|
||||
} finally {
|
||||
setIsCreatingSite(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!isGuideVisible) return null;
|
||||
|
||||
return (
|
||||
<div className="mb-8">
|
||||
@@ -142,413 +220,215 @@ export default function WorkflowGuide() {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Main Workflow Options */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||
{/* Build New Site */}
|
||||
<Card className="p-6 border-2 border-blue-200 dark:border-blue-800 hover:border-blue-400 dark:hover:border-blue-600 transition-colors">
|
||||
<div className="flex items-start gap-4 mb-4">
|
||||
{/* Site Integration Option */}
|
||||
<div className="mb-6">
|
||||
<Card className="p-6 border-2 border-blue-200 dark:border-blue-800">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="size-12 rounded-xl bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center text-white flex-shrink-0">
|
||||
<GridIcon className="h-6 w-6" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-1">
|
||||
Build New Site
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
Create a new website from scratch with IGNY8
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
onClick={async () => {
|
||||
navigate('/sites/builder?type=wordpress');
|
||||
await dismissGuide();
|
||||
}}
|
||||
className="w-full flex items-center justify-between p-4 rounded-lg border-2 border-gray-200 dark:border-gray-700 hover:border-blue-400 dark:hover:border-blue-600 bg-white dark:bg-gray-800 transition-colors group"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<PlugInIcon className="w-5 h-5 text-blue-600 dark:text-blue-400" />
|
||||
<div className="text-left">
|
||||
<div className="font-semibold text-gray-900 dark:text-white">
|
||||
WordPress Self-Hosted Site
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400">
|
||||
Build and sync to your WordPress installation
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ArrowRightIcon className="w-5 h-5 text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors" />
|
||||
</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
navigate('/sites/builder?type=igny8');
|
||||
await dismissGuide();
|
||||
}}
|
||||
className="w-full flex items-center justify-between p-4 rounded-lg border-2 border-gray-200 dark:border-gray-700 hover:border-blue-400 dark:hover:border-blue-600 bg-white dark:bg-gray-800 transition-colors group"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<GridIcon className="w-5 h-5 text-blue-600 dark:text-blue-400" />
|
||||
<div className="text-left">
|
||||
<div className="font-semibold text-gray-900 dark:text-white">
|
||||
IGNY8-Powered IGNY8-Hosted Site
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400">
|
||||
Fully managed site hosted by IGNY8
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ArrowRightIcon className="w-5 h-5 text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors" />
|
||||
</button>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Integrate Existing Site */}
|
||||
<Card className="p-6 border-2 border-green-200 dark:border-green-800 hover:border-green-400 dark:hover:border-green-600 transition-colors">
|
||||
<div className="flex items-start gap-4 mb-4">
|
||||
<div className="size-12 rounded-xl bg-gradient-to-br from-green-500 to-green-600 flex items-center justify-center text-white flex-shrink-0">
|
||||
<PlugInIcon className="h-6 w-6" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-1">
|
||||
Integrate Existing Site
|
||||
Integrate New Site or Existing Site
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
Connect your existing website to IGNY8
|
||||
Connect your WordPress site to IGNY8
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
|
||||
{/* Site Type Selection - 2 columns for future IGNY8 option */}
|
||||
<div className="grid grid-cols-2 gap-4 mb-6">
|
||||
{/* WordPress Site Card - Clickable to expand */}
|
||||
<button
|
||||
onClick={async () => {
|
||||
navigate('/sites?action=integrate&platform=wordpress');
|
||||
await dismissGuide();
|
||||
}}
|
||||
className="w-full flex items-center justify-between p-4 rounded-lg border-2 border-gray-200 dark:border-gray-700 hover:border-green-400 dark:hover:border-green-600 bg-white dark:bg-gray-800 transition-colors group"
|
||||
onClick={handleWordPressCardClick}
|
||||
className={`flex items-center justify-between p-4 rounded-lg border-2 transition-all duration-200 group ${
|
||||
isWordPressExpanded
|
||||
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
|
||||
: 'border-gray-200 dark:border-gray-700 hover:border-blue-400 dark:hover:border-blue-600 bg-white dark:bg-gray-800'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<PlugInIcon className="w-5 h-5 text-green-600 dark:text-green-400" />
|
||||
<PlugInIcon className={`w-5 h-5 ${isWordPressExpanded ? 'text-blue-600 dark:text-blue-400' : 'text-blue-600 dark:text-blue-400'}`} />
|
||||
<div className="text-left">
|
||||
<div className="font-semibold text-gray-900 dark:text-white">
|
||||
Integrate WordPress/Shopify
|
||||
WordPress Site
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400">
|
||||
Sync content with your existing site
|
||||
Integrate new or existing WordPress site
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ArrowRightIcon className="w-5 h-5 text-gray-400 group-hover:text-green-600 dark:group-hover:text-green-400 transition-colors" />
|
||||
<ArrowRightIcon className={`w-5 h-5 transition-transform ${isWordPressExpanded ? 'transform rotate-90' : ''} ${
|
||||
isWordPressExpanded
|
||||
? 'text-blue-600 dark:text-blue-400'
|
||||
: 'text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-400'
|
||||
}`} />
|
||||
</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
navigate('/sites?action=integrate&platform=custom');
|
||||
await dismissGuide();
|
||||
}}
|
||||
className="w-full flex items-center justify-between p-4 rounded-lg border-2 border-gray-200 dark:border-gray-700 hover:border-green-400 dark:hover:border-green-600 bg-white dark:bg-gray-800 transition-colors group"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<FileIcon className="w-5 h-5 text-green-600 dark:text-green-400" />
|
||||
<div className="text-left">
|
||||
<div className="font-semibold text-gray-900 dark:text-white">
|
||||
Custom Site
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400">
|
||||
Connect any custom website
|
||||
</div>
|
||||
|
||||
{/* Placeholder for future IGNY8 option */}
|
||||
<div className="flex items-center justify-center p-4 rounded-lg border-2 border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 opacity-50">
|
||||
<div className="text-center">
|
||||
<div className="font-semibold text-gray-500 dark:text-gray-400 text-sm">
|
||||
IGNY8 Hosted
|
||||
</div>
|
||||
<div className="text-xs text-gray-400 dark:text-gray-500">
|
||||
Coming Soon
|
||||
</div>
|
||||
</div>
|
||||
<ArrowRightIcon className="w-5 h-5 text-gray-400 group-hover:text-green-600 dark:group-hover:text-green-400 transition-colors" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Expanded Site Form - 3 columns: Name, Website Address, Industry */}
|
||||
{isWordPressExpanded && (
|
||||
<div className="space-y-4 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
{/* Site Name, Website Address, and Industry - 3 columns */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
{/* Site Name */}
|
||||
<div>
|
||||
<label className="block text-base font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Site Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={siteName}
|
||||
onChange={(e) => setSiteName(e.target.value)}
|
||||
placeholder="Enter site name"
|
||||
className="w-full px-4 py-2.5 border-2 border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white text-base focus:border-blue-500 focus:ring-2 focus:ring-blue-200 dark:focus:ring-blue-800"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Website Address */}
|
||||
<div>
|
||||
<label className="block text-base font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Website Address
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={websiteAddress}
|
||||
onChange={(e) => setWebsiteAddress(e.target.value)}
|
||||
placeholder="https://example.com"
|
||||
className="w-full px-4 py-2.5 border-2 border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white text-base focus:border-blue-500 focus:ring-2 focus:ring-blue-200 dark:focus:ring-blue-800"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Industry Selection - Using SelectDropdown */}
|
||||
<div>
|
||||
<label className="block text-base font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Select Industry
|
||||
</label>
|
||||
{loadingIndustries ? (
|
||||
<div className="text-base text-gray-500 py-2.5">Loading industries...</div>
|
||||
) : (
|
||||
<SelectDropdown
|
||||
options={industries.map(industry => ({
|
||||
value: industry.slug,
|
||||
label: industry.name,
|
||||
}))}
|
||||
placeholder="-- Select Industry --"
|
||||
value={selectedIndustry?.slug || ''}
|
||||
onChange={(value) => {
|
||||
const industry = industries.find(i => i.slug === value);
|
||||
if (industry) {
|
||||
handleIndustrySelect(industry);
|
||||
}
|
||||
}}
|
||||
className="text-base [&_.igny8-select-styled]:text-base [&_.igny8-select-styled]:py-2.5 [&_button]:text-base"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sector Selection - Cards like IndustriesSectorsKeywords page */}
|
||||
{selectedIndustry && availableSectors.length > 0 && (
|
||||
<div>
|
||||
<label className="block text-base font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Select Sectors
|
||||
</label>
|
||||
<div className="grid grid-cols-5 gap-3">
|
||||
{availableSectors.map((sector) => (
|
||||
<Card
|
||||
key={sector.slug}
|
||||
className={`p-4 hover:shadow-lg transition-all duration-200 border-2 cursor-pointer ${
|
||||
selectedSectors.includes(sector.slug)
|
||||
? 'border-[var(--color-primary)] bg-blue-50 dark:bg-blue-900/20'
|
||||
: 'border-gray-200 dark:border-gray-700'
|
||||
}`}
|
||||
onClick={() => handleSectorToggle(sector.slug)}
|
||||
>
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<h3 className="text-base font-semibold text-gray-900 dark:text-white">
|
||||
{sector.name}
|
||||
</h3>
|
||||
{selectedSectors.includes(sector.slug) && (
|
||||
<CheckCircleIcon className="w-5 h-5 text-[var(--color-primary)] flex-shrink-0" />
|
||||
)}
|
||||
</div>
|
||||
{sector.description && (
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||
{sector.description}
|
||||
</p>
|
||||
)}
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
{selectedSectors.length > 0 && (
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||
{selectedSectors.length} sector{selectedSectors.length !== 1 ? 's' : ''} selected
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Validation Notification Card */}
|
||||
{(!siteName || !siteName.trim() || !selectedIndustry || selectedSectors.length === 0) && (
|
||||
<div className="pt-4 flex justify-center">
|
||||
<div className="w-full max-w-md">
|
||||
<div className="[&_h4]:hidden [&_p]:text-lg [&_p]:font-semibold">
|
||||
<Alert
|
||||
variant="info"
|
||||
title=""
|
||||
message={
|
||||
!siteName || !siteName.trim()
|
||||
? 'Please enter a site name'
|
||||
: !selectedIndustry
|
||||
? 'Please select an industry'
|
||||
: 'Please select at least one sector'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Add Site Button */}
|
||||
<div className="pt-4 flex justify-center">
|
||||
<Button
|
||||
onClick={handleAddSite}
|
||||
disabled={!siteName || !siteName.trim() || !selectedIndustry || selectedSectors.length === 0 || isCreatingSite}
|
||||
variant="solid"
|
||||
tone="brand"
|
||||
size="lg"
|
||||
className={`text-lg font-semibold px-8 py-4 h-auto transition-all duration-200 ${
|
||||
!siteName || !siteName.trim() || !selectedIndustry || selectedSectors.length === 0 || isCreatingSite
|
||||
? ''
|
||||
: 'hover:shadow-lg hover:scale-[1.01] active:scale-[0.99]'
|
||||
}`}
|
||||
>
|
||||
{isCreatingSite ? (
|
||||
<>Creating Site...</>
|
||||
) : (
|
||||
<>Add Site</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Workflow Steps */}
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
||||
Your Content Creation Workflow
|
||||
</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ icon: <ListIcon />, label: 'Discover Keywords', gradient: 'from-blue-500 to-blue-600', path: '/planner/keywords' },
|
||||
{ icon: <GroupIcon />, label: 'Cluster Keywords', gradient: 'from-purple-500 to-purple-600', path: '/planner/clusters' },
|
||||
{ icon: <BoltIcon />, label: 'Generate Ideas', gradient: 'from-orange-500 to-orange-600', path: '/planner/ideas' },
|
||||
{ icon: <FileTextIcon />, label: 'Create Content', gradient: 'from-green-500 to-green-600', path: '/writer/content' },
|
||||
].map((step, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => navigate(step.path)}
|
||||
className="flex items-center gap-3 p-4 rounded-lg border-2 border-gray-200 dark:border-gray-700 hover:border-[var(--color-primary)] dark:hover:border-[var(--color-primary)] bg-white dark:bg-gray-800 transition-colors group"
|
||||
>
|
||||
<div className={`size-10 rounded-lg bg-gradient-to-br ${step.gradient} flex items-center justify-center text-white flex-shrink-0`}>
|
||||
{React.cloneElement(step.icon as React.ReactElement, { className: 'w-5 h-5' })}
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="font-semibold text-sm text-gray-900 dark:text-white group-hover:text-[var(--color-primary)]">
|
||||
{step.label}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress Tracking */}
|
||||
<div className="mb-6">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
Your Progress
|
||||
</h3>
|
||||
<span className="text-sm font-medium text-gray-600 dark:text-gray-400">
|
||||
{completionPercentage}% Complete
|
||||
</span>
|
||||
</div>
|
||||
<ProgressBar
|
||||
value={completionPercentage}
|
||||
className="mb-4"
|
||||
/>
|
||||
|
||||
{/* Milestones */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-3">
|
||||
{[
|
||||
{
|
||||
label: 'Site Created',
|
||||
completed: hasSite,
|
||||
count: hasSite ? 1 : 0,
|
||||
path: '/sites',
|
||||
icon: <GridIcon className="w-4 h-4" />
|
||||
},
|
||||
{
|
||||
label: 'Keywords',
|
||||
completed: keywordsCount > 0,
|
||||
count: keywordsCount,
|
||||
path: '/planner/keywords',
|
||||
icon: <ListIcon className="w-4 h-4" />
|
||||
},
|
||||
{
|
||||
label: 'Clusters',
|
||||
completed: clustersCount > 0,
|
||||
count: clustersCount,
|
||||
path: '/planner/clusters',
|
||||
icon: <GroupIcon className="w-4 h-4" />
|
||||
},
|
||||
{
|
||||
label: 'Content',
|
||||
completed: contentCount > 0,
|
||||
count: contentCount,
|
||||
path: '/writer/content',
|
||||
icon: <FileTextIcon className="w-4 h-4" />
|
||||
},
|
||||
{
|
||||
label: 'Published',
|
||||
completed: publishedCount > 0,
|
||||
count: publishedCount,
|
||||
path: '/writer/published',
|
||||
icon: <CheckCircleIcon className="w-4 h-4" />
|
||||
},
|
||||
].map((milestone, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => {
|
||||
navigate(milestone.path);
|
||||
dismissGuide();
|
||||
}}
|
||||
className={`flex flex-col items-center gap-2 p-3 rounded-lg border-2 transition-colors ${
|
||||
milestone.completed
|
||||
? 'border-green-300 dark:border-green-700 bg-green-50 dark:bg-green-950/20'
|
||||
: 'border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 hover:border-orange-400 dark:hover:border-orange-600'
|
||||
}`}
|
||||
>
|
||||
<div className={`flex items-center justify-center w-8 h-8 rounded-lg ${
|
||||
milestone.completed
|
||||
? 'bg-green-500 text-white'
|
||||
: 'bg-gray-200 dark:bg-gray-700 text-gray-500 dark:text-gray-400'
|
||||
}`}>
|
||||
{milestone.completed ? (
|
||||
<CheckCircleIcon className="w-5 h-5" />
|
||||
) : (
|
||||
milestone.icon
|
||||
)}
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className={`text-xs font-semibold ${
|
||||
milestone.completed
|
||||
? 'text-green-700 dark:text-green-300'
|
||||
: 'text-gray-600 dark:text-gray-400'
|
||||
}`}>
|
||||
{milestone.label}
|
||||
</div>
|
||||
<div className={`text-xs ${
|
||||
milestone.completed
|
||||
? 'text-green-600 dark:text-green-400'
|
||||
: 'text-gray-500 dark:text-gray-500'
|
||||
}`}>
|
||||
{milestone.count}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Contextual CTA based on progress */}
|
||||
{completionPercentage === 0 && (
|
||||
<div className="flex items-center gap-2 p-4 rounded-lg bg-blue-50 dark:bg-blue-950/20 border border-blue-200 dark:border-blue-800 mb-6">
|
||||
<BoltIcon className="w-5 h-5 text-blue-600 dark:text-blue-400 flex-shrink-0" />
|
||||
<div className="flex-1">
|
||||
<div className="font-semibold text-sm text-blue-900 dark:text-blue-100">
|
||||
Get started by creating your first site
|
||||
</div>
|
||||
<div className="text-xs text-blue-700 dark:text-blue-300 mt-1">
|
||||
Choose one of the options above to begin
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasSite && keywordsCount === 0 && (
|
||||
<div className="flex items-center gap-2 p-4 rounded-lg bg-purple-50 dark:bg-purple-950/20 border border-purple-200 dark:border-purple-800 mb-6">
|
||||
<CheckCircleIcon className="w-5 h-5 text-purple-600 dark:text-purple-400 flex-shrink-0" />
|
||||
<div className="flex-1">
|
||||
<div className="font-semibold text-sm text-purple-900 dark:text-purple-100">
|
||||
Great! You've created your first site
|
||||
</div>
|
||||
<div className="text-xs text-purple-700 dark:text-purple-300 mt-1">
|
||||
Now discover keywords to start your content planning
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
navigate('/planner/keywords');
|
||||
await dismissGuide();
|
||||
}}
|
||||
>
|
||||
Discover Keywords
|
||||
<ArrowRightIcon className="w-4 h-4 ml-2" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{keywordsCount > 0 && clustersCount === 0 && (
|
||||
<div className="flex items-center gap-2 p-4 rounded-lg bg-indigo-50 dark:bg-indigo-950/20 border border-indigo-200 dark:border-indigo-800 mb-6">
|
||||
<CheckCircleIcon className="w-5 h-5 text-indigo-600 dark:text-indigo-400 flex-shrink-0" />
|
||||
<div className="flex-1">
|
||||
<div className="font-semibold text-sm text-indigo-900 dark:text-indigo-100">
|
||||
{keywordsCount} keywords added!
|
||||
</div>
|
||||
<div className="text-xs text-indigo-700 dark:text-indigo-300 mt-1">
|
||||
Group them into clusters to organize your content strategy
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
navigate('/planner/clusters');
|
||||
await dismissGuide();
|
||||
}}
|
||||
>
|
||||
Create Clusters
|
||||
<ArrowRightIcon className="w-4 h-4 ml-2" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{clustersCount > 0 && contentCount === 0 && (
|
||||
<div className="flex items-center gap-2 p-4 rounded-lg bg-orange-50 dark:bg-orange-950/20 border border-orange-200 dark:border-orange-800 mb-6">
|
||||
<CheckCircleIcon className="w-5 h-5 text-orange-600 dark:text-orange-400 flex-shrink-0" />
|
||||
<div className="flex-1">
|
||||
<div className="font-semibold text-sm text-orange-900 dark:text-orange-100">
|
||||
{clustersCount} clusters ready!
|
||||
</div>
|
||||
<div className="text-xs text-orange-700 dark:text-orange-300 mt-1">
|
||||
Generate content ideas and start writing
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
navigate('/writer/tasks');
|
||||
await dismissGuide();
|
||||
}}
|
||||
>
|
||||
Create Content
|
||||
<ArrowRightIcon className="w-4 h-4 ml-2" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{contentCount > 0 && publishedCount === 0 && (
|
||||
<div className="flex items-center gap-2 p-4 rounded-lg bg-green-50 dark:bg-green-950/20 border border-green-200 dark:border-green-800 mb-6">
|
||||
<CheckCircleIcon className="w-5 h-5 text-green-600 dark:text-green-400 flex-shrink-0" />
|
||||
<div className="flex-1">
|
||||
<div className="font-semibold text-sm text-green-900 dark:text-green-100">
|
||||
{contentCount} content pieces created!
|
||||
</div>
|
||||
<div className="text-xs text-green-700 dark:text-green-300 mt-1">
|
||||
Review and publish your content to go live
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
navigate('/writer/content');
|
||||
await dismissGuide();
|
||||
}}
|
||||
>
|
||||
Review Content
|
||||
<ArrowRightIcon className="w-4 h-4 ml-2" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Footer Actions */}
|
||||
<div className="pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={dontShowAgain}
|
||||
onChange={setDontShowAgain}
|
||||
label="Don't show this again"
|
||||
id="dont-show-guide"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
if (dontShowAgain) {
|
||||
await dismissGuide();
|
||||
}
|
||||
navigate('/sites');
|
||||
}}
|
||||
>
|
||||
View All Sites
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
if (dontShowAgain) {
|
||||
await dismissGuide();
|
||||
}
|
||||
navigate('/planner/keywords');
|
||||
}}
|
||||
>
|
||||
Start Planning
|
||||
<ArrowRightIcon className="w-4 h-4 ml-2" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
You can always access this guide from the orange "Show Guide" button in the header
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user