Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | 105x 105x 105x 11x 11x 11x 11x 11x 2x 2x 11x 1x 1x 11x 3x 1x 11x 9x 4x 4x 11x | import { DialogDescription } from "@radix-ui/react-dialog";
import { Auth } from "aws-amplify";
import { intervalToDuration } from "date-fns";
import pluralize from "pluralize";
import { useEffect, useState } from "react";
import { useGetUser } from "@/api";
import {
Button,
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components";
import { useCountdown, useIdle } from "@/hooks";
const TWENTY_MINS_IN_MILS = 1000 * 60 * 20;
const TEN_MINS_IN_MILS = 60 * 10;
export const TimeoutModal = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const isIdleForTwentyMins = useIdle(TWENTY_MINS_IN_MILS, {
initialState: false,
});
const [timeoutModalCountdown, { startCountdown, resetCountdown }] =
useCountdown(TEN_MINS_IN_MILS);
const { data: user, isLoading: isUserLoading } = useGetUser();
const onLogOut = () => {
setTimeout(() => {
const preservePrefix = "notifs.";
const preserved: Record<string, string> = {};
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key && key.startsWith(preservePrefix)) {
preserved[key] = localStorage.getItem(key)!;
}
}
localStorage.clear();
Object.entries(preserved).forEach(([key, value]) => {
localStorage.setItem(key, value);
});
}, 100);
Auth.signOut();
};
const onExtendSession = () => {
setIsModalOpen(false);
// artificial delay hiding the countdown reset after modal dismissal
setTimeout(() => {
resetCountdown();
}, 500);
};
useEffect(() => {
if (timeoutModalCountdown === 0) {
onLogOut();
}
}, [timeoutModalCountdown]);
useEffect(() => {
if (user?.user && isIdleForTwentyMins) {
startCountdown();
setIsModalOpen(true);
}
}, [isIdleForTwentyMins, user, isUserLoading, startCountdown]);
const duration = intervalToDuration({
start: 0,
end: timeoutModalCountdown * 1000,
});
return (
<Dialog open={isModalOpen} onOpenChange={onExtendSession}>
<DialogContent className="sm:max-w-[425px]">
<DialogDescription className="sr-only">Session expiring soon</DialogDescription>
<DialogHeader>
<DialogTitle>Session expiring soon</DialogTitle>
</DialogHeader>
<div className="py-4">
<span>
Your session will expire in <strong>{duration.minutes}</strong>{" "}
{pluralize("minute", duration.minutes)} and <strong>{duration.seconds}</strong>{" "}
{pluralize("second", duration.seconds)}.
</span>
</div>
<DialogFooter>
<Button type="submit" onClick={onExtendSession}>
Yes, extend session
</Button>
<Button type="button" variant="outline" onClick={onLogOut}>
No, sign out
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};
|