Files
igny8/docs/plans/implemented/FOOTER-WIDGETS-AUDIT.md
IGNY8 VPS (Salman) 75e5b148f5 reorg
2026-01-11 16:58:57 +00:00

13 KiB

Footer Widgets Audit - Complete Analysis

Date: January 10, 2026
Purpose: Document all footer widgets across Planner and Writer pages to identify data conflicts


SUMMARY

All Planner and Writer pages use StandardThreeWidgetFooter component which displays:

  1. Widget 1 (Left): Page Progress - page-specific metrics
  2. Widget 2 (Middle): Module Stats - uses StandardizedModuleWidget
  3. Widget 3 (Right): Workflow Completion - uses WorkflowCompletionWidget via useWorkflowStats hook

PLANNER MODULE PAGES

Page 1: Keywords (/planner/keywords)

Widget 1: Page Progress

Field Value Source Filter/Criteria
Keywords totalCount Local state (line 49) All keywords for site+sector on current page
Clustered totalClustered Local state (line 50) Keywords with status='mapped'
Unmapped totalUnmapped Local state (line 51) Keywords without cluster_id
Volume totalVolume Calculated from keywords Sum of search volumes
Progress % Calculated (totalClustered / totalCount) * 100 -

Data Loading: Lines 132-183

  • Loads keywords via fetchKeywords({ site_id, sector_id, page, page_size, ...filters })
  • SECTOR FILTERED: Yes - uses activeSector.id
  • Calculates totals from loaded data
  • Issue: Only calculates from CURRENT PAGE data, not all keywords

Widget 2: Module Stats

Field Value Source
Type "planner" Hardcoded prop
Component StandardizedModuleWidget Centralized component

Widget 3: Workflow Completion

Uses useWorkflowStats hook

Field API Endpoint Filter
Keywords Total /v1/planner/keywords/ site_id only (NO sector)
Keywords Clustered /v1/planner/keywords/?status=mapped site_id only
Clusters Created /v1/planner/clusters/ site_id only
Ideas Generated /v1/planner/ideas/ site_id only
Content Drafts /v1/writer/content/?status=draft site_id only
Content Review /v1/writer/content/?status=review site_id only
Content Published /v1/writer/content/?status__in=approved,published site_id only
Images Created /v1/writer/images/ site_id only

Source: frontend/src/hooks/useWorkflowStats.ts (lines 144-234)

  • SECTOR FILTERED: No - intentionally site-wide for consistency
  • Date Filtered: Yes - supports Today, 7d, 30d, 90d, all

Page 2: Clusters (/planner/clusters)

Widget 1: Page Progress

Field Value Source Filter/Criteria
Clusters totalCount Local state (line 46) All clusters for site+sector
With Ideas totalWithIdeas Local state (line 47) Clusters with ideas_count > 0
Keywords Calculated Sum of all clusters' keywords_count From loaded clusters
Ready totalReady Local state (line 48) Clusters with ideas_count === 0
Progress % Calculated (totalWithIdeas / totalCount) * 100 -

Data Loading: Lines 94-127

  • Loads clusters via fetchClusters({ site_id, sector_id, page, page_size, ...filters })
  • SECTOR FILTERED: Yes - uses activeSector.id
  • Calculates totals from loaded data
  • Issue: Only calculates from CURRENT PAGE data

Widget 2 & 3: Same as Keywords page


Page 3: Ideas (/planner/ideas)

Widget 1: Page Progress

Field Value Source Filter/Criteria
Ideas totalCount Local state (line 45) All ideas for site+sector
In Tasks totalInTasks Local state (line 46) Ideas with task_id not null
Pending totalPending Local state (line 47) Ideas without task_id
From Clusters clusters.length Loaded clusters count Unique clusters
Progress % Calculated (totalInTasks / totalCount) * 100 -

Data Loading: Lines 87-133

  • Loads ideas via fetchContentIdeas({ site_id, sector_id, page, page_size, ...filters })
  • SECTOR FILTERED: Yes - uses activeSector.id
  • Loads clusters separately
  • Issue: Only calculates from CURRENT PAGE data

Widget 2 & 3: Same as above


WRITER MODULE PAGES

Page 4: Tasks (/writer/tasks)

