Skip to content

Commit b8bc9ca

Browse files
committed
Add confirm modal to all logouts
1 parent bd473f9 commit b8bc9ca

File tree

5 files changed

+105
-24
lines changed

5 files changed

+105
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useState } from 'react';
2+
import ConfirmLogoutModal from './ConfirmLogoutModal';
3+
import { createPortal } from 'react-dom';
4+
5+
type ButtonProps = React.DetailedHTMLProps<
6+
React.ButtonHTMLAttributes<HTMLButtonElement>,
7+
HTMLButtonElement
8+
>;
9+
10+
export interface ConfirmLogoutButtonProps extends ButtonProps {
11+
children: React.ReactNode;
12+
}
13+
14+
function ConfirmLogoutButton({ children, ...props }: ConfirmLogoutButtonProps) {
15+
const [open, setOpen] = useState(false);
16+
17+
return (
18+
<>
19+
{createPortal(
20+
<ConfirmLogoutModal
21+
open={open}
22+
handleClose={() => setOpen(false)}
23+
/>,
24+
document.body,
25+
)}
26+
<button
27+
{...props}
28+
onClick={() => setOpen(true)}
29+
>
30+
{children}
31+
</button>
32+
</>
33+
);
34+
}
35+
export default ConfirmLogoutButton;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { useContext } from 'react';
2+
import { BsBoxArrowLeft, BsTrash, BsTrash3, BsTrashFill } from 'react-icons/bs';
3+
import { UserContext } from '../context/UserContext';
4+
import IconButton from './IconButton';
5+
import ModalBody from './Modal/ModalBody';
6+
import ModalCloseButton from './Modal/ModalCloseButton';
7+
import ModalDialog, { ModalDialogProps } from './Modal/ModalDialog';
8+
import ModalHeader from './Modal/ModalHeader';
9+
import ModalTitle from './Modal/ModalTitle';
10+
import ModelFooter from './Modal/ModelFooter';
11+
import { useNavigate } from 'react-router-dom';
12+
import toast from 'react-hot-toast';
13+
import Alert from './Helpers/Alert';
14+
15+
export interface ConfirmLogoutModalProps extends ModalDialogProps {}
16+
17+
function ConfirmLogoutModal(props: ConfirmLogoutModalProps) {
18+
const { user, logout } = useContext(UserContext);
19+
const navigate = useNavigate();
20+
21+
async function handleClick() {
22+
navigate('/');
23+
await logout();
24+
toast.success('Successfully logged out');
25+
}
26+
27+
return (
28+
<ModalDialog {...props}>
29+
<ModalHeader closeButton>
30+
<ModalTitle>Logout</ModalTitle>
31+
</ModalHeader>
32+
33+
<ModalBody>
34+
{user.isDemo && (
35+
<Alert className="mb-2">
36+
<BsTrash3 />
37+
This action is going to delete this demo account{' '}
38+
</Alert>
39+
)}
40+
Are you sure do you want to logout?
41+
</ModalBody>
42+
43+
<ModelFooter>
44+
<IconButton
45+
icon={BsBoxArrowLeft}
46+
onClick={handleClick}
47+
>
48+
Logout
49+
</IconButton>
50+
<ModalCloseButton />
51+
</ModelFooter>
52+
</ModalDialog>
53+
);
54+
}
55+
export default ConfirmLogoutModal;

apps/client/src/components/Helpers/Alert.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ function Alert({ children, ...props }: AlertProps) {
1212
{...props}
1313
className={classNames(
1414
'overflow-hidden break-words rounded-sm border border-red-300 bg-red-200 p-4',
15+
'flex items-center gap-2',
1516
props.className,
1617
)}
1718
>

apps/client/src/components/Pages/User/UserSettingsSidebar.tsx

+8-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import { useContext } from 'react';
21
import { BsBoxArrowLeft, BsPersonFill, BsShieldLockFill } from 'react-icons/bs';
3-
import { UserContext } from '../../../context/UserContext';
2+
import ConfirmLogoutButton from '../../ConfirmLogoutButton';
43
import SidebarLink from '../../Sidebar/SidebarLink';
54
import SidebarSection from '../../Sidebar/SidebarSection';
65

76
function UserSettingsSidebar() {
8-
const { logout } = useContext(UserContext);
9-
107
const baseUrl = `/dashboard/user/me`;
118

129
return (
@@ -24,12 +21,13 @@ function UserSettingsSidebar() {
2421
/>
2522
</SidebarSection>
2623
<SidebarSection name="Actions">
27-
<SidebarLink
28-
to="/"
29-
onClick={logout}
30-
icon={BsBoxArrowLeft}
31-
text="Logout"
32-
/>
24+
<ConfirmLogoutButton>
25+
<SidebarLink
26+
to="."
27+
icon={BsBoxArrowLeft}
28+
text="Logout"
29+
/>
30+
</ConfirmLogoutButton>
3331
</SidebarSection>
3432
</nav>
3533
);

apps/client/src/components/UserInfo.tsx

+6-14
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import {
66
BsExclamationOctagon,
77
BsPerson,
88
} from 'react-icons/bs';
9-
import { Link, useNavigate } from 'react-router-dom';
9+
import { Link } from 'react-router-dom';
1010
import Badge from '../Badge';
1111
import { UserContext } from '../context/UserContext';
12+
import ConfirmLogoutButton from './ConfirmLogoutButton';
1213
import Dropdown from './Dropdown/Dropdown';
1314
import DropdownItem from './Dropdown/DropdownItem';
1415
import DropdownMenu from './Dropdown/DropdownMenu';
@@ -17,13 +18,7 @@ import UserAvatar from './UserAvatar';
1718
import UserSettingsDropdownItem from './UserSettingsDropdownItem';
1819

1920
function UserInfo() {
20-
const { user, logout } = useContext(UserContext);
21-
const navigate = useNavigate();
22-
23-
function handleLogout() {
24-
logout();
25-
navigate('/');
26-
}
21+
const { user } = useContext(UserContext);
2722

2823
return (
2924
<Dropdown>
@@ -60,12 +55,9 @@ function UserInfo() {
6055
Report issue
6156
</DropdownItem>
6257
</Link>
63-
<DropdownItem
64-
icon={BsBoxArrowLeft}
65-
onClick={handleLogout}
66-
>
67-
Logout
68-
</DropdownItem>
58+
<ConfirmLogoutButton className="w-full">
59+
<DropdownItem icon={BsBoxArrowLeft}>Logout</DropdownItem>
60+
</ConfirmLogoutButton>
6961
</DropdownMenu>
7062
</Dropdown>
7163
);

0 commit comments

Comments
 (0)