194 lines
6.2 KiB
Markdown
194 lines
6.2 KiB
Markdown
# Footer Widget Pagination Fix - Summary
|
|
|
|
## Problem
|
|
|
|
All pages with `ThreeWidgetFooter` are calculating metrics using **page-filtered arrays** instead of **total counts** from the API. This causes incorrect metric values when users are viewing paginated results.
|
|
|
|
### Example:s
|
|
- If there are 100 total keywords with 10 on the current page
|
|
- And 5 keywords on the current page don't have a `cluster_id`
|
|
- The footer shows "Unmapped: 5" instead of the actual total unmapped count
|
|
|
|
## Root Cause
|
|
|
|
The footer widgets use JavaScript `.filter()` methods on the local `items` array (which only contains the current page's data) instead of making separate API calls to get total counts for each status.
|
|
|
|
```typescript
|
|
// WRONG - Uses page-filtered array
|
|
{ label: 'Unmapped', value: keywords.filter(k => !k.cluster_id).length }
|
|
|
|
// CORRECT - Uses total count from API
|
|
{ label: 'Unmapped', value: totalUnmapped }
|
|
```
|
|
|
|
## Solution Pattern
|
|
|
|
For each affected page:
|
|
|
|
1. **Add state variables for total counts**
|
|
2. **Create a `loadTotalMetrics()` function** that makes lightweight API calls (page_size=1) filtered by status
|
|
3. **Call `loadTotalMetrics()` when site/sector changes**
|
|
4. **Update footer widget** to use the total count state instead of filtering local arrays
|
|
|
|
## Files Fixed
|
|
|
|
### ✅ 1. Keywords.tsx
|
|
- Added: `totalClustered`, `totalUnmapped`, `totalVolume` state
|
|
- Added: `loadTotalMetrics()` function
|
|
- Updated: Footer widget to use total counts
|
|
|
|
### ✅ 2. Clusters.tsx
|
|
- Added: `totalWithIdeas`, `totalReady` state
|
|
- Added: `loadTotalMetrics()` function
|
|
- Updated: Footer widget to use total counts
|
|
|
|
### ⏳ 3. Ideas.tsx
|
|
- **TODO**: Add `totalInTasks`, `totalPending` state
|
|
- **TODO**: Add `loadTotalMetrics()` function with calls to:
|
|
- `fetchContentIdeas({ status: 'queued' })` → `totalInTasks`
|
|
- `fetchContentIdeas({ status: 'new' })` → `totalPending`
|
|
- **TODO**: Update footer widget metrics
|
|
|
|
### ⏳ 4. Tasks.tsx
|
|
- **TODO**: Add total count state variables
|
|
- **TODO**: Add `loadTotalMetrics()` function
|
|
- **TODO**: Update footer widget
|
|
|
|
### ⏳ 5. Content.tsx
|
|
- **TODO**: Add total count state variables for each status (draft, review, approved)
|
|
- **TODO**: Add `loadTotalMetrics()` function
|
|
- **TODO**: Update footer widget
|
|
|
|
### ⏳ 6. Images.tsx
|
|
- **TODO**: Add total count state variables
|
|
- **TODO**: Add `loadTotalMetrics()` function
|
|
- **TODO**: Update footer widget
|
|
|
|
### ⏳ 7. Review.tsx
|
|
- **TODO**: Add total count state variables
|
|
- **TODO**: Add `loadTotalMetrics()` function
|
|
- **TODO**: Update footer widget
|
|
|
|
### ⏳ 8. Approved.tsx
|
|
- **TODO**: Add total count state variables
|
|
- **TODO**: Add `loadTotalMetrics()` function
|
|
- **TODO**: Update footer widget
|
|
|
|
## Implementation Template
|
|
|
|
### Step 1: Add State Variables
|
|
|
|
```typescript
|
|
// Total counts for footer widget (not page-filtered)
|
|
const [totalWithStatus1, setTotalWithStatus1] = useState(0);
|
|
const [totalWithStatus2, setTotalWithStatus2] = useState(0);
|
|
```
|
|
|
|
### Step 2: Create loadTotalMetrics Function
|
|
|
|
```typescript
|
|
// Load total metrics for footer widget (not affected by pagination)
|
|
const loadTotalMetrics = useCallback(async () => {
|
|
if (!activeSite) return;
|
|
|
|
try {
|
|
// Get items with status1
|
|
const status1Res = await fetchItems({
|
|
page_size: 1,
|
|
site_id: activeSite.id,
|
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
|
status: 'status1',
|
|
});
|
|
setTotalWithStatus1(status1Res.count || 0);
|
|
|
|
// Get items with status2
|
|
const status2Res = await fetchItems({
|
|
page_size: 1,
|
|
site_id: activeSite.id,
|
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
|
status: 'status2',
|
|
});
|
|
setTotalWithStatus2(status2Res.count || 0);
|
|
} catch (error) {
|
|
console.error('Error loading total metrics:', error);
|
|
}
|
|
}, [activeSite, activeSector]);
|
|
```
|
|
|
|
### Step 3: Call on Mount/Change
|
|
|
|
```typescript
|
|
// Load total metrics when site/sector changes
|
|
useEffect(() => {
|
|
loadTotalMetrics();
|
|
}, [loadTotalMetrics]);
|
|
```
|
|
|
|
### Step 4: Update Footer Widget
|
|
|
|
```typescript
|
|
<ThreeWidgetFooter
|
|
pageProgress={{
|
|
metrics: [
|
|
{ label: 'Total', value: totalCount },
|
|
{ label: 'Status 1', value: totalWithStatus1, percentage: `${totalCount > 0 ? Math.round((totalWithStatus1 / totalCount) * 100) : 0}%` },
|
|
{ label: 'Status 2', value: totalWithStatus2 },
|
|
],
|
|
progress: {
|
|
value: totalCount > 0 ? Math.round((totalWithStatus1 / totalCount) * 100) : 0,
|
|
label: 'Processed',
|
|
color: 'blue',
|
|
},
|
|
hint: totalWithStatus2 > 0
|
|
? `${totalWithStatus2} items ready for processing`
|
|
: 'All items processed!',
|
|
}}
|
|
// ... rest of props
|
|
/>
|
|
```
|
|
|
|
## Testing Checklist
|
|
|
|
For each fixed page, verify:
|
|
|
|
- [ ] Footer metrics show correct total counts (not page counts)
|
|
- [ ] Metrics update when changing sites
|
|
- [ ] Metrics update when changing sectors
|
|
- [ ] Metrics are consistent with automation page metrics
|
|
- [ ] Performance is acceptable (lightweight API calls with page_size=1)
|
|
|
|
## Related Files
|
|
|
|
- `/frontend/src/components/dashboard/ThreeWidgetFooter.tsx`
|
|
- `/frontend/src/pages/Automation/AutomationPage.tsx` (reference implementation)
|
|
- All planner and writer page files
|
|
|
|
## API Endpoints Used
|
|
|
|
All pages use their respective `fetch*` functions with filters:
|
|
- `fetchKeywords({ status, page_size: 1 })`
|
|
- `fetchClusters({ status, page_size: 1 })`
|
|
- `fetchContentIdeas({ status, page_size: 1 })`
|
|
- `fetchTasks({ status, page_size: 1 })`
|
|
- `fetchContent({ status, page_size: 1 })`
|
|
- `fetchContentImages({ status, page_size: 1 })`
|
|
|
|
The `page_size: 1` ensures minimal data transfer while still getting the count.
|
|
|
|
## Performance Considerations
|
|
|
|
- Each page makes 2-3 additional API calls on load
|
|
- Calls are lightweight (page_size=1, only count is used)
|
|
- Calls are cached until site/sector changes
|
|
- Total overhead: ~100-300ms per page load (acceptable)
|
|
|
|
## Automation Page Consistency
|
|
|
|
The AutomationPage already uses this pattern correctly:
|
|
- Lines 99-149: Fetches total counts for all metrics
|
|
- Uses `fetchKeywords({ status: 'new' })`, `fetchKeywords({ status: 'mapped' })`, etc.
|
|
- Sets metrics in state: `setMetrics({ keywords: { total, new, mapped } })`
|
|
- All stage cards and metric cards use these pre-fetched totals
|
|
|
|
This fix brings all other pages in line with the Automation page's correct implementation.
|