• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CBIIT / crdc-datahub-ui / 15497092546

06 Jun 2025 06:19PM UTC coverage: 65.179% (+2.5%) from 62.708%
15497092546

push

github

web-flow
Merge pull request #726 from CBIIT/CRDCDH-2817

CRDCDH-2817 Vite/Vitest Migration & Upgrade dependencies

3529 of 3882 branches covered (90.91%)

Branch coverage included in aggregate %.

167 of 224 new or added lines in 82 files covered. (74.55%)

7620 existing lines in 126 files now uncovered.

22012 of 35304 relevant lines covered (62.35%)

101.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.62
/src/components/InactivityDialog/InactivityDialog.tsx
1
import React, { useState, useEffect, FC } from "react";
1✔
2
import { Button, Dialog, DialogTitle, styled } from "@mui/material";
1✔
3
import { useNavigate } from "react-router-dom";
1✔
4
import { useSnackbar } from "notistack";
1✔
5
import { useAuthContext } from "../Contexts/AuthContext";
1✔
6
import { Logger, secondsToMinuteString } from "../../utils";
1✔
7
import CloseIcon from "../../assets/icons/close_icon.svg?url";
1✔
8

9
const InactivityWarningDialog = styled(Dialog)({
1✔
10
  "& .MuiDialog-paper": {
1✔
11
    width: "550px",
1✔
12
    height: "320px",
1✔
13
    borderRadius: "8px",
1✔
14
    border: "2px solid var(--secondary-one, #0B7F99)",
1✔
15
    background: "linear-gradient(0deg, #F2F6FA 0%, #F2F6FA 100%), #2E4D7B",
1✔
16
    boxShadow: "0px 4px 45px 0px rgba(0, 0, 0, 0.40)",
1✔
17
  },
1✔
18
  "& #customized-dialog-title": {
1✔
19
    margin: 0,
1✔
20
    paddingLeft: "30px",
1✔
21
    backgroundColor: "#6D89A2",
1✔
22
    color: "#FFFFFF",
1✔
23
    fontFamily: "Lato",
1✔
24
    fontSize: "20px",
1✔
25
    fontWeight: 600,
1✔
26
    letterSpacing: 0,
1✔
27
  },
1✔
28
});
1✔
29

30
const InactivityWarningContent = styled("div")({
1✔
31
  margin: "50px auto",
1✔
32
  color: "#000000",
1✔
33
  fontFamily: "'Nunito', 'Rubik', sans-serif",
1✔
34
  fontSize: "17px",
1✔
35
  fontWeight: 300,
1✔
36
  letterSpacing: 0,
1✔
37
  lineHeight: "24px",
1✔
38
  "& .buttonWrapper": {
1✔
39
    display: "flex",
1✔
40
    justifyContent: "center",
1✔
41
    alignItems: "center",
1✔
42
    textAlign: "center",
1✔
43
  },
1✔
44
  "& .buttonGroup": {
1✔
45
    color: "#FFFFFF",
1✔
46
    fontFamily: "Lato",
1✔
47
    fontSize: "11px",
1✔
48
    lineHeight: "22px",
1✔
49
    width: "150px",
1✔
50
    border: "1px solid #626262",
1✔
51
    marginTop: "30px",
1✔
52
    borderRadius: "4px",
1✔
53
    fontWeight: 500,
1✔
54
  },
1✔
55
  "& .extendButton": {
1✔
56
    backgroundColor: "#566672 !important",
1✔
57
  },
1✔
58
  "& .logOutButton": {
1✔
59
    marginLeft: "20px",
1✔
60
    backgroundColor: "#437BBE !important",
1✔
61
  },
1✔
62
});
1✔
63

64
const SessionTimeoutDialog = styled(Dialog)({
1✔
65
  "& .MuiDialog-paper": {
1✔
66
    width: "550px",
1✔
67
    height: "320px",
1✔
68
    borderRadius: "8px",
1✔
69
    border: "2px solid var(--secondary-one, #0B7F99)",
1✔
70
    background: "linear-gradient(0deg, #F2F6FA 0%, #F2F6FA 100%), #2E4D7B",
1✔
71
    boxShadow: "0px 4px 45px 0px rgba(0, 0, 0, 0.40)",
1✔
72
  },
1✔
73
  "& .closeIcon": {
1✔
74
    cursor: "pointer",
1✔
75
    textAlign: "end",
1✔
76
  },
1✔
77
});
1✔
78

