Mentor Register Page (#48)
* feat: responsive * fix: success register * feat: auth login responsive && auth login implementation * fix: login page button disabled & register page * fix: conflict * fix: button disabled when loading * feat: register and otp integration * Update middleware.ts * feat: OTP Resend * fix: minor * stash * feat: mentor register pages * feat: mentor status page pending and success
This commit is contained in:
@@ -21,7 +21,7 @@ export const usePostLogin = (): UseMutationResult<
|
||||
mutationFn: async (payload) => await postLogin(payload),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
export const usePostRegister = (): UseMutationResult<
|
||||
TResponseMessage,
|
||||
TResponseError,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './button';
|
||||
export * from './input';
|
||||
export * from './textarea';
|
||||
export * from './select'
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./select"
|
||||
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
FC,
|
||||
ReactElement,
|
||||
SelectHTMLAttributes,
|
||||
} from 'react';
|
||||
import { cn } from '@imphnen-frontend-service/utils';
|
||||
|
||||
type TSelectSize = 'sm' | 'md' | 'lg';
|
||||
type Width = 'standard' | 'custom';
|
||||
|
||||
type TSelectProps = Omit<
|
||||
SelectHTMLAttributes<HTMLSelectElement>,
|
||||
'size'
|
||||
> & {
|
||||
size?: TSelectSize;
|
||||
widthform?: Width;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const sizeClasses: Record<TSelectSize, string> = {
|
||||
sm: 'text-[10px] max-h-[34px]',
|
||||
md: 'text-[12px] max-h-[36px]',
|
||||
lg: 'text-[15px] max-h-[38px]',
|
||||
};
|
||||
|
||||
const disabledClass =
|
||||
'opacity-50 hover:border-neutral-200 cursor-not-allowed';
|
||||
|
||||
export const Select: FC<TSelectProps> = ({
|
||||
size = 'md',
|
||||
widthform = 'standard',
|
||||
disabled,
|
||||
className,
|
||||
children,
|
||||
...rest
|
||||
}): ReactElement => {
|
||||
const mergedClassName = cn(
|
||||
`appearance-none px-[12px] py-[8px] text-neutral-800 bg-white placeholder:text-neutral-300 border border-neutral-200 hover:border-blue-300 focus:outline-1 focus:outline-blue-500 rounded-md`,
|
||||
sizeClasses[size],
|
||||
widthform === 'standard' && 'min-w-70',
|
||||
disabled && disabledClass,
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<select className={mergedClassName} disabled={disabled} {...rest}>
|
||||
{children}
|
||||
</select>
|
||||
);
|
||||
};
|
||||
@@ -4,4 +4,6 @@ export * from './input-field';
|
||||
export * from './pagination';
|
||||
export * from './modal/modal';
|
||||
export * from './stepper';
|
||||
export * from './accordion';
|
||||
export * from './accordion';
|
||||
export * from './register-mentor-step';
|
||||
export * from './select-field'
|
||||
@@ -0,0 +1 @@
|
||||
export * from './register-mentor-step';
|
||||
@@ -0,0 +1,53 @@
|
||||
import { FC, ReactElement } from "react";
|
||||
|
||||
type TRegisterMentorStep = {
|
||||
step: number;
|
||||
};
|
||||
|
||||
const steps = [
|
||||
"Informasi Personal",
|
||||
"Detail Mentor",
|
||||
"Sesi Mentoring & Dokumen Pendukung",
|
||||
"Informasi Akun Pribadi",
|
||||
];
|
||||
|
||||
export const RegisterMentorStep: FC<TRegisterMentorStep> = ({ step }): ReactElement => {
|
||||
const progressPercent = ((step - 1) / (steps.length - 1)) * 100;
|
||||
|
||||
return (
|
||||
<div className="relative w-full px-8">
|
||||
{/* Garis dasar (abu/biru muda) */}
|
||||
<div className="absolute top-5 left-8 right-8 h-0.5 bg-blue-100 z-0" />
|
||||
|
||||
{/* Garis progress biru (dinamis) */}
|
||||
<div
|
||||
className="absolute top-5 left-8 h-0.5 bg-blue-500 z-0 transition-all duration-300"
|
||||
style={{ width: `calc(${progressPercent}% - 0.5rem)` }} // -0.5rem agar tidak overlap ke lingkaran
|
||||
/>
|
||||
|
||||
<div className="flex justify-between relative z-10">
|
||||
{steps.map((label, index) => {
|
||||
const currentStep = index + 1;
|
||||
const isActive = currentStep === step;
|
||||
|
||||
return (
|
||||
<div key={index} className="flex flex-col items-center flex-1 text-center">
|
||||
{/* Lingkaran angka */}
|
||||
<div
|
||||
className={`w-10 h-10 rounded-full flex items-center justify-center border-2 ${
|
||||
isActive
|
||||
? "bg-gradient-to-b from-purple-600 to-blue-500 text-white border-transparent"
|
||||
: "bg-white text-gray-700 border-blue-400"
|
||||
}`}
|
||||
>
|
||||
<span className="font-bold">{currentStep}</span>
|
||||
</div>
|
||||
{/* Label */}
|
||||
<span className="text-xs text-blue-600 mt-2 leading-tight">{label}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './select-field'
|
||||
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
FC,
|
||||
ReactElement,
|
||||
SelectHTMLAttributes,
|
||||
DetailedHTMLProps,
|
||||
} from 'react';
|
||||
import { Select } from '../../atoms'; // Custom select atom kamu
|
||||
import { cn } from '@imphnen-frontend-service/utils';
|
||||
|
||||
export type TSelectSize = 'sm' | 'md' | 'lg';
|
||||
|
||||
export type TSelectFieldProps = Omit<
|
||||
DetailedHTMLProps<SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>,
|
||||
'size'
|
||||
> & {
|
||||
label: string;
|
||||
size?: TSelectSize;
|
||||
error?: string;
|
||||
helperText?: string;
|
||||
htmlFor?: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const sizeClasses: Record<TSelectSize, { label: string; helperText: string }> = {
|
||||
lg: {
|
||||
label: 'text-p3 font-medium',
|
||||
helperText: 'text-label3 font-normal',
|
||||
},
|
||||
md: {
|
||||
label: 'text-label1 font-medium',
|
||||
helperText: 'text-label2 font-normal',
|
||||
},
|
||||
sm: {
|
||||
label: 'text-label2 font-medium',
|
||||
helperText: 'text-label2 font-normal',
|
||||
},
|
||||
};
|
||||
|
||||
export const SelectField: FC<TSelectFieldProps> = ({
|
||||
label,
|
||||
size = 'md',
|
||||
error,
|
||||
helperText,
|
||||
htmlFor,
|
||||
disabled,
|
||||
className,
|
||||
children,
|
||||
...rest
|
||||
}): ReactElement => {
|
||||
return (
|
||||
<div className="flex flex-col gap-[8px]">
|
||||
<label
|
||||
htmlFor={htmlFor}
|
||||
className={cn(
|
||||
'items-start justify-item-start text-start !text-neutral-800',
|
||||
sizeClasses[size].label
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
|
||||
<Select
|
||||
{...(htmlFor && { id: htmlFor })}
|
||||
size={size}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
error &&
|
||||
'border-danger-500 hover:border-danger-500 focus:outline-danger-500',
|
||||
className,
|
||||
disabled && 'opacity-50 cursor-not-allowed'
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Select>
|
||||
|
||||
{error ? (
|
||||
<p className="text-danger-500 text-label1 text-left">{error}</p>
|
||||
) : (
|
||||
helperText && (
|
||||
<p
|
||||
className={cn(
|
||||
'text-label2 text-left',
|
||||
sizeClasses[size].helperText
|
||||
)}
|
||||
>
|
||||
{helperText}
|
||||
</p>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -6,14 +6,14 @@ import { FC, ReactElement } from "react";
|
||||
function AuthBanner({text, href}: {text: string, href: string}){
|
||||
return (
|
||||
<div className='hidden xl:block relative rounded-md'>
|
||||
<img src="/image/95319c4f9953dfe6180200e529dfcea5.webp" alt="Banner" className='w-[420px] h-[632px] object-[80%] object-cover rounded-lg' />
|
||||
<img src="/image/95319c4f9953dfe6180200e529dfcea5.webp" alt="Banner" className='w-[420px] min-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 />
|
||||
<p>{text}</p>
|
||||
</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'>
|
||||
<div className='absolute bottom-0 bg-gradient-to-t from-primary-500 to-transparent w-full rounded-b-lg min-h-[263px] flex flex-col items-center justify-center'>
|
||||
<img src="/image/9261045e09137f3fcb925a78c55b6ddb.webp" alt="Logo" width={317} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user