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

CBIIT / crdc-datahub-ui / 11936654675

20 Nov 2024 03:36PM UTC coverage: 54.194% (+0.4%) from 53.816%
11936654675

Pull #538

github

web-flow
Merge c22c3f883 into 468753eff
Pull Request #538: Misc Optimizations

2571 of 5232 branches covered (49.14%)

Branch coverage included in aggregate %.

0 of 1 new or added line in 1 file covered. (0.0%)

50 existing lines in 3 files now uncovered.

3690 of 6321 relevant lines covered (58.38%)

136.54 hits per line

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

0.0
/src/components/InactivityDialog/InactivityDialog.tsx
1
import React, { useState, useEffect } from "react";
2
import { Button, Dialog, DialogTitle, styled } from "@mui/material";
3
import { useNavigate } from "react-router-dom";
4
import GenericAlert from "../GenericAlert";
5

6
// import env from '../../utils/env';
7

8
import { useAuthContext } from "../Contexts/AuthContext";
9

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

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

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

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

123
const secondsToMinuteString = (seconds) => new Date(seconds * 1000).toISOString().substring(14, 19);
×
124

125
const InactivityDialog = () => {
×
126
  const authData = useAuthContext();
×
127
  const { isLoggedIn } = authData;
×
128
  const [warning, setWarning] = useState(false);
×
129
  const [timedOut, setTimedOut] = useState(false);
×
130
  const [intervalID, setIntervalID] = useState<NodeJS.Timer>(null);
×
131
  const navigate = useNavigate();
×
132
  const [showLogoutAlert, setShowLogoutAlert] = useState<boolean>(false);
×
133
  const thresholdTime = 300;
×
134

135
  const [timeLeft, setTimeLeft] = useState(thresholdTime);
×
136
  const extendSession = async () => {
×
137
    const AUTH_API = `${window.origin}/api/authn/authenticated`;
×
138
    try {
×
139
      const res = await fetch(AUTH_API, {
×
140
        method: "POST",
141
        headers: {
142
          Accept: "application/json",
143
          "Content-Type": "application/json",
144
        },
145
      })
UNCOV
146
        .then((response) => response.json())
×
147
        .catch(() => {});
148

UNCOV
149
      if (res.status) {
×
150
        setWarning(false);
×
151
      }
152
    } catch (e) {
153
      // Add Erro handler here.
154
    }
155
  };
156

157
  const handleExtendSession = () => {
×
UNCOV
158
    extendSession();
×
159
  };
160

161
  const handleSignOutNoBanner = async () => {
×
162
    const logoutStatus = await authData.logout();
×
UNCOV
163
    if (logoutStatus) {
×
UNCOV
164
      navigate("/");
×
165
      setWarning(false);
×
166
    }
167
  };
168

169
  const handleSignOut = async () => {
×
UNCOV
170
    const logoutStatus = await authData.logout();
×
UNCOV
171
    if (logoutStatus) {
×
UNCOV
172
      navigate("/");
×
173
      setWarning(false);
×
174
      setShowLogoutAlert(true);
×
175
      setTimeout(() => setShowLogoutAlert(false), 10000);
×
176
    }
177
  };
178

179
  const loadData = async () => {
×
UNCOV
180
    try {
×
UNCOV
181
      const SESSION_TTL_API = `${window.origin}/api/authn/session-ttl`;
×
182

183
      const res = await fetch(SESSION_TTL_API);
×
184
      const data = await res.json();
×
UNCOV
185
      const { ttl } = data;
×
186
      if (ttl <= 0) {
×
187
        // If user did not select any option and timed out in BE.
UNCOV
188
        handleSignOutNoBanner();
×
189
        setTimedOut(true);
×
190
      } else if (ttl > 0 && ttl <= thresholdTime) {
×
191
        setTimeLeft(ttl);
×
192
        setWarning(true);
×
193
      }
194
    } catch (e) {
195
      // Add Erro handler here.
196
    }
197
  };
198

UNCOV
199
  useEffect(() => {
×
200
    if (isLoggedIn) {
×
201
      // NOTE: 1000 milliseconds = 1 second, PING_INTERVAL * 1000 = PING_INTERVAL milliseconds;
UNCOV
202
      const ID = setInterval(loadData, 10 * 1000);
×
203
      setIntervalID(ID);
×
204
    } else {
205
      clearInterval(intervalID);
×
206
    }
207
    return () => clearInterval(intervalID);
×
208
  }, [isLoggedIn]);
209

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

296
export default InactivityDialog;
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