diff --git a/docs/plans/IMPLEMENTATION-PLAN-PHASES-1-5-6.md b/docs/plans/IMPLEMENTATION-PLAN-PHASES-1-5-6.md new file mode 100644 index 00000000..bb1d62fe --- /dev/null +++ b/docs/plans/IMPLEMENTATION-PLAN-PHASES-1-5-6.md @@ -0,0 +1,896 @@ +# Implementation Plan: Phases 1, 5, and 6 + +**Created:** January 9, 2026 +**Target:** Safe, verified execution of cleanup, UX improvements, and data backup + +--- + +## Table of Contents + +1. [Phase 1: Code Cleanup & Technical Debt](#phase-1-code-cleanup--technical-debt) +2. [Phase 5: UX Improvements](#phase-5-ux-improvements) +3. [Phase 6: Data Backup & Cleanup](#phase-6-data-backup--cleanup) +4. [Execution Checklist](#execution-checklist) + +--- + +# Phase 1: Code Cleanup & Technical Debt + +## 1.1 Pre-Cleanup Verification + +### 1.1.1 Create Safety Branch +```bash +# BEFORE ANY CHANGES - Create a safety branch +cd /data/app/igny8 +git checkout -b cleanup/phase-1-$(date +%Y%m%d) +git push origin cleanup/phase-1-$(date +%Y%m%d) +``` + +### 1.1.2 Run Full Test Suite (Baseline) +```bash +# Backend tests +cd /data/app/igny8/backend +python manage.py test --verbosity=2 > /tmp/test-baseline-backend.log 2>&1 +echo "Exit code: $?" + +# Frontend build check +cd /data/app/igny8/frontend +npm run build > /tmp/test-baseline-frontend.log 2>&1 +echo "Exit code: $?" + +# Frontend lint check +npm run lint > /tmp/test-baseline-lint.log 2>&1 +``` + +**✅ CHECKPOINT:** All tests must pass before proceeding. + +--- + +## 1.2 Frontend Cleanup - Empty/Unused Folders + +### Files to Delete (Verified Empty/Unused) + +| Path | Reason | Verified | +|------|--------|----------| +| `frontend/src/pages/Admin/` | Empty folder | ⬜ | +| `frontend/src/pages/admin/` | Empty folder (duplicate lowercase) | ⬜ | +| `frontend/src/pages/settings/` | Empty folder (lowercase duplicate) | ⬜ | +| `frontend/src/components/debug/` | Empty debug folder | ⬜ | +| `frontend/src/components/widgets/` | Empty folder | ⬜ | +| `frontend/src/components/metrics/` | Empty folder | ⬜ | + +### Execution Steps: + +```bash +# Step 1: Verify folders are empty +cd /data/app/igny8/frontend/src + +# Check each folder before deletion +ls -la pages/Admin/ 2>/dev/null || echo "Admin/ doesn't exist or empty" +ls -la pages/admin/ 2>/dev/null || echo "admin/ doesn't exist or empty" +ls -la pages/settings/ 2>/dev/null || echo "settings/ doesn't exist or empty" +ls -la components/debug/ 2>/dev/null || echo "debug/ doesn't exist or empty" +ls -la components/widgets/ 2>/dev/null || echo "widgets/ doesn't exist or empty" +ls -la components/metrics/ 2>/dev/null || echo "metrics/ doesn't exist or empty" + +# Step 2: Remove empty folders (only if confirmed empty) +rmdir pages/Admin 2>/dev/null +rmdir pages/admin 2>/dev/null +rmdir pages/settings 2>/dev/null +rmdir components/debug 2>/dev/null +rmdir components/widgets 2>/dev/null +rmdir components/metrics 2>/dev/null +``` + +**✅ CHECKPOINT:** Run `npm run build` - must succeed. + +--- + +## 1.3 Frontend Cleanup - Template/Sample Components + +### Components to Delete (Never Used - Template/Demo Code) + +| Path | File Count | Reason | +|------|------------|--------| +| `frontend/src/components/ecommerce/` | 7 files | E-commerce template components - not used in app | +| `frontend/src/components/sample-componeents/` | 2 files | Sample HTML files with typo in folder name | +| `frontend/src/components/charts/bar/` | - | Unused bar chart template | +| `frontend/src/components/charts/line/` | - | Unused line chart template | +| `frontend/src/components/tables/BasicTables/` | - | Unused basic table template | + +### Pre-Delete Verification: + +```bash +# Search for any imports of these components +cd /data/app/igny8/frontend + +# Check ecommerce imports +grep -r "ecommerce" src/ --include="*.ts" --include="*.tsx" | grep -v "node_modules" + +# Check sample imports +grep -r "sample-componeents" src/ --include="*.ts" --include="*.tsx" + +# Check charts/bar imports +grep -r "charts/bar" src/ --include="*.ts" --include="*.tsx" + +# Check charts/line imports +grep -r "charts/line" src/ --include="*.ts" --include="*.tsx" + +# Check BasicTables imports +grep -r "BasicTables" src/ --include="*.ts" --include="*.tsx" +``` + +### Execution (Only if no imports found): + +```bash +cd /data/app/igny8/frontend/src + +# Delete unused template folders +rm -rf components/ecommerce/ +rm -rf components/sample-componeents/ +rm -rf components/charts/bar/ +rm -rf components/charts/line/ +rm -rf components/tables/BasicTables/ + +# If charts folder is now empty, remove it +rmdir components/charts 2>/dev/null || true +# If tables folder is now empty, remove it +rmdir components/tables 2>/dev/null || true +``` + +**✅ CHECKPOINT:** Run `npm run build` - must succeed. + +--- + +## 1.4 Frontend Cleanup - Deprecated Files + +### Individual Files to Delete + +| File | Reason | +|------|--------| +| `frontend/src/components/Automation/CurrentProcessingCard.old.tsx` | Old deprecated version | + +### Execution: + +```bash +# Verify no imports exist +cd /data/app/igny8/frontend +grep -r "CurrentProcessingCard.old" src/ + +# If no results, safe to delete +rm src/components/Automation/CurrentProcessingCard.old.tsx +``` + +**✅ CHECKPOINT:** Run `npm run build` - must succeed. + +--- + +## 1.5 Console.log Cleanup + +### Files with console.log statements to review: + +| File | Line(s) | Action | +|------|---------|--------| +| `src/services/api.ts` | 2010, 2015 | Review - may need for debugging | +| `src/components/UserProfile/UserMetaCard.tsx` | 11 | Remove | +| `src/components/UserProfile/UserAddressCard.tsx` | 11 | Remove | +| `src/components/UserProfile/UserInfoCard.tsx` | 11 | Remove | +| `src/components/Automation/ConfigModal.tsx` | 42 | Remove | +| `src/components/common/ImageQueueModal.tsx` | 227, 229, 239, 242, 247, 251, 259, 262 | Remove all | +| `src/components/common/ImageGenerationCard.tsx` | 107, 125, 129, 141, 142, 151, 178 | Remove all | + +### Execution Strategy: + +**Option A: Manual removal (safer)** +Edit each file and remove console.log statements manually. + +**Option B: Automated with review** +```bash +cd /data/app/igny8/frontend + +# Find all console.log in src (excluding node_modules) +grep -rn "console.log" src/ --include="*.ts" --include="*.tsx" > /tmp/console-logs.txt + +# Review the file before any automated removal +cat /tmp/console-logs.txt +``` + +### Per-File Actions: + +```typescript +// In UserMetaCard.tsx, UserAddressCard.tsx, UserInfoCard.tsx - REMOVE: +console.log("Saving changes..."); + +// In ConfigModal.tsx - REMOVE: +console.log('Saving config with delays:', dataToSave); + +// In ImageQueueModal.tsx - REMOVE ALL console.log statements + +// In ImageGenerationCard.tsx - REMOVE ALL console.log statements + +// In api.ts - KEEP or convert to proper logging (these may be useful) +``` + +**✅ CHECKPOINT:** Run `npm run build && npm run lint` - must succeed. + +--- + +## 1.6 ESLint Verification + +```bash +cd /data/app/igny8/frontend + +# Run full lint check +npm run lint + +# If errors exist, fix them: +npm run lint -- --fix +``` + +**✅ CHECKPOINT:** Zero lint errors. + +--- + +## 1.7 Post-Cleanup Verification + +```bash +# 1. Full build +cd /data/app/igny8/frontend +npm run build + +# 2. Type check +npx tsc --noEmit + +# 3. Start dev server and manually verify app loads +npm run dev +# Open http://localhost:5173 and verify: +# - Dashboard loads +# - All sidebar navigation works +# - No console errors in browser + +# 4. Commit changes +cd /data/app/igny8 +git add -A +git status # Review all changes +git commit -m "Phase 1: Code cleanup - remove unused pages, components, and console.logs" +``` + +--- + +# Phase 5: UX Improvements + +## 5.1 Pre-Implementation Setup + +### 5.1.1 Create Feature Branch +```bash +cd /data/app/igny8 +git checkout main # or your main branch +git pull +git checkout -b feature/phase-5-ux-improvements +``` + +--- + +## 5.2 Search Modal Enhancement + +### 5.2.1 Current State Analysis + +**Location:** Search functionality likely in header/navigation components + +**Research Required:** +```bash +cd /data/app/igny8/frontend + +# Find existing search component +grep -rn "search" src/components/header/ --include="*.tsx" +grep -rn "Search" src/components/ --include="*.tsx" | head -20 + +# Find search-related stores +grep -rn "search" src/store/ --include="*.ts" +``` + +### 5.2.2 Implementation Tasks + +| Task | File(s) | Details | +|------|---------|---------| +| Add keyboard shortcut | `src/components/header/Search*.tsx` | Cmd/Ctrl+K to open | +| Add search filters | Search component | Filter by type (keyword, content, site) | +| Add recent searches | Search component + localStorage | Store last 5 searches | +| Improve results display | Search results component | Show context snippets | +| Add quick actions | Search results | Quick action buttons | + +### 5.2.3 Keyboard Shortcut Implementation + +```typescript +// Add to App.tsx or a global hook +useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if ((e.metaKey || e.ctrlKey) && e.key === 'k') { + e.preventDefault(); + // Open search modal + setSearchOpen(true); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); +}, []); +``` + +### 5.2.4 Verification + +- [ ] Cmd/Ctrl+K opens search modal +- [ ] Search filters work correctly +- [ ] Recent searches persist across sessions +- [ ] Results show relevant context +- [ ] Quick actions function properly + +--- + +## 5.3 Image Regeneration Feature + +### 5.3.1 Backend Requirements + +**Check existing endpoint:** +```bash +cd /data/app/igny8/backend + +# Find image generation endpoints +grep -rn "image" igny8_core/modules/writer/ --include="*.py" | head -20 +grep -rn "regenerate" igny8_core/ --include="*.py" +``` + +**Required API endpoint (if not exists):** +``` +POST /api/v1/writer/images/{id}/regenerate/ +Body: { reason?: string, prompt_adjustment?: string } +Response: { task_id: string, status: "queued" } +``` + +### 5.3.2 Frontend Implementation + +**File: `frontend/src/pages/Writer/Images.tsx`** + +Add regenerate button to each image card: + +```typescript +// Add to image card actions +const handleRegenerate = async (imageId: number) => { + const reason = await showRegenerateModal(); + if (reason !== null) { + await api.post(`/v1/writer/images/${imageId}/regenerate/`, { reason }); + // Refresh list or show status + } +}; + +// Button in image card + +``` + +**File: `frontend/src/pages/Writer/ContentView.tsx`** + +Add regenerate for featured image: + +```typescript +// In featured image section (admin/editor only) +{(user.role === 'admin' || user.role === 'editor') && ( + +)} +``` + +### 5.3.3 Verification + +- [ ] Regenerate button appears on `/writer/images` page +- [ ] Regenerate modal prompts for reason +- [ ] API call succeeds and image regenerates +- [ ] Status updates correctly +- [ ] Featured image regenerate works in content view +- [ ] Role-based visibility works (admin/editor only) + +--- + +## 5.4 User Flow Polish + +### 5.4.1 Signup to First Content Flow Testing + +**Test Checklist:** + +| Step | URL | Verify | +|------|-----|--------| +| 1. Signup | `/signup` | Form submits, verification email sent | +| 2. Verify Email | `/verify-email?token=...` | Email verified, redirect to app | +| 3. Onboarding | `/setup/wizard` | All steps complete without errors | +| 4. Add Site | Sites → Add Site | WordPress connection successful | +| 5. Add Keywords | `/planner/keywords` | Import works, keywords appear | +| 6. Clustering | `/planner/clusters` | AI clustering completes | +| 7. Generate Content | `/writer/tasks` | Content generates successfully | +| 8. Publish | Content → Publish | Content appears on WordPress | + +### 5.4.2 Issue Documentation Template + +```markdown +## Issue: [Brief Description] + +**Step:** [Which step in flow] +**URL:** [Page URL] +**Expected:** [What should happen] +**Actual:** [What happened] +**Steps to Reproduce:** +1. ... +2. ... + +**Screenshots/Logs:** [Attach if applicable] +**Severity:** [Blocking/Major/Minor] +``` + +### 5.4.3 Post-Implementation Verification + +```bash +# Build and test +cd /data/app/igny8/frontend +npm run build +npm run lint + +# Commit +git add -A +git commit -m "Phase 5: UX improvements - search modal, image regeneration, flow polish" +``` + +--- + +# Phase 6: Data Backup & Cleanup + +## 6.1 Pre-Backup Safety Steps + +### 6.1.1 Create Backup Branch +```bash +cd /data/app/igny8 +git checkout main +git checkout -b backup/pre-v1-cleanup-$(date +%Y%m%d) +``` + +### 6.1.2 Full Database Backup +```bash +# Create backup directory +mkdir -p /data/app/igny8/backups/$(date +%Y%m%d) + +# PostgreSQL full backup +pg_dump -h localhost -U your_user -d igny8_db > /data/app/igny8/backups/$(date +%Y%m%d)/full_backup.sql + +# Verify backup +ls -la /data/app/igny8/backups/$(date +%Y%m%d)/ +head -50 /data/app/igny8/backups/$(date +%Y%m%d)/full_backup.sql +``` + +**✅ CHECKPOINT:** Backup file exists and has content. + +--- + +## 6.2 System Configuration Export + +### 6.2.1 Create Export Directory Structure +```bash +mkdir -p /data/app/igny8/backups/config +``` + +### 6.2.2 Export Django Models (System Config) + +**Create management command:** +```bash +# File: backend/igny8_core/management/commands/export_system_config.py +``` + +```python +# backend/igny8_core/management/commands/export_system_config.py +from django.core.management.base import BaseCommand +from django.core import serializers +import json +import os +from datetime import datetime + +class Command(BaseCommand): + help = 'Export system configuration data to JSON files' + + def add_arguments(self, parser): + parser.add_argument( + '--output-dir', + default='backups/config', + help='Output directory for config files' + ) + + def handle(self, *args, **options): + output_dir = options['output_dir'] + os.makedirs(output_dir, exist_ok=True) + + # Import models here to avoid circular imports + from igny8_core.modules.billing.models import Plan, CreditCostConfig + from igny8_core.modules.system.models import ( + AIModelConfig, GlobalIntegrationSettings, SystemSettings + ) + from igny8_core.auth.models import Industry, Sector, SeedKeyword + # Add other system models as needed + + exports = { + 'plans': Plan.objects.all(), + 'credit_costs': CreditCostConfig.objects.all(), + 'ai_models': AIModelConfig.objects.all(), + # 'global_integrations': GlobalIntegrationSettings.objects.all(), + # 'system_settings': SystemSettings.objects.all(), + 'industries': Industry.objects.all(), + 'sectors': Sector.objects.all(), + 'seed_keywords': SeedKeyword.objects.all(), + } + + for name, queryset in exports.items(): + try: + data = serializers.serialize('json', queryset, indent=2) + filepath = os.path.join(output_dir, f'{name}.json') + with open(filepath, 'w') as f: + f.write(data) + self.stdout.write( + self.style.SUCCESS(f'Exported {queryset.count()} {name} to {filepath}') + ) + except Exception as e: + self.stdout.write( + self.style.ERROR(f'Failed to export {name}: {str(e)}') + ) + + # Export timestamp + with open(os.path.join(output_dir, 'export_metadata.json'), 'w') as f: + json.dump({ + 'exported_at': datetime.now().isoformat(), + 'exports': list(exports.keys()) + }, f, indent=2) + + self.stdout.write(self.style.SUCCESS('System config export complete!')) +``` + +### 6.2.3 Run Export + +```bash +cd /data/app/igny8/backend + +# Run the export command +python manage.py export_system_config --output-dir=../backups/config + +# Verify exports +ls -la ../backups/config/ +``` + +**✅ CHECKPOINT:** All config JSON files exist and contain data. + +--- + +## 6.3 User Data Cleanup + +### ⚠️ DANGER ZONE - READ CAREFULLY ⚠️ + +This section PERMANENTLY DELETES user data. Ensure: +1. Full backup completed (6.1.2) +2. Config exported (6.2) +3. You are in the correct environment (NOT PRODUCTION until ready) + +### 6.3.1 Create Cleanup Management Command + +```python +# backend/igny8_core/management/commands/cleanup_user_data.py +from django.core.management.base import BaseCommand +from django.db import transaction + +class Command(BaseCommand): + help = 'Clean up all user-generated data (DESTRUCTIVE)' + + def add_arguments(self, parser): + parser.add_argument( + '--confirm', + action='store_true', + help='Confirm you want to delete all user data' + ) + parser.add_argument( + '--dry-run', + action='store_true', + help='Show what would be deleted without deleting' + ) + + def handle(self, *args, **options): + if not options['confirm'] and not options['dry_run']: + self.stdout.write( + self.style.ERROR('Must use --confirm or --dry-run flag') + ) + return + + # Import models + from igny8_core.auth.models import Site + from igny8_core.business.planning.models import Keywords, Clusters + from igny8_core.modules.writer.models import ( + ContentIdea, Task, Content, ContentImage + ) + from igny8_core.modules.publisher.models import PublishingRecord, SyncEvent + from igny8_core.modules.billing.models import CreditTransaction, CreditUsageLog + # Add other models + + models_to_clear = [ + ('Keywords', Keywords), + ('Clusters', Clusters), + ('ContentIdeas', ContentIdea), + ('Tasks', Task), + ('Content', Content), + ('ContentImages', ContentImage), + ('PublishingRecords', PublishingRecord), + ('SyncEvents', SyncEvent), + ('CreditTransactions', CreditTransaction), + ('CreditUsageLogs', CreditUsageLog), + # Sites should be last (foreign keys) + ('Sites', Site), + ] + + if options['dry_run']: + self.stdout.write(self.style.WARNING('DRY RUN - No data will be deleted')) + for name, model in models_to_clear: + count = model.objects.count() + self.stdout.write(f' Would delete {count} {name}') + return + + # Actual deletion + with transaction.atomic(): + for name, model in models_to_clear: + count = model.objects.count() + model.objects.all().delete() + self.stdout.write( + self.style.SUCCESS(f'Deleted {count} {name}') + ) + + self.stdout.write(self.style.SUCCESS('User data cleanup complete!')) +``` + +### 6.3.2 Execute Cleanup (Step by Step) + +```bash +cd /data/app/igny8/backend + +# Step 1: DRY RUN - See what will be deleted +python manage.py cleanup_user_data --dry-run + +# Step 2: Review output carefully +# - Are the counts expected? +# - Is this the right environment? + +# Step 3: ONLY if absolutely sure, run actual cleanup +python manage.py cleanup_user_data --confirm +``` + +### 6.3.3 Clear Media Storage + +```bash +# List media files first +ls -la /data/app/igny8/backend/media/ + +# Backup media if needed +cp -r /data/app/igny8/backend/media/ /data/app/igny8/backups/$(date +%Y%m%d)/media/ + +# Clear generated images (be specific about paths) +rm -rf /data/app/igny8/backend/media/generated_images/* +rm -rf /data/app/igny8/backend/media/content_images/* + +# Verify +ls -la /data/app/igny8/backend/media/ +``` + +### 6.3.4 Clear Logs + +```bash +# Backup logs first +cp -r /data/app/igny8/backend/logs/ /data/app/igny8/backups/$(date +%Y%m%d)/logs/ + +# Clear log files (keep empty files for app to write) +> /data/app/igny8/backend/logs/publish-sync-logs/*.log +> /data/app/igny8/backend/celerybeat-schedule + +# Or remove all logs +rm -f /data/app/igny8/backend/logs/**/*.log +``` + +--- + +## 6.4 Configuration Lock (V1.0) + +### 6.4.1 Document Final Configuration + +Create documentation file: + +```bash +mkdir -p /data/app/igny8/docs/90-REFERENCE/ +``` + +```markdown +# V1.0 Configuration Reference + +**Locked:** [DATE] +**Version:** 1.0.0 + +## Plans Configuration + +| Plan | Credits | Sites | Price | Interval | +|------|---------|-------|-------|----------| +| Starter | X | 1 | $X/mo | monthly | +| Growth | X | 3 | $X/mo | monthly | +| Scale | X | 10 | $X/mo | monthly | + +## Credit Costs + +| Operation | Cost | +|-----------|------| +| Basic Image | 1 credit | +| Quality Image | 5 credits | +| Premium Image | 15 credits | +| Clustering | Token-based | +| Content Generation | Token-based | + +## AI Model Configurations + +[Document all AI model settings] + +--- + +**CHANGE POLICY:** Any changes require version bump and documented release. +``` + +### 6.4.2 Git Tag for V1.0 + +```bash +cd /data/app/igny8 + +# Ensure all changes committed +git status +git add -A +git commit -m "Phase 6: Pre-launch cleanup complete" + +# Create annotated tag +git tag -a v1.0.0 -m "IGNY8 V1.0.0 - Production Release" + +# Push tag +git push origin v1.0.0 +``` + +--- + +## 6.5 Post-Cleanup Verification + +### 6.5.1 Database Verification + +```bash +cd /data/app/igny8/backend + +# Run Django check +python manage.py check + +# Verify system config still exists +python manage.py shell << 'EOF' +from igny8_core.modules.billing.models import Plan +from igny8_core.auth.models import Industry, Sector +print(f"Plans: {Plan.objects.count()}") +print(f"Industries: {Industry.objects.count()}") +print(f"Sectors: {Sector.objects.count()}") +EOF + +# Verify user data cleared +python manage.py shell << 'EOF' +from igny8_core.auth.models import Site +from igny8_core.business.planning.models import Keywords +print(f"Sites: {Site.objects.count()}") +print(f"Keywords: {Keywords.objects.count()}") +EOF +``` + +### 6.5.2 Application Verification + +```bash +# Start backend +cd /data/app/igny8/backend +python manage.py runserver & + +# Start frontend +cd /data/app/igny8/frontend +npm run dev & + +# Manual checks: +# 1. Can login as admin +# 2. Dashboard loads (empty state) +# 3. Plans visible in settings +# 4. Can create new user account +# 5. Onboarding flow works +``` + +--- + +# Execution Checklist + +## Phase 1 Checklist + +- [ ] Created safety branch +- [ ] Ran baseline tests (all pass) +- [ ] Deleted empty folders (6 folders) +- [ ] Build succeeds after empty folder deletion +- [ ] Deleted template/sample components (ecommerce, sample-componeents, charts, tables) +- [ ] Build succeeds after template deletion +- [ ] Deleted `CurrentProcessingCard.old.tsx` +- [ ] Removed console.log statements (reviewed each) +- [ ] ESLint passes with zero errors +- [ ] TypeScript compiles without errors +- [ ] Manual app verification complete +- [ ] Changes committed + +## Phase 5 Checklist + +- [ ] Created feature branch +- [ ] Researched existing search implementation +- [ ] Implemented keyboard shortcut (Cmd/Ctrl+K) +- [ ] Added search filters +- [ ] Added recent searches +- [ ] Improved results display +- [ ] Added image regenerate to `/writer/images` +- [ ] Added featured image regenerate to content view +- [ ] Backend endpoint created/verified +- [ ] Role-based visibility works +- [ ] Tested full signup-to-publish flow +- [ ] Documented any issues found +- [ ] Changes committed + +## Phase 6 Checklist + +- [ ] Created backup branch +- [ ] Full database backup created +- [ ] Backup file verified (has content) +- [ ] Created export_system_config command +- [ ] Exported all system config (plans, industries, etc.) +- [ ] Config files verified (JSON valid) +- [ ] Created cleanup_user_data command +- [ ] Ran dry-run cleanup (reviewed counts) +- [ ] **CONFIRMED correct environment** +- [ ] Executed user data cleanup +- [ ] Cleared media storage +- [ ] Backed up and cleared logs +- [ ] Created V1.0 config documentation +- [ ] Created git tag v1.0.0 +- [ ] Verified system config still exists +- [ ] Verified user data cleared +- [ ] Application starts and functions + +--- + +## Rollback Procedures + +### Phase 1 Rollback +```bash +git checkout main +git branch -D cleanup/phase-1-* +``` + +### Phase 5 Rollback +```bash +git checkout main +git branch -D feature/phase-5-ux-improvements +``` + +### Phase 6 Rollback (Database) +```bash +# Restore from backup +psql -h localhost -U your_user -d igny8_db < /data/app/igny8/backups/YYYYMMDD/full_backup.sql + +# Restore media +cp -r /data/app/igny8/backups/YYYYMMDD/media/* /data/app/igny8/backend/media/ +``` + +--- + +**Document Owner:** IGNY8 Team +**Review:** Before each phase execution +**Approval Required:** Phase 6 cleanup requires explicit approval diff --git a/frontend/src/components/Automation/ConfigModal.tsx b/frontend/src/components/Automation/ConfigModal.tsx index fbdd95fb..458c27b2 100644 --- a/frontend/src/components/Automation/ConfigModal.tsx +++ b/frontend/src/components/Automation/ConfigModal.tsx @@ -39,7 +39,6 @@ const ConfigModal: React.FC = ({ config, onSave, onCancel }) = within_stage_delay: formData.within_stage_delay || 3, between_stage_delay: formData.between_stage_delay || 5, }; - console.log('Saving config with delays:', dataToSave); onSave(dataToSave); }; diff --git a/frontend/src/components/Automation/CurrentProcessingCard.old.tsx b/frontend/src/components/Automation/CurrentProcessingCard.old.tsx deleted file mode 100644 index fea9834d..00000000 --- a/frontend/src/components/Automation/CurrentProcessingCard.old.tsx +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Current Processing Card Component - * Shows real-time automation progress with currently processing items - */ -import React, { useEffect, useState } from 'react'; -import { automationService, ProcessingState } from '../../services/automationService'; - -interface CurrentProcessingCardProps { - runId: string; - siteId: number; - currentStage: number; - onComplete?: () => void; -} - -const CurrentProcessingCard: React.FC = ({ - runId, - siteId, - currentStage, - onComplete, -}) => { - const [processingState, setProcessingState] = useState(null); - const [error, setError] = useState(null); - - useEffect(() => { - let isMounted = true; - - const fetchState = async () => { - try { - const state = await automationService.getCurrentProcessing(siteId, runId); - - if (!isMounted) return; - - setProcessingState(state); - setError(null); - - // If stage completed (all items processed), trigger refresh - if (state && state.processed_items >= state.total_items && state.total_items > 0) { - onComplete?.(); - } - } catch (err) { - if (!isMounted) return; - console.error('Error fetching processing state:', err); - setError('Failed to load processing state'); - } - }; - - // Initial fetch - fetchState(); - - // Poll every 3 seconds - const interval = setInterval(fetchState, 3000); - - return () => { - isMounted = false; - clearInterval(interval); - }; - }, [siteId, runId, onComplete]); - - if (error) { - return ( -
-

