Compare commits

..

3 Commits

8 changed files with 153 additions and 75 deletions

View File

@ -2,7 +2,7 @@ import { Link } from 'react-router'
import { APP } from '~/data/meta' import { APP } from '~/data/meta'
export default function Banner() { export const Banner = () => {
return ( return (
<div className="min-h-[65px] sm:mx-10"> <div className="min-h-[65px] sm:mx-10">
<div className="relative"> <div className="relative">

View File

@ -5,7 +5,7 @@ interface BreadcrumbProperty {
slug: string slug: string
} }
const Breadcrumb = (property: BreadcrumbProperty) => { export const Breadcrumb = (property: BreadcrumbProperty) => {
const { slug } = property const { slug } = property
return ( return (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -20,5 +20,3 @@ const Breadcrumb = (property: BreadcrumbProperty) => {
</div> </div>
) )
} }
export default Breadcrumb

View 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>
)
}

View File

@ -40,7 +40,7 @@ const dataSocialMedia = [
}, },
] ]
const IconsSocial: FC<SocialMediaProperties> = ({ className }) => { export const IconsSocial: FC<SocialMediaProperties> = ({ className }) => {
return ( return (
<div className={twMerge('flex gap-2', className)}> <div className={twMerge('flex gap-2', className)}>
{dataSocialMedia.map(({ url, icon: Icon }, index) => ( {dataSocialMedia.map(({ url, icon: Icon }, index) => (
@ -56,5 +56,3 @@ const IconsSocial: FC<SocialMediaProperties> = ({ className }) => {
</div> </div>
) )
} }
export default IconsSocial

View File

@ -2,9 +2,9 @@ import { type PropsWithChildren } from 'react'
import { PopupModal } from '~/components/popup/modal' import { PopupModal } from '~/components/popup/modal'
import { SuccessModal } from '~/components/popup/success-modal' import { SuccessModal } from '~/components/popup/success-modal'
import Banner from '~/components/ui/banner' import { Banner } from '~/components/ui/banner'
import { useNewsContext } from '~/contexts/news' import { useNewsContext } from '~/contexts/news'
import FormForgotPassword from '~/layouts/news/form-forgot-password' import { FormForgotPassword } from '~/layouts/news/form-forgot-password'
import { FormLogin } from '~/layouts/news/form-login' import { FormLogin } from '~/layouts/news/form-login'
import { FormRegister } from '~/layouts/news/form-register' import { FormRegister } from '~/layouts/news/form-register'
@ -50,6 +50,7 @@ export const NewsDefaultLayout = (properties: PropsWithChildren) => {
setIsRegisterOpen={setIsRegisterOpen} setIsRegisterOpen={setIsRegisterOpen}
setIsLoginOpen={setIsLoginOpen} setIsLoginOpen={setIsLoginOpen}
setIsForgetOpen={setForgetOpen} setIsForgetOpen={setForgetOpen}
setIsSuccessModalOpen={setIsSuccessModalOpen}
/> />
</PopupModal> </PopupModal>

View File

@ -1,6 +1,6 @@
import { Button } from '~/components/ui/button' import { Button } from '~/components/ui/button'
export default function FormForgotPassword() { export const FormForgotPassword = () => {
return ( return (
<div className="flex flex-col items-center justify-center"> <div className="flex flex-col items-center justify-center">
<div className="w-full max-w-md"> <div className="w-full max-w-md">

View File

@ -1,90 +1,93 @@
// import { EyeIcon, EyeOffIcon } from 'lucide-react' // 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 { 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 = { type TProperties = {
setIsRegisterOpen: Dispatch<SetStateAction<boolean>> setIsRegisterOpen: Dispatch<SetStateAction<boolean>>
setIsLoginOpen: Dispatch<SetStateAction<boolean>> setIsLoginOpen: Dispatch<SetStateAction<boolean>>
setIsForgetOpen: Dispatch<SetStateAction<boolean>> setIsForgetOpen: Dispatch<SetStateAction<boolean>>
setIsSuccessModalOpen: Dispatch<SetStateAction<boolean>>
} }
export const FormLogin = (properties: TProperties) => { export const FormLogin = (properties: TProperties) => {
const { setIsRegisterOpen, setIsLoginOpen, setIsForgetOpen } = properties const {
const [showPassword, setShowPassword] = useState(false) 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 ( return (
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<form> <FormProvider {...formMethods}>
{/* Input Email / No Telepon */} <form
<div className="mb-4"> onSubmit={onSubmit}
<label className="space-y-4"
htmlFor="email" >
className="mb-1 block text-gray-700" <Input
> id="email"
Email/No. Telepon label="Email / No Telepon"
</label>
<input
type="text"
placeholder="Contoh: legal@legalgo.id" placeholder="Contoh: legal@legalgo.id"
className="focus:inheriten w-full rounded-md border border-[#DFDFDF] p-2" name="email"
/> />
</div>
{/* Input Password */} <Input
<div className="relative mb-4"> id="password"
<label label="Kata Sandi"
htmlFor="password"
className="mb-1 block text-gray-700 focus:outline-[#2E2F7C]"
>
Kata Sandi
</label>
<input
type={showPassword ? 'text' : 'password'}
placeholder="Masukkan 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 */} {/* Lupa Kata Sandi */}
<div className="mb-4 flex items-center justify-between text-sm"> <div className="flex items-center justify-between text-sm">
<span className="text-gray-600">Lupa Kata Sandi?</span> <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 <Button
onClick={() => { type="submit"
setIsLoginOpen(false) className="w-full rounded-md bg-[#2E2F7C] py-2 text-white transition hover:bg-blue-800"
setIsForgetOpen(true)
}}
className="font-semibold text-[#2E2F7C]"
variant="link"
> >
Reset Kata Sandi Masuk
</Button> </Button>
</div> </form>
</FormProvider>
{/* Tombol Masuk */}
<Button className="w-full rounded-md bg-[#2E2F7C] py-2 text-white transition hover:bg-blue-800">
Masuk
</Button>
</form>
{/* Link Daftar */} {/* Link Daftar */}
<div className="mt-4 text-center text-sm"> <div className="mt-4 text-center text-sm">

View File

@ -1,7 +1,7 @@
import Breadcrumb from '~/components/ui/breadcrumb' import { Breadcrumb } from '~/components/ui/breadcrumb'
import { Card } from '~/components/ui/card' import { Card } from '~/components/ui/card'
import { Carousel } from '~/components/ui/carousel' import { Carousel } from '~/components/ui/carousel'
import IconsSocial from '~/components/ui/social-share' import { IconsSocial } from '~/components/ui/social-share'
import { BERITA, CONTENT } from './data' import { BERITA, CONTENT } from './data'