79
const SessionTimeoutContent = styled("div")({
1✔
80
  justifyContent: "space-between",
1✔
81
  paddingRight: "33px",
1✔
82
  paddingLeft: "33px",
1✔
83
  paddingTop: "10px",
1✔
84
  fontFamily: "lato",
1✔
85
  textAlign: "center",
1✔
86
  "& .sessionTimeoutTitle": {
1✔
87
    fontSize: "25px",
1✔
88
    fontWeight: "bold",
1✔
89
    paddingBottom: "12px",
1✔
90
    color: "#566672",
1✔
91
  },
1✔
92
  "& .sessionTimeoutMessage": {
1✔
93
    fontSize: "17px",
1✔
94
    paddingBottom: "14px",
1✔
95
  },
1✔
96
  "& .buttonWrapper": {
1✔
97
    display: "flex",
1✔
98
    justifyContent: "center",
1✔
99
    alignItems: "center",
1✔
100
    textAlign: "center",
1✔
101
  },
1✔
102
  "& .buttonGroup": {
1✔
103
    color: "#FFFFFF",
1✔
104
    fontFamily: "Lato",
1✔
105
    fontSize: "11px",
1✔
106
    lineHeight: "22px",
1✔
107
    width: "90px",
1✔
108
    border: "1px solid #626262",
1✔
109
    marginTop: "30px",
1✔
110
    borderRadius: "4px",
1✔
111
    fontWeight: 500,
1✔
112
  },
1✔
113
  "& .closeButton": {
1✔
114
    backgroundColor: "#566672 !important",
1✔
115
  },
1✔
116
  "& .loginButton": {
1✔
117
    marginLeft: "20px",
1✔
118
    backgroundColor: "#437BBE !important",
1✔
119
  },
1✔
120
});
1✔
121

122
/**
123
 * The time (in seconds) at which the timeout warning banner should be displayed.
124
 */
125
const timeoutThresholdSeconds = 300;
1✔
126

127
/**
128
 * An inactivity dialog that handles session the TTL ping and timeout.
129
 *
130
 * @returns InactivityDialog component
131
 */
