Add src/components/onboarding/PasswordRequirements.jsx

This commit is contained in:
Eric Lay 2026-03-11 08:43:19 -05:00
parent f2d1b864e8
commit 4a7a0cb26a
1 changed files with 51 additions and 0 deletions

View File

@ -0,0 +1,51 @@
import React from "react";
import { Check, X } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
const requirements = [
{ label: "At least 8 characters long", test: (p) => p.length >= 8 },
{ label: "Contains an uppercase letter", test: (p) => /[A-Z]/.test(p) },
{ label: "Contains a lowercase letter", test: (p) => /[a-z]/.test(p) },
{ label: "Contains a number", test: (p) => /[0-9]/.test(p) },
{ label: "Contains a special character (!@#$%^&*)", test: (p) => /[!@#$%^&*(),.?":{}|<>]/.test(p) },
];
export function validatePassword(password) {
return requirements.every((req) => req.test(password));
}
export default function PasswordRequirements({ password, visible }) {
return (
<AnimatePresence>
{visible && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: "auto" }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.2 }}
className="overflow-hidden"
>
<div className="bg-slate-50 rounded-xl p-4 border border-slate-200 mt-2 space-y-2">
<p className="text-xs font-semibold text-slate-500 uppercase tracking-wider mb-2">
Password Requirements
</p>
{requirements.map((req, i) => {
const met = req.test(password);
return (
<div key={i} className="flex items-center gap-2">
<div
className={`w-4 h-4 rounded-full flex items-center justify-center transition-all duration-200 ${
met ? "bg-emerald-500" : "bg-slate-300"
}`}
>
{met ? (
<Check className="w-2.5 h-2.5 text-white" />
) : (
<X className="w-2.5 h-2.5 text-white" />
)}
</div>
<span
className={`text-sm transition-colors duration-200 ${
met ? "text-emerald-700 font-medium" : "text-slate-500"
}`}