feat: persist chart type, indicator toggles, and markers across navigation and logout
Browse files- StockChart.tsx: initialize chartType, showSMA, showEMA, showRSI from localStorage on mount
- StockChart.tsx: add effects to persist indicator state changes to localStorage per email+ticker
- StockChart.tsx: fallback markers load/save to cached quantiq_last_logged_in_email to survive async user loads
frontend/src/components/StockChart.tsx
CHANGED
|
@@ -162,20 +162,60 @@ export default function StockChart({ activeTicker, chartData, activeStats, chart
|
|
| 162 |
const currentPrice = chartData.length > 0 ? chartData[chartData.length - 1].price : null;
|
| 163 |
|
| 164 |
// Chart States
|
| 165 |
-
const [chartType, setChartType] = useState<'line' | 'candle'>(
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
const [isMaximized, setIsMaximized] = useState<boolean>(() => {
|
| 170 |
return sessionStorage.getItem('quantiq_restore_maximized_chart') === 'true';
|
| 171 |
});
|
| 172 |
|
| 173 |
-
//
|
| 174 |
useEffect(() => {
|
|
|
|
|
|
|
|
|
|
| 175 |
if (sessionStorage.getItem('quantiq_restore_maximized_chart') === 'true') {
|
| 176 |
sessionStorage.removeItem('quantiq_restore_maximized_chart');
|
| 177 |
}
|
| 178 |
-
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
|
| 180 |
// Zoom Factor and Scroll/Pan states (only active in maximized view)
|
| 181 |
const [zoomFactor, setZoomFactor] = useState<number>(1.0);
|
|
@@ -206,8 +246,9 @@ export default function StockChart({ activeTicker, chartData, activeStats, chart
|
|
| 206 |
color: string;
|
| 207 |
}
|
| 208 |
const [markers, setMarkers] = useState<ChartMarker[]>(() => {
|
| 209 |
-
|
| 210 |
-
|
|
|
|
| 211 |
if (saved) {
|
| 212 |
try {
|
| 213 |
return JSON.parse(saved);
|
|
@@ -221,8 +262,9 @@ export default function StockChart({ activeTicker, chartData, activeStats, chart
|
|
| 221 |
|
| 222 |
// Reload markers on ticker/user change
|
| 223 |
useEffect(() => {
|
| 224 |
-
|
| 225 |
-
|
|
|
|
| 226 |
if (saved) {
|
| 227 |
try {
|
| 228 |
setMarkers(JSON.parse(saved));
|
|
@@ -237,8 +279,9 @@ export default function StockChart({ activeTicker, chartData, activeStats, chart
|
|
| 237 |
|
| 238 |
// Save markers to localStorage when updated
|
| 239 |
useEffect(() => {
|
| 240 |
-
|
| 241 |
-
|
|
|
|
| 242 |
}
|
| 243 |
}, [markers, activeTicker, user?.email]);
|
| 244 |
const [showAddMarkerForm, setShowAddMarkerForm] = useState<boolean>(false);
|
|
|
|
| 162 |
const currentPrice = chartData.length > 0 ? chartData[chartData.length - 1].price : null;
|
| 163 |
|
| 164 |
// Chart States
|
| 165 |
+
const [chartType, setChartType] = useState<'line' | 'candle'>(() => {
|
| 166 |
+
const email = localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 167 |
+
const saved = localStorage.getItem(`quantiq_chart_type_${email}_${activeTicker}`);
|
| 168 |
+
return (saved as 'line' | 'candle') || 'line';
|
| 169 |
+
});
|
| 170 |
+
const [showSMA, setShowSMA] = useState<boolean>(() => {
|
| 171 |
+
const email = localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 172 |
+
const saved = localStorage.getItem(`quantiq_show_sma_${email}_${activeTicker}`);
|
| 173 |
+
return saved === 'true';
|
| 174 |
+
});
|
| 175 |
+
const [showEMA, setShowEMA] = useState<boolean>(() => {
|
| 176 |
+
const email = localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 177 |
+
const saved = localStorage.getItem(`quantiq_show_ema_${email}_${activeTicker}`);
|
| 178 |
+
return saved === 'true';
|
| 179 |
+
});
|
| 180 |
+
const [showRSI, setShowRSI] = useState<boolean>(() => {
|
| 181 |
+
const email = localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 182 |
+
const saved = localStorage.getItem(`quantiq_show_rsi_${email}_${activeTicker}`);
|
| 183 |
+
return saved === 'true';
|
| 184 |
+
});
|
| 185 |
const [isMaximized, setIsMaximized] = useState<boolean>(() => {
|
| 186 |
return sessionStorage.getItem('quantiq_restore_maximized_chart') === 'true';
|
| 187 |
});
|
| 188 |
|
| 189 |
+
// Track email & clear restoration flag on mount
|
| 190 |
useEffect(() => {
|
| 191 |
+
if (user?.email) {
|
| 192 |
+
localStorage.setItem('quantiq_last_logged_in_email', user.email);
|
| 193 |
+
}
|
| 194 |
if (sessionStorage.getItem('quantiq_restore_maximized_chart') === 'true') {
|
| 195 |
sessionStorage.removeItem('quantiq_restore_maximized_chart');
|
| 196 |
}
|
| 197 |
+
}, [user]);
|
| 198 |
+
|
| 199 |
+
// Persist chartType, SMA, EMA, and RSI states on change
|
| 200 |
+
useEffect(() => {
|
| 201 |
+
const email = user?.email || localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 202 |
+
localStorage.setItem(`quantiq_chart_type_${email}_${activeTicker}`, chartType);
|
| 203 |
+
}, [chartType, activeTicker, user]);
|
| 204 |
+
|
| 205 |
+
useEffect(() => {
|
| 206 |
+
const email = user?.email || localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 207 |
+
localStorage.setItem(`quantiq_show_sma_${email}_${activeTicker}`, String(showSMA));
|
| 208 |
+
}, [showSMA, activeTicker, user]);
|
| 209 |
+
|
| 210 |
+
useEffect(() => {
|
| 211 |
+
const email = user?.email || localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 212 |
+
localStorage.setItem(`quantiq_show_ema_${email}_${activeTicker}`, String(showEMA));
|
| 213 |
+
}, [showEMA, activeTicker, user]);
|
| 214 |
+
|
| 215 |
+
useEffect(() => {
|
| 216 |
+
const email = user?.email || localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 217 |
+
localStorage.setItem(`quantiq_show_rsi_${email}_${activeTicker}`, String(showRSI));
|
| 218 |
+
}, [showRSI, activeTicker, user]);
|
| 219 |
|
| 220 |
// Zoom Factor and Scroll/Pan states (only active in maximized view)
|
| 221 |
const [zoomFactor, setZoomFactor] = useState<number>(1.0);
|
|
|
|
| 246 |
color: string;
|
| 247 |
}
|
| 248 |
const [markers, setMarkers] = useState<ChartMarker[]>(() => {
|
| 249 |
+
const email = localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 250 |
+
if (activeTicker) {
|
| 251 |
+
const saved = localStorage.getItem(`quantiq_markers_${email}_${activeTicker}`);
|
| 252 |
if (saved) {
|
| 253 |
try {
|
| 254 |
return JSON.parse(saved);
|
|
|
|
| 262 |
|
| 263 |
// Reload markers on ticker/user change
|
| 264 |
useEffect(() => {
|
| 265 |
+
const email = user?.email || localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 266 |
+
if (activeTicker) {
|
| 267 |
+
const saved = localStorage.getItem(`quantiq_markers_${email}_${activeTicker}`);
|
| 268 |
if (saved) {
|
| 269 |
try {
|
| 270 |
setMarkers(JSON.parse(saved));
|
|
|
|
| 279 |
|
| 280 |
// Save markers to localStorage when updated
|
| 281 |
useEffect(() => {
|
| 282 |
+
const email = user?.email || localStorage.getItem('quantiq_last_logged_in_email') || 'generic';
|
| 283 |
+
if (activeTicker) {
|
| 284 |
+
localStorage.setItem(`quantiq_markers_${email}_${activeTicker}`, JSON.stringify(markers));
|
| 285 |
}
|
| 286 |
}, [markers, activeTicker, user?.email]);
|
| 287 |
const [showAddMarkerForm, setShowAddMarkerForm] = useState<boolean>(false);
|