Skip to content

Commit 63ba4a4

Browse files
committed
feat: add session polling to detect expired JWT and auto-update auth state
1 parent 94d1f0f commit 63ba4a4

4 files changed

Lines changed: 62 additions & 13 deletions

File tree

src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Routes from "components/Routes";
44
import theme from "design/theme";
55
import { useAppDispatch } from "hooks/useAppDispatch";
66
import { useGAPageviews } from "hooks/useGAPageviews";
7+
import { useSessionPoller } from "hooks/useSessionPoller";
78
import { useEffect, useState } from "react";
89
import React from "react";
910
import { BrowserRouter, useLocation } from "react-router-dom";
@@ -26,6 +27,7 @@ function AuthHandler() {
2627
const navigate = useNavigate();
2728
const hasProcessedOAuthRef = React.useRef(false);
2829

30+
useSessionPoller();
2931
// Handle browser back/forward navigation
3032
useEffect(() => {
3133
const handlePopState = () => {

src/components/User/Dashboard/DatasetOrganizer/LLMPanel.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ import {
1818
getConversionScriptPrompt,
1919
getBIDSPlanPrompt,
2020
} from "./utils/llmPrompts";
21-
import { Close, ContentCopy, Download, AutoAwesome } from "@mui/icons-material";
21+
import {
22+
Close,
23+
ContentCopy,
24+
Download,
25+
AutoAwesome,
26+
DriveFileMove,
27+
} from "@mui/icons-material";
2228
import {
2329
Box,
2430
Paper,
@@ -1427,7 +1433,7 @@ const LLMPanel: React.FC<LLMPanelProps> = ({
14271433
? "✓ 2. Generate BIDS Trio"
14281434
: "2. Generate BIDS Trio"}
14291435
</Button>
1430-
<Typography
1436+
{/* <Typography
14311437
variant="body2"
14321438
sx={{
14331439
textAlign: "left",
@@ -1436,7 +1442,7 @@ const LLMPanel: React.FC<LLMPanelProps> = ({
14361442
}}
14371443
>
14381444
Ready to Generate Script ↓
1439-
</Typography>
1445+
</Typography> */}
14401446
</Box>
14411447
</Box>
14421448

@@ -1456,7 +1462,7 @@ const LLMPanel: React.FC<LLMPanelProps> = ({
14561462
"&.Mui-disabled": { background: "#e0e0e0", color: "#9e9e9e" },
14571463
}}
14581464
>
1459-
{loading ? "Generating..." : "3a. Generate BIDSPlan.yaml"}
1465+
{loading ? "Generating..." : "3. Generate BIDSPlan.yaml"}
14601466
</Button>
14611467

14621468
{/* <Button
@@ -1531,17 +1537,16 @@ const LLMPanel: React.FC<LLMPanelProps> = ({
15311537
>
15321538
Copy
15331539
</Button>
1534-
<Button
1540+
{/* <Button
15351541
size="small"
15361542
startIcon={<Download />}
15371543
// onClick={handleDownload}
15381544
// disabled={!generatedScript}
15391545
onClick={bidsPlan ? handleDownloadPlan : handleDownload}
15401546
disabled={!bidsPlan && !generatedScript}
15411547
>
1542-
{/* Download */}
15431548
{bidsPlan ? "Download BIDSPlan.yaml" : "Download Script"}
1544-
</Button>
1549+
</Button> */}
15451550
<Button
15461551
size="small"
15471552
startIcon={<Download />}
@@ -1553,13 +1558,12 @@ const LLMPanel: React.FC<LLMPanelProps> = ({
15531558
</Button>
15541559
<Button
15551560
size="small"
1556-
startIcon={<Download />}
1561+
startIcon={<DriveFileMove />}
15571562
onClick={handleSaveZip}
15581563
disabled={!bidsPlan || !trioGenerated}
15591564
sx={{ color: Colors.darkGreen, borderColor: Colors.darkGreen }}
1560-
variant="outlined"
15611565
>
1562-
💾 Save to VFS
1566+
Save to Virtual File System
15631567
</Button>
15641568
</Box>
15651569

src/components/User/Dashboard/DatasetOrganizer/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,9 @@ const DatasetOrganizer: React.FC = () => {
281281
},
282282
}}
283283
>
284-
Generate BIDS Script
284+
Generate BIDS Plan
285285
</Button>
286-
<Button
286+
{/* <Button
287287
variant="contained"
288288
startIcon={<GetApp />}
289289
onClick={handleExportJSON}
@@ -298,7 +298,7 @@ const DatasetOrganizer: React.FC = () => {
298298
}}
299299
>
300300
Export JSON
301-
</Button>
301+
</Button> */}
302302
<Button
303303
variant="contained"
304304
startIcon={<Save />}

src/hooks/useSessionPoller.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { useAppDispatch } from "./useAppDispatch";
2+
import { useAppSelector } from "./useAppSelector";
3+
import { useEffect, useRef } from "react";
4+
import { getCurrentUser } from "redux/auth/auth.action";
5+
6+
const POLL_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
7+
8+
export const useSessionPoller = () => {
9+
const dispatch = useAppDispatch();
10+
const isLoggedIn = useAppSelector((state) => state.auth.isLoggedIn);
11+
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
12+
13+
// Interval polling
14+
useEffect(() => {
15+
if (!isLoggedIn) {
16+
if (intervalRef.current) clearInterval(intervalRef.current);
17+
return;
18+
}
19+
20+
intervalRef.current = setInterval(() => {
21+
dispatch(getCurrentUser());
22+
}, POLL_INTERVAL_MS);
23+
24+
return () => {
25+
if (intervalRef.current) clearInterval(intervalRef.current);
26+
};
27+
}, [isLoggedIn, dispatch]);
28+
29+
// Immediate check when user returns to the tab
30+
useEffect(() => {
31+
if (!isLoggedIn) return;
32+
33+
const handleVisibilityChange = () => {
34+
if (document.visibilityState === "visible") {
35+
dispatch(getCurrentUser());
36+
}
37+
};
38+
39+
document.addEventListener("visibilitychange", handleVisibilityChange);
40+
return () =>
41+
document.removeEventListener("visibilitychange", handleVisibilityChange);
42+
}, [isLoggedIn, dispatch]);
43+
};

0 commit comments

Comments
 (0)