Skip to content

Instantly share code, notes, and snippets.

@jonathasborges1
Created September 19, 2024 00:19
Show Gist options
  • Save jonathasborges1/897bf32a410dca7fddadfda8ff1b892c to your computer and use it in GitHub Desktop.
Save jonathasborges1/897bf32a410dca7fddadfda8ff1b892c to your computer and use it in GitHub Desktop.
Componentes Reutilizáveis em ReactJS com Material UI e TypeScript - Barra de Força de Senha
import { useEffect, useState } from "react";
import { Grid, LinearProgress, Typography, useTheme } from "@mui/material";
import CheckIcon from "@mui/icons-material/Check";
import CloseIcon from "@mui/icons-material/Close";
interface StrengthOptions {
isStrong: boolean;
label: string;
}
const passwordCriteria = {
hasNumber: /\d/,
hasUppercase: /[A-Z]/,
hasLowercase: /[a-z]/,
hasSymbol: /[!@#$%^&*(),.?":{}|<>_]/,
minLength: 8,
strongLenght: 12,
};
const getPasswordStrength = (password: string): number => {
const regExps = [
passwordCriteria.hasNumber,
passwordCriteria.hasUppercase,
passwordCriteria.hasLowercase,
passwordCriteria.hasSymbol,
];
const lengthTest = password.length >= passwordCriteria.minLength;
const stronglengthTest = password.length >= passwordCriteria.strongLenght;
const regexTests = regExps.map((regex) => regex.test(password));
// Conta quantos critérios são verdadeiros
const numCriteriaMet = regexTests.filter(Boolean).length;
// Adiciona um ponto de força se a senha atender a pelo menos três critérios de caracter e o comprimento mínimo
const allCriteriaBonus = (numCriteriaMet > 3 && lengthTest) ? 1 : 0;
return numCriteriaMet + allCriteriaBonus + Number(lengthTest) + Number(stronglengthTest);
};
const updateStrongOptions = (
password: string,
confirmPassword: string
): StrengthOptions[] => {
return [
{
isStrong: passwordCriteria.hasNumber.test(password),
label: "Número",
},
{
isStrong: passwordCriteria.hasUppercase.test(password),
label: "Letra Maiúscula",
},
{
isStrong: passwordCriteria.hasLowercase.test(password),
label: "Letra Minúscula",
},
{
isStrong: passwordCriteria.hasSymbol.test(password),
label: "Símbolo",
},
{
isStrong: password.length >= passwordCriteria.minLength,
label: "Pelo menos 8 caracteres",
},
{
isStrong: password === confirmPassword && confirmPassword.length > 0,
label: "Senhas conferem",
},
];
};
enum strengthLevels {
lowPass = "Senha Fraca",
middlePass = "Senha Média",
strongPass = "Senha Forte",
}
const PasswordStrengthBar: React.FC<{
newPass: string;
newPassConfirmation: string;
}> = ({ newPass, newPassConfirmation }) => {
const theme = useTheme();
const vermelho = theme.palette.tagsAndStatus[2]; // #ff6666
const amarelo = theme.palette.tagsAndStatus[1]; // #FDC742
const verde = theme.palette.tagsAndStatus[0]; // #0BB873
const cinza = theme.palette.tagsAndStatus[6]; // #D5D1CB
const [strength, setStrength] = useState<number>(0);
const [strongOptions, setStrongOptions] = useState<StrengthOptions[] | null>(null);
useEffect(() => {
const handleSetStrength = () => {
setStrength(getPasswordStrength(newPass));
};
const handleSetOptions = () => {
setStrongOptions(updateStrongOptions(newPass, newPassConfirmation));
};
handleSetStrength();
handleSetOptions();
}, [newPass, newPassConfirmation]);
const applyColor = (strength: number) => {
if (strength <= 2) return vermelho; // 0,1,2
if (strength >= 3 && strength <= 4) return amarelo; // 3,4
if (strength >= 5) return verde; // 5,6
};
const getStrengthLevels = (strength: number) => {
if (strength <= 2) return strengthLevels.lowPass; // 0,1,2
if (strength >= 3 && strength <= 4) return strengthLevels.middlePass; // 3,4
if (strength >= 5) return strengthLevels.strongPass; // 5
};
return (
<Grid container gap={1}>
<Grid item xs={12}>
<Grid container gap={1.45} justifyContent={"center"} sx={{ opacity: 0.6 }}>
{Array.from({ length: 7 }).map((_, index) => {
return (
<Grid item key={index} xs={1.43} >
<LinearProgress
variant="determinate"
value={100}
sx={{
borderRadius: 2,
height: "6px",
"& .MuiLinearProgress-bar": {
backgroundColor:
index < strength ? applyColor(index) : cinza,
},
}}
/>
</Grid>
);
})}
</Grid>
</Grid>
<Grid
item
xs={12}
sx={{ display: "flex", justifyContent: "space-between" }}
>
<Typography variant={"caption"} sx={{ color: applyColor(strength-1) }}>
{getStrengthLevels(strength-1)}
</Typography>
<Typography variant={"caption"}> Min. 8 Caracteres </Typography>
</Grid>
<Grid item xs={12} >
{strongOptions?.map((option, index) => {
return (
<Grid container key={index} alignItems={"center"} gap={0.5}>
<Grid item sx={{ pt: 1 }}>
{option.isStrong ? (
<CheckIcon sx={{ color: verde }} />
) : (
<CloseIcon sx={{ color: vermelho }} />
)}
</Grid>
<Grid item>
<Typography variant={"caption"} sx={{ fontWeight:500, color: theme.palette.subTitles.main }} > {option.label} </Typography>
</Grid>
</Grid>
);
})}
</Grid>
</Grid>
);
};
export default PasswordStrengthBar;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment