Merge remote-tracking branch 'origin/master' into feature/slicing
This commit is contained in:
commit
7334e07537
78
app/components/ui/input.tsx
Normal file
78
app/components/ui/input.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import { useState, type ComponentProps, type ReactNode } from 'react'
|
||||
import {
|
||||
get,
|
||||
useFormContext,
|
||||
type FieldError,
|
||||
type FieldValues,
|
||||
type Path,
|
||||
type RegisterOptions,
|
||||
} from 'react-hook-form'
|
||||
|
||||
import { EyeIcon } from '~/components/icons/eye'
|
||||
|
||||
import { Button } from './button'
|
||||
|
||||
type TInputProperties<T extends FieldValues> = Omit<
|
||||
ComponentProps<'input'>,
|
||||
'size'
|
||||
> & {
|
||||
id: string
|
||||
label?: ReactNode
|
||||
name: Path<T>
|
||||
rules?: RegisterOptions
|
||||
}
|
||||
|
||||
export const Input = <TFormValues extends Record<string, unknown>>(
|
||||
properties: TInputProperties<TFormValues>,
|
||||
) => {
|
||||
const { id, label, name, rules, type = 'text', ...rest } = properties
|
||||
const [inputType, setInputType] = useState(type)
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
} = useFormContext()
|
||||
|
||||
const error: FieldError = get(errors, name)
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<label
|
||||
htmlFor={id}
|
||||
className="mb-1 block text-gray-700"
|
||||
>
|
||||
{label} {error && <span className="text-red-500">{error.message}</span>}
|
||||
</label>
|
||||
<input
|
||||
id={id}
|
||||
type={inputType}
|
||||
className="w-full rounded-md border border-[#DFDFDF] p-2"
|
||||
{...register(name, rules)}
|
||||
{...rest}
|
||||
/>
|
||||
{type === 'password' && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="icon"
|
||||
size="fit"
|
||||
className="absolute top-9 right-3 text-gray-500"
|
||||
onClick={() =>
|
||||
setInputType(inputType === 'password' ? 'text' : 'password')
|
||||
}
|
||||
>
|
||||
{inputType === 'password' ? (
|
||||
<EyeIcon
|
||||
width={15}
|
||||
height={15}
|
||||
/>
|
||||
) : (
|
||||
<EyeIcon
|
||||
width={15}
|
||||
height={15}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -50,6 +50,7 @@ export const NewsDefaultLayout = (properties: PropsWithChildren) => {
|
||||
setIsRegisterOpen={setIsRegisterOpen}
|
||||
setIsLoginOpen={setIsLoginOpen}
|
||||
setIsForgetOpen={setForgetOpen}
|
||||
setIsSuccessModalOpen={setIsSuccessModalOpen}
|
||||
/>
|
||||
</PopupModal>
|
||||
|
||||
|
||||
@ -1,90 +1,93 @@
|
||||
// import { EyeIcon, EyeOffIcon } from 'lucide-react'
|
||||
import { useState, type Dispatch, type SetStateAction } from 'react'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { type Dispatch, type SetStateAction } from 'react'
|
||||
import { FormProvider, useForm } from 'react-hook-form'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { EyeIcon } from '~/components/icons/eye'
|
||||
import { Button } from '~/components/ui/button'
|
||||
import { Input } from '~/components/ui/input'
|
||||
|
||||
const loginSchema = z.object({
|
||||
email: z.string().email('Email tidak valid'),
|
||||
password: z.string().min(6, 'Kata sandi minimal 6 karakter'),
|
||||
})
|
||||
|
||||
export type TLoginSchema = z.infer<typeof loginSchema>
|
||||
|
||||
type TProperties = {
|
||||
setIsRegisterOpen: Dispatch<SetStateAction<boolean>>
|
||||
setIsLoginOpen: Dispatch<SetStateAction<boolean>>
|
||||
setIsForgetOpen: Dispatch<SetStateAction<boolean>>
|
||||
setIsSuccessModalOpen: Dispatch<SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
export const FormLogin = (properties: TProperties) => {
|
||||
const { setIsRegisterOpen, setIsLoginOpen, setIsForgetOpen } = properties
|
||||
const [showPassword, setShowPassword] = useState(false)
|
||||
const {
|
||||
setIsRegisterOpen,
|
||||
setIsLoginOpen,
|
||||
setIsForgetOpen,
|
||||
setIsSuccessModalOpen,
|
||||
} = properties
|
||||
|
||||
const formMethods = useForm<TLoginSchema>({
|
||||
resolver: zodResolver(loginSchema),
|
||||
})
|
||||
|
||||
const { handleSubmit } = formMethods
|
||||
|
||||
const onSubmit = handleSubmit((data) => {
|
||||
console.log('data', data) // eslint-disable-line no-console
|
||||
setIsSuccessModalOpen(true)
|
||||
setIsLoginOpen(false)
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center">
|
||||
<div className="w-full max-w-md">
|
||||
<form>
|
||||
{/* Input Email / No Telepon */}
|
||||
<div className="mb-4">
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="mb-1 block text-gray-700"
|
||||
>
|
||||
Email/No. Telepon
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
<FormProvider {...formMethods}>
|
||||
<form
|
||||
onSubmit={onSubmit}
|
||||
className="space-y-4"
|
||||
>
|
||||
<Input
|
||||
id="email"
|
||||
label="Email / No Telepon"
|
||||
placeholder="Contoh: legal@legalgo.id"
|
||||
className="focus:inheriten w-full rounded-md border border-[#DFDFDF] p-2"
|
||||
name="email"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Input Password */}
|
||||
<div className="relative mb-4">
|
||||
<label
|
||||
htmlFor="password"
|
||||
className="mb-1 block text-gray-700 focus:outline-[#2E2F7C]"
|
||||
>
|
||||
Kata Sandi
|
||||
</label>
|
||||
<input
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
<Input
|
||||
id="password"
|
||||
label="Kata Sandi"
|
||||
placeholder="Masukkan Kata Sandi"
|
||||
className="w-full rounded-md border border-[#DFDFDF] p-2 pr-10 focus:outline-[#2E2F7C]"
|
||||
name="password"
|
||||
type="password"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="absolute top-9 right-3 text-gray-500"
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
>
|
||||
{showPassword ? (
|
||||
<EyeIcon
|
||||
width={15}
|
||||
height={15}
|
||||
/>
|
||||
) : (
|
||||
<EyeIcon
|
||||
width={15}
|
||||
height={15}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Lupa Kata Sandi */}
|
||||
<div className="mb-4 flex items-center justify-between text-sm">
|
||||
<span className="text-gray-600">Lupa Kata Sandi?</span>
|
||||
{/* Lupa Kata Sandi */}
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-gray-600">Lupa Kata Sandi?</span>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setIsLoginOpen(false)
|
||||
setIsForgetOpen(true)
|
||||
}}
|
||||
className="font-semibold text-[#2E2F7C]"
|
||||
variant="link"
|
||||
>
|
||||
Reset Kata Sandi
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Tombol Masuk */}
|
||||
<Button
|
||||
onClick={() => {
|
||||
setIsLoginOpen(false)
|
||||
setIsForgetOpen(true)
|
||||
}}
|
||||
className="font-semibold text-[#2E2F7C]"
|
||||
variant="link"
|
||||
type="submit"
|
||||
className="w-full rounded-md bg-[#2E2F7C] py-2 text-white transition hover:bg-blue-800"
|
||||
>
|
||||
Reset Kata Sandi
|
||||
Masuk
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Tombol Masuk */}
|
||||
<Button className="w-full rounded-md bg-[#2E2F7C] py-2 text-white transition hover:bg-blue-800">
|
||||
Masuk
|
||||
</Button>
|
||||
</form>
|
||||
</form>
|
||||
</FormProvider>
|
||||
|
||||
{/* Link Daftar */}
|
||||
<div className="mt-4 text-center text-sm">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user