Flow Meter Sidebar Refactor Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Refactor the Flow Meter page to use a sidebar layout with filters and actions, similar to the Heat Map page.
Architecture: The page will use a flex container with a fixed-width left sidebar (384px on desktop) containing filters and action buttons, and a flexible main content area for site cards, charts, and tables. On mobile, the sidebar stacks above the content.
Tech Stack: React, TypeScript, Tailwind CSS, existing DateRangeSelector component, Iconify icons
Task 1: Create the Flex Container Layout Wrapper
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx:622-626
Step 1: Update the main element to use flex layout
Find the return statement (around line 622) and modify the <main> element structure:
// BEFORE (line 625):
<main>
<PageBreadcrumb title="Flow Meter" />
// AFTER:
<main className="relative">
<PageBreadcrumb title="Flow Meter" />
<div className="flex flex-col lg:flex-row gap-5 h-[calc(100vh-180px)] min-h-[600px]">
{/* Sidebar will go here */}
{/* Main content wrapper */}
<div className="flex-1 overflow-y-auto">Step 2: Verify the app compiles
Run: pnpm build:check Expected: Build succeeds (may have warnings, but no errors)
Step 3: Commit
git add src/app/(admin)/(pages)/flow-meter/index.tsx
git commit -m "refactor(flow-meter): add flex container layout wrapper"Task 2: Create the Sidebar Structure with Header
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx
Step 1: Add the sidebar div after the flex container opening
Insert after <div className="flex flex-col lg:flex-row gap-5 h-[calc(100vh-180px)] min-h-[600px]">:
{/* Control Panel Sidebar */}
<div className="lg:w-96 w-full max-h-[40vh] lg:max-h-none overflow-y-auto bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 flex-shrink-0">
<div className="p-6 space-y-6">
{/* Sidebar Header */}
<div>
<h2 className="text-xl font-semibold text-slate-800 dark:text-slate-100 flex items-center gap-2">
<Icon
className="w-6 h-6 text-blue-600 dark:text-blue-400"
icon="solar:drop-bold-duotone"
/>
Flow Meter Controls
</h2>
<p className="text-sm text-slate-600 dark:text-slate-400 mt-1">
Adjust filters and actions
</p>
</div>
{/* Filters and Actions sections will go here */}
</div>
</div>Step 2: Verify the app compiles and renders
Run: pnpm dev Expected: Page loads with empty sidebar visible on the left
Step 3: Commit
git add src/app/(admin)/(pages)/flow-meter/index.tsx
git commit -m "refactor(flow-meter): add sidebar structure with header"Task 3: Add Data Filters Section to Sidebar
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx
Step 1: Add the Data Filters section inside the sidebar
Insert after the sidebar header div, inside <div className="p-6 space-y-6">:
{/* Data Filters Section */}
<div className="space-y-4 rounded-lg border border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/50 p-4">
<h3 className="text-sm font-medium text-slate-700 dark:text-slate-300 flex items-center gap-2">
<Icon className="w-4 h-4" icon="solar:filter-bold-duotone" />
Data Filters
</h3>
{/* Mine Site Selector */}
<div>
<div className="flex items-center gap-2 mb-2">
<Icon
className="w-4 h-4 text-slate-600 dark:text-slate-400"
icon="solar:buildings-2-bold-duotone"
/>
<label className="text-sm font-medium text-slate-700 dark:text-slate-300">
Mine Site
</label>
</div>
<select
className="w-full px-3 py-2 text-sm border border-slate-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 focus:ring-2 focus:ring-primary focus:border-transparent"
value={selectedSite ?? ""}
onChange={(e) => {
setSelectedSite(e.target.value || null);
}}
>
<option value="">All Sites</option>
{flowMeterEnabledSites.map((site) => (
<option key={site.id} value={site.name}>
{site.name}
</option>
))}
</select>
{selectedSite && (
<div className="text-xs text-slate-600 dark:text-slate-400 mt-2">
Showing data for {selectedSite}
</div>
)}
</div>
{/* Date Range Selector */}
<div>
<div className="flex items-center gap-2 mb-2">
<Icon
className="w-4 h-4 text-slate-600 dark:text-slate-400"
icon="solar:calendar-bold-duotone"
/>
<label className="text-sm font-medium text-slate-700 dark:text-slate-300">
Date Range
</label>
</div>
<DateRangeSelector
dataDateRange={actualDataDateRange}
value={dateRange}
onChange={handleDateRangeChange}
/>
</div>
</div>Step 2: Remove the old DateRangeSelector from main content
Find and remove this block (around line 727-732):
{/* Date Range Selector */}
<DateRangeSelector
dataDateRange={actualDataDateRange}
value={dateRange}
onChange={handleDateRangeChange}
/>Step 3: Verify the app compiles and date filter works
Run: pnpm dev Expected: Date range selector appears in sidebar, changing dates updates the data
Step 4: Commit
git add src/app/(admin)/(pages)/flow-meter/index.tsx
git commit -m "refactor(flow-meter): move date range selector to sidebar filters"Task 4: Add Actions Section to Sidebar
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx
Step 1: Add the Actions section after Data Filters section
Insert after the Data Filters section closing </div>:
{/* Actions Section */}
<div className="space-y-3 rounded-lg border border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/50 p-4">
<h3 className="text-sm font-medium text-slate-700 dark:text-slate-300 flex items-center gap-2">
<Icon className="w-4 h-4" icon="solar:widget-bold-duotone" />
Actions
</h3>
{/* Manage Sites Button */}
<button
className="w-full inline-flex items-center justify-center gap-2 px-4 py-2 rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 hover:bg-slate-50 dark:hover:bg-slate-700 transition-colors text-sm"
type="button"
onClick={() => {
setShowVisibilityManager(true);
}}
>
<Icon className="w-4 h-4" icon="solar:settings-bold-duotone" />
Manage Sites
</button>
{/* Refresh Data Button */}
<button
className="w-full inline-flex items-center justify-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-blue-400 disabled:cursor-not-allowed transition-colors text-sm"
disabled={isRefreshing}
onClick={() => {
setIsConfigModalOpen(true);
}}
>
<Icon
className={`h-4 w-4 ${isRefreshing ? "animate-spin" : ""}`}
icon={
isRefreshing
? "svg-spinners:ring-resize"
: "solar:refresh-bold-duotone"
}
/>
{isRefreshing ? "Refreshing..." : "Refresh Data"}
</button>
{/* Manage Refills Link */}
<Link
className="w-full inline-flex items-center justify-center gap-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors text-sm"
to="/refill-management"
>
<Icon className="h-4 w-4" icon="solar:box-bold-duotone" />
Manage Refills
</Link>
{/* Calibration Reminder Link */}
<Link
className="w-full inline-flex items-center justify-center gap-2 px-4 py-2 bg-amber-600 text-white rounded-lg hover:bg-amber-700 transition-colors text-sm"
to="/calibration-reminders"
>
<Icon className="h-4 w-4" icon="solar:compass-bold-duotone" />
Calibration Reminder
</Link>
{/* Export Report Button */}
<button
className="w-full inline-flex items-center justify-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors text-sm disabled:opacity-50 disabled:cursor-not-allowed"
disabled={!selectedSiteSummary || selectedSiteSummary.records.length === 0}
onClick={() => {
void handleExportAllCharts();
}}
>
<Icon className="h-4 w-4" icon="solar:download-bold-duotone" />
Export Report
</button>
</div>Step 2: Verify the app compiles and buttons work
Run: pnpm dev Expected: All action buttons appear in sidebar and function correctly
Step 3: Commit
git add src/app/(admin)/(pages)/flow-meter/index.tsx
git commit -m "refactor(flow-meter): add actions section to sidebar"Task 5: Update Sites Header and Remove Old Buttons
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx
Step 1: Simplify the Sites header row
Find the Sites header section (around line 653-707) and replace it with:
{/* Site Selection Grid */}
<div className="mb-6">
<div className="mb-4 flex items-center justify-between">
<h2 className="text-xl font-semibold text-slate-900 dark:text-slate-100">
Sites
</h2>
<div className="flex items-center gap-2">
<label className="text-sm text-slate-600 dark:text-slate-400">
Sort by:
</label>
<select
className="rounded border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-slate-900 dark:text-slate-100 hover:bg-slate-50 dark:hover:bg-slate-700 transition-colors"
value={siteSortBy}
onChange={(e) => {
setSiteSortBy(e.target.value as typeof siteSortBy);
}}
>
<option value="name-asc">Name (A-Z)</option>
<option value="name-desc">Name (Z-A)</option>
<option value="usage-desc">Usage (High to Low)</option>
<option value="usage-asc">Usage (Low to High)</option>
<option value="events-desc">Events (Most to Least)</option>
<option value="events-asc">Events (Least to Most)</option>
</select>
</div>
</div>Step 2: Verify the app compiles
Run: pnpm dev Expected: Sites header shows only title and sort dropdown
Step 3: Commit
git add src/app/(admin)/(pages)/flow-meter/index.tsx
git commit -m "refactor(flow-meter): simplify sites header, keep only sort dropdown"Task 6: Update Site Cards Grid Columns
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx
Step 1: Change the grid columns
Find the site cards grid (around line 708):
// BEFORE:
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
// AFTER:
<div className="grid grid-cols-1 gap-4 md:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3">Step 2: Verify the grid layout on different screen sizes
Run: pnpm dev Expected: Cards display in 3 columns on xl, 2 on lg, 1 on md and below
Step 3: Commit
git add src/app/(admin)/(pages)/flow-meter/index.tsx
git commit -m "refactor(flow-meter): adjust site cards grid to 3 columns max"Task 7: Remove Duplicate Action Buttons from Chart Section
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx
Step 1: Remove the action buttons from the Daily Usage chart header
Find the chart section header (around line 804-843) and simplify it:
// BEFORE (lines 804-843):
<div className="mb-6">
<div className="mb-4 flex items-center justify-between">
<h2 className="text-xl font-semibold text-slate-900 dark:text-slate-100">
{getChartTitle("Daily Dustloc Usage")}
</h2>
<div className="flex items-center gap-3">
<Link ... Manage Refills />
<Link ... Calibration Reminder />
<button ... Export Report />
</div>
</div>
// AFTER:
<div className="mb-6">
<div className="mb-4">
<h2 className="text-xl font-semibold text-slate-900 dark:text-slate-100">
{getChartTitle("Daily Dustloc Usage")}
</h2>
</div>Step 2: Verify the app compiles and chart section looks clean
Run: pnpm dev Expected: Chart section shows only the title, no duplicate buttons
Step 3: Commit
git add src/app/(admin)/(pages)/flow-meter/index.tsx
git commit -m "refactor(flow-meter): remove duplicate action buttons from chart section"Task 8: Close the Layout Wrapper Divs
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx
Step 1: Add closing divs before the modals
Find the end of the main content (before the modals, around line 1240) and add:
{/* End of main content wrapper */}
</div>
{/* End of flex container */}
</div>
{/* Scraper Configuration Modal */}
<ScraperConfigModalStep 2: Verify the app compiles without errors
Run: pnpm build:check Expected: Build succeeds with no errors
Step 3: Commit
git add src/app/(admin)/(pages)/flow-meter/index.tsx
git commit -m "refactor(flow-meter): close layout wrapper divs correctly"Task 9: Add Refresh Message to Sidebar
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx
Step 1: Move the refresh message into the sidebar Actions section
Find the refresh message block (around line 628-651) and move it into the Actions section, after the Refresh Data button:
{/* Refresh Status Message */}
{refreshMessage && (
<div
className={`p-2 rounded-md text-xs ${
refreshMessage.includes("successfully")
? "bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-400 border border-green-200 dark:border-green-800"
: "bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-400 border border-red-200 dark:border-red-800"
}`}
>
<div className="flex items-center gap-2">
<Icon
className="h-3.5 w-3.5 flex-shrink-0"
icon={
refreshMessage.includes("successfully")
? "solar:check-circle-bold"
: "solar:danger-circle-bold"
}
/>
<p>{refreshMessage}</p>
</div>
</div>
)}Step 2: Remove the old refresh message from the main content area
Delete the original refresh message block that was at the top of the main content.
Step 3: Verify the app compiles and refresh message appears in sidebar
Run: pnpm dev Expected: Refresh message appears in sidebar after triggering refresh
Step 4: Commit
git add src/app/(admin)/(pages)/flow-meter/index.tsx
git commit -m "refactor(flow-meter): move refresh message to sidebar"Task 10: Final Testing and Cleanup
Files:
- Modify:
src/app/(admin)/(pages)/flow-meter/index.tsx
Step 1: Run linting and fix any issues
Run: pnpm lint:fix Expected: No errors, warnings acceptable
Step 2: Run type checking
Run: pnpm build:check Expected: Build succeeds
Step 3: Manual testing checklist
- [ ] Sidebar appears on left on desktop (lg+)
- [ ] Sidebar stacks above content on mobile
- [ ] Mine Site selector in sidebar works
- [ ] Date Range selector in sidebar works
- [ ] All action buttons in sidebar work:
- [ ] Manage Sites opens modal
- [ ] Refresh Data opens config modal
- [ ] Manage Refills navigates to /refill-management
- [ ] Calibration Reminder navigates to /calibration-reminders
- [ ] Export Report exports when site has data
- [ ] Sort dropdown in main area works
- [ ] Site cards display in 3/2/1 columns correctly
- [ ] Clicking site cards selects them
- [ ] Charts and tables display for selected site
- [ ] Scrolling works independently in sidebar and main content
Step 4: Final commit
git add -A
git commit -m "refactor(flow-meter): complete sidebar layout refactor
- Add left sidebar with Flow Meter Controls header
- Move filters (Mine Site, Date Range) to sidebar
- Move action buttons to sidebar (Manage Sites, Refresh Data, etc.)
- Keep Sort dropdown in main content area
- Adjust site cards grid to 3 columns max
- Responsive layout: sidebar stacks on mobile
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"Summary
This plan refactors the Flow Meter page in 10 incremental tasks:
- Create flex container layout wrapper
- Add sidebar structure with header
- Add Data Filters section (Mine Site, Date Range)
- Add Actions section (all buttons)
- Simplify Sites header (keep only Sort)
- Update site cards grid columns
- Remove duplicate buttons from chart section
- Close layout wrapper divs
- Move refresh message to sidebar
- Final testing and cleanup
Each task is independently committable and testable.