Widget 1: Page Progress

Field Value Source Filter/Criteria
Tasks totalCount Local state (line 47) All tasks for site+sector
Drafted totalDrafted Local state (line 48) Tasks with content created
Pending totalPending Local state (line 49) Tasks without content
Priority totalPriority Local state (line 50) Tasks with priority=true
Progress % Calculated (totalDrafted / totalCount) * 100 -

Data Loading: Lines 139-182

  • Loads tasks via fetchTasks({ site_id, sector_id, page, page_size, ...filters })
  • SECTOR FILTERED: Yes - uses activeSector.id
  • Calculates totals from loaded data
  • Issue: Only calculates from CURRENT PAGE data

Widget 2: Module Stats

Field Value Source
Type "writer" Hardcoded prop
Component StandardizedModuleWidget Centralized component

Widget 3: Workflow Completion

Same as Planner pages - uses useWorkflowStats hook


Page 5: Content/Drafts (/writer/content)

Widget 1: Page Progress

Field Value Source Filter/Criteria
Content totalCount Local state (line 43) All content for site+sector
Published totalPublished Local state (line 44) Content with site_status='published'
In Review totalInReview Local state (line 45) Content with status='review'
Approved totalApproved Local state (line 46) Content with status='approved'
Progress % Calculated (totalPublished / totalCount) * 100 -

Data Loading: Lines 84-112

  • Loads content via fetchContent({ site_id, sector_id, page, page_size, ...filters })
  • SECTOR FILTERED: Yes - uses activeSector.id
  • Issue: Only calculates from CURRENT PAGE data

Widget 2 & 3: Same as Tasks page


Page 6: Review (/writer/review)

Widget 1: Page Progress

Field Value Source Filter/Criteria
In Review totalCount Local state (line 39) Content with status='review'
Approved totalApproved Local state (line 40) From review that moved to approved
Pending totalPending Local state (line 41) Still in review status
Priority totalPriority Local state (line 42) With priority flag
Progress % Calculated (totalApproved / totalCount) * 100 -

Data Loading: Lines 77-105

  • Loads review content via fetchContent({ site_id, sector_id, status: 'review', page, page_size })
  • SECTOR FILTERED: Yes - uses activeSector.id
  • Pre-filtered: Only loads status='review'
  • Issue: Only calculates from CURRENT PAGE data

Widget 2 & 3: Same as other Writer pages


Page 7: Approved (/writer/approved)

Widget 1: Page Progress

Field Value Source Filter/Criteria
Approved totalCount Local state (line 39) Content with status='approved'
Published totalPublished Local state (line 40) With site_status='published'
Scheduled totalScheduled Local state (line 41) With site_status='scheduled'
Ready totalReady Local state (line 42) With site_status='not_published'
Progress % Calculated (totalPublished / totalCount) * 100 -

Data Loading: Lines 77-107

  • Loads approved content via fetchContent({ site_id, sector_id, status: 'approved', page, page_size })
  • SECTOR FILTERED: Yes - uses activeSector.id
  • Pre-filtered: Only loads status='approved'
  • Issue: Only calculates from CURRENT PAGE data

Widget 2 & 3: Same as other Writer pages


Page 8: Images (/writer/images)

Widget 1: Page Progress

Field Value Source Filter/Criteria
Images totalCount Local state (line 44) All images for site+sector
Featured totalFeatured Local state (line 45) Images with image_type='featured'
In-Article totalInArticle Local state (line 46) Images with image_type='in_article'
Linked totalLinked Local state (line 47) Images with content_id not null
Progress % Calculated (totalLinked / totalCount) * 100 -

Data Loading: Lines 98-144

  • Loads images via fetchImages({ site_id, sector_id, page, page_size, ...filters })
  • SECTOR FILTERED: Yes - uses activeSector.id
  • Issue: Only calculates from CURRENT PAGE data

Widget 2 & 3: Same as other Writer pages


ROOT CAUSES OF DATA CONFLICTS

Problem 1: Page-Level vs Site-Wide Data

Conflict: Widget 1 (Page Progress) shows page-filtered counts, Widget 3 (Workflow) shows site-wide counts

Widget Scope Sector Filter Date Filter Data Source
Widget 1 (Page Progress) Current page only YES NO Local state from paginated API
Widget 2 (Module Stats) Site-wide NO NO Centralized hook (StandardizedModuleWidget)
Widget 3 (Workflow) Site-wide NO YES (optional) useWorkflowStats hook

Example Conflict:

  • Keywords page shows "17 Keywords" in Page Progress (Widget 1) ← from current page
  • Workflow widget shows "17 Keywords Clustered" (Widget 3) ← from ALL keywords site-wide
  • If user is on page 2, Widget 1 shows page 2 keywords, but Widget 3 shows total site keywords

Problem 2: Sector Filtering Inconsistency

Conflict: Widget 1 filters by sector, Widget 3 does NOT

Component Sector Filtered? Reasoning
Page Progress (Widget 1) YES Shows current page data which is sector-filtered
Module Stats (Widget 2) NO Centralized module-level stats
Workflow Widget (Widget 3) NO Intentionally site-wide for consistency across pages

User's Point: If only 1 sector exists, sector filter doesn't matter - but data STILL conflicts because Widget 1 shows PAGINATED data

Problem 3: Pagination vs Total Counts

Critical Issue: Widget 1 calculates totals from current page data only, not all records

Example on Keywords page (lines 182-183):

setTotalCount(keywords.length);  // ← Only current page!
setTotalClustered(keywords.filter(k => k.status === 'mapped').length);  // ← Only current page!

Should be:

setTotalCount(response.count);  // ← Total from API
setTotalClustered(/* need separate API call or response field */);

Problem 4: Different Time Ranges

Widget Time Filtering
Widget 1 NO time filter - shows ALL data for site+sector
Widget 3 YES time filter - supports Today, 7d, 30d, 90d buttons

Fix 1: Make Page Progress Show Site-Wide Totals

Current: Calculates from paginated data Should Be: Use response.count from API for totals

Files to Fix:

  • frontend/src/pages/Planner/Keywords.tsx
  • frontend/src/pages/Planner/Clusters.tsx
  • frontend/src/pages/Planner/Ideas.tsx
  • frontend/src/pages/Writer/Tasks.tsx
  • frontend/src/pages/Writer/Content.tsx
  • frontend/src/pages/Writer/Review.tsx
  • frontend/src/pages/Writer/Approved.tsx
  • frontend/src/pages/Writer/Images.tsx

Change Pattern:

// OLD (WRONG):
setTotalCount(items.length);  // Only current page

// NEW (CORRECT):
setTotalCount(response.count);  // Total count from API

Fix 2: Document That Widgets Show Different Scopes

Add tooltips/help text:

  • Widget 1: "Page statistics (current filters)"
  • Widget 3: "Site-wide workflow progress (all sectors)"

Fix 3: Consider Adding Sector Filter Option to Widget 3

Alternative: Add toggle in Workflow Widget to switch between:

  • Site-wide (current behavior)
  • Current sector only (match Widget 1)

ADDITIONAL FINDINGS

Publishing Tab Issues

File: frontend/src/pages/Sites/Settings.tsx

Issue: Day selection and time slot changes auto-save immediately instead of waiting for "Save Publishing Settings" button

Lines with auto-save:

  • Line 1195: Publishing days button click calls savePublishingSettings({ publish_days: newDays })
  • Line 1224: Remove time slot calls savePublishingSettings({ publish_time_slots: newSlots })
  • Line 1236: Add time slot calls savePublishingSettings({ publish_time_slots: newSlots })

Fix: Remove savePublishingSettings() calls from these onChange handlers, let user click the Save button at line 1278


SUMMARY TABLE: ALL PAGES

Page Widget 1 Scope Widget 1 Sector Filter Widget 3 Scope Widget 3 Sector Filter Conflict?
Keywords Current page YES Site-wide NO YES
Clusters Current page YES Site-wide NO YES
Ideas Current page YES Site-wide NO YES
Tasks Current page YES Site-wide NO YES
Content Current page YES Site-wide NO YES
Review Current page YES Site-wide NO YES
Approved Current page YES Site-wide NO YES
Images Current page YES Site-wide NO YES

Conclusion: ALL pages have the pagination vs site-wide conflict. The sector filtering is actually a secondary issue.


END OF AUDIT