132
const InactivityDialog: FC = () => {
1✔
133
  const navigate = useNavigate();
5✔
134
  const { enqueueSnackbar } = useSnackbar();
5✔
135
  const { isLoggedIn, logout } = useAuthContext();
5✔
136

137
  const [warning, setWarning] = useState<boolean>(false);
5✔
138
  const [timedOut, setTimedOut] = useState<boolean>(false);
5✔
139
  const [timeLeft, setTimeLeft] = useState<number>(timeoutThresholdSeconds);
5✔
140

141
  const extendSession = async () => {
5✔
142
    try {
×
143
      const res = await fetch(`${window.origin}/api/authn/authenticated`, {
×
UNCOV
144
        method: "POST",
×
UNCOV
145
        headers: {
×
UNCOV
146
          Accept: "application/json",
×
UNCOV
147
          "Content-Type": "application/json",
×
UNCOV
148
        },
×
UNCOV
149
      })
×
150
        .then((response) => response.json())
×
UNCOV
151
        .catch(() => {});
×
152

153
      if (res.status) {
×
154
        setWarning(false);
×
UNCOV
155
      }
×
UNCOV
156
    } catch (e) {
×
157
      Logger.error("Error in extending session", e);
×
UNCOV
158
    }
×
UNCOV
159
  };
×
160

161
  const handleExtendSession = () => {
5✔
162
    extendSession();
×
UNCOV
163
  };
×
164

165
  const handleSignOutNoBanner = async () => {
5✔
166
    const logoutStatus = await logout();
1✔
167
    if (logoutStatus) {
1✔
168
      navigate("/");
1✔
169
      setWarning(false);
1✔
170
    }
1✔
171
  };
1✔
172

173
  const handleSignOut = async () => {
5✔
174
    const logoutStatus = await logout();
×
175
    if (logoutStatus) {
×
176
      navigate("/");
×
177
      setWarning(false);
×
178
      enqueueSnackbar("You have been logged out.", { variant: "default" });
×
UNCOV
179
    }
×
UNCOV
180
  };
×
181

182
  const loadData = async () => {
5✔
183
    try {
3✔
184
      const res = await fetch(`${window.origin}/api/authn/session-ttl`);
3✔
185
      const data = await res.json();
2✔
186
      const { ttl } = data;
2✔
187
      if (ttl <= 0) {
3✔
188
        // If user did not select any option and timed out in BE.
189
        handleSignOutNoBanner();
1✔
190
        setTimedOut(true);
1✔
191
      } else if (ttl > 0 && ttl <= timeoutThresholdSeconds) {
1!
192
        setTimeLeft(ttl);
×
193
        setWarning(true);
×
UNCOV
194
      }
×
195
    } catch (e) {
3✔
196
      Logger.error("Error in fetching session ttl", e);
1✔
197
    }
1✔
198
  };
3✔
199

200
  useEffect(() => {
5✔
201
    let ID: ReturnType<typeof setInterval>;
3✔
202
    if (isLoggedIn) {
3✔
203
      ID = setInterval(loadData, 10 * 1000);
3✔
204
    } else {
3!
205
      clearInterval(ID);
×
UNCOV
206
    }
×
207

208
    return () => clearInterval(ID);
3✔
209
  }, [isLoggedIn]);
5✔
210

211
  return (
5✔
212
    <>
5✔
213
      <InactivityWarningDialog open={warning}>
5✔
214
        <DialogTitle id="customized-dialog-title">Session Timeout Warning</DialogTitle>
5✔
215
        <InactivityWarningContent>
5✔
216
          This session is about to expire due to inactivity.
217
          <br />
5✔
218
          You will be logged out in
219
          {` ${secondsToMinuteString(timeLeft)} `}
5✔
220
          minutes.
221
          <br />
5✔
222
          Please elect to extend this session or logout.
223
          <div className="buttonWrapper">
5✔
224
            <Button
5✔
225
              variant="contained"
5✔
226
              className="buttonGroup extendButton"
5✔
227
              onClick={handleExtendSession}
5✔
228
              disableElevation={false}
5✔
229
            >
230
              EXTEND SESSION
231
            </Button>
5✔
232
            <Button
5✔
233
              variant="contained"
5✔
234
              className="buttonGroup logOutButton"
5✔
235
              onClick={handleSignOut}
5✔
236
              disableElevation={false}
5✔
237
            >
238
              LOGOUT
239
            </Button>
5✔
240
          </div>
5✔
241
        </InactivityWarningContent>
5✔
242
      </InactivityWarningDialog>
5✔
243
      <SessionTimeoutDialog open={timedOut}>
5✔
244
        <DialogTitle>
5✔
245
          <div
5✔
246
            role="button"
5✔
247
            className="closeIcon"
5✔
248
            onClick={() => setTimedOut(false)}
5✔
249
            tabIndex={0}
5✔
250
            onKeyDown={(e) => {
5✔
251
              if (e.key === "Enter") {
×
252
                setTimedOut(false);
×
UNCOV
253
              }
×
UNCOV
254
            }}
×
255
          >
256
            <img style={{ height: 10, marginBottom: 2 }} src={CloseIcon} alt="close icon" />
5✔
257
          </div>
5✔
258
        </DialogTitle>
5✔
259
        <SessionTimeoutContent>
5✔
260
          <div className="sessionTimeoutTitle">Your session has expired.</div>
5✔
261
          <br />
5✔
262
          <div className="sessionTimeoutMessage">Please login again to continue working.</div>
5✔
263
          <div className="buttonWrapper">
5✔
264
            <Button
5✔
265
              variant="contained"
5✔
266
              className="buttonGroup closeButton"
5✔
267
              onClick={() => setTimedOut(false)}
5✔
268
              disableElevation={false}
5✔
269
            >
270
              CLOSE
271
            </Button>
5✔
272
            <Button
5✔
273
              variant="contained"
5✔
274
              className="buttonGroup loginButton"
5✔
275
              onClick={() => {
5✔
276
                setTimedOut(false);
×
277
                navigate("login");
×
UNCOV
278
              }}
×
279
              disableElevation={false}
5✔
280
            >
281
              LOGIN
282
            </Button>
5✔
283
          </div>
5✔
284
        </SessionTimeoutContent>
5✔
285
      </SessionTimeoutDialog>
5✔
286
    </>
5✔
287
  );
288
};
5✔
289

290
export default InactivityDialog;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc