[staff] Add option for toggling email 2fa

This commit is contained in:
Neeraj Gupta
2024-11-27 11:49:52 +05:30
parent 8d32cba241
commit 4e1bc124ff
3 changed files with 249 additions and 1 deletions

View File

@@ -47,6 +47,7 @@ interface Security {
isTwoFactorEnabled: boolean;
passkeys: string;
passkeyCount: number;
canDisableEmailMFA: boolean;
}
interface UserResponse {
@@ -189,6 +190,7 @@ const App: React.FC = () => {
0) > 0
? "Enabled"
: "Disabled",
"Can Disable EmailMFA": userDataResponse.details?.profileData.canDisableEmailMFA ? "Yes":"No",
AuthCodes: `${userDataResponse.authCodes ?? 0}`,
},
};

View File

@@ -0,0 +1,183 @@
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Paper,
} from "@mui/material";
import React, { useState } from "react";
import { getEmail, getToken } from "../App"; // Import getEmail and getToken functions
import { apiOrigin } from "../services/support";
interface UserData {
subscription?: {
userID: string;
// Add other properties as per your API response structure
};
// Add other properties as per your API response structure
}
interface ToggleEmailMFAProps {
open: boolean;
handleClose: () => void;
handleToggleEmailMFA: (status: boolean) => void; // Callback to handle toggling Email MFA
}
const ToggleEmailMFA: React.FC<ToggleEmailMFAProps> = ({
open,
handleClose,
handleToggleEmailMFA,
}) => {
const [loading, setLoading] = useState(false);
const handleToggle = async (enable: boolean) => {
try {
setLoading(true);
const email = getEmail();
const token = getToken();
if (!email) {
throw new Error("Email not found");
}
if (!token) {
throw new Error("Token not found");
}
const encodedEmail = encodeURIComponent(email);
// Fetch user data
const userUrl = `${apiOrigin}/admin/user?email=${encodedEmail}`;
const userResponse = await fetch(userUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Auth-Token": token,
},
});
if (!userResponse.ok) {
throw new Error("Failed to fetch user data");
}
const userData = (await userResponse.json()) as UserData;
const userId = userData.subscription?.userID;
if (!userId) {
throw new Error("User ID not found");
}
// Toggle Email MFA action
const toggleEmailMFAUrl = `${apiOrigin}/admin/user/update-email-mfa`;
const body = JSON.stringify({ userID: userId, emailMFA: enable });
const toggleEmailMFAResponse = await fetch(toggleEmailMFAUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Auth-Token": token,
},
body: body,
});
if (!toggleEmailMFAResponse.ok) {
const errorResponse = await toggleEmailMFAResponse.text();
throw new Error(`Failed to update Email MFA: ${errorResponse}`);
}
handleToggleEmailMFA(enable); // Notify parent component of successful action with status
handleClose(); // Close dialog on successful action
console.log(`Email MFA ${enable ? "enabled" : "disabled"} successfully`);
} catch (error) {
if (error instanceof Error) {
alert(error.message);
} else {
alert("Failed to update Email MFA");
}
} finally {
setLoading(false);
}
};
const handleCancel = () => {
handleClose(); // Close dialog
};
return (
<div>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
PaperComponent={Paper}
sx={{
width: "499px",
height: "286px",
margin: "auto",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
}}
BackdropProps={{
style: {
backgroundColor: "rgba(255, 255, 255, 0.9)", // Semi-transparent backdrop
},
}}
>
<DialogTitle id="alert-dialog-title">
{"Toggle Email MFA"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Do you want to enable or disable Email MFA for this account?
</DialogContentText>
</DialogContent>
<DialogActions sx={{ justifyContent: "center" }}>
<Button
onClick={handleCancel}
sx={{
bgcolor: "white",
color: "black",
"&:hover": { bgcolor: "#FAFAFA" },
}}
>
Cancel
</Button>
<Button
onClick={() => {
handleToggle(true).catch((error: unknown) =>
console.error(error),
);
}}
sx={{
bgcolor: "#4CAF50",
color: "white",
"&:hover": { bgcolor: "#45A049" },
}}
disabled={loading}
>
{loading ? "Processing..." : "Enable Email MFA"}
</Button>
<Button
onClick={() => {
handleToggle(false).catch((error: unknown) =>
console.error(error),
);
}}
sx={{
bgcolor: "#F4473D",
color: "white",
"&:hover": { bgcolor: "#E53935" },
}}
disabled={loading}
>
{loading ? "Processing..." : "Disable Email MFA"}
</Button>
</DialogActions>
</Dialog>
</div>
);
};
export default ToggleEmailMFA;

View File

@@ -18,6 +18,7 @@ import DeleteAccount from "./DeleteAccont";
import Disable2FA from "./Disable2FA";
import DisablePasskeys from "./DisablePasskeys";
import UpdateSubscription from "./UpdateSubscription";
import ToggleEmailMFA from "./ToggleEmailMFA";
export interface UserData {
User: Record<string, string>;
@@ -32,8 +33,11 @@ interface UserComponentProps {
const UserComponent: React.FC<UserComponentProps> = ({ userData }) => {
const [deleteAccountOpen, setDeleteAccountOpen] = React.useState(false);
const [email2FAEnabled, setEmail2FAEnabled] = React.useState(false);
const [email2FAOpen, setEmail2FAToggleOpen] = React.useState(false);
const [disable2FAOpen, setDisable2FAOpen] = React.useState(false);
const [twoFactorEnabled, setTwoFactorEnabled] = React.useState(false);
const [canDisableEmailMFA, setCanDisableEmailMFA] = React.useState(false);
const [updateSubscriptionOpen, setUpdateSubscriptionOpen] =
React.useState(false);
const [changeEmailOpen, setChangeEmailOpen] = React.useState(false);
@@ -41,6 +45,8 @@ const UserComponent: React.FC<UserComponentProps> = ({ userData }) => {
React.useEffect(() => {
setTwoFactorEnabled(userData?.Security["Two factor 2FA"] === "Enabled");
setEmail2FAEnabled(userData?.Security["Email MFA"] === "Enabled");
setCanDisableEmailMFA(userData?.Security["Can Disable EmailMFA"] === "Yes");
}, [userData]);
const handleEditEmail = () => setChangeEmailOpen(true);
@@ -62,9 +68,12 @@ const UserComponent: React.FC<UserComponentProps> = ({ userData }) => {
onDeleteAccount={handleDeleteAccountClick}
onEditSubscription={handleEditSubscription}
onDisablePasskeys={handleDisablePasskeys}
canDisableEmailMFA={canDisableEmailMFA}
twoFactorEnabled={twoFactorEnabled}
setTwoFactorEnabled={setTwoFactorEnabled}
setDisable2FAOpen={setDisable2FAOpen}
email2FAEnabled={email2FAEnabled}
setEmail2FAToggleOpen={setEmail2FAToggleOpen}
/>
</Grid>
))}
@@ -78,6 +87,11 @@ const UserComponent: React.FC<UserComponentProps> = ({ userData }) => {
handleClose={() => setDisable2FAOpen(false)}
handleDisable2FA={() => setTwoFactorEnabled(false)}
/>
<ToggleEmailMFA
open={email2FAOpen}
handleClose={() => setEmail2FAToggleOpen(false)}
handleToggleEmailMFA={(status) => setEmail2FAToggleOpen(status)}
/>
<UpdateSubscription
open={updateSubscriptionOpen}
onClose={() => setUpdateSubscriptionOpen(false)}
@@ -102,9 +116,12 @@ interface DataTableProps {
onDeleteAccount: () => void;
onEditSubscription: () => void;
onDisablePasskeys: () => void;
canDisableEmailMFA: boolean;
twoFactorEnabled: boolean;
setTwoFactorEnabled: (enabled: boolean) => void;
setDisable2FAOpen: (open: boolean) => void;
email2FAEnabled: boolean;
setEmail2FAToggleOpen: (open: boolean) => void;
}
const DataTable: React.FC<DataTableProps> = ({
@@ -114,9 +131,12 @@ const DataTable: React.FC<DataTableProps> = ({
onDeleteAccount,
onEditSubscription,
onDisablePasskeys,
canDisableEmailMFA,
twoFactorEnabled,
setTwoFactorEnabled,
setDisable2FAOpen,
email2FAEnabled,
setEmail2FAToggleOpen,
}) => (
<TableContainer
component={Paper}
@@ -186,7 +206,9 @@ const DataTable: React.FC<DataTableProps> = ({
aria-label={title}
>
<TableBody>
{Object.entries(data).map(([label, value], index) => (
{Object.entries(data)
.filter(([label]) => label !== "Can Disable EmailMFA")
.map(([label, value], index) => (
<TableRow key={label}>
<TableCell
component="th"
@@ -217,9 +239,12 @@ const DataTable: React.FC<DataTableProps> = ({
value,
onEditEmail,
onDisablePasskeys,
canDisableEmailMFA,
twoFactorEnabled,
setTwoFactorEnabled,
setDisable2FAOpen,
email2FAEnabled,
setEmail2FAToggleOpen,
)}
</TableCell>
</TableRow>
@@ -234,9 +259,12 @@ const renderTableCellContent = (
value: string,
onEditEmail: () => void,
onDisablePasskeys: () => void,
canToggleEmailMFA: boolean,
twoFactorEnabled: boolean,
setTwoFactorEnabled: (enabled: boolean) => void,
setDisable2FAOpen: (open: boolean) => void,
email2FAEnabled: boolean,
setEmail2FAToggleOpen: (open: boolean) => void,
) => {
switch (label) {
case "Email":
@@ -307,6 +335,41 @@ const renderTableCellContent = (
)}
</Box>
);
case "Email MFA":
return (
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "right",
width: "100%",
paddingRight: "50px",
}}
>
<Typography sx={{ marginRight: "1px" }}>{value}</Typography>
{canToggleEmailMFA && (
<Switch
checked={email2FAEnabled}
onChange={(e) => {
setEmail2FAToggleOpen(true);
}}
sx={{
"& .MuiSwitch-switchBase.Mui-checked": {
color: "#00B33C",
"&:hover": {
backgroundColor:
"rgba(0, 179, 60, 0.08)",
},
},
"& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track":
{
backgroundColor: "#00B33C",
},
}}
/>
)}
</Box>
);
default:
return <Typography>{value}</Typography>;
}