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:
Naufal Azmi
2025-07-13 03:40:23 +07:00
committed by GitHub
parent dcd4ef88d6
commit 228f92e9ed
21 changed files with 609 additions and 8 deletions
+3 -1
View File
@@ -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>
);
};