Skip to content

Commit

Permalink
Merge pull request #60 from deepraj21/main
Browse files Browse the repository at this point in the history
Update UI of Signup
  • Loading branch information
deepraj21 authored Oct 21, 2024
2 parents 4184121 + 11d0a86 commit 5f744b6
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 40 deletions.
31 changes: 31 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
149 changes: 109 additions & 40 deletions client/src/components/Auth/user-auth-form-signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLDivElement> { }
interface PasswordRules {
Expand All @@ -31,8 +33,15 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
const [usernameError, setUsernameError] = useState<string>("");
const [passwordRules, setPasswordRules] = useState<PasswordRules | null>(null);
const [isPasswordValid, setIsPasswordValid] = useState<boolean>(false);
const allRulesPassed = passwordRules && Object.values(passwordRules).every((passed) => passed === true);
const [hasStartedTyping, setHasStartedTyping] = useState(false);
const navigate = useNavigate();

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setHasStartedTyping(true);
handlePasswordChange(e);
};

// Username availability check with debounce
useEffect(() => {
const checkUsernameAvailability = async () => {
Expand Down Expand Up @@ -157,26 +166,57 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
<Label className="sr-only" htmlFor="username">
Username
</Label>
<Input
id="username"
placeholder="Username"
type="text"
autoCapitalize="none"
autoComplete="username"
autoCorrect="off"
disabled={isLoading}
value={username}
onChange={(e) => setUsername(e.target.value)}
className='dark:bg-zinc-900'
required
/>
{isUsernameAvailable === false && (
<p className="text-red-500">Username is not available</p>
)}
{isUsernameAvailable === true && (
<p className="text-green-500">Username is available</p>
)}
{usernameError && <p className="text-red-500">{usernameError}</p>}

{/* Container for input and icon */}
<div className="relative flex items-center">
<Input
id="username"
placeholder="Username"
type="text"
autoCapitalize="none"
autoComplete="username"
autoCorrect="off"
disabled={isLoading}
value={username}
onChange={(e) => 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 && (
<HoverCard>
<HoverCardTrigger asChild>
<Check className="absolute right-3 text-green-500" />
</HoverCardTrigger>
<HoverCardContent className="text-green-500 text-sm bg-zinc-900">
Username is available
</HoverCardContent>
</HoverCard>
)}
{isUsernameAvailable === false && (
<HoverCard>
<HoverCardTrigger asChild>
<X className="absolute right-3 text-red-500" />
</HoverCardTrigger>
<HoverCardContent className="text-red-500 text-sm bg-zinc-900">
Username is not available
Username is not available
</HoverCardContent>
</HoverCard>
)}

{usernameError && (
<HoverCard>
<HoverCardTrigger asChild>
<X className="absolute right-3 text-red-500" />
</HoverCardTrigger>
<HoverCardContent className="text-red-500 text-sm bg-zinc-900">
{usernameError}
</HoverCardContent>
</HoverCard>
)}
</div>
</div>
<div className="grid gap-1">
<Label className="sr-only" htmlFor="email">
Expand All @@ -200,26 +240,55 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
<Label className="sr-only" htmlFor="password">
Password
</Label>
<Input
id="password"
placeholder="Password"
type="password"
autoComplete="current-password"
disabled={isLoading}
value={password}
onChange={handlePasswordChange}
className='dark:bg-zinc-900'
required
/>
{passwordRules &&
Object.entries(passwordRules).map(([rule, passed]) => (
<p
key={rule}
className={passed ? "text-green-500" : "text-red-500"}
>
{passwordRuleMessages[rule as keyof PasswordRules]}
</p>
))}

<div className="relative flex items-center">
<Input
id="password"
placeholder="Password"
type="password"
autoComplete="current-password"
disabled={isLoading}
value={password}
onChange={handleInputChange}
className="dark:bg-zinc-900 pr-10"
required
/>

{/* Show the validation only after user has started typing */}
{hasStartedTyping && (
<>
{allRulesPassed ? (
<HoverCard>
<HoverCardTrigger asChild>
<Check className="absolute right-3 text-green-500" />
</HoverCardTrigger>
<HoverCardContent className="text-green-500 text-sm bg-zinc-900">
{passwordRules &&
Object.entries(passwordRules).map(([rule, passed]) => (
<p key={rule} className={passed ? "text-green-500" : "text-red-500"}>
{passwordRuleMessages[rule as keyof typeof passwordRuleMessages]}
</p>
))}
</HoverCardContent>
</HoverCard>
) : (
<HoverCard>
<HoverCardTrigger asChild>
<X className="absolute right-3 text-red-500" />
</HoverCardTrigger>
<HoverCardContent className="text-red-500 text-sm bg-zinc-900">
{passwordRules &&
Object.entries(passwordRules).map(([rule, passed]) => (
<p key={rule} className={passed ? "text-green-500" : "text-red-500"}>
{passwordRuleMessages[rule as keyof typeof passwordRuleMessages]}
</p>
))}
</HoverCardContent>
</HoverCard>
)}
</>
)}
</div>
</div>
<Button
disabled={
Expand Down
27 changes: 27 additions & 0 deletions client/src/components/ui/hover-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as React from "react"
import * as HoverCardPrimitive from "@radix-ui/react-hover-card"

import { cn } from "@/lib/utils"

const HoverCard = HoverCardPrimitive.Root

const HoverCardTrigger = HoverCardPrimitive.Trigger

const HoverCardContent = React.forwardRef<
React.ElementRef<typeof HoverCardPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<HoverCardPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName

export { HoverCard, HoverCardTrigger, HoverCardContent }

0 comments on commit 5f744b6

Please sign in to comment.