feat: Forgot Password Slicing, fix: webp image
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 263 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.8 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.6 MiB |
@@ -0,0 +1,12 @@
|
||||
import { FC, ReactElement } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
export const AppLayout: FC = (): ReactElement => {
|
||||
return (
|
||||
<main className="bg-primary-50 min-h-screen">
|
||||
<Outlet />
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppLayout;
|
||||
@@ -0,0 +1,12 @@
|
||||
import { FC, ReactElement } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
export const AppLayout: FC = (): ReactElement => {
|
||||
return (
|
||||
<main className="bg-primary-50 min-h-screen">
|
||||
<Outlet />
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppLayout;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { FC, ReactElement } from 'react';
|
||||
import { RegisterResetBanner } from "@imphnen-frontend-service/ui/organisms";
|
||||
import { ForgotStep, OtpForm } from "@imphnen-frontend-service/ui/molecules";
|
||||
import { Button, Input } from '@imphnen-frontend-service/ui/atoms';
|
||||
|
||||
export const Components: FC = (): ReactElement => {
|
||||
return (
|
||||
<div className='flex flex-col justify-center items-center min-h-screen py-[60px] px-[80px]'>
|
||||
<div className='bg-white min-w-[1120px] min-h-[712px] p-10 rounded-2xl shadow-md flex gap-6'>
|
||||
<RegisterResetBanner />
|
||||
<div className='border-2 border-primary-500/50 w-[596px] rounded-lg py-[70px] px-[48px] flex flex-col justify-center'>
|
||||
<ForgotStep step={2} />
|
||||
<h3 className='mt-5 text-3xl font-semibold text-primary-500'>Forgot Password</h3>
|
||||
<h5 className='mt-2 text-xl font-medium text-primary-500'>Yeay~! Pesan dari dunia lain (a.k.a email-mu) sudah tiba!</h5>
|
||||
<OtpForm />
|
||||
<Button>Summon Password Baru!</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Components;
|
||||
@@ -0,0 +1,24 @@
|
||||
import { FC, ReactElement } from 'react';
|
||||
import { RegisterResetBanner } from "@imphnen-frontend-service/ui/organisms";
|
||||
import { ForgotStep } from "@imphnen-frontend-service/ui/molecules";
|
||||
import { Button, Input } from '@imphnen-frontend-service/ui/atoms';
|
||||
|
||||
export const Components: FC = (): ReactElement => {
|
||||
return (
|
||||
<div className='flex flex-col justify-center items-center min-h-screen py-[60px] px-[80px]'>
|
||||
<div className='bg-white min-w-[1120px] min-h-[712px] p-10 rounded-2xl shadow-md flex gap-6'>
|
||||
<RegisterResetBanner />
|
||||
<div className='border-2 border-primary-500/50 w-[596px] rounded-lg py-[70px] px-[48px] flex flex-col justify-center'>
|
||||
<ForgotStep step={1} />
|
||||
<h3 className='mt-5 text-3xl font-semibold text-primary-500'>Forgot Password</h3>
|
||||
<h5 className='mt-2 text-xl font-medium text-primary-500'>Masukkan email-mu, dan biarkan kami memanggil password-mu kembali dari dunia lain!</h5>
|
||||
<h6 className='text-gray-600 mt-8'>Email</h6>
|
||||
<Input type='email' size='lg' placeholder='Contoh: yourname@mail.com'></Input>
|
||||
<Button variant='primary' className='mt-7'>Kirim Kode OTP ^^</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Components;
|
||||
@@ -0,0 +1,12 @@
|
||||
import { FC, ReactElement } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
export const AppLayout: FC = (): ReactElement => {
|
||||
return (
|
||||
<main className="bg-primary-50 min-h-screen">
|
||||
<Outlet />
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppLayout;
|
||||
@@ -0,0 +1,34 @@
|
||||
import { FC, ReactElement } from 'react';
|
||||
import { RegisterResetBanner } from "@imphnen-frontend-service/ui/organisms";
|
||||
import { ForgotStep } from "@imphnen-frontend-service/ui/molecules";
|
||||
import { Button, Input } from '@imphnen-frontend-service/ui/atoms';
|
||||
|
||||
export const Components: FC = (): ReactElement => {
|
||||
return (
|
||||
<div className='flex flex-col justify-center items-center min-h-screen py-[60px] px-[80px]'>
|
||||
<div className='bg-white min-w-[1120px] min-h-[712px] p-10 rounded-2xl shadow-md flex gap-6'>
|
||||
<RegisterResetBanner />
|
||||
<div className='border-2 border-primary-500/50 w-[596px] rounded-lg py-[70px] px-[48px] flex flex-col justify-center'>
|
||||
<ForgotStep step={3} />
|
||||
<h3 className='mt-5 text-3xl font-semibold text-primary-500'>Forgot Password</h3>
|
||||
<h5 className='mt-2 text-md font-medium text-primary-500'>Sekarang, buatlah password baru yang lebih kuat, seperti jurus andalanmu!<span role="img" aria-label='emoji'>🔥⚡</span></h5>
|
||||
<div className='my-4'>
|
||||
<h6 className='text-gray-700'>Password Baru</h6>
|
||||
<Input className='w-full' type="password" placeholder='Buat password sekokoh armor legendary!'/>
|
||||
<h6 className='text-gray-700 mt-5'>Ulang Password Baru</h6>
|
||||
<Input className='w-full' type="password" placeholder='Pastikan Cocok! Jangan sampai ada typo, Senpai~!'/>
|
||||
</div>
|
||||
<div className='mb-4 text-gray-700 flex flex-col gap-3 text-sm'>
|
||||
<h6><span role='img' aria-label='emoji'>💡</span> Tips dari kami:</h6>
|
||||
<h6><span role='img' aria-label='emoji'>✅ </span> Buat kombinasi huruf besar, kecil, angka, dan simbol untuk kekuatan maksimal!</h6>
|
||||
<h6><span role='img' aria-label='emoji'>✅</span> Pastikan kamu ingat password-mu atau simpan di tempat aman~</h6>
|
||||
<h6>Masukkan password baru dan bersiaplah untuk kembali bertualang!</h6>
|
||||
</div>
|
||||
<Button className='mt-5'>Summon Password Baru!</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Components;
|
||||
@@ -34,7 +34,7 @@ export const Components: FC = (): ReactElement => {
|
||||
</div>
|
||||
<Button className='w-full my-3 text-gray-500 gap-2' variant='secondary'>
|
||||
<p>Log In With Google</p>
|
||||
<img src="/image/33978ce5bed2da9bf9d73acad802182a.png" alt="Google Icon" width={24}/>
|
||||
<img src="/image/33978ce5bed2da9bf9d73acad802182a.webp" alt="Google Icon" width={24}/>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { FC, ReactElement } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
export const AppLayout: FC = (): ReactElement => {
|
||||
return (
|
||||
<main className="bg-primary-50 min-h-screen">
|
||||
<Outlet />
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppLayout;
|
||||
@@ -0,0 +1,19 @@
|
||||
import { FC, ReactElement } from 'react';
|
||||
import { RegisterResetBanner } from "@imphnen-frontend-service/ui/organisms";
|
||||
import { Button, Input } from '@imphnen-frontend-service/ui/atoms';
|
||||
|
||||
export const Components: FC = (): ReactElement => {
|
||||
return (
|
||||
<div className='flex flex-col justify-center items-center min-h-screen py-[60px] px-[80px]'>
|
||||
<div className='bg-white min-w-[1120px] min-h-[712px] p-10 rounded-2xl shadow-md flex gap-6'>
|
||||
<RegisterResetBanner />
|
||||
<div className='border-2 border-primary-500/50 w-[596px] rounded-lg py-[70px] px-[96px] flex justify-center'>
|
||||
<div className='w-[404px]'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Components;
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from 'react';
|
||||
import { cn } from '@imphnen-frontend-service/utils';
|
||||
|
||||
type TInputType = 'text' | 'email';
|
||||
type TInputType = 'text' | 'email' | 'password';
|
||||
type TInputSize = 'sm' | 'md' | 'lg';
|
||||
|
||||
type TInputProps = Omit<
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { DetailedHTMLProps, FC, InputHTMLAttributes, ReactElement } from "react"
|
||||
|
||||
type TForgotStepProps = Omit<
|
||||
DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
|
||||
'size' | 'type'
|
||||
> & {
|
||||
step: number
|
||||
};
|
||||
|
||||
export const ForgotStep: FC<TForgotStepProps> = ({
|
||||
step = 1,
|
||||
...rest
|
||||
}): ReactElement => {
|
||||
return (
|
||||
<div className="w-full grid grid-cols-3 gap-3">
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<div className={`${step === 1 ? "bg-primary-500" : "bg-primary-200"} px-5 py-2 rounded-md w-full`}></div>
|
||||
<h4 className={`${step === 1 ? "text-primary-500" : "text-gray-500"} text-xs`}>Masukkan Email</h4>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<div className={`${step === 2 ? "bg-primary-500" : "bg-primary-200"} px-5 py-2 rounded-md w-full`}></div>
|
||||
<h4 className={`${step === 2 ? "text-primary-500" : "text-gray-500"} text-xs`}>Verifikasi OTP</h4>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center gap-2">
|
||||
<div className={`${step === 3 ? "bg-primary-500" : "bg-primary-200"} px-5 py-2 rounded-md w-full`}></div>
|
||||
<h4 className={`${step === 3 ? "text-primary-500" : "text-gray-500"} text-xs`}>Summon Password ^^</h4>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './forgot-step';
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./forgot-step";
|
||||
export * from "./forgot-step";
|
||||
export * from "./otp-form";
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./otp-form"
|
||||
@@ -0,0 +1,60 @@
|
||||
// eslint-disable-next-line @nx/enforce-module-boundaries
|
||||
import { Input } from "@imphnen-frontend-service/ui/atoms";
|
||||
import { ChangeEvent, DetailedHTMLProps, FC, InputHTMLAttributes, ReactElement, useRef, useState } from "react"
|
||||
|
||||
type TForgotStepProps = Omit<
|
||||
DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>,
|
||||
'size' | 'type'
|
||||
> & {
|
||||
|
||||
};
|
||||
|
||||
export const OtpForm: FC<TForgotStepProps> = ({
|
||||
step = 1,
|
||||
...rest
|
||||
}): ReactElement => {
|
||||
const [cell, setCell] = useState(new Array(6).fill(""))
|
||||
const inputRef = useRef([])
|
||||
|
||||
const handleChange = (index: number, e: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value
|
||||
if (!(/^[0-9]?$/.test(value))) return;
|
||||
|
||||
const newCell = [...cell]
|
||||
newCell[index] = value
|
||||
setCell(newCell)
|
||||
|
||||
if(value && index < 6 - 1){
|
||||
(inputRef.current[index + 1] as HTMLInputElement).focus()
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyDown = (index: number, e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if(e.key === "Backspace" && !cell[index] && index > 0){
|
||||
const newCell = [...cell]
|
||||
newCell[index] = ""
|
||||
setCell(newCell)
|
||||
|
||||
const ref = (inputRef.current[index - 1] as HTMLInputElement)
|
||||
ref.focus()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full grid grid-cols-6 gap-3 my-10">
|
||||
{cell.map((v, i) => (
|
||||
<Input
|
||||
placeholder=""
|
||||
ref={(el) => {
|
||||
inputRef.current.push(el as never)
|
||||
return inputRef.current[i]
|
||||
}}
|
||||
onChange={(e) => handleChange(i, e)}
|
||||
onKeyDown={(e) => handleKeyDown(i, e)}
|
||||
size="lg"
|
||||
value={cell[i]}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { FC, ReactElement } from "react";
|
||||
function AuthBanner({text, href}: {text: string, href: string}){
|
||||
return (
|
||||
<div className='relative rounded-md'>
|
||||
<img src="/image/95319c4f9953dfe6180200e529dfcea5.jpeg" alt="Banner" className='w-[420px] h-[632px] object-[80%] object-cover rounded-lg' />
|
||||
<img src="/image/95319c4f9953dfe6180200e529dfcea5.webp" alt="Banner" className='w-[420px] h-[632px] object-[80%] object-cover rounded-lg' />
|
||||
<div className='absolute top-0 bg-gradient-to-b from-primary-500 to-transparent w-full rounded-t-lg h-[163px] py-5 px-5'>
|
||||
<Button variant='secondary' className='gap-2' onClick={() => document.location.href = `${href}`}>
|
||||
<ArrowLeftOutlined />
|
||||
@@ -14,7 +14,7 @@ function AuthBanner({text, href}: {text: string, href: string}){
|
||||
</Button>
|
||||
</div>
|
||||
<div className='absolute bottom-0 bg-gradient-to-t from-primary-500 to-transparent w-full rounded-b-lg h-[263px] flex flex-col items-center justify-center'>
|
||||
<img src="/image/9261045e09137f3fcb925a78c55b6ddb.png" alt="Logo" width={317} />
|
||||
<img src="/image/9261045e09137f3fcb925a78c55b6ddb.webp" alt="Logo" width={317} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user