diff --git a/client/package-lock.json b/client/package-lock.json index 97b0444..4512bc5 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -14,6 +14,7 @@ "@radix-ui/react-collapsible": "^1.1.1", "@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2", + "@radix-ui/react-hover-card": "^1.1.2", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-navigation-menu": "^1.2.0", @@ -1417,6 +1418,36 @@ } } }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.2.tgz", + "integrity": "sha512-Y5w0qGhysvmqsIy6nQxaPa6mXNKznfoGjOfBgzOjocLxr2XlSjqBMYQQL+FfyogsMuX+m8cZyQGYhJxvxUzO4w==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-icons": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", diff --git a/client/package.json b/client/package.json index 41db929..aca3282 100644 --- a/client/package.json +++ b/client/package.json @@ -16,6 +16,7 @@ "@radix-ui/react-collapsible": "^1.1.1", "@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2", + "@radix-ui/react-hover-card": "^1.1.2", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-navigation-menu": "^1.2.0", diff --git a/client/src/components/Auth/user-auth-form-signup.tsx b/client/src/components/Auth/user-auth-form-signup.tsx index e5ac695..e620e1e 100644 --- a/client/src/components/Auth/user-auth-form-signup.tsx +++ b/client/src/components/Auth/user-auth-form-signup.tsx @@ -9,6 +9,8 @@ import { Icons } from "@/components/ui/icons"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/hover-card"; +import { Check, X } from "lucide-react"; interface UserAuthFormProps extends React.HTMLAttributes { } interface PasswordRules { @@ -31,8 +33,15 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) { const [usernameError, setUsernameError] = useState(""); const [passwordRules, setPasswordRules] = useState(null); const [isPasswordValid, setIsPasswordValid] = useState(false); + const allRulesPassed = passwordRules && Object.values(passwordRules).every((passed) => passed === true); + const [hasStartedTyping, setHasStartedTyping] = useState(false); const navigate = useNavigate(); + const handleInputChange = (e: React.ChangeEvent) => { + setHasStartedTyping(true); + handlePasswordChange(e); + }; + // Username availability check with debounce useEffect(() => { const checkUsernameAvailability = async () => { @@ -157,26 +166,57 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) { - setUsername(e.target.value)} - className='dark:bg-zinc-900' - required - /> - {isUsernameAvailable === false && ( -

Username is not available

- )} - {isUsernameAvailable === true && ( -

Username is available

- )} - {usernameError &&

{usernameError}

} + + {/* Container for input and icon */} +
+ setUsername(e.target.value)} + className="dark:bg-zinc-900 pr-10" // Add padding to the right for the icon + required + /> + + {/* HoverCard for the green tick */} + {isUsernameAvailable && ( + + + + + + Username is available + + + )} + {isUsernameAvailable === false && ( + + + + + + Username is not available + Username is not available + + + )} + + {usernameError && ( + + + + + + {usernameError} + + + )} +