feat: complete core state variables (Task 3.1)
- Add datetime imports for date handling - Add data state variables: last_updated, raw_data, latest_date_in_data - Set last_seen date defaults (6 months ago to today) - Add last_updated_display computed var for top bar - Update top bar to show dynamic refresh timestamp
This commit is contained in:
+18
-16
@@ -93,24 +93,26 @@ cd pathways_app && timeout 60 python -m reflex run 2>&1 | head -30
|
|||||||
## Phase 3: State Management
|
## Phase 3: State Management
|
||||||
|
|
||||||
### 3.1 Core State Variables
|
### 3.1 Core State Variables
|
||||||
- [ ] Define filter state variables in `AppState`:
|
- [x] Define filter state variables in `AppState`:
|
||||||
- `initiated_filter_enabled: bool = False`
|
- `initiated_filter_enabled: bool = False`
|
||||||
- `initiated_from: datetime`
|
- `initiated_from_date: str = ""` (ISO date string)
|
||||||
- `initiated_to: datetime`
|
- `initiated_to_date: str = ""`
|
||||||
- `last_seen_filter_enabled: bool = True`
|
- `last_seen_filter_enabled: bool = True`
|
||||||
- `last_seen_from: datetime` (default: 6 months ago)
|
- `last_seen_from_date: str` (default: 6 months ago, computed at class definition)
|
||||||
- `last_seen_to: datetime` (default: latest in dataset)
|
- `last_seen_to_date: str` (default: today, updated on data load)
|
||||||
- `selected_drugs: List[str]` (default: all)
|
- `selected_drugs: list[str] = []` (empty = all)
|
||||||
- `selected_indications: List[str]` (default: all)
|
- `selected_indications: list[str] = []` (empty = all)
|
||||||
- `selected_directorates: List[str]` (default: all)
|
- `selected_directorates: list[str] = []` (empty = all)
|
||||||
- [ ] Define data state variables:
|
- [x] Define data state variables:
|
||||||
- `data_loaded: bool`
|
- `data_loaded: bool = False`
|
||||||
- `total_records: int`
|
- `total_records: int = 0`
|
||||||
- `last_updated: datetime`
|
- `last_updated: str = ""` (ISO timestamp)
|
||||||
- `filtered_data: pd.DataFrame` (or computed)
|
- `raw_data: list[dict[str, Any]] = []` (list of dicts, Reflex-friendly)
|
||||||
- [ ] Define UI state variables:
|
- `latest_date_in_data: str = ""` (for "to" date defaults)
|
||||||
- `chart_loading: bool`
|
- [x] Define UI state variables:
|
||||||
- `error_message: str`
|
- `chart_loading: bool = False`
|
||||||
|
- `error_message: str = ""`
|
||||||
|
- `current_chart: str = "icicle"`
|
||||||
|
|
||||||
### 3.2 Data Loading
|
### 3.2 Data Loading
|
||||||
- [ ] Create `load_data()` method that reads from SQLite
|
- [ ] Create `load_data()` method that reads from SQLite
|
||||||
|
|||||||
+62
-5
@@ -5,6 +5,9 @@ Single-page dashboard with reactive filtering and real-time chart updates.
|
|||||||
Design reference: DESIGN_SYSTEM.md
|
Design reference: DESIGN_SYSTEM.md
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
from pathways_app.styles import (
|
from pathways_app.styles import (
|
||||||
@@ -41,24 +44,51 @@ class AppState(rx.State):
|
|||||||
Will be expanded in Phase 3 with full filter state and data management.
|
Will be expanded in Phase 3 with full filter state and data management.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Placeholder state variables (expanded in Phase 3)
|
# =========================================================================
|
||||||
|
# Data State Variables
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
|
# Data loading status
|
||||||
data_loaded: bool = False
|
data_loaded: bool = False
|
||||||
total_records: int = 0
|
total_records: int = 0
|
||||||
chart_loading: bool = False
|
chart_loading: bool = False
|
||||||
error_message: str = ""
|
error_message: str = ""
|
||||||
|
|
||||||
|
# Data freshness tracking
|
||||||
|
last_updated: str = "" # ISO format timestamp of last data load
|
||||||
|
|
||||||
|
# Raw data storage - list of dicts (Reflex-friendly)
|
||||||
|
# Each dict represents a patient record with keys like:
|
||||||
|
# UPID, Drug Name, Intervention Date, Price Actual, Directory, etc.
|
||||||
|
raw_data: list[dict[str, Any]] = []
|
||||||
|
|
||||||
|
# Latest date in dataset (detected on load, used for "to" date defaults)
|
||||||
|
latest_date_in_data: str = ""
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# UI State Variables
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
# Placeholder for current chart type (for top bar tabs)
|
# Placeholder for current chart type (for top bar tabs)
|
||||||
current_chart: str = "icicle"
|
current_chart: str = "icicle"
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# Filter State Variables
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
# Filter toggle state
|
# Filter toggle state
|
||||||
initiated_filter_enabled: bool = False
|
initiated_filter_enabled: bool = False
|
||||||
last_seen_filter_enabled: bool = True
|
last_seen_filter_enabled: bool = True
|
||||||
|
|
||||||
# Date filter values (ISO format strings for simplicity)
|
# Date filter values (ISO format strings YYYY-MM-DD)
|
||||||
|
# Initiated filter: Defaults empty (filter is OFF by default)
|
||||||
initiated_from_date: str = ""
|
initiated_from_date: str = ""
|
||||||
initiated_to_date: str = ""
|
initiated_to_date: str = ""
|
||||||
last_seen_from_date: str = ""
|
|
||||||
last_seen_to_date: str = ""
|
# Last Seen filter: Defaults to last 6 months (filter is ON by default)
|
||||||
|
# These will be updated on data load to use actual latest date
|
||||||
|
last_seen_from_date: str = (datetime.now() - timedelta(days=180)).strftime("%Y-%m-%d")
|
||||||
|
last_seen_to_date: str = datetime.now().strftime("%Y-%m-%d")
|
||||||
|
|
||||||
# Available options for dropdowns (populated from data in Phase 3)
|
# Available options for dropdowns (populated from data in Phase 3)
|
||||||
available_drugs: list[str] = ["Drug A", "Drug B", "Drug C", "Drug D", "Drug E"]
|
available_drugs: list[str] = ["Drug A", "Drug B", "Drug C", "Drug D", "Drug E"]
|
||||||
@@ -292,6 +322,33 @@ class AppState(rx.State):
|
|||||||
return "—"
|
return "—"
|
||||||
return f"{self.indication_match_rate:.0f}%"
|
return f"{self.indication_match_rate:.0f}%"
|
||||||
|
|
||||||
|
@rx.var
|
||||||
|
def last_updated_display(self) -> str:
|
||||||
|
"""Format last updated timestamp for display in top bar."""
|
||||||
|
if not self.last_updated:
|
||||||
|
return "Never"
|
||||||
|
try:
|
||||||
|
# Parse ISO format timestamp
|
||||||
|
dt = datetime.fromisoformat(self.last_updated)
|
||||||
|
now = datetime.now()
|
||||||
|
diff = now - dt
|
||||||
|
|
||||||
|
if diff.days == 0:
|
||||||
|
if diff.seconds < 60:
|
||||||
|
return "Just now"
|
||||||
|
if diff.seconds < 3600:
|
||||||
|
mins = diff.seconds // 60
|
||||||
|
return f"{mins}m ago"
|
||||||
|
hours = diff.seconds // 3600
|
||||||
|
return f"{hours}h ago"
|
||||||
|
if diff.days == 1:
|
||||||
|
return "Yesterday"
|
||||||
|
if diff.days < 7:
|
||||||
|
return f"{diff.days}d ago"
|
||||||
|
return dt.strftime("%d %b %Y")
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return "Unknown"
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Layout Components
|
# Layout Components
|
||||||
@@ -630,7 +687,7 @@ def top_bar() -> rx.Component:
|
|||||||
rx.text(
|
rx.text(
|
||||||
rx.cond(
|
rx.cond(
|
||||||
AppState.data_loaded,
|
AppState.data_loaded,
|
||||||
"Last refreshed: recently",
|
"Refreshed: " + AppState.last_updated_display,
|
||||||
"Connecting...",
|
"Connecting...",
|
||||||
),
|
),
|
||||||
font_size="11px",
|
font_size="11px",
|
||||||
|
|||||||
Reference in New Issue
Block a user