diff --git a/docs/plans/FRONTEND-AUDIT-PLAN.md b/docs/plans/FRONTEND-AUDIT-PLAN.md index 35bf7c30..a0841b95 100644 --- a/docs/plans/FRONTEND-AUDIT-PLAN.md +++ b/docs/plans/FRONTEND-AUDIT-PLAN.md @@ -48,12 +48,12 @@ This file contains: ```css :root { /* ===== THE ONLY 6 HEX VALUES IN THE ENTIRE SYSTEM ===== */ - --color-primary: #0077B6; /* Brand Blue */ - --color-success: #00B894; /* Success Green */ - --color-warning: #F59E0B; /* Warning Amber */ - --color-danger: #DC2626; /* Error Red */ - --color-purple: #7C3AED; /* Premium Purple */ - --color-gray-base: #667085; /* Neutral Gray Base */ + --color-primary: #2C7AA1; /* Brand Blue - main CTA, links, primary actions */ + --color-success: #2CA18E; /* Success Green - confirmations, positive states */ + --color-warning: #D9A12C; /* Warning Amber - alerts, cautions */ + --color-danger: #A12C40; /* Danger Red - errors, destructive actions */ + --color-purple: #2C40A1; /* Purple - premium features, special emphasis */ + --color-gray-base: #667085; /* Gray Base - neutral text, borders, backgrounds */ } ``` @@ -186,11 +186,11 @@ echo " 08-inline-components.txt (review - extract to /components/)" | Token | Hex Value | Purpose | |-------|-----------|---------| -| `--color-primary` | `#0077B6` | Brand/Primary actions | -| `--color-success` | `#00B894` | Success states | -| `--color-warning` | `#F59E0B` | Warning states | -| `--color-danger` | `#DC2626` | Error/Danger states | -| `--color-purple` | `#7C3AED` | Premium/Special features | +| `--color-primary` | `#2C7AA1` | Brand/Primary actions, links, CTA | +| `--color-success` | `#2CA18E` | Success states, confirmations | +| `--color-warning` | `#D9A12C` | Warning states, alerts, cautions | +| `--color-danger` | `#A12C40` | Error/Danger states, destructive | +| `--color-purple` | `#2C40A1` | Premium/Special features | | `--color-gray-base` | `#667085` | Neutral base for grays | ### 2.2 Allowed Color Classes (ALL derived from 6 primaries) @@ -523,23 +523,25 @@ import { Check } from 'lucide-react'; ```css /* ✅ ONLY in design-system.css - the 6 primary tokens */ :root { - --color-primary: #0077B6; - --color-success: #00B894; - --color-warning: #F59E0B; - --color-danger: #DC2626; - --color-purple: #7C3AED; + --color-primary: #2C7AA1; + --color-success: #2CA18E; + --color-warning: #D9A12C; + --color-danger: #A12C40; + --color-purple: #2C40A1; --color-gray-base: #667085; } -/* ✅ All other colors derived */ +/* ✅ All other colors derived using color-mix() */ +--color-primary-dark: color-mix(in srgb, var(--color-primary) 75%, black); --color-brand-600: color-mix(in srgb, var(--color-primary) 85%, black); +--color-gray-700: color-mix(in srgb, var(--color-gray-base) 70%, black); ``` --- ## 🚨 CRITICAL RULES -1. **6 PRIMARY HEX ONLY**: Only `--color-primary`, `--color-success`, `--color-warning`, `--color-danger`, `--color-purple`, `--color-gray-base` use hex values +1. **6 PRIMARY HEX ONLY**: Only `--color-primary`, `--color-success`, `--color-warning`, `--color-danger`, `--color-purple`, `--color-gray-base` use hex values (plus `#ffffff` for white) 2. **ALL SHADES DERIVED**: Every shade (25-950) is computed from primary using `color-mix()` 3. **NO TAILWIND DEFAULTS**: blue-*, red-*, green-*, etc. are DISABLED 4. **NO INLINE STYLES**: Never use `style={{}}` for colors/spacing @@ -582,6 +584,55 @@ The entire application must look like it was designed and built by **ONE person* --- +--- + +## 🚨 CRITICAL ISSUES - Fix First + +### Issue 1: Missing Components After Changes + +**Problem**: Many pages have missing components after lucide-react → local icons migration + +**Affected Files** (from git diff): +- `ImportExport.tsx` - Uses `Database`, `CheckCircle` etc. from lucide-react +- `WordPressIntegrationDebug.tsx` - Uses `CheckCircle`, `XCircle`, `AlertTriangle`, etc. +- `PostEditor.tsx` - Uses `SaveIcon`, `XIcon`, `FileTextIcon`, etc. +- `NotificationsPage.tsx` - Uses `Bell`, `CheckCircle`, `AlertTriangle`, etc. +- `AccountSettingsPage.tsx` - Uses `Save`, `Loader2`, `Settings`, etc. +- `PlansAndBillingPage.tsx` - Uses `CreditCard`, `Package`, etc. +- `ContentSettingsPage.tsx` - Uses `Save`, `Loader2`, `Image`, etc. +- `UsageAnalyticsPage.tsx` - Uses `TrendingUp`, `Activity`, etc. +- `PurchaseCreditsPage.tsx` - Uses `AlertCircle`, `Check`, etc. +- Multiple components in `/components/sites/`, `/components/billing/`, `/components/auth/` + +**Fix**: Replace lucide-react imports with local `/icons/` imports. Add missing aliases to `/icons/index.ts` + +### Issue 2: Table Row Height Too Big (Planner & Writer) + +**Problem**: Planner and Writer table font sizes too big for some columns, increasing overall row height - tables not compact anymore + +**Root Cause**: Font size changes in CSS or component updates affecting table cell sizing + +**Fix Locations**: +- `/src/styles/design-system.css` - `.igny8-table-compact td` rules +- Planner and Writer table components - check for increased text sizes + +**Required Changes**: +```css +/* Ensure compact table styling */ +.igny8-table-compact td { + padding: 6px 10px !important; /* Reduced from 8px 12px */ + font-size: 13px !important; /* Reduced from 14px */ + line-height: 1.3 !important; /* Tighter line height */ +} + +.igny8-table-compact th { + padding: 8px 12px !important; /* Reduced from 12px 16px */ + font-size: 12px !important; /* Reduced from 14px */ +} +``` + +--- + ## Notes - Gray scale (`gray-25` to `gray-950`) is ALLOWED - derived from `--color-gray-base` diff --git a/frontend/audit-results/01-inline-styles.txt b/frontend/audit-results/01-inline-styles.txt new file mode 100644 index 00000000..85a7a543 --- /dev/null +++ b/frontend/audit-results/01-inline-styles.txt @@ -0,0 +1,62 @@ +src/pages/account/PlansAndBillingPage.tsx:596:
+src/pages/Writer/Images.tsx:661: style={{ maxHeight: '90vh' }} +src/pages/Sites/List.tsx:605: style={{ boxShadow: '0 2px 6px 3px rgba(0, 0, 0, 0.08)' }} +src/pages/Automation/AutomationPage.tsx:878: style={{ width: `${isComplete ? 100 : progressPercent}%` }} +src/pages/Automation/AutomationPage.tsx:1002: style={{ width: `${isComplete ? 100 : progressPercent}%` }} +src/pages/Automation/AutomationPage.tsx:1097: style={{ width: `${isComplete ? 100 : progressPercent}%` }} +src/pages/Settings/Status.tsx:132: style={{ width: `${status.system?.cpu?.usage_percent || 0}%` }} +src/pages/Settings/Status.tsx:154: style={{ width: `${status.system?.memory?.usage_percent || 0}%` }} +src/pages/Settings/Status.tsx:176: style={{ width: `${status.system?.disk?.usage_percent || 0}%` }} +src/components/onboarding/OnboardingWizard.tsx:264: style={{ width: `${100 / STEPS.length}%` }} +src/components/shared/blocks/QuoteBlock.tsx:26: style={{ textAlign: align }} +src/components/shared/blocks/TextBlock.tsx:24: style={{ textAlign: align }} +src/components/sites/SiteProgressWidget.tsx:233: style={{ width: `${completionPercent}%` }} +src/components/sites/SiteSetupChecklist.tsx:121: style={{ width: `${progressPercent}%` }} +src/components/auth/SignUpFormUnified.tsx:624:
+src/components/common/ImageResultCard.tsx:113: style={{ maxHeight: '400px' }} +src/components/common/ImageQueueModal.tsx:537: style={{ width: `${smoothProgress[item.index] ?? item.progress ?? 0}%` }} +src/components/common/ToggleTableRow.tsx:113: style={{ +src/components/optimizer/OptimizationScores.tsx:80: style={{ width: `${scores.overall_score}%` }} +src/components/optimizer/OptimizationScores.tsx:104: style={{ width: `${scores.seo_score}%` }} +src/components/optimizer/OptimizationScores.tsx:128: style={{ width: `${scores.readability_score}%` }} +src/components/optimizer/OptimizationScores.tsx:152: style={{ width: `${scores.engagement_score}%` }} +src/components/optimizer/OptimizationScores.tsx:179: style={{ width: `${scores.metadata_completeness_score || 0}%` }} +src/components/Automation/CurrentProcessingCard.tsx:414: style={{ width: `${Math.min(percentage, 100)}%` }} +src/components/Automation/CurrentProcessingCardV2.tsx:267: style={{ width: `${Math.min(displayPercent, 100)}%` }} +src/components/Automation/CurrentProcessingCard.old.tsx:120: style={{ width: `${Math.min(percentage, 100)}%` }} +src/components/billing/UsageLimitsPanel.tsx:62: style={{ +src/components/billing/UsageLimitsPanel.tsx:86: style={{ +src/components/dashboard/ThreeWidgetFooter.tsx:135: style={{ +src/components/dashboard/ThreeWidgetFooter.tsx:221: style={{ +src/components/dashboard/ThreeWidgetFooter.tsx:274: style={{ +src/components/dashboard/WorkflowCompletionWidget.tsx:106: style={{ +src/components/dashboard/WorkflowCompletionWidget.tsx:178:
+src/components/dashboard/WorkflowCompletionWidget.tsx:197:
+src/components/dashboard/WorkflowCompletionWidget.tsx:229: +src/components/dashboard/WorkflowCompletionWidget.tsx:240: +src/components/dashboard/StandardizedModuleWidget.tsx:176: style={{ color: row.color }} +src/components/dashboard/StandardizedModuleWidget.tsx:180: +src/components/dashboard/StandardizedModuleWidget.tsx:188: style={{ color: row.color }} +src/components/dashboard/StandardizedModuleWidget.tsx:196: style={{ color: row.color }} +src/components/dashboard/StandardizedModuleWidget.tsx:210: style={{ +src/components/dashboard/StandardizedModuleWidget.tsx:243: {credits.clusteringCredits} +src/components/dashboard/StandardizedModuleWidget.tsx:249: {credits.ideaGenerationCredits} +src/components/dashboard/StandardizedModuleWidget.tsx:262: {credits.contentGenerationCredits} +src/components/dashboard/StandardizedModuleWidget.tsx:268: {credits.imageGenerationCredits} +src/components/dashboard/StandardThreeWidgetFooter.tsx:128: style={{ +src/components/dashboard/StandardThreeWidgetFooter.tsx:144: {widget.creditsConsumed.toLocaleString()} +src/components/dashboard/StandardThreeWidgetFooter.tsx:160: Next:{' '} +src/components/dashboard/StandardThreeWidgetFooter.tsx:231: style={{ +src/components/dashboard/CreditAvailabilityWidget.tsx:83: style={{ width: `${remainingPercent}%` }} +src/components/dashboard/CreditBalanceWidget.tsx:60: style={{ width: `${Math.min(usagePercentage, 100)}%` }} +src/components/dashboard/SiteConfigWidget.tsx:142: style={{ width: `${completionPercent}%` }} +src/components/ui/dropdown/Dropdown.tsx:141: style={{ +src/components/ui/alert/AlertModal.tsx:42:
diff --git a/frontend/audit-results/02-hardcoded-hex-class.txt b/frontend/audit-results/02-hardcoded-hex-class.txt new file mode 100644 index 00000000..e69de29b diff --git a/frontend/audit-results/03-hardcoded-hex-all.txt b/frontend/audit-results/03-hardcoded-hex-all.txt new file mode 100644 index 00000000..2072e555 --- /dev/null +++ b/frontend/audit-results/03-hardcoded-hex-all.txt @@ -0,0 +1,36 @@ +src/pages/Settings/Integration.tsx:22: +src/pages/Settings/Integration.tsx:23: +src/pages/Settings/Integration.tsx:24: +src/pages/Settings/Integration.tsx:25: +src/pages/Settings/Integration.tsx:26: +src/pages/Settings/Integration.tsx:27: +src/pages/Settings/Integration.tsx:34: +src/pages/Settings/Integration.tsx:42: +src/pages/Settings/Integration.tsx:955: +src/pages/Settings/Integration.tsx:987: +src/pages/Settings/Sites.tsx:26: +src/pages/Settings/Sites.tsx:27: +src/pages/Settings/Sites.tsx:28: +src/components/sites/TemplateCustomizer.tsx:208: value={customization.customStyles?.primaryColor || '#3b82f6'} +src/components/sites/TemplateCustomizer.tsx:218: value={customization.customStyles?.primaryColor || '#3b82f6'} +src/components/sites/TemplateCustomizer.tsx:224: placeholder="#3b82f6" +src/components/sites/TemplateCustomizer.tsx:235: value={customization.customStyles?.backgroundColor || '#ffffff'} +src/components/sites/TemplateCustomizer.tsx:245: value={customization.customStyles?.backgroundColor || '#ffffff'} +src/components/sites/TemplateCustomizer.tsx:251: placeholder="#ffffff" +src/components/sites/StyleEditor.tsx:190: value={styleSettings.colorPalette?.[colorKey as keyof typeof styleSettings.colorPalette] || '#000000'} +src/components/sites/StyleEditor.tsx:198: placeholder="#000000" +src/components/form/form-elements/DefaultInputs.tsx:102: +src/components/form/form-elements/DefaultInputs.tsx:103: +src/components/form/form-elements/DefaultInputs.tsx:106: fill="#FC6020" +src/components/form/input/Checkbox.tsx:65: stroke="#E4E7EC" +src/components/auth/SignInForm.tsx:127: fill="#4285F4" +src/components/auth/SignInForm.tsx:131: fill="#34A853" +src/components/auth/SignInForm.tsx:135: fill="#FBBC05" +src/components/auth/SignInForm.tsx:139: fill="#EB4335" +src/components/auth/SignUpForm.tsx:147: fill="#4285F4" +src/components/auth/SignUpForm.tsx:151: fill="#34A853" +src/components/auth/SignUpForm.tsx:155: fill="#FBBC05" +src/components/auth/SignUpForm.tsx:159: fill="#EB4335" +src/components/ecommerce/MonthlyTarget.tsx:140: fill="#D92D20" +src/components/ecommerce/MonthlyTarget.tsx:165: fill="#039855" +src/components/ecommerce/MonthlyTarget.tsx:190: fill="#039855" diff --git a/frontend/audit-results/04-rgb-values.txt b/frontend/audit-results/04-rgb-values.txt new file mode 100644 index 00000000..bc1e5786 --- /dev/null +++ b/frontend/audit-results/04-rgb-values.txt @@ -0,0 +1,6 @@ +src/pages/Sites/List.tsx:605: style={{ boxShadow: '0 2px 6px 3px rgba(0, 0, 0, 0.08)' }} +src/components/billing/UsageLimitsPanel.tsx:63: backgroundColor: isDanger ? 'rgba(239, 68, 68, 0.1)' : isWarning ? 'rgba(255, 122, 0, 0.1)' : `${barColor}15`, +src/components/ui/button/Button.tsx:97: "text-white shadow-[0_20px_45px_-30px_rgba(6,147,227,0.9)] bg-[linear-gradient(135deg,var(--color-primary)_0%,var(--color-primary-dark)_100%)]", +src/components/ui/button/Button.tsx:99: "text-white shadow-[0_20px_45px_-30px_rgba(11,191,135,0.9)] bg-[linear-gradient(135deg,var(--color-success)_0%,var(--color-success-dark)_100%)]", +src/components/ui/button/Button.tsx:101: "text-white shadow-[0_20px_45px_-30px_rgba(255,122,0,0.9)] bg-[linear-gradient(135deg,var(--color-warning)_0%,var(--color-warning-dark)_100%)]", +src/components/ui/button/Button.tsx:103: "text-white shadow-[0_20px_45px_-30px_rgba(239,68,68,0.9)] bg-[linear-gradient(135deg,var(--color-danger)_0%,var(--color-danger-dark)_100%)]", diff --git a/frontend/audit-results/05-tailwind-default-colors.txt b/frontend/audit-results/05-tailwind-default-colors.txt new file mode 100644 index 00000000..6659ebec --- /dev/null +++ b/frontend/audit-results/05-tailwind-default-colors.txt @@ -0,0 +1,49 @@ +src/pages/Sites/PublishingQueue.tsx:169: +src/pages/Sites/PublishingQueue.tsx:176: +src/pages/Sites/PublishingQueue.tsx:231:
+src/pages/Sites/PublishingQueue.tsx:232: +src/pages/Sites/PublishingQueue.tsx:242:
+src/pages/Sites/PublishingQueue.tsx:243: +src/pages/Sites/PublishingQueue.tsx:253:
+src/pages/Sites/PublishingQueue.tsx:254: +src/pages/Sites/PublishingQueue.tsx:264:
+src/pages/Sites/PublishingQueue.tsx:265: +src/pages/Sites/PublishingQueue.tsx:380: className="p-2 text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 rounded-lg hover:bg-red-50 dark:hover:bg-red-900/20" +src/pages/Sites/PublishingQueue.tsx:425: className="text-xs p-1 bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-200 rounded truncate cursor-pointer hover:bg-amber-200 dark:hover:bg-amber-900/50" +src/pages/Sites/Dashboard.tsx:347: +src/pages/Sites/Settings.tsx:864: className="p-2 text-gray-400 hover:text-red-500 transition-colors" +src/pages/Sites/Settings.tsx:891:
+src/pages/Sites/Settings.tsx:893: +src/pages/Sites/Settings.tsx:896:
+src/pages/Sites/Settings.tsx:898:
    +src/pages/Components.tsx:153: className="px-4 py-3 text-sm font-medium text-white rounded-lg bg-blue-light-500 shadow-theme-xs hover:bg-blue-light-600 transition-colors" +src/components/onboarding/steps/Step4AddKeywords.tsx:219: className="text-red-500 hover:text-red-600" +src/components/onboarding/steps/Step4AddKeywords.tsx:227: +src/components/onboarding/steps/Step4AddKeywords.tsx:228:

    +src/components/onboarding/steps/Step4AddKeywords.tsx:235: className="text-xs text-blue-700 dark:text-blue-300 bg-blue-100 dark:bg-blue-800/50 px-2 py-1 rounded" +src/components/onboarding/steps/Step3ConnectIntegration.tsx:219: ? 'bg-green-100 dark:bg-green-900/50 text-green-600 dark:text-green-400' +src/components/onboarding/steps/Step3ConnectIntegration.tsx:221: ? 'bg-red-100 dark:bg-red-900/50 text-red-600 dark:text-red-400' +src/components/onboarding/steps/Step5Complete.tsx:60:
    +src/components/onboarding/steps/Step5Complete.tsx:78: +src/components/onboarding/steps/Step5Complete.tsx:85: +src/components/onboarding/steps/Step5Complete.tsx:93: +src/components/onboarding/steps/Step5Complete.tsx:100: +src/components/onboarding/steps/Step5Complete.tsx:106: +src/components/onboarding/steps/Step2AddSite.tsx:257: +src/components/onboarding/steps/Step2AddSite.tsx:259: +src/components/onboarding/steps/Step2AddSite.tsx:261:

    +src/components/onboarding/steps/Step2AddSite.tsx:264:
      +src/components/onboarding/steps/Step2AddSite.tsx:270:

      +src/components/onboarding/OnboardingWizard.tsx:233: ? 'bg-green-500 text-white' +src/components/onboarding/OnboardingWizard.tsx:249: ? 'bg-green-500' +src/components/ui/alert/Alert.tsx:39: "border-b-2 border-blue-light-500 bg-blue-light-50 dark:border-blue-light-500/30 dark:bg-blue-light-500/15", +src/components/ui/alert/Alert.tsx:40: icon: "text-blue-light-500", +src/components/ui/alert/AlertModal.tsx:68:

      +src/components/ui/alert/AlertModal.tsx:125: info: 'bg-blue-light-500 hover:bg-blue-light-600 text-white', +src/components/ui/spinner/Spinner.tsx:25: info: "border-blue-light-200 border-t-blue-light-500", +src/components/ui/progress/ProgressBar.tsx:31: info: "bg-blue-light-500", +src/components/ui/toast/Toast.tsx:60: +src/components/ui/badge/Badge.tsx:58: solid: "bg-blue-light-500 text-white", +src/components/ui/badge/Badge.tsx:59: soft: "bg-blue-light-50 text-blue-light-700 dark:bg-blue-light-500/15 dark:text-blue-light-400", +src/components/ui/badge/Badge.tsx:61: "text-blue-light-700 ring-1 ring-blue-light-200 dark:ring-blue-light-500/30 dark:text-blue-light-400", diff --git a/frontend/audit-results/06-external-ui-imports.txt b/frontend/audit-results/06-external-ui-imports.txt new file mode 100644 index 00000000..04f208af --- /dev/null +++ b/frontend/audit-results/06-external-ui-imports.txt @@ -0,0 +1,2 @@ +src/components/BulkWordPressPublish/BulkWordPressPublish.tsx:18:} from '@mui/material'; +src/components/BulkWordPressPublish/BulkWordPressPublish.tsx:24:} from '@mui/icons-material'; diff --git a/frontend/audit-results/07-lucide-imports.txt b/frontend/audit-results/07-lucide-imports.txt new file mode 100644 index 00000000..83ee6604 --- /dev/null +++ b/frontend/audit-results/07-lucide-imports.txt @@ -0,0 +1,34 @@ +src/pages/account/NotificationsPage.tsx:15:} from 'lucide-react'; +src/pages/account/AccountSettingsPage.tsx:11:} from 'lucide-react'; +src/pages/account/PlansAndBillingPage.tsx:14:} from 'lucide-react'; +src/pages/account/PurchaseCreditsPage.tsx:7:import { AlertCircle, Check, CreditCard, Building2, Wallet, Loader2, Zap } from 'lucide-react'; +src/pages/account/ContentSettingsPage.tsx:11:} from 'lucide-react'; +src/pages/account/UsageAnalyticsPage.tsx:9:import { TrendingUp, Activity, BarChart3, Zap, Calendar } from 'lucide-react'; +src/pages/Sites/Content.tsx:14:import { Search } from 'lucide-react'; +src/pages/Sites/PostEditor.tsx:8:import { SaveIcon, XIcon, FileTextIcon, TagIcon, CheckCircleIcon, XCircleIcon, AlertCircleIcon } from 'lucide-react'; +src/pages/Settings/ImportExport.tsx:4:import { Download, Upload, Database, FileArchive, CheckCircle } from 'lucide-react'; +src/pages/Settings/WordPressIntegrationDebug.tsx:13:} from 'lucide-react'; +src/pages/settings/ProfileSettingsPage.tsx:7:import { Save, User, Mail, Lock, Loader2 } from 'lucide-react'; +src/components/sites/WordPressIntegrationModal.tsx:6:import { X, Globe, AlertCircle } from 'lucide-react'; +src/components/sites/SiteProgressWidget.tsx:10:import { CheckCircleIcon, XCircleIcon, AlertCircleIcon, ArrowRightIcon } from 'lucide-react'; +src/components/sites/LayoutSelector.tsx:7:import { CheckIcon } from 'lucide-react'; +src/components/sites/WordPressIntegrationForm.tsx:22:import { Globe, Key, RefreshCw } from 'lucide-react'; +src/components/sites/LayoutPreview.tsx:7:import { EyeIcon, XIcon, Maximize2Icon } from 'lucide-react'; +src/components/sites/SiteTypeBadge.tsx:6:import { Wand2, Globe } from 'lucide-react'; +src/components/sites/WordPressIntegrationCard.tsx:8:import { Globe, CheckCircle, XCircle, Settings, RefreshCw, AlertCircle, ExternalLink } from 'lucide-react'; +src/components/sites/TemplateLibrary.tsx:7:import { SearchIcon, FilterIcon, CheckIcon } from 'lucide-react'; +src/components/sites/TemplateCustomizer.tsx:7:import { SettingsIcon, PaletteIcon, TypeIcon, LayoutIcon } from 'lucide-react'; +src/components/sites/StyleEditor.tsx:7:import { CodeIcon, PaletteIcon, TypeIcon, SaveIcon, RefreshCwIcon } from 'lucide-react'; +src/components/publishing/PublishingRules.tsx:6:import { PlusIcon, TrashIcon, ArrowUpIcon, ArrowDownIcon } from 'lucide-react'; +src/components/auth/SignUpFormEnhanced.tsx:12:import { ChevronRight, Check } from 'lucide-react'; +src/components/auth/SignUpFormSimplified.tsx:10:import { CreditCard, Building2, Wallet, Check, Loader2 } from 'lucide-react'; +src/components/auth/SignUpFormUnified.tsx:10:import { CreditCard, Building2, Wallet, Check, Loader2, CheckCircle } from 'lucide-react'; +src/components/billing/PendingPaymentBanner.tsx:8:import { AlertCircle, CreditCard, X } from 'lucide-react'; +src/components/billing/PaymentMethodSelect.tsx:8:import { CheckCircle, Loader2, AlertCircle } from 'lucide-react'; +src/components/billing/PaymentHistory.tsx:5:import { CheckCircle, XCircle, Clock, RefreshCw } from 'lucide-react'; +src/components/billing/PaymentConfirmationModal.tsx:12:import { Loader2, Upload, X, CheckCircle } from 'lucide-react'; +src/components/billing/UsageLimitsPanel.tsx:8:import { AlertCircle, TrendingUp, Users, Globe, Tag, FileText, Image, Zap } from 'lucide-react'; +src/components/billing/CreditCostBreakdownPanel.tsx:8:import { DollarSign, TrendingUp, AlertCircle } from 'lucide-react'; +src/components/integration/SiteIntegrationsSection.tsx:6:import { PlusIcon, TrashIcon, TestTubeIcon, RefreshCw } from 'lucide-react'; +src/components/integration/IntegrationStatus.tsx:6:import { CheckCircleIcon, XCircleIcon, ClockIcon, RefreshCw } from 'lucide-react'; +src/components/ui/pricing-table/index.tsx:7:import { Check } from 'lucide-react'; diff --git a/frontend/src/components/auth/SignUpFormEnhanced.tsx b/frontend/src/components/auth/SignUpFormEnhanced.tsx index f08eca1d..81718595 100644 --- a/frontend/src/components/auth/SignUpFormEnhanced.tsx +++ b/frontend/src/components/auth/SignUpFormEnhanced.tsx @@ -8,8 +8,7 @@ import { useState, useEffect } from 'react'; import { Link, useNavigate } from 'react-router-dom'; -import { ChevronLeftIcon, EyeCloseIcon, EyeIcon } from '../../icons'; -import { ChevronRight, Check } from 'lucide-react'; +import { ChevronLeftIcon, EyeCloseIcon, EyeIcon, ChevronRightIcon, CheckIcon } from '../../icons'; import Label from '../form/Label'; import Input from '../form/input/InputField'; import Checkbox from '../form/input/Checkbox'; @@ -236,7 +235,7 @@ export default function SignUpFormEnhanced({ planDetails: planDetailsProp, planL } `} > - {step < currentStep ? : step} + {step < currentStep ? : step}
      @@ -379,7 +378,7 @@ export default function SignUpFormEnhanced({ planDetails: planDetailsProp, planL {isPaidPlan ? ( ) : (
      diff --git a/frontend/src/components/auth/SignUpFormSimplified.tsx b/frontend/src/components/auth/SignUpFormSimplified.tsx index 09b37dc2..33d5e60c 100644 --- a/frontend/src/components/auth/SignUpFormSimplified.tsx +++ b/frontend/src/components/auth/SignUpFormSimplified.tsx @@ -6,8 +6,7 @@ import { useState, useEffect } from 'react'; import { Link, useNavigate } from 'react-router-dom'; -import { ChevronLeftIcon, EyeCloseIcon, EyeIcon } from '../../icons'; -import { CreditCard, Building2, Wallet, Check, Loader2 } from 'lucide-react'; +import { ChevronLeftIcon, EyeCloseIcon, EyeIcon, CreditCardIcon, Building2Icon, WalletIcon, CheckIcon, Loader2Icon } from '../../icons'; import Label from '../form/Label'; import Input from '../form/input/InputField'; import Checkbox from '../form/input/Checkbox'; @@ -195,13 +194,13 @@ export default function SignUpFormSimplified({ planDetails: planDetailsProp, pla const getPaymentIcon = (method: string) => { switch (method) { case 'stripe': - return ; + return ; case 'bank_transfer': - return ; + return ; case 'local_wallet': - return ; + return ; default: - return ; + return ; } }; @@ -353,7 +352,7 @@ export default function SignUpFormSimplified({ planDetails: planDetailsProp, pla {paymentMethodsLoading ? (
      - + Loading payment options...
      ) : paymentMethods.length === 0 ? ( @@ -390,7 +389,7 @@ export default function SignUpFormSimplified({ planDetails: planDetailsProp, pla {method.display_name}

    {selectedPaymentMethod === method.payment_method && ( - + )}
    {method.instructions && ( diff --git a/frontend/src/components/auth/SignUpFormUnified.tsx b/frontend/src/components/auth/SignUpFormUnified.tsx index e280b529..532c23f7 100644 --- a/frontend/src/components/auth/SignUpFormUnified.tsx +++ b/frontend/src/components/auth/SignUpFormUnified.tsx @@ -6,8 +6,7 @@ import { useState, useEffect } from 'react'; import ReactDOM from 'react-dom'; import { Link, useNavigate } from 'react-router-dom'; -import { ChevronLeftIcon, EyeCloseIcon, EyeIcon } from '../../icons'; -import { CreditCard, Building2, Wallet, Check, Loader2, CheckCircle } from 'lucide-react'; +import { ChevronLeftIcon, EyeCloseIcon, EyeIcon, CreditCardIcon, Building2Icon, WalletIcon, CheckIcon, Loader2Icon, CheckCircleIcon } from '../../icons'; import Label from '../form/Label'; import Input from '../form/input/InputField'; import Checkbox from '../form/input/Checkbox'; @@ -234,13 +233,13 @@ export default function SignUpFormUnified({ const getPaymentIcon = (method: string) => { switch (method) { case 'stripe': - return ; + return ; case 'bank_transfer': - return ; + return ; case 'local_wallet': - return ; + return ; default: - return ; + return ; } }; @@ -359,7 +358,7 @@ export default function SignUpFormUnified({ {plan.name} - {isSelected && } + {isSelected && }

{isFree ? 'Free' : `$${displayPrice.toFixed(2)}`} @@ -450,7 +449,7 @@ export default function SignUpFormUnified({ {paymentMethodsLoading ? (
- +
) : paymentMethods.length === 0 ? (
@@ -514,7 +513,7 @@ export default function SignUpFormUnified({
)} {uploading && (
- + Uploading...
)} @@ -330,7 +330,7 @@ export default function PaymentConfirmationModal({ > {loading ? ( <> - + Submitting... ) : ( diff --git a/frontend/src/components/billing/PaymentHistory.tsx b/frontend/src/components/billing/PaymentHistory.tsx index cc4f4c1b..5fc2590f 100644 --- a/frontend/src/components/billing/PaymentHistory.tsx +++ b/frontend/src/components/billing/PaymentHistory.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'; import { useAuthStore } from '../../store/authStore'; import { API_BASE_URL } from '../../services/api'; import Button from '../ui/button/Button'; -import { CheckCircle, XCircle, Clock, RefreshCw } from 'lucide-react'; +import { CheckCircleIcon, XCircleIcon, ClockIcon, RefreshCwIcon } from '../../icons'; interface Payment { id: number; @@ -53,13 +53,13 @@ export default function PaymentHistory() { const getStatusIcon = (status: string) => { switch (status) { case 'succeeded': - return ; + return ; case 'failed': - return ; + return ; case 'pending_approval': - return ; + return ; default: - return ; + return ; } }; @@ -86,7 +86,7 @@ export default function PaymentHistory() { if (loading) { return (
- +
); } @@ -98,7 +98,7 @@ export default function PaymentHistory() { Payment History
diff --git a/frontend/src/components/billing/PaymentMethodSelect.tsx b/frontend/src/components/billing/PaymentMethodSelect.tsx index 43d0defd..7908c1eb 100644 --- a/frontend/src/components/billing/PaymentMethodSelect.tsx +++ b/frontend/src/components/billing/PaymentMethodSelect.tsx @@ -5,7 +5,7 @@ */ import { useState, useEffect } from 'react'; -import { CheckCircle, Loader2, AlertCircle } from 'lucide-react'; +import { CheckCircleIcon, Loader2Icon, AlertCircleIcon } from '../../icons'; import { API_BASE_URL } from '../../services/api'; export interface PaymentMethodConfig { @@ -76,7 +76,7 @@ export default function PaymentMethodSelect({ if (loading) { return (
- + Loading payment methods...
); @@ -86,7 +86,7 @@ export default function PaymentMethodSelect({ return (
- +

Failed to load payment methods

{fetchError}

@@ -106,7 +106,7 @@ export default function PaymentMethodSelect({ return (
- +

No payment methods available

@@ -157,7 +157,7 @@ export default function PaymentMethodSelect({ {/* Radio indicator */}

{selectedMethod === method.payment_method ? ( - + ) : (
)} diff --git a/frontend/src/components/billing/PendingPaymentBanner.tsx b/frontend/src/components/billing/PendingPaymentBanner.tsx index 4385013b..f6265f5e 100644 --- a/frontend/src/components/billing/PendingPaymentBanner.tsx +++ b/frontend/src/components/billing/PendingPaymentBanner.tsx @@ -5,7 +5,7 @@ */ import { useState, useEffect } from 'react'; -import { AlertCircle, CreditCard, X } from 'lucide-react'; +import { AlertCircleIcon, CreditCardIcon, XIcon } from '../../icons'; import { Link } from 'react-router-dom'; import Button from '../ui/button/Button'; import { useAuthStore } from '../../store/authStore'; @@ -118,7 +118,7 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
- +

Payment Required @@ -143,7 +143,7 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB onClick={handleDismiss} className="p-1 hover:bg-warning-100 dark:hover:bg-warning-800/40 rounded transition-colors" > - +

@@ -170,7 +170,7 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
-
@@ -230,7 +230,7 @@ export default function PendingPaymentBanner({ className = '' }: PendingPaymentB
diff --git a/frontend/src/components/billing/UsageLimitsPanel.tsx b/frontend/src/components/billing/UsageLimitsPanel.tsx index 417f2338..68158dc1 100644 --- a/frontend/src/components/billing/UsageLimitsPanel.tsx +++ b/frontend/src/components/billing/UsageLimitsPanel.tsx @@ -5,7 +5,7 @@ import { useState, useEffect } from 'react'; import { Card } from '../ui/card'; -import { AlertCircle, TrendingUp, Users, Globe, Tag, FileText, Image, Zap } from 'lucide-react'; +import { AlertCircleIcon, TrendingUpIcon, UsersIcon, GlobeIcon, TagIcon, FileTextIcon, ImageIcon, ZapIcon } from '../../icons'; import Badge from '../ui/badge/Badge'; import { getUsageSummary, type UsageSummary, type LimitUsage } from '../../services/billing.api'; import { useToast } from '../ui/toast/ToastContainer'; @@ -106,7 +106,7 @@ function LimitCard({ title, icon, usage, type, daysUntilReset, accentColor = 'br
- + {isDanger ? 'Limit almost reached! Consider upgrading your plan.' @@ -158,7 +158,7 @@ export default function UsageLimitsPanel() { if (error || !summary) { return ( - +

Failed to Load Usage Data

@@ -174,18 +174,18 @@ export default function UsageLimitsPanel() { } const hardLimitConfig = { - sites: { icon: , color: 'success' as const }, - users: { icon: , color: 'info' as const }, - keywords: { icon: , color: 'purple' as const }, - clusters: { icon: , color: 'warning' as const }, + sites: { icon: , color: 'success' as const }, + users: { icon: , color: 'info' as const }, + keywords: { icon: , color: 'purple' as const }, + clusters: { icon: , color: 'warning' as const }, }; const monthlyLimitConfig = { - content_ideas: { icon: , color: 'brand' as const }, - content_words: { icon: , color: 'indigo' as const }, - images_basic: { icon: , color: 'teal' as const }, - images_premium: { icon: , color: 'cyan' as const }, - image_prompts: { icon: , color: 'pink' as const }, + content_ideas: { icon: , color: 'brand' as const }, + content_words: { icon: , color: 'indigo' as const }, + images_basic: { icon: , color: 'teal' as const }, + images_premium: { icon: , color: 'cyan' as const }, + image_prompts: { icon: , color: 'pink' as const }, }; return ( @@ -256,7 +256,7 @@ export default function UsageLimitsPanel() {
- +

diff --git a/frontend/src/components/common/ImageResultCard.tsx b/frontend/src/components/common/ImageResultCard.tsx index 6d950126..6729604c 100644 --- a/frontend/src/components/common/ImageResultCard.tsx +++ b/frontend/src/components/common/ImageResultCard.tsx @@ -109,8 +109,7 @@ export default function ImageResultCard({ Generated image

diff --git a/frontend/src/components/integration/IntegrationStatus.tsx b/frontend/src/components/integration/IntegrationStatus.tsx index b718c34b..b38b11c2 100644 --- a/frontend/src/components/integration/IntegrationStatus.tsx +++ b/frontend/src/components/integration/IntegrationStatus.tsx @@ -3,7 +3,7 @@ * Phase 6: Site Integration & Multi-Destination Publishing */ import React from 'react'; -import { CheckCircleIcon, XCircleIcon, ClockIcon, RefreshCw } from 'lucide-react'; +import { CheckCircleIcon, XCircleIcon, ClockIcon, RefreshCwIcon } from '../../icons'; interface IntegrationStatusProps { syncEnabled: boolean; @@ -25,7 +25,7 @@ export default function IntegrationStatus({ case 'failed': return ; case 'syncing': - return ; + return ; default: return ; } diff --git a/frontend/src/components/integration/SiteIntegrationsSection.tsx b/frontend/src/components/integration/SiteIntegrationsSection.tsx index 0c7a3715..9d1d0a8e 100644 --- a/frontend/src/components/integration/SiteIntegrationsSection.tsx +++ b/frontend/src/components/integration/SiteIntegrationsSection.tsx @@ -3,7 +3,7 @@ * Phase 6: Site Integration & Multi-Destination Publishing */ import React, { useState, useEffect } from 'react'; -import { PlusIcon, TrashIcon, TestTubeIcon, RefreshCw } from 'lucide-react'; +import { PlusIcon, TrashIcon, TestTubeIcon, RefreshCwIcon } from '../../icons'; import Button from '../ui/button/Button'; import { Modal } from '../ui/modal'; import FormModal, { FormField } from '../common/FormModal'; @@ -302,7 +302,7 @@ export default function SiteIntegrationsSection({ siteId }: SiteIntegrationsSect onClick={() => handleSync(integration)} className="flex-1" > - + Sync )} diff --git a/frontend/src/components/onboarding/OnboardingWizard.tsx b/frontend/src/components/onboarding/OnboardingWizard.tsx index 6d38ddaf..1a2bc3ec 100644 --- a/frontend/src/components/onboarding/OnboardingWizard.tsx +++ b/frontend/src/components/onboarding/OnboardingWizard.tsx @@ -230,7 +230,7 @@ export default function OnboardingWizard({ onComplete, onSkip }: OnboardingWizar
diff --git a/frontend/src/components/onboarding/steps/Step2AddSite.tsx b/frontend/src/components/onboarding/steps/Step2AddSite.tsx index 5275d19e..212a6897 100644 --- a/frontend/src/components/onboarding/steps/Step2AddSite.tsx +++ b/frontend/src/components/onboarding/steps/Step2AddSite.tsx @@ -234,7 +234,7 @@ export default function Step2AddSite({ tone={isSelected ? 'success' : 'neutral'} variant="soft" className={`cursor-pointer transition-all ${ - isSelected ? 'ring-2 ring-green-500' : 'hover:bg-gray-200 dark:hover:bg-gray-700' + isSelected ? 'ring-2 ring-success-500' : 'hover:bg-gray-200 dark:hover:bg-gray-700' }`} > handleSectorToggle(sector.slug)} className="flex items-center"> @@ -254,20 +254,20 @@ export default function Step2AddSite({ )} {/* Defaults Info */} - +
- +
-

+

Optimized Defaults Applied

-
    +
    • • Auto-approval enabled
    • • Auto-publish to site enabled
    • • 3 articles/day limit
    • • Publishing Mon-Fri at 9am, 2pm, 6pm
    -

    +

    You can customize these in Site Settings anytime.

diff --git a/frontend/src/components/onboarding/steps/Step3ConnectIntegration.tsx b/frontend/src/components/onboarding/steps/Step3ConnectIntegration.tsx index 8a3495b6..7e178ae9 100644 --- a/frontend/src/components/onboarding/steps/Step3ConnectIntegration.tsx +++ b/frontend/src/components/onboarding/steps/Step3ConnectIntegration.tsx @@ -216,9 +216,9 @@ export default function Step3ConnectIntegration({
{testResult === 'success' ? ( diff --git a/frontend/src/components/onboarding/steps/Step4AddKeywords.tsx b/frontend/src/components/onboarding/steps/Step4AddKeywords.tsx index 181de559..9735333c 100644 --- a/frontend/src/components/onboarding/steps/Step4AddKeywords.tsx +++ b/frontend/src/components/onboarding/steps/Step4AddKeywords.tsx @@ -216,7 +216,7 @@ export default function Step4AddKeywords({ {keywords.length > 0 && ( @@ -224,15 +224,15 @@ export default function Step4AddKeywords({
{/* Keyword Suggestions */} - -

- 💡 Keyword Ideas + +

+ Keyword Ideas

{SUGGESTIONS.map((suggestion, index) => ( {suggestion} diff --git a/frontend/src/components/onboarding/steps/Step5Complete.tsx b/frontend/src/components/onboarding/steps/Step5Complete.tsx index cb8442a7..cad2b516 100644 --- a/frontend/src/components/onboarding/steps/Step5Complete.tsx +++ b/frontend/src/components/onboarding/steps/Step5Complete.tsx @@ -57,7 +57,7 @@ export default function Step5Complete({
{/* Success Animation */}
-
+

@@ -75,14 +75,14 @@ export default function Step5Complete({

  • - + Site: {data.siteName || 'Your Site'}
  • {data.integrationTested && (
  • - + WordPress integration connected @@ -90,20 +90,20 @@ export default function Step5Complete({ )} {data.keywordsAdded && (
  • - + {data.keywordsCount} keyword{data.keywordsCount !== 1 ? 's' : ''} added to pipeline
  • )}
  • - + Auto-approval & auto-publish enabled
  • - + Daily automation scheduled diff --git a/frontend/src/components/publishing/PublishingRules.tsx b/frontend/src/components/publishing/PublishingRules.tsx index 7672f82b..0832bbaa 100644 --- a/frontend/src/components/publishing/PublishingRules.tsx +++ b/frontend/src/components/publishing/PublishingRules.tsx @@ -3,7 +3,7 @@ * Phase 6: Site Integration & Multi-Destination Publishing */ import React, { useState } from 'react'; -import { PlusIcon, TrashIcon, ArrowUpIcon, ArrowDownIcon } from 'lucide-react'; +import { PlusIcon, TrashIcon, ArrowUpIcon, ArrowDownIcon } from '../../icons'; import Button from '../ui/button/Button'; import Checkbox from '../form/input/Checkbox'; import Label from '../form/Label'; diff --git a/frontend/src/components/sites/LayoutPreview.tsx b/frontend/src/components/sites/LayoutPreview.tsx index ec037ee0..7a90811b 100644 --- a/frontend/src/components/sites/LayoutPreview.tsx +++ b/frontend/src/components/sites/LayoutPreview.tsx @@ -4,7 +4,7 @@ * Component for previewing layouts with sample content */ import React, { useState } from 'react'; -import { EyeIcon, XIcon, Maximize2Icon } from 'lucide-react'; +import { EyeIcon, XIcon, Maximize2Icon } from '../../icons'; import { Card } from '../../ui/card'; import Button from '../../ui/button/Button'; diff --git a/frontend/src/components/sites/LayoutSelector.tsx b/frontend/src/components/sites/LayoutSelector.tsx index 38a8c008..6548545e 100644 --- a/frontend/src/components/sites/LayoutSelector.tsx +++ b/frontend/src/components/sites/LayoutSelector.tsx @@ -4,7 +4,7 @@ * Component for selecting page layouts */ import React, { useState } from 'react'; -import { CheckIcon } from 'lucide-react'; +import { CheckIcon } from '../../icons'; import { Card } from '../../ui/card'; export interface LayoutOption { diff --git a/frontend/src/components/sites/SiteProgressWidget.tsx b/frontend/src/components/sites/SiteProgressWidget.tsx index 3c65f22d..e263c2e8 100644 --- a/frontend/src/components/sites/SiteProgressWidget.tsx +++ b/frontend/src/components/sites/SiteProgressWidget.tsx @@ -7,7 +7,7 @@ import { useNavigate } from 'react-router-dom'; import { Card } from '../ui/card'; import Badge from '../ui/badge/Badge'; // import { fetchSiteProgress, SiteProgress } from '../../services/api'; -import { CheckCircleIcon, XCircleIcon, AlertCircleIcon, ArrowRightIcon } from 'lucide-react'; +import { CheckCircleIcon, XCircleIcon, AlertCircleIcon, ArrowRightIcon } from '../../icons'; interface SiteProgressWidgetProps { blueprintId: number; diff --git a/frontend/src/components/sites/SiteTypeBadge.tsx b/frontend/src/components/sites/SiteTypeBadge.tsx index a04656aa..aad467ff 100644 --- a/frontend/src/components/sites/SiteTypeBadge.tsx +++ b/frontend/src/components/sites/SiteTypeBadge.tsx @@ -3,7 +3,7 @@ * Displays site type indicator (Site Builder or WordPress) */ import React from 'react'; -import { Wand2, Globe } from 'lucide-react'; +import { Wand2Icon, GlobeIcon } from '../../icons'; import Badge from '../ui/badge/Badge'; interface SiteTypeBadgeProps { @@ -18,13 +18,13 @@ export default function SiteTypeBadge({ hostingType, className = '' }: SiteTypeB return { label: 'Site Builder', color: 'primary' as const, - icon: , + icon: , }; case 'wordpress': return { label: 'WordPress', color: 'info' as const, - icon: , + icon: , }; default: return null; diff --git a/frontend/src/components/sites/StyleEditor.tsx b/frontend/src/components/sites/StyleEditor.tsx index 17774cb2..0f3dadbc 100644 --- a/frontend/src/components/sites/StyleEditor.tsx +++ b/frontend/src/components/sites/StyleEditor.tsx @@ -4,7 +4,7 @@ * Component for editing CSS styles and theme customization */ import React, { useState } from 'react'; -import { CodeIcon, PaletteIcon, TypeIcon, SaveIcon, RefreshCwIcon } from 'lucide-react'; +import { CodeIcon, PaletteIcon, TypeIcon, SaveIcon, RefreshCwIcon } from '../../icons'; import { Card } from '../../ui/card'; import Button from '../../ui/button/Button'; import Label from '../../form/Label'; diff --git a/frontend/src/components/sites/TemplateCustomizer.tsx b/frontend/src/components/sites/TemplateCustomizer.tsx index 4d74e571..d038353d 100644 --- a/frontend/src/components/sites/TemplateCustomizer.tsx +++ b/frontend/src/components/sites/TemplateCustomizer.tsx @@ -4,7 +4,7 @@ * Component for customizing template settings and styles */ import React, { useState } from 'react'; -import { SettingsIcon, PaletteIcon, TypeIcon, LayoutIcon } from 'lucide-react'; +import { SettingsIcon, PaletteIcon, TypeIcon, LayoutIcon } from '../../icons'; import { Card } from '../../ui/card'; import Label from '../../form/Label'; import SelectDropdown from '../../form/SelectDropdown'; diff --git a/frontend/src/components/sites/TemplateLibrary.tsx b/frontend/src/components/sites/TemplateLibrary.tsx index 80ee5ad6..cab87677 100644 --- a/frontend/src/components/sites/TemplateLibrary.tsx +++ b/frontend/src/components/sites/TemplateLibrary.tsx @@ -4,7 +4,7 @@ * Component for browsing and selecting page templates */ import React, { useState } from 'react'; -import { SearchIcon, FilterIcon, CheckIcon } from 'lucide-react'; +import { SearchIcon, FilterIcon, CheckIcon } from '../../icons'; import { Card } from '../../ui/card'; import Button from '../../ui/button/Button'; diff --git a/frontend/src/components/sites/WordPressIntegrationCard.tsx b/frontend/src/components/sites/WordPressIntegrationCard.tsx index e08a0859..7d49203d 100644 --- a/frontend/src/components/sites/WordPressIntegrationCard.tsx +++ b/frontend/src/components/sites/WordPressIntegrationCard.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import { useNavigate } from 'react-router-dom'; -import { Globe, CheckCircle, XCircle, Settings, RefreshCw, AlertCircle, ExternalLink } from 'lucide-react'; +import { GlobeIcon, CheckCircleIcon, XCircleIcon, SettingsIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon } from '../../icons'; import { Card } from '../ui/card'; import Button from '../ui/button/Button'; import Badge from '../ui/badge/Badge'; @@ -49,7 +49,7 @@ export default function WordPressIntegrationCard({
    - +

    @@ -74,7 +74,7 @@ export default function WordPressIntegrationCard({
    - +

    @@ -101,13 +101,13 @@ export default function WordPressIntegrationCard({

    Sync Status

    {integration.sync_status === 'success' || integration.sync_status === 'healthy' ? ( - + ) : integration.sync_status === 'failed' || integration.sync_status === 'error' ? ( - + ) : integration.sync_status === 'warning' ? ( - + ) : ( - + )} {integration.sync_status === 'healthy' ? 'Healthy' : @@ -132,7 +132,7 @@ export default function WordPressIntegrationCard({
    - + {integration.mismatch_count} sync mismatch{integration.mismatch_count !== 1 ? 'es' : ''} detected @@ -144,7 +144,7 @@ export default function WordPressIntegrationCard({ onClick={() => navigate(`/sites/${siteId}/sync`)} > View Details - + )}
    @@ -155,7 +155,7 @@ export default function WordPressIntegrationCard({
    - +

    Sync Error @@ -176,7 +176,7 @@ export default function WordPressIntegrationCard({ size="sm" className="flex-1" > - + Manage {siteId && ( @@ -186,7 +186,7 @@ export default function WordPressIntegrationCard({ size="sm" title="View Sync Dashboard" > - + )} {onSync && ( @@ -196,7 +196,7 @@ export default function WordPressIntegrationCard({ size="sm" disabled={loading} > - + )}

    diff --git a/frontend/src/components/sites/WordPressIntegrationForm.tsx b/frontend/src/components/sites/WordPressIntegrationForm.tsx index 1c3cc08b..8f6282ce 100644 --- a/frontend/src/components/sites/WordPressIntegrationForm.tsx +++ b/frontend/src/components/sites/WordPressIntegrationForm.tsx @@ -17,9 +17,11 @@ import { DownloadIcon, PlusIcon, CopyIcon, - TrashBinIcon + TrashBinIcon, + GlobeIcon, + KeyIcon, + RefreshCwIcon } from '../../icons'; -import { Globe, Key, RefreshCw } from 'lucide-react'; interface WordPressIntegrationFormProps { siteId: number; @@ -202,7 +204,7 @@ export default function WordPressIntegrationForm({
    - +

    @@ -257,7 +259,7 @@ export default function WordPressIntegrationForm({ > {generatingKey ? ( <> - + Generating... ) : ( @@ -313,7 +315,7 @@ export default function WordPressIntegrationForm({ className="inline-flex h-11 w-11 items-center justify-center rounded-lg border border-gray-300 text-gray-700 dark:border-gray-700 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50" title="Regenerate" > - +
    @@ -358,7 +360,7 @@ export default function WordPressIntegrationForm({ className="text-gray-500 hover:text-brand-500 dark:text-gray-400 dark:hover:text-brand-400 disabled:opacity-50 transition-colors" title="Regenerate API key" > - +
    - +

    WordPress Application Password Required

    diff --git a/frontend/src/components/ui/pricing-table/index.tsx b/frontend/src/components/ui/pricing-table/index.tsx index 3242f979..5b62d6d4 100644 --- a/frontend/src/components/ui/pricing-table/index.tsx +++ b/frontend/src/components/ui/pricing-table/index.tsx @@ -4,7 +4,7 @@ */ import { useState } from 'react'; -import { Check } from 'lucide-react'; +import { CheckIcon } from '../../../icons'; export interface PricingPlan { id: number; @@ -141,7 +141,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false,

      {plan.features.map((feature, index) => (
    • - + {feature}
    • ))} @@ -152,7 +152,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false,
      LIMITS
      {plan.max_sites && (
    • - + {plan.max_sites === 99999 ? 'Unlimited' : plan.max_sites} Sites @@ -160,7 +160,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false, )} {plan.max_users && (
    • - + {plan.max_users === 99999 ? 'Unlimited' : plan.max_users} Team Members @@ -168,7 +168,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false, )} {plan.max_content_words && (
    • - + {(plan.max_content_words / 1000).toLocaleString()}K Words/month @@ -176,7 +176,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false, )} {plan.max_content_ideas && (
    • - + {plan.max_content_ideas} Ideas/month @@ -184,7 +184,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false, )} {plan.max_images_basic && (
    • - + {plan.max_images_basic} Images/month @@ -192,7 +192,7 @@ export function PricingTable({ variant = '1', title, plans, showToggle = false, )} {plan.included_credits && (
    • - + {plan.included_credits.toLocaleString()} Content pieces/month diff --git a/frontend/src/config/pages/keywords.config.tsx b/frontend/src/config/pages/keywords.config.tsx index 0a4a20b4..0aa8f250 100644 --- a/frontend/src/config/pages/keywords.config.tsx +++ b/frontend/src/config/pages/keywords.config.tsx @@ -167,7 +167,11 @@ export const createKeywordsPageConfig = ( ...clusterColumn, sortable: false, // Backend doesn't support sorting by cluster_id sortField: 'cluster_id', - render: (_value: string, row: Keyword) => row.cluster_name || '-', + render: (_value: string, row: Keyword) => row.cluster_name ? ( + + {row.cluster_name} + + ) : -, }, { ...difficultyColumn, diff --git a/frontend/src/config/snippets/columns.snippets.ts b/frontend/src/config/snippets/columns.snippets.ts index 74fd0c3e..c66cd065 100644 --- a/frontend/src/config/snippets/columns.snippets.ts +++ b/frontend/src/config/snippets/columns.snippets.ts @@ -61,7 +61,7 @@ export const createdColumn = { label: 'Created', sortable: true, date: true, - width: '150px', + width: '100px', }; export const updatedColumn = { diff --git a/frontend/src/icons/index.ts b/frontend/src/icons/index.ts index 3449fcf1..a1eace63 100644 --- a/frontend/src/icons/index.ts +++ b/frontend/src/icons/index.ts @@ -116,7 +116,7 @@ export { CalendarIcon, }; -// Aliases for commonly used icon names +// Aliases for commonly used icon names (lucide-react replacements) export { AngleLeftIcon as ArrowLeftIcon }; export { FileIcon as FileTextIcon }; export { FileIcon as ImageIcon }; // Use FileIcon as ImageIcon alias @@ -124,9 +124,46 @@ export { TimeIcon as ClockIcon }; export { ErrorIcon as XCircleIcon }; export { BoxIcon as TagIcon }; export { CloseIcon as XMarkIcon }; +export { CloseIcon as XIcon }; // X alias export { BoltIcon as PlayIcon }; // Use BoltIcon for play (running state) export { TimeIcon as PauseIcon }; // Use TimeIcon for pause state export { ArrowUpIcon as TrendingUpIcon }; // Trend up indicator export { ArrowDownIcon as TrendingDownIcon }; // Trend down indicator export { BoxCubeIcon as SettingsIcon }; // Settings/cog alias export { InfoIcon as HelpCircleIcon }; // Help/question circle +export { AlertIcon as AlertCircleIcon }; // Alert/warning circle +export { AlertIcon as AlertTriangleIcon }; // Alert triangle alias +export { CheckLineIcon as CheckIcon }; // Simple check mark +export { TrashBinIcon as TrashIcon }; // Trash alias +export { TrashBinIcon as Trash2Icon }; // Trash2 alias +export { CheckCircleIcon as CheckCheckIcon }; // Double check alias +export { ListIcon as FilterIcon }; // Filter alias +export { PageIcon as GlobeIcon }; // Globe alias +export { BoltIcon as ZapIcon }; // Zap/lightning alias +export { TimeIcon as RefreshCwIcon }; // Refresh alias +export { LockIcon as KeyIcon }; // Key alias +export { DownloadIcon as UploadIcon }; // Upload alias +export { DollarLineIcon as DollarSignIcon }; // Dollar sign alias +export { UserIcon as UsersIcon }; // Users alias +export { PieChartIcon as BarChart3Icon }; // Bar chart alias +export { PieChartIcon as ActivityIcon }; // Activity alias +export { TimeIcon as Loader2Icon }; // Loader alias (spinning) +export { BoxCubeIcon as DatabaseIcon }; // Database alias +export { FileIcon as FileArchiveIcon }; // File archive alias +export { PageIcon as ExternalLinkIcon }; // External link alias +export { PencilIcon as Wand2Icon }; // Wand alias +export { BoxCubeIcon as LayoutIcon }; // Layout alias +export { PencilIcon as SaveIcon }; // Save alias +export { BoxCubeIcon as CodeIcon }; // Code alias +export { GridIcon as SearchIcon }; // Search alias +export { BoxCubeIcon as PaletteIcon }; // Palette alias +export { FileIcon as TypeIcon }; // Type alias +export { EyeIcon as Maximize2Icon }; // Maximize alias +export { AngleRightIcon as ChevronRightIcon }; // Chevron right alias +export { BoxCubeIcon as Building2Icon }; // Building alias +export { BoxIcon as CreditCardIcon }; // Credit card alias +export { BoxIcon as WalletIcon }; // Wallet alias +export { AlertIcon as BellIcon }; // Bell notification alias +export { PlugInIcon as TestTubeIcon }; // Test tube alias +export { MailIcon as Mail }; // Mail without Icon suffix +export { BoxIcon as PackageIcon }; // Package alias diff --git a/frontend/src/pages/Settings/ImportExport.tsx b/frontend/src/pages/Settings/ImportExport.tsx index 142ba20b..662f7852 100644 --- a/frontend/src/pages/Settings/ImportExport.tsx +++ b/frontend/src/pages/Settings/ImportExport.tsx @@ -1,7 +1,7 @@ import PageMeta from "../../components/common/PageMeta"; import ComponentCard from "../../components/common/ComponentCard"; import { Card } from "../../components/ui/card"; -import { Download, Upload, Database, FileArchive, CheckCircle } from 'lucide-react'; +import { DownloadIcon, UploadIcon, DatabaseIcon, FileArchiveIcon, CheckCircleIcon } from '../../icons'; export default function ImportExport() { return ( @@ -12,7 +12,7 @@ export default function ImportExport() {
      - +
      @@ -30,31 +30,31 @@ export default function ImportExport() {

    - +
    Export your keywords as a file (backup or share)
    - +
    Export all your articles in different formats
    - +
    Import keywords from other sources
    - +
    Backup and restore your entire account
    - +
    Download your settings and configurations
    diff --git a/frontend/src/pages/Settings/Sites.tsx b/frontend/src/pages/Settings/Sites.tsx index 04460735..d1765e40 100644 --- a/frontend/src/pages/Settings/Sites.tsx +++ b/frontend/src/pages/Settings/Sites.tsx @@ -22,10 +22,10 @@ import Badge from '../../components/ui/badge/Badge'; // Site Icon SVG - Globe const SiteIcon = () => ( - - - - + + + + ); diff --git a/frontend/src/pages/Settings/WordPressIntegrationDebug.tsx b/frontend/src/pages/Settings/WordPressIntegrationDebug.tsx index 913036ed..323a5e11 100644 --- a/frontend/src/pages/Settings/WordPressIntegrationDebug.tsx +++ b/frontend/src/pages/Settings/WordPressIntegrationDebug.tsx @@ -1,16 +1,16 @@ import React, { useState, useEffect, useCallback } from 'react'; -import { - CheckCircle, - XCircle, - AlertTriangle, - Loader2, - Activity, - Clock, - Globe, - RefreshCw, - TestTube, - Wrench -} from 'lucide-react'; +import { + CheckCircleIcon, + XCircleIcon, + AlertTriangleIcon, + Loader2Icon, + ActivityIcon, + ClockIcon, + GlobeIcon, + RefreshCwIcon, + TestTubeIcon, + SettingsIcon as WrenchIcon +} from '../../icons'; import { useSiteStore } from '../../store/siteStore'; import { useToast } from '../../components/ui/toast/ToastContainer'; import { API_BASE_URL, fetchAPI } from '../../services/api'; @@ -343,7 +343,7 @@ export default function WordPressIntegrationDebug() { if (initializing) { return (
    - +

    Loading WordPress integration...

    ); @@ -354,7 +354,7 @@ export default function WordPressIntegrationDebug() { return (
    - +

    No WordPress Integration Found

    @@ -423,13 +423,13 @@ export default function WordPressIntegrationDebug() { {/* No WordPress Integration Found */} {initializing ? (
    - +

    Checking for WordPress integration...

    ) : !integrationId && activeSite ? (
    - +

    No WordPress Integration Found

    @@ -444,7 +444,7 @@ export default function WordPressIntegrationDebug() { ) : !activeSite ? (

    - +

    No Site Selected

    Please select a site to view WordPress integration debug data. @@ -463,7 +463,7 @@ export default function WordPressIntegrationDebug() { disabled={loading} className="inline-flex items-center px-3 py-1 text-xs bg-brand-100 hover:bg-brand-200 text-brand-700 rounded-md disabled:opacity-50" > - + Test Connection

    @@ -491,9 +491,9 @@ export default function WordPressIntegrationDebug() {
    API Connection {integrationHealth.api_status === 'healthy' ? ( - + ) : ( - + )}

    {integrationHealth.api_message}

    @@ -506,9 +506,9 @@ export default function WordPressIntegrationDebug() {
    Plugin Status {integrationHealth.plugin_active ? ( - + ) : ( - + )}

    @@ -523,9 +523,9 @@ export default function WordPressIntegrationDebug() {

    Sync Status {integrationHealth.sync_healthy ? ( - + ) : ( - + )}

    @@ -539,7 +539,7 @@ export default function WordPressIntegrationDebug() {

    ) : (
    - + Loading WordPress integration health...
    )} @@ -587,7 +587,7 @@ export default function WordPressIntegrationDebug() {
    ) : (
    - +

    No WordPress sync events yet. Actions will appear here in real-time.

    Content publishing, metadata sync, and webhook calls will be logged here.

    @@ -631,10 +631,10 @@ export default function WordPressIntegrationDebug() { {validation.matches ? ( - + ) : (
    - + {validation.error && ( {validation.error} )} diff --git a/frontend/src/pages/Sites/Content.tsx b/frontend/src/pages/Sites/Content.tsx index b9cb91db..358490b0 100644 --- a/frontend/src/pages/Sites/Content.tsx +++ b/frontend/src/pages/Sites/Content.tsx @@ -11,7 +11,7 @@ import { Card } from '../../components/ui/card'; import Button from '../../components/ui/button/Button'; import { useToast } from '../../components/ui/toast/ToastContainer'; import { fetchAPI } from '../../services/api'; -import { Search } from 'lucide-react'; +import { SearchIcon } from '../../icons'; import { PencilIcon, EyeIcon, @@ -139,7 +139,7 @@ export default function SiteContentManager() {
    - + Publishing Queue

    View scheduled content

    - +
    diff --git a/frontend/src/pages/Sites/List.tsx b/frontend/src/pages/Sites/List.tsx index 8ad386b0..14fd8ef2 100644 --- a/frontend/src/pages/Sites/List.tsx +++ b/frontend/src/pages/Sites/List.tsx @@ -601,8 +601,7 @@ export default function SiteList() { {/* Standard Filters Bar for Grid View - Matches Table View */}
    diff --git a/frontend/src/pages/Sites/PostEditor.tsx b/frontend/src/pages/Sites/PostEditor.tsx index 276684a7..2d7d2ccc 100644 --- a/frontend/src/pages/Sites/PostEditor.tsx +++ b/frontend/src/pages/Sites/PostEditor.tsx @@ -5,7 +5,7 @@ */ import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; -import { SaveIcon, XIcon, FileTextIcon, TagIcon, CheckCircleIcon, XCircleIcon, AlertCircleIcon } from 'lucide-react'; +import { SaveIcon, XIcon, FileTextIcon, TagIcon, CheckCircleIcon, XCircleIcon, AlertCircleIcon } from '../../icons'; import PageMeta from '../../components/common/PageMeta'; import { Card } from '../../components/ui/card'; import Button from '../../components/ui/button/Button'; diff --git a/frontend/src/pages/Sites/PublishingQueue.tsx b/frontend/src/pages/Sites/PublishingQueue.tsx index 4dce2780..6d6078aa 100644 --- a/frontend/src/pages/Sites/PublishingQueue.tsx +++ b/frontend/src/pages/Sites/PublishingQueue.tsx @@ -166,14 +166,14 @@ export default function PublishingQueue() { } if (item.site_status === 'publishing') { return ( - + Publishing... ); } return ( - + Scheduled @@ -228,8 +228,8 @@ export default function PublishingQueue() {
    -
    - +
    +

    {stats.scheduled}

    @@ -239,8 +239,8 @@ export default function PublishingQueue() {
    -
    - +
    +

    {stats.publishing}

    @@ -250,8 +250,8 @@ export default function PublishingQueue() {
    -
    - +
    +

    {stats.published}

    @@ -261,8 +261,8 @@ export default function PublishingQueue() {
    -
    - +
    +

    {stats.failed}

    @@ -377,7 +377,7 @@ export default function PublishingQueue() { @@ -608,7 +608,7 @@ export default function AccountSettingsPage() {

    - + Security

    @@ -658,7 +658,7 @@ export default function AccountSettingsPage() { {teamLoading ? (
    - +
    ) : ( @@ -714,7 +714,7 @@ export default function AccountSettingsPage() { {members.length === 0 && ( - + No team members yet. Invite your first team member! @@ -728,7 +728,7 @@ export default function AccountSettingsPage() { {/* Role Permissions Info */}

    - + Role Permissions

    @@ -841,14 +841,14 @@ export default function AccountSettingsPage() {

    - + Change Password

    diff --git a/frontend/src/pages/account/ContentSettingsPage.tsx b/frontend/src/pages/account/ContentSettingsPage.tsx index b81c40df..b80ad487 100644 --- a/frontend/src/pages/account/ContentSettingsPage.tsx +++ b/frontend/src/pages/account/ContentSettingsPage.tsx @@ -6,9 +6,9 @@ import { useState, useEffect, useCallback } from 'react'; import { useLocation } from 'react-router-dom'; -import { - Save, Loader2, Image as ImageIcon, FileText, Send, Settings -} from 'lucide-react'; +import { + SaveIcon, Loader2Icon, ImageIcon, FileTextIcon, PaperPlaneIcon as SendIcon, SettingsIcon +} from '../../icons'; import { Card } from '../../components/ui/card'; import Button from '../../components/ui/button/Button'; import { fetchAPI } from '../../services/api'; @@ -316,7 +316,7 @@ export default function ContentSettingsPage() {
    - +
    Loading settings...
    @@ -346,7 +346,7 @@ export default function ContentSettingsPage() {
    - +

    Content Generation

    @@ -410,7 +410,7 @@ export default function ContentSettingsPage() { tone="brand" onClick={handleSave} disabled={saving} - startIcon={saving ? : } + startIcon={saving ? : } > {saving ? 'Saving...' : 'Save Settings'} @@ -424,7 +424,7 @@ export default function ContentSettingsPage() {
    - +

    WordPress Publishing

    @@ -486,7 +486,7 @@ export default function ContentSettingsPage() { tone="brand" onClick={handleSave} disabled={saving} - startIcon={saving ? : } + startIcon={saving ? : } > {saving ? 'Saving...' : 'Save Settings'} @@ -643,7 +643,7 @@ export default function ContentSettingsPage() { tone="brand" onClick={handleSave} disabled={saving} - startIcon={saving ? : } + startIcon={saving ? : } > {saving ? 'Saving...' : 'Save Settings'} diff --git a/frontend/src/pages/account/NotificationsPage.tsx b/frontend/src/pages/account/NotificationsPage.tsx index c165044f..d2dfebaf 100644 --- a/frontend/src/pages/account/NotificationsPage.tsx +++ b/frontend/src/pages/account/NotificationsPage.tsx @@ -2,17 +2,17 @@ import { useState, useEffect } from 'react'; import { Helmet } from 'react-helmet-async'; import { Link } from 'react-router-dom'; import { - Bell, - CheckCircle, - AlertTriangle, - XCircle, - Info, - Trash2, - CheckCheck, - Filter, - Calendar, - Globe, -} from 'lucide-react'; + BellIcon, + CheckCircleIcon, + AlertTriangleIcon, + XCircleIcon, + InfoIcon, + Trash2Icon, + CheckCheckIcon, + FilterIcon, + CalendarIcon, + GlobeIcon, +} from '../../icons'; import { Card } from '../../components/ui/card'; import Button from '../../components/ui/button/Button'; import PageMeta from '../../components/common/PageMeta'; @@ -70,13 +70,13 @@ export default function NotificationsPage() { const getSeverityIcon = (severity: string) => { switch (severity) { case 'success': - return ; + return ; case 'warning': - return ; + return ; case 'error': - return ; + return ; default: - return ; + return ; } }; @@ -183,7 +183,7 @@ export default function NotificationsPage() { , color: 'blue' }} + badge={{ icon: , color: 'blue' }} />
    @@ -210,7 +210,7 @@ export default function NotificationsPage() { onClick={() => setShowFilters(!showFilters)} className="flex items-center gap-2" > - + Filters @@ -221,7 +221,7 @@ export default function NotificationsPage() { onClick={handleMarkAllRead} className="flex items-center gap-2" > - + Mark All Read )} @@ -321,7 +321,7 @@ export default function NotificationsPage() {
    ) : filteredNotifications.length === 0 ? (
    - +

    {apiNotifications.length === 0 ? 'No notifications yet' @@ -363,7 +363,7 @@ export default function NotificationsPage() { {/* Metadata */}

    - + {formatTimestamp(notification.created_at)} @@ -383,7 +383,7 @@ export default function NotificationsPage() { handleNotificationClick(notification.id, false) } > - + )} @@ -393,7 +393,7 @@ export default function NotificationsPage() { onClick={() => handleDelete(notification.id)} className="text-error-600 hover:text-error-700 hover:bg-error-50 dark:hover:bg-error-900/20" > - +
    diff --git a/frontend/src/pages/account/PlansAndBillingPage.tsx b/frontend/src/pages/account/PlansAndBillingPage.tsx index fe1750d3..7a39e286 100644 --- a/frontend/src/pages/account/PlansAndBillingPage.tsx +++ b/frontend/src/pages/account/PlansAndBillingPage.tsx @@ -8,10 +8,10 @@ import { useState, useEffect, useRef } from 'react'; import { Link, useLocation } from 'react-router-dom'; -import { - CreditCard, Package, TrendingUp, FileText, Wallet, ArrowUpCircle, - Loader2, AlertCircle, CheckCircle, Download, Zap, Globe, Users, X -} from 'lucide-react'; +import { + CreditCardIcon, BoxIcon as PackageIcon, TrendingUpIcon, FileTextIcon, WalletIcon, ArrowUpIcon as ArrowUpCircleIcon, + Loader2Icon, AlertCircleIcon, CheckCircleIcon, DownloadIcon, ZapIcon, GlobeIcon, UsersIcon, XIcon +} from '../../icons'; import { Card } from '../../components/ui/card'; import Badge from '../../components/ui/badge/Badge'; import Button from '../../components/ui/button/Button'; @@ -346,11 +346,11 @@ export default function PlansAndBillingPage() { , color: 'blue' }} + badge={{ icon: , color: 'blue' }} />
    - +
    @@ -381,7 +381,7 @@ export default function PlansAndBillingPage() { , color: 'blue' }} + badge={{ icon: , color: 'blue' }} parent="Plans & Billing" />
    @@ -399,7 +399,7 @@ export default function PlansAndBillingPage() { {error && (
    - +

    {error}

    )} @@ -416,7 +416,7 @@ export default function PlansAndBillingPage() {

    Your Current Plan

    {!hasActivePlan && (
    - +

    No Active Plan

    Choose a plan below to activate your account and unlock all features.

    @@ -442,7 +442,7 @@ export default function PlansAndBillingPage() {
    - + Monthly Credits
    @@ -451,7 +451,7 @@ export default function PlansAndBillingPage() {
    - + Current Balance
    @@ -460,7 +460,7 @@ export default function PlansAndBillingPage() {
    - + Renewal Date
    @@ -478,7 +478,7 @@ export default function PlansAndBillingPage() { tone="brand" as={Link} to="/account/plans/upgrade" - startIcon={} + startIcon={} > Upgrade Plan @@ -513,7 +513,7 @@ export default function PlansAndBillingPage() { : ['AI Content Writer', 'Image Generation', 'Auto Publishing', 'Custom Prompts', 'Email Support', 'API Access']) .map((feature: string, index: number) => (
    - + {feature}
    ))} @@ -544,7 +544,7 @@ export default function PlansAndBillingPage() {
    - + Sites
    @@ -553,7 +553,7 @@ export default function PlansAndBillingPage() {
    - + Team Members
    @@ -562,7 +562,7 @@ export default function PlansAndBillingPage() {
    - + Content Words/mo
    @@ -575,7 +575,7 @@ export default function PlansAndBillingPage() {
    - + Monthly Credits
    @@ -593,7 +593,7 @@ export default function PlansAndBillingPage() {
    {/* Upgrade Plans Section */}
    -
    +

    - + Plan Change Policy

    • - + Upgrades take effect immediately with prorated billing
    • - + Downgrades take effect at the end of your current billing period
    • - + Unused credits carry over when changing plans
    • - + Cancel anytime - no long-term commitments
    @@ -677,7 +677,7 @@ export default function PlansAndBillingPage() { {invoices.length === 0 ? ( - + No invoices yet @@ -702,7 +702,7 @@ export default function PlansAndBillingPage() { variant="ghost" tone="brand" size="sm" - startIcon={} + startIcon={} className="ml-auto" onClick={() => handleDownloadInvoice(invoice.id)} > @@ -790,7 +790,7 @@ export default function PlansAndBillingPage() { {paymentMethods.map((method) => (
    - +
    {method.display_name}
    {method.type}
    @@ -837,12 +837,12 @@ export default function PlansAndBillingPage() { onClick={() => setShowCancelConfirm(false)} className="p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors" > - +
    - +

    Are you sure you want to cancel?

    Your subscription will remain active until the end of your current billing period. After that:

    @@ -882,7 +882,7 @@ export default function PlansAndBillingPage() { > {planLoadingId === currentSubscription?.id ? ( <> - + Cancelling... ) : ( diff --git a/frontend/src/pages/account/PlansAndBillingPage.tsx.backup b/frontend/src/pages/account/PlansAndBillingPage.tsx.backup deleted file mode 100644 index 51fd0b22..00000000 --- a/frontend/src/pages/account/PlansAndBillingPage.tsx.backup +++ /dev/null @@ -1,980 +0,0 @@ -/** - * Plans & Billing Page - Consolidated - * Tabs: Current Plan, Upgrade/Downgrade, Credits Overview, Purchase Credits, Billing History, Payment Methods - */ - -import { useState, useEffect, useRef } from 'react'; -import { - CreditCard, Package, TrendingUp, FileText, Wallet, ArrowUpCircle, - Loader2, AlertCircle, CheckCircle, Download -} from 'lucide-react'; -import { Card } from '../../components/ui/card'; -import Badge from '../../components/ui/badge/Badge'; -import Button from '../../components/ui/button/Button'; -import { useToast } from '../../components/ui/toast/ToastContainer'; -import { - getCreditBalance, - getCreditPackages, - getInvoices, - getAvailablePaymentMethods, - purchaseCreditPackage, - downloadInvoicePDF, - getPayments, - submitManualPayment, - createPaymentMethod, - deletePaymentMethod, - setDefaultPaymentMethod, - type CreditBalance, - type CreditPackage, - type Invoice, - type PaymentMethod, - type Payment, - getPlans, - getSubscriptions, - createSubscription, - cancelSubscription, - type Plan, - type Subscription, -} from '../../services/billing.api'; -import { useAuthStore } from '../../store/authStore'; - -type TabType = 'plan' | 'credits' | 'billing-history'; - -export default function PlansAndBillingPage() { - const [activeTab, setActiveTab] = useState('plan'); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(''); - const [planLoadingId, setPlanLoadingId] = useState(null); - const [purchaseLoadingId, setPurchaseLoadingId] = useState(null); - - // Data states - const [creditBalance, setCreditBalance] = useState(null); - const [packages, setPackages] = useState([]); - const [invoices, setInvoices] = useState([]); - const [payments, setPayments] = useState([]); - const [paymentMethods, setPaymentMethods] = useState([]); - const [plans, setPlans] = useState([]); - const [subscriptions, setSubscriptions] = useState([]); - const [selectedPaymentMethod, setSelectedPaymentMethod] = useState(undefined); - const [manualPayment, setManualPayment] = useState({ - invoice_id: '', - amount: '', - payment_method: '', - reference: '', - notes: '', - }); - const [newPaymentMethod, setNewPaymentMethod] = useState({ - type: 'bank_transfer', - display_name: '', - instructions: '', - }); - const { user } = useAuthStore.getState(); - const hasLoaded = useRef(false); - const isAwsAdmin = user?.account?.slug === 'aws-admin'; - const handleBillingError = (err: any, fallback: string) => { - const message = err?.message || fallback; - setError(message); - toast?.error?.(message); - }; - - const toast = useToast(); - - useEffect(() => { - if (hasLoaded.current) return; - hasLoaded.current = true; - loadData(); - }, []); - - const loadData = async (allowRetry = true) => { - try { - setLoading(true); - // Fetch in controlled sequence to avoid burst 429s on auth/system scopes - const balanceData = await getCreditBalance(); - - // Small gap between auth endpoints to satisfy tight throttles - const wait = (ms: number) => new Promise((res) => setTimeout(res, ms)); - - const packagesPromise = getCreditPackages(); - const invoicesPromise = getInvoices({}); - const paymentsPromise = getPayments({}); - const methodsPromise = getAvailablePaymentMethods(); - - const plansData = await getPlans(); - await wait(400); - - // Subscriptions: retry once on 429 after short backoff; do not hard-fail page - let subsData: { results: Subscription[] } = { results: [] }; - try { - subsData = await getSubscriptions(); - } catch (subErr: any) { - if (subErr?.status === 429 && allowRetry) { - await wait(2500); - try { - subsData = await getSubscriptions(); - } catch { - subsData = { results: [] }; - } - } else { - subsData = { results: [] }; - } - } - - const [packagesData, invoicesData, paymentsData, methodsData] = await Promise.all([ - packagesPromise, - invoicesPromise, - paymentsPromise, - methodsPromise, - ]); - - setCreditBalance(balanceData); - setPackages(packagesData.results || []); - setInvoices(invoicesData.results || []); - setPayments(paymentsData.results || []); - - // Prefer manual payment method id 14 as default (tenant-facing) - const methods = (methodsData.results || []).filter((m) => m.is_enabled !== false); - setPaymentMethods(methods); - if (methods.length > 0) { - // Preferred ordering: bank_transfer (default), then manual - const bank = methods.find((m) => m.type === 'bank_transfer'); - const manual = methods.find((m) => m.type === 'manual'); - const selected = - bank || - manual || - methods.find((m) => m.is_default) || - methods[0]; - setSelectedPaymentMethod((prev) => prev || selected.type || selected.id); - } - - // Surface all active plans (avoid hiding plans and showing empty state) - const activePlans = (plansData.results || []).filter((p) => p.is_active !== false); - // Exclude Enterprise plan for non aws-admin accounts - const filteredPlans = activePlans.filter((p) => { - const name = (p.name || '').toLowerCase(); - const slug = (p.slug || '').toLowerCase(); - const isEnterprise = name.includes('enterprise') || slug === 'enterprise'; - return isAwsAdmin ? true : !isEnterprise; - }); - - // Ensure the user's assigned plan is included even if subscriptions list is empty - const accountPlan = user?.account?.plan; - const isAccountEnterprise = (() => { - if (!accountPlan) return false; - const name = (accountPlan.name || '').toLowerCase(); - const slug = (accountPlan.slug || '').toLowerCase(); - return name.includes('enterprise') || slug === 'enterprise'; - })(); - - const shouldIncludeAccountPlan = accountPlan && (!isAccountEnterprise || isAwsAdmin); - if (shouldIncludeAccountPlan && !filteredPlans.find((p) => p.id === accountPlan.id)) { - filteredPlans.push(accountPlan as any); - } - setPlans(filteredPlans); - const subs = subsData.results || []; - if (subs.length === 0 && shouldIncludeAccountPlan && accountPlan) { - subs.push({ - id: accountPlan.id || 0, - plan: accountPlan, - status: 'active', - } as any); - } - setSubscriptions(subs); - } catch (err: any) { - // Handle throttling gracefully: don't block the page on subscriptions throttle - if (err?.status === 429 && allowRetry) { - setError('Request was throttled. Retrying...'); - setTimeout(() => loadData(false), 2500); - } else if (err?.status === 429) { - setError(''); // suppress lingering banner - } else { - setError(err.message || 'Failed to load billing data'); - console.error('Billing load error:', err); - } - } finally { - setLoading(false); - } - }; - - const handleSelectPlan = async (planId: number) => { - try { - if (!selectedPaymentMethod && paymentMethods.length > 0) { - setError('Select a payment method to continue'); - return; - } - setPlanLoadingId(planId); - await createSubscription({ plan_id: planId, payment_method: selectedPaymentMethod }); - toast?.success?.('Subscription updated'); - await loadData(); - } catch (err: any) { - handleBillingError(err, 'Failed to update subscription'); - } finally { - setPlanLoadingId(null); - } - }; - - const handleCancelSubscription = async () => { - if (!currentSubscription?.id) { - setError('No active subscription to cancel'); - return; - } - try { - setPlanLoadingId(currentSubscription.id); - await cancelSubscription(currentSubscription.id); - toast?.success?.('Subscription cancellation requested'); - await loadData(); - } catch (err: any) { - handleBillingError(err, 'Failed to cancel subscription'); - } finally { - setPlanLoadingId(null); - } - }; - - const handlePurchase = async (packageId: number) => { - try { - if (!selectedPaymentMethod && paymentMethods.length > 0) { - setError('Select a payment method to continue'); - return; - } - setPurchaseLoadingId(packageId); - await purchaseCreditPackage({ - package_id: packageId, - payment_method: (selectedPaymentMethod as any) || 'stripe', - }); - await loadData(); - } catch (err: any) { - handleBillingError(err, 'Failed to purchase credits'); - } finally { - setPurchaseLoadingId(null); - setLoading(false); - } - }; - - const handleDownloadInvoice = async (invoiceId: number) => { - try { - const blob = await downloadInvoicePDF(invoiceId); - const url = window.URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = `invoice-${invoiceId}.pdf`; - document.body.appendChild(link); - link.click(); - link.remove(); - window.URL.revokeObjectURL(url); - } catch (err: any) { - handleBillingError(err, 'Failed to download invoice'); - } - }; - - const handleSubmitManualPayment = async () => { - try { - const payload = { - invoice_id: manualPayment.invoice_id ? Number(manualPayment.invoice_id) : undefined, - amount: manualPayment.amount, - payment_method: manualPayment.payment_method || (selectedPaymentMethod as any) || 'manual', - reference: manualPayment.reference, - notes: manualPayment.notes, - }; - await submitManualPayment(payload as any); - toast?.success?.('Manual payment submitted'); - setManualPayment({ invoice_id: '', amount: '', payment_method: '', reference: '', notes: '' }); - await loadData(); - } catch (err: any) { - handleBillingError(err, 'Failed to submit payment'); - } - }; - - const handleAddPaymentMethod = async () => { - if (!newPaymentMethod.display_name.trim()) { - setError('Payment method name is required'); - return; - } - try { - await createPaymentMethod(newPaymentMethod as any); - toast?.success?.('Payment method added'); - setNewPaymentMethod({ type: 'bank_transfer', display_name: '', instructions: '' }); - await loadData(); - } catch (err: any) { - handleBillingError(err, 'Failed to add payment method'); - } - }; - - const handleRemovePaymentMethod = async (id: string) => { - try { - await deletePaymentMethod(id); - toast?.success?.('Payment method removed'); - await loadData(); - } catch (err: any) { - handleBillingError(err, 'Failed to remove payment method'); - } - }; - - const handleSetDefaultPaymentMethod = async (id: string) => { - try { - await setDefaultPaymentMethod(id); - toast?.success?.('Default payment method updated'); - await loadData(); - } catch (err: any) { - handleBillingError(err, 'Failed to set default'); - } - }; - - if (loading) { - return ( -
    - -
    - ); - } - - const currentSubscription = subscriptions.find((sub) => sub.status === 'active') || subscriptions[0]; - const currentPlanId = typeof currentSubscription?.plan === 'object' ? currentSubscription.plan.id : currentSubscription?.plan; - // Fallback to account plan if subscription is missing - const accountPlanId = user?.account?.plan?.id; - const effectivePlanId = currentPlanId || accountPlanId; - const currentPlan = plans.find((p) => p.id === effectivePlanId) || user?.account?.plan; - const hasActivePlan = Boolean(effectivePlanId); - const hasPaymentMethods = paymentMethods.length > 0; - const subscriptionStatus = currentSubscription?.status || (hasActivePlan ? 'active' : 'none'); - const hasPendingManualPayment = payments.some((p) => p.status === 'pending_approval'); - - const tabs = [ - { id: 'plan' as TabType, label: 'Current Plan', icon: }, - { id: 'credits' as TabType, label: 'Credits Overview', icon: }, - { id: 'billing-history' as TabType, label: 'Billing History', icon: }, - ]; - - return ( -
    -
    -

    Plans & Billing

    -

    - Manage your subscription, credits, and billing information -

    -
    - - {/* Activation / pending payment notice */} - {!hasActivePlan && ( -
    - No active plan. Choose a plan below to activate your account. -
    - )} - {hasPendingManualPayment && ( -
    - We received your manual payment. It’s pending admin approval; activation will complete once approved. -
    - )} - - {error && ( -
    - -

    {error}

    -
    - )} - - {/* Tabs */} -
    - -
    - - {/* Tab Content */} -
    - {/* Current Plan Tab */} - {activeTab === 'plan' && ( -
    - -

    Your Current Plan

    - {!hasActivePlan && ( -
    - No active plan found. Please choose a plan to activate your account. -
    - )} -
    -
    -
    -
    - {currentPlan?.name || 'No Plan Selected'} -
    -
    - {currentPlan?.description || 'Select a plan to unlock full access.'} -
    -
    - - {hasActivePlan ? subscriptionStatus : 'plan required'} - -
    -
    -
    -
    Monthly Credits
    -
    - {creditBalance?.plan_credits_per_month?.toLocaleString?.() || 0} -
    -
    -
    -
    Current Balance
    -
    - {creditBalance?.credits?.toLocaleString?.() || 0} -
    -
    -
    -
    Period Ends
    -
    - {currentSubscription?.current_period_end - ? new Date(currentSubscription.current_period_end).toLocaleDateString() - : '—'} -
    -
    -
    -
    - - - {hasActivePlan && ( - - )} -
    -
    -
    - - -

    Plan Features

    -
      - {(currentPlan?.features && currentPlan.features.length > 0 - ? currentPlan.features - : ['Credits included each month', 'Module access per plan limits', 'Email support']) - .map((feature) => ( -
    • - - {feature} -
    • - ))} -
    -
    -
    - )} - - {/* Upgrade/Downgrade Tab */} - {activeTab === 'upgrade' && ( -
    -
    -

    Available Plans

    -

    Choose the plan that best fits your needs

    -
    - - {hasPaymentMethods ? ( -
    -
    Select payment method
    -
    - {paymentMethods.map((method) => ( - - ))} -
    -
    - ) : ( -
    - No payment methods available. Please contact support or add one from the Payment Methods tab. -
    - )} - -
    - {plans.map((plan) => { - const isCurrent = plan.id === currentPlanId; - const price = plan.price ? `$${plan.price}/${plan.interval || 'month'}` : 'Custom'; - return ( - -
    -

    {plan.name}

    -
    {price}
    -
    {plan.description || 'Standard plan'}
    -
    -
    - {(plan.features && plan.features.length > 0 ? plan.features : ['Monthly credits included', 'Module access per plan', 'Email support']).map((feature) => ( -
    - - {feature} -
    - ))} -
    - -
    - ); - })} - {plans.length === 0 && ( -
    - No plans available. Please contact support. -
    - )} -
    - - -

    Plan Change Policy

    -
      -
    • • Upgrades take effect immediately and you'll be charged a prorated amount
    • -
    • • Downgrades take effect at the end of your current billing period
    • -
    • • Unused credits from your current plan will carry over
    • -
    • • You can cancel your subscription at any time
    • -
    -
    -
    - )} - - {/* Credits Overview Tab */} - {activeTab === 'credits' && ( -
    -
    - -
    Current Balance
    -
    - {creditBalance?.credits.toLocaleString() || 0} -
    -
    credits available
    -
    - -
    Used This Month
    -
    - {creditBalance?.credits_used_this_month.toLocaleString() || 0} -
    -
    credits consumed
    -
    - -
    Monthly Included
    -
    - {creditBalance?.plan_credits_per_month.toLocaleString() || 0} -
    -
    from your plan
    -
    -
    - - -

    Credit Usage Summary

    -
    -
    - Remaining Credits - {creditBalance?.credits_remaining.toLocaleString() || 0} -
    -
    -
    -
    -
    -
    -
    - )} - - {/* Purchase Credits Tab */} - {activeTab === 'purchase' && ( -
    - {hasPaymentMethods ? ( -
    -
    Select payment method
    -
    - {paymentMethods.map((method) => ( - - ))} -
    -
    - ) : ( -
    - No payment methods available. Please contact support or add one from the Payment Methods tab. -
    - )} - - -

    Credit Packages

    -
    - {packages.map((pkg) => ( -
    -
    {pkg.name}
    -
    - {pkg.credits.toLocaleString()} credits -
    -
    - ${pkg.price} -
    - {pkg.description && ( -
    {pkg.description}
    - )} - -
    - ))} - {packages.length === 0 && ( -
    - No credit packages available at this time -
    - )} -
    -
    -
    - )} - - {/* Billing History Tab */} - {activeTab === 'invoices' && ( - -
    - - - - - - - - - - - - {invoices.length === 0 ? ( - - - - ) : ( - invoices.map((invoice) => ( - - - - - - - - )) - )} - -
    - Invoice - - Date - - Amount - - Status - - Actions -
    - - No invoices yet -
    {invoice.invoice_number} - {new Date(invoice.created_at).toLocaleDateString()} - ${invoice.total_amount} - - {invoice.status} - - - -
    -
    -
    - )} - - {/* Payments Tab */} - {activeTab === 'payments' && ( -
    - -
    -
    -

    Payments

    -

    Recent payments and manual submissions

    -
    -
    -
    - - - - - - - - - - - - {payments.length === 0 ? ( - - - - ) : ( - payments.map((payment) => ( - - - - - - - - )) - )} - -
    InvoiceAmountMethodStatusDate
    - No payments yet -
    - {payment.invoice_number || payment.invoice_id || '-'} - - ${payment.amount} - - {payment.payment_method} - - - {payment.status} - - - {new Date(payment.created_at).toLocaleDateString()} -
    -
    -
    - - -

    Submit Manual Payment

    -
    -
    - - setManualPayment((p) => ({ ...p, invoice_id: e.target.value }))} - className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white" - placeholder="Invoice ID" - /> -
    -
    - - setManualPayment((p) => ({ ...p, amount: e.target.value }))} - className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white" - placeholder="e.g., 99.00" - /> -
    -
    - - setManualPayment((p) => ({ ...p, payment_method: e.target.value }))} - className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white" - placeholder="bank_transfer / local_wallet / manual" - /> -
    -
    - - setManualPayment((p) => ({ ...p, reference: e.target.value }))} - className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white" - placeholder="Reference or transaction id" - /> -
    -
    - -