Tank Alert Management Page Design
Overview
A dedicated admin page for monitoring and managing tank level alerts. This page provides visibility into the entire alert lifecycle: detection → queue → email sending.
Route: /settings/tank-alertsAccess: Admin only Navigation: Settings menu, below Email Schedules
Problem Statement
The tank level email schedule process is complex and invisible to users:
- Detect low water level tanks
- Create alerts and add to send queue
- Send aggregated email at 8:00 AM next day
Users cannot monitor the status and progress of this workflow. This page solves that by providing a management interface for all tank alerts.
Page Structure
┌─────────────────────────────────────────────────┐
│ Tank Alert Management [立即发送] │
├─────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 待发送 │ │ 已发送 │ │ 已解决 │ │ 总告警 │ │
│ │ 5 │ │ 12 │ │ 8 │ │ 25 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────┤
│ [待发送] [已发送] [已解决] │
├─────────────────────────────────────────────────┤
│ ☑ 全选 站点筛选: [全部 ▼] [批量发送] [批量删除] │
├─────────────────────────────────────────────────┤
│ 告警列表... │
└─────────────────────────────────────────────────┘Features
Display Features
- Pending alerts list - Alerts with
notified=falseandresolved_at=null - Sent alerts list - Alerts with
notified=true - Resolved alerts list - Alerts with
resolved_atnot null - Statistics overview - Counts for pending, sent, resolved, and total alerts
Management Operations
- Mark as sent - Skip email, mark alert as
notified=true - Mark as resolved - Set
resolved_attimestamp - Modify send date - Change
scheduled_send_date - Send immediately - Trigger email send now (single or batch)
- Delete alert - Remove alert record permanently
Data Model
Alert Status Definition
typescript
type AlertStatus = 'pending' | 'sent' | 'resolved';
// pending: resolved_at = null AND notified = false
// sent: notified = true AND resolved_at = null
// resolved: resolved_at != nullList Item Data Structure
typescript
type TankAlertListItem = {
// Alert basic info
id: string;
assetId: string;
triggeredAt: Date;
scheduledSendDate: Date;
notified: boolean;
resolvedAt?: Date;
// Tank info (joined)
assetDisplayId: string;
siteName: string;
// Real-time water level (calculated)
currentLitres?: number;
capacityLitres?: number;
percentRemaining?: number;
// Computed status
status: AlertStatus;
};Service Methods
typescript
// tankAlertManagementService.ts
// Get all alerts with filtering
getAllAlerts(filters: { status?: AlertStatus; siteId?: string }): Promise<TankAlertListItem[]>
// Get statistics
getAlertStats(): Promise<{ pending: number; sent: number; resolved: number; total: number }>
// Update scheduled send date
updateScheduledDate(alertId: string, newDate: Date): Promise<void>
// Mark as sent (without sending email)
markAsSent(alertIds: string[]): Promise<void>
// Mark as resolved
markAsResolved(alertIds: string[]): Promise<void>
// Delete alerts
deleteAlerts(alertIds: string[]): Promise<void>
// Send alert email immediately (calls Edge Function)
sendAlertEmailNow(alertIds: string[]): Promise<void>File Structure
src/features/tank-alerts/
├── components/
│ ├── TankAlertManagement.tsx # Main page component
│ ├── TankAlertStats.tsx # Statistics overview cards
│ ├── TankAlertTabs.tsx # Tab switching component
│ ├── TankAlertTable.tsx # Alert list table
│ ├── TankAlertRow.tsx # Single alert row display
│ ├── MiniTankIndicator.tsx # Mini tank icon visualization
│ └── TankAlertActions.tsx # Action buttons group
├── hooks/
│ └── useTankAlerts.ts # Data fetching and operations hook
├── services/
│ └── tankAlertManagementService.ts # Extends existing tankAlertService
└── types.ts # Type definitionsUI Component Details
Statistics Cards (TankAlertStats)
Four cards in horizontal layout, clickable to switch to corresponding tab:
- Pending (orange) - pending count
- Sent (green) - sent count
- Resolved (gray) - resolved count
- Total (blue) - total count
Alert Table Columns (TankAlertTable)
| Column | Width | Content |
|---|---|---|
| ☑ | 40px | Checkbox (pending tab only) |
| Tank | 60px | MiniTankIndicator mini tank icon |
| Tank | 150px | asset_display_id |
| Site | 120px | site_name |
| Level | 140px | 12,500L / 50,000L (25%) |
| Triggered | 150px | triggered_at formatted |
| Scheduled | 120px | scheduled_send_date (pending tab) |
| Sent At | 120px | sent time (sent tab) |
| Resolved At | 120px | resolved_at (resolved tab) |
| Actions | 150px | Action buttons |
Action Buttons by Tab
Pending Tab:
- 📤 Send Now - Single immediate send
- 📅 Change Date - Modal to modify scheduled_send_date
- ✅ Mark Sent - Skip sending, mark as sent
- ✓ Mark Resolved - Mark as resolved
- 🗑️ Delete
Sent Tab:
- ✓ Mark Resolved
- 🗑️ Delete
Resolved Tab:
- 🗑️ Delete
Bulk Actions Bar
When multiple records selected, show bulk action bar at top:
Selected 3 items [Bulk Send] [Bulk Mark Sent] [Bulk Mark Resolved] [Bulk Delete] [Cancel]Interaction Flows
Send Immediately Flow
- User clicks "Send Now" (single or batch)
- Confirmation dialog: "Send X alert email(s) now?"
- Call Edge Function
send-tank-level-alert - On success, refresh list, alerts move to "Sent" tab
- Show Toast: "Successfully sent X alert email(s)"
Modify Send Date Flow
- Click "Change Date" button
- Date picker modal opens (default: current scheduled_send_date)
- Select new date and confirm
- Update database, refresh list
- Show Toast: "Send date updated"
Delete Confirmation
- Single delete: "Delete this alert record? This action cannot be undone."
- Bulk delete: "Delete X selected alert records? This action cannot be undone."
Edge Cases
| Case | Handling |
|---|---|
| Water level cannot be calculated | Show -- or N/A, mini tank shows gray |
| Alert's tank has been deleted | Show asset_id, label "Tank deleted" |
| Email send fails | Show error Toast, alert stays in pending |
| Empty list | Show empty state: "No [pending/sent/resolved] alerts" |
| Network error | Show error message with retry button |
Auto Refresh
- Load data on page open
- Auto refresh statistics every 60 seconds
- Refresh current list after any operation
Route Configuration
typescript
// In Routes.tsx
{
path: 'tank-alerts',
element: (
<ProtectedRoute adminOnly>
<TankAlertManagement />
</ProtectedRoute>
),
}Navigation Menu
Add to Settings menu in sidebar, below Email Schedules:
typescript
{
label: 'Tank Alerts',
path: '/settings/tank-alerts',
icon: AlertTriangle, // or similar icon
adminOnly: true,
}