Merge pull request #306 from adithyaakrishna/feat/reveal-password

feat: added feature to show/hide password
This commit is contained in:
Lucas Smith
2023-09-20 12:38:09 +10:00
committed by GitHub
9 changed files with 175 additions and 64 deletions
@@ -68,7 +68,7 @@ export const UploadDocument = ({ className }: UploadDocumentProps) => {
{isLoading && ( {isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-white/50"> <div className="absolute inset-0 flex items-center justify-center bg-white/50">
<Loader className="h-12 w-12 animate-spin text-slate-500" /> <Loader className="text-muted-foreground h-12 w-12 animate-spin" />
</div> </div>
)} )}
</div> </div>
@@ -43,7 +43,7 @@ export default async function BillingSettingsPage() {
<div> <div>
<h3 className="text-lg font-medium">Billing</h3> <h3 className="text-lg font-medium">Billing</h3>
<p className="mt-2 text-sm text-slate-500"> <p className="text-muted-foreground mt-2 text-sm">
Your subscription is{' '} Your subscription is{' '}
{subscription.status !== SubscriptionStatus.INACTIVE ? 'active' : 'inactive'}. {subscription.status !== SubscriptionStatus.INACTIVE ? 'active' : 'inactive'}.
{subscription?.periodEnd && ( {subscription?.periodEnd && (
@@ -67,7 +67,7 @@ export default async function BillingSettingsPage() {
)} )}
{!billingPortalUrl && ( {!billingPortalUrl && (
<p className="max-w-[60ch] text-base text-slate-500"> <p className="text-muted-foreground max-w-[60ch] text-base">
You do not currently have a customer record, this should not happen. Please contact You do not currently have a customer record, this should not happen. Please contact
support for assistance. support for assistance.
</p> </p>
@@ -9,7 +9,7 @@ export default async function PasswordSettingsPage() {
<div> <div>
<h3 className="text-lg font-medium">Password</h3> <h3 className="text-lg font-medium">Password</h3>
<p className="mt-2 text-sm text-slate-500">Here you can update your password.</p> <p className="text-muted-foreground mt-2 text-sm">Here you can update your password.</p>
<hr className="my-4" /> <hr className="my-4" />
@@ -9,7 +9,7 @@ export default async function ProfileSettingsPage() {
<div> <div>
<h3 className="text-lg font-medium">Profile</h3> <h3 className="text-lg font-medium">Profile</h3>
<p className="mt-2 text-sm text-slate-500">Here you can edit your personal details.</p> <p className="text-muted-foreground mt-2 text-sm">Here you can edit your personal details.</p>
<hr className="my-4" /> <hr className="my-4" />
@@ -44,7 +44,7 @@ export const PeriodSelector = () => {
return ( return (
<Select defaultValue={period} onValueChange={onPeriodChange}> <Select defaultValue={period} onValueChange={onPeriodChange}>
<SelectTrigger className="max-w-[200px] text-slate-500"> <SelectTrigger className="text-muted-foreground max-w-[200px]">
<SelectValue /> <SelectValue />
</SelectTrigger> </SelectTrigger>
+56 -19
View File
@@ -1,7 +1,9 @@
'use client'; 'use client';
import { useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { Loader } from 'lucide-react'; import { Eye, EyeOff, Loader } from 'lucide-react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';
@@ -36,6 +38,9 @@ export type PasswordFormProps = {
export const PasswordForm = ({ className }: PasswordFormProps) => { export const PasswordForm = ({ className }: PasswordFormProps) => {
const { toast } = useToast(); const { toast } = useToast();
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const { const {
register, register,
handleSubmit, handleSubmit,
@@ -92,15 +97,31 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
Password Password
</Label> </Label>
<Input <div className="relative">
id="password" <Input
type="password" id="password"
minLength={6} type={showPassword ? 'text' : 'password'}
maxLength={72} minLength={6}
autoComplete="new-password" maxLength={72}
className="bg-background mt-2" autoComplete="new-password"
{...register('password')} className="bg-background mt-2 pr-10"
/> {...register('password')}
/>
<Button
variant="link"
type="button"
className="absolute right-0 top-0 flex h-full items-center justify-center pr-3"
aria-label={showPassword ? 'Mask password' : 'Reveal password'}
onClick={() => setShowPassword((show) => !show)}
>
{showPassword ? (
<EyeOff className="text-muted-foreground h-5 w-5" />
) : (
<Eye className="text-muted-foreground h-5 w-5" />
)}
</Button>
</div>
<FormErrorMessage className="mt-1.5" error={errors.password} /> <FormErrorMessage className="mt-1.5" error={errors.password} />
</div> </div>
@@ -110,15 +131,31 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
Repeat Password Repeat Password
</Label> </Label>
<Input <div className="relative">
id="repeated-password" <Input
type="password" id="repeated-password"
minLength={6} type={showConfirmPassword ? 'text' : 'password'}
maxLength={72} minLength={6}
autoComplete="new-password" maxLength={72}
className="bg-background mt-2" autoComplete="new-password"
{...register('repeatedPassword')} className="bg-background mt-2 pr-10"
/> {...register('repeatedPassword')}
/>
<Button
variant="link"
type="button"
className="absolute right-0 top-0 flex h-full items-center justify-center pr-3"
aria-label={showConfirmPassword ? 'Mask password' : 'Reveal password'}
onClick={() => setShowConfirmPassword((show) => !show)}
>
{showConfirmPassword ? (
<EyeOff className="text-muted-foreground h-5 w-5" />
) : (
<Eye className="text-muted-foreground h-5 w-5" />
)}
</Button>
</div>
<FormErrorMessage className="mt-1.5" error={errors.repeatedPassword} /> <FormErrorMessage className="mt-1.5" error={errors.repeatedPassword} />
</div> </div>
@@ -1,8 +1,11 @@
'use client'; 'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { Eye, EyeOff } from 'lucide-react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';
@@ -37,6 +40,9 @@ export const ResetPasswordForm = ({ className, token }: ResetPasswordFormProps)
const { toast } = useToast(); const { toast } = useToast();
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const { const {
register, register,
reset, reset,
@@ -96,15 +102,31 @@ export const ResetPasswordForm = ({ className, token }: ResetPasswordFormProps)
<span>Password</span> <span>Password</span>
</Label> </Label>
<Input <div className="relative">
id="password" <Input
type="password" id="password"
minLength={6} type={showPassword ? 'text' : 'password'}
maxLength={72} minLength={6}
autoComplete="current-password" maxLength={72}
className="bg-background mt-2" autoComplete="new-password"
{...register('password')} className="bg-background mt-2 pr-10"
/> {...register('password')}
/>
<Button
variant="link"
type="button"
className="absolute right-0 top-0 flex h-full items-center justify-center pr-3"
aria-label={showPassword ? 'Mask password' : 'Reveal password'}
onClick={() => setShowPassword((show) => !show)}
>
{showPassword ? (
<EyeOff className="text-muted-foreground h-5 w-5" />
) : (
<Eye className="text-muted-foreground h-5 w-5" />
)}
</Button>
</div>
<FormErrorMessage className="mt-1.5" error={errors.password} /> <FormErrorMessage className="mt-1.5" error={errors.password} />
</div> </div>
@@ -114,15 +136,31 @@ export const ResetPasswordForm = ({ className, token }: ResetPasswordFormProps)
<span>Repeat Password</span> <span>Repeat Password</span>
</Label> </Label>
<Input <div className="relative">
id="repeatedPassword" <Input
type="password" id="repeated-password"
minLength={6} type={showConfirmPassword ? 'text' : 'password'}
maxLength={72} minLength={6}
autoComplete="current-password" maxLength={72}
className="bg-background mt-2" autoComplete="new-password"
{...register('repeatedPassword')} className="bg-background mt-2 pr-10"
/> {...register('repeatedPassword')}
/>
<Button
variant="link"
type="button"
className="absolute right-0 top-0 flex h-full items-center justify-center pr-3"
aria-label={showConfirmPassword ? 'Mask password' : 'Reveal password'}
onClick={() => setShowConfirmPassword((show) => !show)}
>
{showConfirmPassword ? (
<EyeOff className="text-muted-foreground h-5 w-5" />
) : (
<Eye className="text-muted-foreground h-5 w-5" />
)}
</Button>
</div>
<FormErrorMessage className="mt-1.5" error={errors.repeatedPassword} /> <FormErrorMessage className="mt-1.5" error={errors.repeatedPassword} />
</div> </div>
+28 -11
View File
@@ -1,11 +1,11 @@
'use client'; 'use client';
import { useEffect } from 'react'; import { useEffect, useState } from 'react';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { Loader } from 'lucide-react'; import { Eye, EyeOff, Loader } from 'lucide-react';
import { signIn } from 'next-auth/react'; import { signIn } from 'next-auth/react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { FcGoogle } from 'react-icons/fc'; import { FcGoogle } from 'react-icons/fc';
@@ -43,6 +43,7 @@ export const SignInForm = ({ className }: SignInFormProps) => {
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const { toast } = useToast(); const { toast } = useToast();
const [showPassword, setShowPassword] = useState(false);
const { const {
register, register,
@@ -128,15 +129,31 @@ export const SignInForm = ({ className }: SignInFormProps) => {
<span>Password</span> <span>Password</span>
</Label> </Label>
<Input <div className="relative">
id="password" <Input
type="password" id="password"
minLength={6} type={showPassword ? 'text' : 'password'}
maxLength={72} minLength={6}
autoComplete="current-password" maxLength={72}
className="bg-background mt-2" autoComplete="current-password"
{...register('password')} className="bg-background mt-2 pr-10"
/> {...register('password')}
/>
<Button
variant="link"
type="button"
className="absolute right-0 top-0 flex h-full items-center justify-center pr-3"
aria-label={showPassword ? 'Mask password' : 'Reveal password'}
onClick={() => setShowPassword((show) => !show)}
>
{showPassword ? (
<EyeOff className="text-muted-foreground h-5 w-5" />
) : (
<Eye className="text-muted-foreground h-5 w-5" />
)}
</Button>
</div>
<FormErrorMessage className="mt-1.5" error={errors.password} /> <FormErrorMessage className="mt-1.5" error={errors.password} />
</div> </div>
+29 -10
View File
@@ -1,7 +1,9 @@
'use client'; 'use client';
import { useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { Loader } from 'lucide-react'; import { Eye, EyeOff, Loader } from 'lucide-react';
import { signIn } from 'next-auth/react'; import { signIn } from 'next-auth/react';
import { Controller, useForm } from 'react-hook-form'; import { Controller, useForm } from 'react-hook-form';
import { z } from 'zod'; import { z } from 'zod';
@@ -31,6 +33,7 @@ export type SignUpFormProps = {
export const SignUpForm = ({ className }: SignUpFormProps) => { export const SignUpForm = ({ className }: SignUpFormProps) => {
const { toast } = useToast(); const { toast } = useToast();
const [showPassword, setShowPassword] = useState(false);
const { const {
control, control,
@@ -106,15 +109,31 @@ export const SignUpForm = ({ className }: SignUpFormProps) => {
Password Password
</Label> </Label>
<Input <div className="relative">
id="password" <Input
type="password" id="password"
minLength={6} type={showPassword ? 'text' : 'password'}
maxLength={72} minLength={6}
autoComplete="new-password" maxLength={72}
className="bg-background mt-2" autoComplete="new-password"
{...register('password')} className="bg-background mt-2 pr-10"
/> {...register('password')}
/>
<Button
variant="link"
type="button"
className="absolute right-0 top-0 flex h-full items-center justify-center pr-3"
aria-label={showPassword ? 'Mask password' : 'Reveal password'}
onClick={() => setShowPassword((show) => !show)}
>
{showPassword ? (
<EyeOff className="text-muted-foreground h-5 w-5" />
) : (
<Eye className="text-muted-foreground h-5 w-5" />
)}
</Button>
</div>
</div> </div>
<div> <div>