{error}

-
- ); - } - - if (!processingState) { - return null; - } - - const percentage = processingState.percentage; - - return ( -
- {/* Header */} -
-
-
- - - -
-
-

- Automation In Progress -

-

- Stage {currentStage}: {processingState.stage_name} - - {processingState.stage_type} - -

-
-
-
-
- {percentage}% -
-
- {processingState.processed_items}/{processingState.total_items} processed -
-
-
- - {/* Progress Bar */} -
-
-
-
-
- - {/* Currently Processing and Up Next */} -
- {/* Currently Processing */} -
-

- Currently Processing: -

-
- {processingState.currently_processing.length > 0 ? ( - processingState.currently_processing.map((item, idx) => ( -
- - - {item.title} - -
- )) - ) : ( -
- No items currently processing -
- )} -
-
- - {/* Up Next */} -
-

- Up Next: -

-
- {processingState.up_next.length > 0 ? ( - <> - {processingState.up_next.map((item, idx) => ( -
- - - {item.title} - -
- ))} - {processingState.remaining_count > processingState.up_next.length + processingState.currently_processing.length && ( -
- + {processingState.remaining_count - processingState.up_next.length - processingState.currently_processing.length} more in queue -
- )} - - ) : ( -
- Queue empty -
- )} -
-
-
-
- ); -}; - -export default CurrentProcessingCard; diff --git a/frontend/src/components/UserProfile/UserAddressCard.tsx b/frontend/src/components/UserProfile/UserAddressCard.tsx index 55da4b6a..17452197 100644 --- a/frontend/src/components/UserProfile/UserAddressCard.tsx +++ b/frontend/src/components/UserProfile/UserAddressCard.tsx @@ -8,7 +8,6 @@ export default function UserAddressCard() { const { isOpen, openModal, closeModal } = useModal(); const handleSave = () => { // Handle save logic here - console.log("Saving changes..."); closeModal(); }; return ( diff --git a/frontend/src/components/UserProfile/UserInfoCard.tsx b/frontend/src/components/UserProfile/UserInfoCard.tsx index a431d218..7e666f00 100644 --- a/frontend/src/components/UserProfile/UserInfoCard.tsx +++ b/frontend/src/components/UserProfile/UserInfoCard.tsx @@ -8,7 +8,6 @@ export default function UserInfoCard() { const { isOpen, openModal, closeModal } = useModal(); const handleSave = () => { // Handle save logic here - console.log("Saving changes..."); closeModal(); }; return ( diff --git a/frontend/src/components/UserProfile/UserMetaCard.tsx b/frontend/src/components/UserProfile/UserMetaCard.tsx index 3f38a1ce..f53f8ce6 100644 --- a/frontend/src/components/UserProfile/UserMetaCard.tsx +++ b/frontend/src/components/UserProfile/UserMetaCard.tsx @@ -8,7 +8,6 @@ export default function UserMetaCard() { const { isOpen, openModal, closeModal } = useModal(); const handleSave = () => { // Handle save logic here - console.log("Saving changes..."); closeModal(); }; return ( diff --git a/frontend/src/components/billing/UsageLimitsPanel.tsx b/frontend/src/components/billing/UsageLimitsPanel.tsx index 681eaad9..e72764cc 100644 --- a/frontend/src/components/billing/UsageLimitsPanel.tsx +++ b/frontend/src/components/billing/UsageLimitsPanel.tsx @@ -26,7 +26,7 @@ function LimitCard({ title, icon, usage, type, daysUntilReset, accentColor = 'br // Determine progress bar color - use inline styles for dynamic colors let barColor = 'var(--color-brand-500)'; - let badgeVariant: 'soft' = 'soft'; + const badgeVariant: 'soft' = 'soft'; let badgeTone: 'brand' | 'warning' | 'danger' | 'success' | 'info' | 'purple' | 'indigo' | 'pink' | 'teal' | 'cyan' = accentColor; // Color mapping for progress bars - using CSS variables diff --git a/frontend/src/components/charts/bar/BarChartOne.tsx b/frontend/src/components/charts/bar/BarChartOne.tsx deleted file mode 100644 index f818f951..00000000 --- a/frontend/src/components/charts/bar/BarChartOne.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import Chart from "react-apexcharts"; -import { ApexOptions } from "apexcharts"; - -export default function BarChartOne() { - const options: ApexOptions = { - colors: ["var(--color-primary)"], - chart: { - fontFamily: "Outfit, sans-serif", - type: "bar", - height: 180, - toolbar: { - show: false, - }, - }, - plotOptions: { - bar: { - horizontal: false, - columnWidth: "39%", - borderRadius: 5, - borderRadiusApplication: "end", - }, - }, - dataLabels: { - enabled: false, - }, - stroke: { - show: true, - width: 4, - colors: ["transparent"], - }, - xaxis: { - categories: [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ], - axisBorder: { - show: false, - }, - axisTicks: { - show: false, - }, - }, - legend: { - show: true, - position: "top", - horizontalAlign: "left", - fontFamily: "Outfit", - }, - yaxis: { - title: { - text: undefined, - }, - }, - grid: { - yaxis: { - lines: { - show: true, - }, - }, - }, - fill: { - opacity: 1, - }, - - tooltip: { - x: { - show: false, - }, - y: { - formatter: (val: number) => `${val}`, - }, - }, - }; - const series = [ - { - name: "Sales", - data: [168, 385, 201, 298, 187, 195, 291, 110, 215, 390, 280, 112], - }, - ]; - return ( -
-
- -
-
- ); -} diff --git a/frontend/src/components/charts/line/LineChartOne.tsx b/frontend/src/components/charts/line/LineChartOne.tsx deleted file mode 100644 index 6321c43a..00000000 --- a/frontend/src/components/charts/line/LineChartOne.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import Chart from "react-apexcharts"; -import { ApexOptions } from "apexcharts"; - -export default function LineChartOne() { - const options: ApexOptions = { - legend: { - show: false, // Hide legend - position: "top", - horizontalAlign: "left", - }, - colors: ["var(--color-primary)", "var(--color-brand-300)"], // Define line colors - chart: { - fontFamily: "Outfit, sans-serif", - height: 310, - type: "line", // Set the chart type to 'line' - toolbar: { - show: false, // Hide chart toolbar - }, - }, - stroke: { - curve: "straight", // Define the line style (straight, smooth, or step) - width: [2, 2], // Line width for each dataset - }, - - fill: { - type: "gradient", - gradient: { - opacityFrom: 0.55, - opacityTo: 0, - }, - }, - markers: { - size: 0, // Size of the marker points - strokeColors: "#fff", // Marker border color - strokeWidth: 2, - hover: { - size: 6, // Marker size on hover - }, - }, - grid: { - xaxis: { - lines: { - show: false, // Hide grid lines on x-axis - }, - }, - yaxis: { - lines: { - show: true, // Show grid lines on y-axis - }, - }, - }, - dataLabels: { - enabled: false, // Disable data labels - }, - tooltip: { - enabled: true, // Enable tooltip - x: { - format: "dd MMM yyyy", // Format for x-axis tooltip - }, - }, - xaxis: { - type: "category", // Category-based x-axis - categories: [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ], - axisBorder: { - show: false, // Hide x-axis border - }, - axisTicks: { - show: false, // Hide x-axis ticks - }, - tooltip: { - enabled: false, // Disable tooltip for x-axis points - }, - }, - yaxis: { - labels: { - style: { - fontSize: "12px", // Adjust font size for y-axis labels - colors: ["var(--color-gray-500)"], // Color of the labels - }, - }, - title: { - text: "", // Remove y-axis title - style: { - fontSize: "0px", - }, - }, - }, - }; - - const series = [ - { - name: "Sales", - data: [180, 190, 170, 160, 175, 165, 170, 205, 230, 210, 240, 235], - }, - { - name: "Revenue", - data: [40, 30, 50, 40, 55, 40, 70, 100, 110, 120, 150, 140], - }, - ]; - return ( -
-
- -
-
- ); -} diff --git a/frontend/src/components/common/ImageGenerationCard.tsx b/frontend/src/components/common/ImageGenerationCard.tsx index d07f7b2b..dc46fe3f 100644 --- a/frontend/src/components/common/ImageGenerationCard.tsx +++ b/frontend/src/components/common/ImageGenerationCard.tsx @@ -104,8 +104,6 @@ export default function ImageGenerationCard({ }, [API_BASE_URL]); const handleGenerate = async () => { - console.log('[ImageGenerationCard] handleGenerate called'); - if (!prompt.trim()) { toast.error('Please enter a prompt description'); return; @@ -122,11 +120,8 @@ export default function ImageGenerationCard({ ? (imageSettings.model || 'dall-e-3') : (imageSettings.runwareModel || 'runware:97@1'); - console.log('[ImageGenerationCard] Service and model:', { service, model, imageSettings }); - // Build prompt with template (similar to reference plugin) const fullPrompt = `Create a high-quality ${imageType} image. ${prompt}`; - console.log('[ImageGenerationCard] Full prompt:', fullPrompt.substring(0, 100) + '...'); const requestBody = { prompt: fullPrompt, @@ -138,9 +133,6 @@ export default function ImageGenerationCard({ model: model, }; - console.log('[ImageGenerationCard] Making request to image generation endpoint'); - console.log('[ImageGenerationCard] Request body:', requestBody); - // fetchAPI extracts data from unified format {success: true, data: {...}} // So data is the extracted response payload const data = await fetchAPI('/v1/system/settings/integrations/image_generation/generate/', { @@ -148,8 +140,6 @@ export default function ImageGenerationCard({ body: JSON.stringify(requestBody), }); - console.log('[ImageGenerationCard] Response data:', data); - // fetchAPI extracts data from unified format, so data is the response payload // If fetchAPI didn't throw, the request was successful if (!data || typeof data !== 'object') { @@ -175,7 +165,6 @@ export default function ImageGenerationCard({ }) ); - console.log('[ImageGenerationCard] Image generation successful:', imageData); toast.success('Image generated successfully!'); } catch (err: any) { console.error('[ImageGenerationCard] Error in handleGenerate:', { diff --git a/frontend/src/components/common/ImageQueueModal.tsx b/frontend/src/components/common/ImageQueueModal.tsx index f18af1d8..85509488 100644 --- a/frontend/src/components/common/ImageQueueModal.tsx +++ b/frontend/src/components/common/ImageQueueModal.tsx @@ -218,37 +218,29 @@ export default function ImageQueueModal({ // Stop polling after max attempts if (pollAttempts > maxPollAttempts) { - console.warn('Polling timeout reached, stopping'); clearInterval(pollInterval); return; } try { - console.log(`[ImageQueueModal] Polling task status (attempt ${pollAttempts}):`, taskId); const data = await fetchAPI(`/v1/system/settings/task_progress/${taskId}/`); - console.log(`[ImageQueueModal] Task status response:`, data); // Check if data is valid (not HTML error page) if (!data || typeof data !== 'object') { - console.warn('Invalid task status response:', data); return; } // Check state (task_progress returns 'state', not 'status') const taskState = data.state || data.status; - console.log(`[ImageQueueModal] Task state:`, taskState); if (taskState === 'SUCCESS' || taskState === 'FAILURE') { - console.log(`[ImageQueueModal] Task completed with state:`, taskState); clearInterval(pollInterval); // Update final state if (taskState === 'SUCCESS' && data.result) { - console.log(`[ImageQueueModal] Updating queue from result:`, data.result); updateQueueFromTaskResult(data.result); } else if (taskState === 'SUCCESS' && data.meta && data.meta.result) { // Some responses have result in meta - console.log(`[ImageQueueModal] Updating queue from meta result:`, data.meta.result); updateQueueFromTaskResult(data.meta.result); } return; @@ -256,10 +248,7 @@ export default function ImageQueueModal({ // Update progress from task meta if (data.meta) { - console.log(`[ImageQueueModal] Updating queue from meta:`, data.meta); updateQueueFromTaskMeta(data.meta); - } else { - console.log(`[ImageQueueModal] No meta data in response`); } } catch (error: any) { // Check if it's a JSON parse error (HTML response) or API error diff --git a/frontend/src/components/ecommerce/CountryMap.tsx b/frontend/src/components/ecommerce/CountryMap.tsx deleted file mode 100644 index 9f838412..00000000 --- a/frontend/src/components/ecommerce/CountryMap.tsx +++ /dev/null @@ -1,94 +0,0 @@ -// react plugin for creating vector maps -import { VectorMap } from "@react-jvectormap/core"; -import { worldMill } from "@react-jvectormap/world"; - -// Define the component props -interface CountryMapProps { - mapColor?: string; -} - -const CountryMap: React.FC = ({ mapColor }) => { - return ( - - ); -}; - -export default CountryMap; diff --git a/frontend/src/components/ecommerce/DemographicCard.tsx b/frontend/src/components/ecommerce/DemographicCard.tsx deleted file mode 100644 index 4070f34b..00000000 --- a/frontend/src/components/ecommerce/DemographicCard.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { useState } from "react"; -import { Dropdown } from "../ui/dropdown/Dropdown"; -import { DropdownItem } from "../ui/dropdown/DropdownItem"; -import { MoreDotIcon } from "../../icons"; -import CountryMap from "./CountryMap"; -import IconButton from "../ui/button/IconButton"; - -export default function DemographicCard() { - const [isOpen, setIsOpen] = useState(false); - - function toggleDropdown() { - setIsOpen(!isOpen); - } - - function closeDropdown() { - setIsOpen(false); - } - return ( -
-
-
-

- Customers Demographic -

-

- Number of customer based on country -

-
-
- } /> - - - View More - - - Delete - - -
-
-
-
- -
-
- -
-
-
-
- usa -
-
-

- USA -

- - 2,379 Customers - -
-
- -
-
-
-
-

- 79% -

-
-
- -
-
-
- france -
-
-

- France -

- - 589 Customers - -
-
- -
-
-
-
-

- 23% -

-
-
-
-
- ); -} diff --git a/frontend/src/components/ecommerce/EcommerceMetrics.tsx b/frontend/src/components/ecommerce/EcommerceMetrics.tsx deleted file mode 100644 index 9d4f1a8b..00000000 --- a/frontend/src/components/ecommerce/EcommerceMetrics.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { - ArrowDownIcon, - ArrowUpIcon, - BoxIconLine, - GroupIcon, -} from "../../icons"; -import Badge from "../ui/badge/Badge"; - -export default function EcommerceMetrics() { - return ( -
- {/* */} -
-
- -
- -
-
- - Customers - -

- 3,782 -

-
- - - 11.01% - -
-
- {/* */} - - {/* */} -
-
- -
-
-
- - Orders - -

- 5,359 -

-
- - - - 9.05% - -
-
- {/* */} -
- ); -} diff --git a/frontend/src/components/ecommerce/MonthlySalesChart.tsx b/frontend/src/components/ecommerce/MonthlySalesChart.tsx deleted file mode 100644 index 95faa83f..00000000 --- a/frontend/src/components/ecommerce/MonthlySalesChart.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import Chart from "react-apexcharts"; -import { ApexOptions } from "apexcharts"; -import { Dropdown } from "../ui/dropdown/Dropdown"; -import { DropdownItem } from "../ui/dropdown/DropdownItem"; -import { MoreDotIcon } from "../../icons"; -import { useState } from "react"; -import IconButton from "../ui/button/IconButton"; - -export default function MonthlySalesChart() { - const options: ApexOptions = { - colors: ["var(--color-primary)"], - chart: { - fontFamily: "Outfit, sans-serif", - type: "bar", - height: 180, - toolbar: { - show: false, - }, - }, - plotOptions: { - bar: { - horizontal: false, - columnWidth: "39%", - borderRadius: 5, - borderRadiusApplication: "end", - }, - }, - dataLabels: { - enabled: false, - }, - stroke: { - show: true, - width: 4, - colors: ["transparent"], - }, - xaxis: { - categories: [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ], - axisBorder: { - show: false, - }, - axisTicks: { - show: false, - }, - }, - legend: { - show: true, - position: "top", - horizontalAlign: "left", - fontFamily: "Outfit", - }, - yaxis: { - title: { - text: undefined, - }, - }, - grid: { - yaxis: { - lines: { - show: true, - }, - }, - }, - fill: { - opacity: 1, - }, - - tooltip: { - x: { - show: false, - }, - y: { - formatter: (val: number) => `${val}`, - }, - }, - }; - const series = [ - { - name: "Sales", - data: [168, 385, 201, 298, 187, 195, 291, 110, 215, 390, 280, 112], - }, - ]; - const [isOpen, setIsOpen] = useState(false); - - function toggleDropdown() { - setIsOpen(!isOpen); - } - - function closeDropdown() { - setIsOpen(false); - } - return ( -
-
-

- Monthly Sales -

-
- } /> - - - View More - - - Delete - - -
-
- -
-
- -
-
-
- ); -} diff --git a/frontend/src/components/ecommerce/MonthlyTarget.tsx b/frontend/src/components/ecommerce/MonthlyTarget.tsx deleted file mode 100644 index 9077738e..00000000 --- a/frontend/src/components/ecommerce/MonthlyTarget.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import Chart from "react-apexcharts"; -import { ApexOptions } from "apexcharts"; -import { useState } from "react"; -import { Dropdown } from "../ui/dropdown/Dropdown"; -import { DropdownItem } from "../ui/dropdown/DropdownItem"; -import { MoreDotIcon } from "../../icons"; -import IconButton from "../ui/button/IconButton"; - -export default function MonthlyTarget() { - const series = [75.55]; - const options: ApexOptions = { - colors: ["var(--color-primary)"], - chart: { - fontFamily: "Outfit, sans-serif", - type: "radialBar", - height: 330, - sparkline: { - enabled: true, - }, - }, - plotOptions: { - radialBar: { - startAngle: -85, - endAngle: 85, - hollow: { - size: "80%", - }, - track: { - background: "var(--color-gray-200)", - strokeWidth: "100%", - margin: 5, // margin is in pixels - }, - dataLabels: { - name: { - show: false, - }, - value: { - fontSize: "36px", - fontWeight: "600", - offsetY: -40, - color: "var(--color-gray-800)", - formatter: function (val) { - return val + "%"; - }, - }, - }, - }, - }, - fill: { - type: "solid", - colors: ["var(--color-primary)"], - }, - stroke: { - lineCap: "round", - }, - labels: ["Progress"], - }; - const [isOpen, setIsOpen] = useState(false); - - function toggleDropdown() { - setIsOpen(!isOpen); - } - - function closeDropdown() { - setIsOpen(false); - } - return ( -
-
-
-
-

- Monthly Target -

-

- Target you’ve set for each month -

-
-
- } /> - - - View More - - - Delete - - -
-
-
-
- -
- - - +10% - -
-

- You earn $3287 today, it's higher than last month. Keep up your good - work! -

-
- -
-
-

- Target -

-

- $20K - - - -

-
- -
- -
-

- Revenue -

-

- $20K - - - -

-
- -
- -
-

- Today -

-

- $20K - - - -

-
-
-
- ); -} diff --git a/frontend/src/components/ecommerce/RecentOrders.tsx b/frontend/src/components/ecommerce/RecentOrders.tsx deleted file mode 100644 index d98ad20d..00000000 --- a/frontend/src/components/ecommerce/RecentOrders.tsx +++ /dev/null @@ -1,209 +0,0 @@ -import { - Table, - TableBody, - TableCell, - TableHeader, - TableRow, -} from "../ui/table"; -import Badge from "../ui/badge/Badge"; -import Button from "../ui/button/Button"; - -// Define the TypeScript interface for the table rows -interface Product { - id: number; // Unique identifier for each product - name: string; // Product name - variants: string; // Number of variants (e.g., "1 Variant", "2 Variants") - category: string; // Category of the product - price: string; // Price of the product (as a string with currency symbol) - // status: string; // Status of the product - image: string; // URL or path to the product image - status: "Delivered" | "Pending" | "Canceled"; // Status of the product -} - -// Define the table data using the interface -const tableData: Product[] = [ - { - id: 1, - name: "MacBook Pro 13”", - variants: "2 Variants", - category: "Laptop", - price: "$2399.00", - status: "Delivered", - image: "/images/product/product-01.jpg", // Replace with actual image URL - }, - { - id: 2, - name: "Apple Watch Ultra", - variants: "1 Variant", - category: "Watch", - price: "$879.00", - status: "Pending", - image: "/images/product/product-02.jpg", // Replace with actual image URL - }, - { - id: 3, - name: "iPhone 15 Pro Max", - variants: "2 Variants", - category: "SmartPhone", - price: "$1869.00", - status: "Delivered", - image: "/images/product/product-03.jpg", // Replace with actual image URL - }, - { - id: 4, - name: "iPad Pro 3rd Gen", - variants: "2 Variants", - category: "Electronics", - price: "$1699.00", - status: "Canceled", - image: "/images/product/product-04.jpg", // Replace with actual image URL - }, - { - id: 5, - name: "AirPods Pro 2nd Gen", - variants: "1 Variant", - category: "Accessories", - price: "$240.00", - status: "Delivered", - image: "/images/product/product-05.jpg", // Replace with actual image URL - }, -]; - -export default function RecentOrders() { - return ( -
-
-
-

- Recent Orders -

-
- -
- - -
-
-
- - {/* Table Header */} - - - - Products - - - Category - - - Price - - - Status - - - - - {/* Table Body */} - - - {tableData.map((product) => ( - - -
-
- {product.name} -
-
-

- {product.name} -

- - {product.variants} - -
-
-
- - {product.price} - - - {product.category} - - - - {product.status} - - -
- ))} -
-
-
-
- ); -} diff --git a/frontend/src/components/ecommerce/StatisticsChart.tsx b/frontend/src/components/ecommerce/StatisticsChart.tsx deleted file mode 100644 index c169853e..00000000 --- a/frontend/src/components/ecommerce/StatisticsChart.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import Chart from "react-apexcharts"; -import { ApexOptions } from "apexcharts"; -import ChartTab from "../common/ChartTab"; - -export default function StatisticsChart() { - const options: ApexOptions = { - legend: { - show: false, // Hide legend - position: "top", - horizontalAlign: "left", - }, - colors: ["var(--color-primary)", "var(--color-brand-300)"], // Define line colors - chart: { - fontFamily: "Outfit, sans-serif", - height: 310, - type: "line", // Set the chart type to 'line' - toolbar: { - show: false, // Hide chart toolbar - }, - }, - stroke: { - curve: "straight", // Define the line style (straight, smooth, or step) - width: [2, 2], // Line width for each dataset - }, - - fill: { - type: "gradient", - gradient: { - opacityFrom: 0.55, - opacityTo: 0, - }, - }, - markers: { - size: 0, // Size of the marker points - strokeColors: "#fff", // Marker border color - strokeWidth: 2, - hover: { - size: 6, // Marker size on hover - }, - }, - grid: { - xaxis: { - lines: { - show: false, // Hide grid lines on x-axis - }, - }, - yaxis: { - lines: { - show: true, // Show grid lines on y-axis - }, - }, - }, - dataLabels: { - enabled: false, // Disable data labels - }, - tooltip: { - enabled: true, // Enable tooltip - x: { - format: "dd MMM yyyy", // Format for x-axis tooltip - }, - }, - xaxis: { - type: "category", // Category-based x-axis - categories: [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ], - axisBorder: { - show: false, // Hide x-axis border - }, - axisTicks: { - show: false, // Hide x-axis ticks - }, - tooltip: { - enabled: false, // Disable tooltip for x-axis points - }, - }, - yaxis: { - labels: { - style: { - fontSize: "12px", // Adjust font size for y-axis labels - colors: ["var(--color-gray-500)"], // Color of the labels - }, - }, - title: { - text: "", // Remove y-axis title - style: { - fontSize: "0px", - }, - }, - }, - }; - - const series = [ - { - name: "Sales", - data: [180, 190, 170, 160, 175, 165, 170, 205, 230, 210, 240, 235], - }, - { - name: "Revenue", - data: [40, 30, 50, 40, 55, 40, 70, 100, 110, 120, 150, 140], - }, - ]; - return ( -
-
-
-

- Statistics -

-

- Target you’ve set for each month -

-
-
- -
-
- -
-
- -
-
-
- ); -} diff --git a/frontend/src/components/sample-componeents/kanban-sample-with-ready-touse-classes.html b/frontend/src/components/sample-componeents/kanban-sample-with-ready-touse-classes.html deleted file mode 100644 index 9763b1ee..00000000 --- a/frontend/src/components/sample-componeents/kanban-sample-with-ready-touse-classes.html +++ /dev/null @@ -1,546 +0,0 @@ -
- -
-
-
- - - - - - - -
- -
- - - -
-
-
- - - -
- -
-
-

- To Do - - 3 - -

- -
- - -
-
- - -
-
-
-

- Finish user onboarding -

- -
- - - - - Tomorrow - - - - - - - - 1 - -
-
- -
- user -
-
-
- - -
-
-
-

- Solve the Dribbble prioritisation issue with the team -

- -
- - - - - Jan 8, 2027 - - - - - - - - 2 - - - - - - - - 1 - -
- - - Marketing - -
- -
- user -
-
-
- - -
-
-
-

- Change license and remove products -

- -
- - - - - Jan 8, 2027 - -
- - - Dev - -
- -
- user -
-
-
-
- - -
-
-

- In Progress - - 5 - -

- -
- - -
-
- - -
-
-
-

- Work In Progress (WIP) Dashboard -

- -
- - - - - Today - - - - - - - - 1 - -
-
- -
- user -
-
-
- - -
-
-
-

- Kanban Flow Manager -

- -
- - - - - Feb 12, 2027 - - - - - - - - 8 - - - - - - - - 2 - -
- - - Template - -
- -
- user -
-
-
- - -
-
-

- Product Update - Q4 2024 -

- -

- Dedicated form for a category of users that will perform - actions. -

- -
- task -
- -
-
- - - - - Feb 12, 2027 - - - - - - - - 8 - -
- -
- user -
-
-
-
- - -
-
-
-

- Make figbot send comment when ticket is auto-moved - back to inbox -

- -
- - - - - Mar 08, 2027 - - - - - - - - 1 - -
-
- -
- user -
-
-
-
- - -
-
-

- Completed - - 4 - -

- -
- - -
-
- - -
-
-
-

- Manage internal feedback -

- -
- - - - - Tomorrow - - - - - - - - 1 - -
-
- -
- user -
-
-
- - -
-
-
-

- Do some projects on React Native with Flutter -

- -
- - - - - Jan 8, 2027 - -
- - - Development - -
- -
- user -
-
-
- - -
-
-
-

- Design marketing assets -

- -
- - - - - Jan 8, 2027 - - - - - - - - 2 - - - - - - - - 1 - -
- - - Marketing - -
- -
- user -
-
-
- - -
-
-
-

- Kanban Flow Manager -

- -
- - - - - Feb 12, 2027 - - - - - - - - 8 - -
- - - Template - -
- -
- user -
-
-
-
-
- -
\ No newline at end of file diff --git a/frontend/src/components/sample-componeents/tasks-list-sample.html b/frontend/src/components/sample-componeents/tasks-list-sample.html deleted file mode 100644 index ded288db..00000000 --- a/frontend/src/components/sample-componeents/tasks-list-sample.html +++ /dev/null @@ -1,788 +0,0 @@ -
- -
-
-
- - - - - - - -
- -
- - - -
-
-
- - - -
- -
-
-

- To Do - - 3 - -

- -
- - -
-
- - -
-
-
- - - - - - - -
- -
- - Marketing - - -
-
- - - - - Tomorrow - - - - - - - - 1 - -
- -
- user -
-
-
-
-
- - -
-
-
- - - - - - - -
- -
-
-
- - - - - Jan 8, 2027 - - - - - - - - 2 - - - - - - - - 1 - -
- -
- user -
-
-
-
-
- - -
-
-
- - - - - - - -
- -
- - Marketing - - -
-
- - - - - Feb 12, 2027 - - - - - - - - 1 - -
- -
- user -
-
-
-
-
-
- - -
-
-

- In Progress - - 4 - -

- -
- - -
-
- - -
-
-
- - - - - - - -
- -
-
-
- - - - - Today - - - - - - - - 1 - -
- -
- user -
-
-
-
-
- - -
-
-
- - - - - - - -
- -
- - Template - - -
-
- - - - - Feb 12, 2027 - - - - - - - - 8 - - - - - - - - 2 - -
- -
- user -
-
-
-
-
- - -
-
-
- - - - - - - -
- -
-
-
- - - - - Feb 12, 2027 - - - - - - - - 8 - -
- -
- user -
-
-
-
-
- - -
-
-
- - - - - - - -
- -
-
-
- - - - - Mar 08, 2027 - - - - - - - - 1 - -
- -
- user -
-
-
-
-
-
- - -
-
-

- Completed - - 4 - -

- -
- - -
-
- - -
-
-
- - - - - - - -
- -
-
-
- - - - - Tomorrow - - - - - - - - 1 - -
- -
- user -
-
-
-
-
- - -
-
-
- - - - - - - -
- -
- - Development - - -
-
- - - - - Jan 8, 2027 - -
- -
- user -
-
-
-
-
- - -
-
-
- - - - - - - -
- -
- - Marketing - - -
-
- - - - - Jan 8, 2027 - - - - - - - - 2 - - - - - - - - 1 - -
- -
- user -
-
-
-
-
- - -
-
-
- - - - - - - -
- -
- - Template - - -
-
- - - - - Feb 12, 2027 - - - - - - - - 8 - -
- -
- user -
-
-
-
-
-
-
- -
\ No newline at end of file diff --git a/frontend/src/components/tables/BasicTables/BasicTableOne.tsx b/frontend/src/components/tables/BasicTables/BasicTableOne.tsx deleted file mode 100644 index 9e7c4576..00000000 --- a/frontend/src/components/tables/BasicTables/BasicTableOne.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import { - Table, - TableBody, - TableCell, - TableHeader, - TableRow, -} from "../../ui/table"; - -import Badge from "../../ui/badge/Badge"; - -interface Order { - id: number; - user: { - image: string; - name: string; - role: string; - }; - projectName: string; - team: { - images: string[]; - }; - status: string; - budget: string; -} - -// Define the table data using the interface -const tableData: Order[] = [ - { - id: 1, - user: { - image: "/images/user/user-17.jpg", - name: "Lindsey Curtis", - role: "Web Designer", - }, - projectName: "Agency Website", - team: { - images: [ - "/images/user/user-22.jpg", - "/images/user/user-23.jpg", - "/images/user/user-24.jpg", - ], - }, - budget: "3.9K", - status: "Active", - }, - { - id: 2, - user: { - image: "/images/user/user-18.jpg", - name: "Kaiya George", - role: "Project Manager", - }, - projectName: "Technology", - team: { - images: ["/images/user/user-25.jpg", "/images/user/user-26.jpg"], - }, - budget: "24.9K", - status: "Pending", - }, - { - id: 3, - user: { - image: "/images/user/user-17.jpg", - name: "Zain Geidt", - role: "Content Writing", - }, - projectName: "Blog Writing", - team: { - images: ["/images/user/user-27.jpg"], - }, - budget: "12.7K", - status: "Active", - }, - { - id: 4, - user: { - image: "/images/user/user-20.jpg", - name: "Abram Schleifer", - role: "Digital Marketer", - }, - projectName: "Social Media", - team: { - images: [ - "/images/user/user-28.jpg", - "/images/user/user-29.jpg", - "/images/user/user-30.jpg", - ], - }, - budget: "2.8K", - status: "Cancel", - }, - { - id: 5, - user: { - image: "/images/user/user-21.jpg", - name: "Carla George", - role: "Front-end Developer", - }, - projectName: "Website", - team: { - images: [ - "/images/user/user-31.jpg", - "/images/user/user-32.jpg", - "/images/user/user-33.jpg", - ], - }, - budget: "4.5K", - status: "Active", - }, -]; - -export default function BasicTableOne() { - return ( -
-
- - {/* Table Header */} - - - - User - - - Project Name - - - Team - - - Status - - - Budget - - - - - {/* Table Body */} - - {tableData.map((order) => ( - - -
-
- {order.user.name} -
-
- - {order.user.name} - - - {order.user.role} - -
-
-
- - {order.projectName} - - -
- {order.team.images.map((teamImage, index) => ( -
- {`Team -
- ))} -
-
- - - {order.status} - - - - {order.budget} - -
- ))} -
-
-
-
- ); -} diff --git a/frontend/src/pages/Setup/IndustriesSectorsKeywords.tsx b/frontend/src/pages/Setup/IndustriesSectorsKeywords.tsx index 3bf2da0b..7eb35bc8 100644 --- a/frontend/src/pages/Setup/IndustriesSectorsKeywords.tsx +++ b/frontend/src/pages/Setup/IndustriesSectorsKeywords.tsx @@ -120,7 +120,7 @@ export default function IndustriesSectorsKeywords() { try { // Get already-attached keywords across ALL sectors for this site - let attachedSeedKeywordIds = new Set(); + const attachedSeedKeywordIds = new Set(); try { const { fetchKeywords, fetchSiteSectors } = await import('../../services/api'); // Get all sectors for the site diff --git a/frontend/src/pages/Sites/Settings.tsx b/frontend/src/pages/Sites/Settings.tsx index 999f1f23..529d80d1 100644 --- a/frontend/src/pages/Sites/Settings.tsx +++ b/frontend/src/pages/Sites/Settings.tsx @@ -410,7 +410,7 @@ export default function SiteSettings() { const loadIndustries = async () => { try { const response = await fetchIndustries(); - let allIndustries = response.industries || []; + const allIndustries = response.industries || []; // Note: For existing sites with industries already configured, // we show ALL industries so users can change their selection. diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index f0d1a5b7..6dc16cd5 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -227,14 +227,14 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo } // Throw authentication error - let err: any = new Error(errorMessage); + const err: any = new Error(errorMessage); err.status = 403; err.data = errorData; throw err; } // Not an auth error - could be permissions/plan issue - don't force logout - let err: any = new Error(errorMessage); + const err: any = new Error(errorMessage); err.status = 403; err.data = errorData; throw err; @@ -243,7 +243,7 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo if (e.status === 403) throw e; // Parsing failed - throw generic 403 error - let err: any = new Error(text || response.statusText); + const err: any = new Error(text || response.statusText); err.status = 403; throw err; } @@ -251,7 +251,7 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo // Handle 402 Payment Required - plan/limits issue if (response.status === 402) { - let err: any = new Error(response.statusText); + const err: any = new Error(response.statusText); err.status = response.status; try { const parsed = text ? JSON.parse(text) : null; @@ -295,7 +295,7 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo logout(); // Throw error to stop request processing - let err: any = new Error(errorData.error || 'Session ended'); + const err: any = new Error(errorData.error || 'Session ended'); err.status = 401; err.data = errorData; throw err; @@ -368,7 +368,7 @@ export async function fetchAPI(endpoint: string, options?: RequestInit & { timeo return null; } else { // Retry failed - parse and throw the retry error (not the original 401) - let retryError: any = new Error(retryResponse.statusText); + const retryError: any = new Error(retryResponse.statusText); retryError.status = retryResponse.status; try { const retryErrorData = JSON.parse(retryText);