From 6c5c5db47b869f295ca02317203cdc4a3e8d3d20 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Tue, 4 Aug 2026 20:04:41 +0700 Subject: [PATCH] feat(dimentorin): mentor register flow wired to API (4-step form, validation, submit, redirect pending) --- .../src/app/auth/register-mentor/page.tsx | 328 +++++++++--------- libs/service/src/api/dimentorin/index.ts | 12 + libs/service/src/hooks/dimentorin/index.ts | 10 + libs/service/src/types/dimentorin/index.ts | 35 ++ 4 files changed, 214 insertions(+), 171 deletions(-) diff --git a/apps/dimentorin/src/app/auth/register-mentor/page.tsx b/apps/dimentorin/src/app/auth/register-mentor/page.tsx index 88b6305..8eedbe6 100644 --- a/apps/dimentorin/src/app/auth/register-mentor/page.tsx +++ b/apps/dimentorin/src/app/auth/register-mentor/page.tsx @@ -1,11 +1,80 @@ import { FC, ReactElement, useState } from 'react'; -import { ControlledInputField, RegisterResetBanner } from '@imphnen-frontend-service/ui/organisms'; -import { Button, Select } from '@imphnen-frontend-service/ui/atoms'; +import { RegisterResetBanner } from '@imphnen-frontend-service/ui/organisms'; +import { Button } from '@imphnen-frontend-service/ui/atoms'; import { ArrowLeftOutlined, ArrowRightOutlined } from '@ant-design/icons'; import { InputField, RegisterMentorStep, SelectField } from '@imphnen-frontend-service/ui/molecules'; +import { usePostRegisterMentor, TMentorRegisterRequest } from '@imphnen-frontend-service/service'; +import { useNavigate } from 'react-router-dom'; export const Components: FC = (): ReactElement => { - const [ step, setStep ] = useState(1) + const [step, setStep] = useState(1) + const [submitting, setSubmitting] = useState(false) + const [error, setError] = useState("") + const [form, setForm] = useState({ + email: "", password: "", confirmPassword: "", + fullname: "", phone_number: "", gender: "", domicile: "", + legal_name: "", phone_for_verification: "", identity_document_url: "", + last_education: "", bio: "", linkedin_url: "", github_url: "", + cv_url: "", portfolio_url: "", industries: "", expertise: "", languages: "", + current_company: "", current_role: "", years_of_experience: "", + topics_of_interest: "", preferred_mentee_level: "", preferred_mentoring_formats: "", + availability_commitment: "", mentoring_rate_amount: "", + }) + const setF = (k: string, v: string) => setForm((f) => ({ ...f, [k]: v })) + const registerMutation = usePostRegisterMentor() + const navigate = useNavigate() + + const handleSubmit = async () => { + setError("") + if (form.password !== form.confirmPassword) { + setError("Password dan konfirmasi tidak sama.") + return + } + const payload: TMentorRegisterRequest = { + email: form.email, + password: form.password, + fullname: form.fullname, + phone_number: form.phone_number || null, + identity_and_verification: { + legal_name: form.legal_name || form.fullname, + gender: form.gender || null, + domicile: form.domicile || null, + identity_document_url: form.identity_document_url || "https://example.com/identity.jpg", + phone_for_verification: form.phone_for_verification || null, + }, + professional_profile: { + bio: form.bio, + last_education: form.last_education || null, + linkedin_url: form.linkedin_url || null, + github_url: form.github_url || null, + cv_url: form.cv_url || null, + portfolio_url: form.portfolio_url || null, + industries: form.industries.split(",").map((s) => s.trim()).filter(Boolean), + expertise: form.expertise.split(",").map((s) => s.trim()).filter(Boolean), + languages: form.languages.split(",").map((s) => s.trim()).filter(Boolean), + current_company: form.current_company, + current_role: form.current_role, + years_of_experience: Number(form.years_of_experience) || 0, + }, + mentoring_logistics: { + topics_of_interest: form.topics_of_interest.split(",").map((s) => s.trim()).filter(Boolean), + preferred_mentee_level: [form.preferred_mentee_level].filter(Boolean), + preferred_mentoring_formats: form.preferred_mentoring_formats.split(",").map((s) => s.trim()).filter(Boolean), + availability_commitment: form.availability_commitment, + mentoring_rate_amount: Number(form.mentoring_rate_amount) || 0, + }, + } + setSubmitting(true) + try { + await registerMutation.mutateAsync(payload) + navigate('/auth/register-mentor/pending') + } catch (e: unknown) { + const msg = (e as { response?: { data?: { message?: string } } })?.response?.data?.message + setError(msg || "Gagal mendaftar sebagai mentor. Coba lagi.") + } finally { + setSubmitting(false) + } + } return (
@@ -13,13 +82,6 @@ export const Components: FC = (): ReactElement => {
-

Register @@ -27,60 +89,44 @@ export const Components: FC = (): ReactElement => {

Welcome to the team, Mentor - powered by IMPHNEN
-
+ e.preventDefault()}>
setF('fullname', e.target.value)} />
setF('gender', e.target.value)} > - - - + + +
setF('phone_number', e.target.value)} />
setF('domicile', e.target.value)} > - - - + + +
setF('last_education', e.target.value)} > - + @@ -90,145 +136,85 @@ export const Components: FC = (): ReactElement => {
- - - - - - - - - - + setF('current_company', e.target.value)} /> + setF('current_role', e.target.value)} /> + setF('expertise', e.target.value)} /> + setF('industries', e.target.value)} /> + setF('languages', e.target.value)} /> + setF('years_of_experience', e.target.value)} /> + setF('bio', e.target.value)} />
- - + setF('topics_of_interest', e.target.value)} /> + setF('preferred_mentee_level', e.target.value)}> + + + + - - - - - - + setF('preferred_mentoring_formats', e.target.value)} /> + setF('availability_commitment', e.target.value)} /> + setF('mentoring_rate_amount', e.target.value)} /> + setF('linkedin_url', e.target.value)} /> + setF('portfolio_url', e.target.value)} />
Silahkan isi dalam angka (Contoh:500.000)
- - - + setF('email', e.target.value)} /> + setF('password', e.target.value)} /> + setF('confirmPassword', e.target.value)} />
+ {error &&

{error}

}
- - -
@@ -239,4 +225,4 @@ export const Components: FC = (): ReactElement => { ); }; -export default Components; +export default Components; \ No newline at end of file diff --git a/libs/service/src/api/dimentorin/index.ts b/libs/service/src/api/dimentorin/index.ts index 182f13f..b3a12c3 100644 --- a/libs/service/src/api/dimentorin/index.ts +++ b/libs/service/src/api/dimentorin/index.ts @@ -6,6 +6,7 @@ import { TMentorAvailability, TMentorDetail, TMentorListParams, + TMentorRegisterRequest, TSessionFeedbackRequest, TSessionListResponse, TBookSessionRequest, @@ -133,3 +134,14 @@ export const getArticleById = async (id: string): Promise => { }); return data.data; }; + +export const postRegisterMentor = async ( + payload: TMentorRegisterRequest +): Promise => { + const { data } = await api({ + method: 'POST', + url: '/dimentorin/mentors/create', + data: payload, + }); + return data; +}; diff --git a/libs/service/src/hooks/dimentorin/index.ts b/libs/service/src/hooks/dimentorin/index.ts index 9468a09..eabeeb7 100644 --- a/libs/service/src/hooks/dimentorin/index.ts +++ b/libs/service/src/hooks/dimentorin/index.ts @@ -12,6 +12,7 @@ import { getMentors, getMySessions, postBookSession, + postRegisterMentor, postSessionFeedback, } from '../../api/dimentorin'; import { @@ -22,6 +23,7 @@ import { TMentorAvailability, TMentorDetail, TMentorListParams, + TMentorRegisterRequest, TSessionFeedbackRequest, TSessionListResponse, } from '../../types/dimentorin'; @@ -112,6 +114,14 @@ export const usePostSessionFeedback = (sessionId: string) => { }); }; +export const usePostRegisterMentor = () => { + return useMutation({ + mutationKey: ['post-register-mentor'], + mutationFn: async (payload: TMentorRegisterRequest) => + await postRegisterMentor(payload), + }); +}; + export const useGetArticles = ( params?: TArticleListParams ): UseQueryResult => { diff --git a/libs/service/src/types/dimentorin/index.ts b/libs/service/src/types/dimentorin/index.ts index 1000191..767c8da 100644 --- a/libs/service/src/types/dimentorin/index.ts +++ b/libs/service/src/types/dimentorin/index.ts @@ -120,3 +120,38 @@ export type TArticleListParams = { per_page?: number; category?: string; }; + +export type TMentorRegisterRequest = { + email: string; + password: string; + fullname: string; + phone_number?: string | null; + identity_and_verification: { + legal_name: string; + gender?: string | null; + domicile?: string | null; + identity_document_url: string; + phone_for_verification?: string | null; + }; + professional_profile: { + bio: string; + last_education?: string | null; + linkedin_url?: string | null; + github_url?: string | null; + cv_url?: string | null; + portfolio_url?: string | null; + industries: string[]; + expertise: string[]; + languages: string[]; + current_company: string; + current_role: string; + years_of_experience: number; + }; + mentoring_logistics: { + topics_of_interest: string[]; + preferred_mentee_level: string[]; + preferred_mentoring_formats: string[]; + availability_commitment: string; + mentoring_rate_amount: number; + }; +};