fix: job seekers unable to submit verification documents
All checks were successful
build-and-release / build (push) Successful in 1m51s
All checks were successful
build-and-release / build (push) Successful in 1m51s
The dashboard's Submit for Verification widget checked profile_data for
a documents/documents_data field that GET /api/jobseeker/profile/me never
returns, so the Submit button stayed permanently disabled. Even bypassing
that, it POSTed {document_urls: []}, a field the backend doesn't
recognize, instead of the profile_data shape submit-for-verification
actually expects.
Now fetches the job seeker's real uploaded documents via
GET /api/jobseeker/profile/documents, checks the correct document_type
field, and submits profile_data merged with the uploaded document URLs.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
18a9161e4f
commit
070c4bdab1
2 changed files with 25 additions and 12 deletions
|
|
@ -13,7 +13,7 @@ import ProfileCompletionWidget from './widgets/ProfileCompletionWidget';
|
||||||
import VerificationWidget from './widgets/VerificationWidget';
|
import VerificationWidget from './widgets/VerificationWidget';
|
||||||
import AiUsageWidget from './widgets/AiUsageWidget';
|
import AiUsageWidget from './widgets/AiUsageWidget';
|
||||||
import VerificationSubmissionGuide from './VerificationSubmissionGuide';
|
import VerificationSubmissionGuide from './VerificationSubmissionGuide';
|
||||||
import { fetchProfile } from '~/lib/api';
|
import { fetchProfile, fetchDocuments } from '~/lib/api';
|
||||||
import {
|
import {
|
||||||
getBasicFields,
|
getBasicFields,
|
||||||
getDocFields,
|
getDocFields,
|
||||||
|
|
@ -101,6 +101,7 @@ export default function MyDashboardPage(props: Props) {
|
||||||
const [draggingIdx, setDraggingIdx] = createSignal<number | null>(null);
|
const [draggingIdx, setDraggingIdx] = createSignal<number | null>(null);
|
||||||
const [visibleWidgets, setVisibleWidgets] = createSignal<Set<string>>(new Set());
|
const [visibleWidgets, setVisibleWidgets] = createSignal<Set<string>>(new Set());
|
||||||
const [profileData, setProfileData] = createSignal<Record<string, any>>({});
|
const [profileData, setProfileData] = createSignal<Record<string, any>>({});
|
||||||
|
const [documents, setDocuments] = createSignal<any[]>([]);
|
||||||
const [submitting, setSubmitting] = createSignal(false);
|
const [submitting, setSubmitting] = createSignal(false);
|
||||||
|
|
||||||
const getRoleType = (): string => {
|
const getRoleType = (): string => {
|
||||||
|
|
@ -135,6 +136,11 @@ export default function MyDashboardPage(props: Props) {
|
||||||
const data = await fetchProfile(prefix);
|
const data = await fetchProfile(prefix);
|
||||||
if (data) setProfileData(data);
|
if (data) setProfileData(data);
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
|
if (props.roleKey === 'JOB_SEEKER') {
|
||||||
|
try {
|
||||||
|
setDocuments(await fetchDocuments(prefix));
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const missingBasicLabels = createMemo(() => {
|
const missingBasicLabels = createMemo(() => {
|
||||||
|
|
@ -148,12 +154,10 @@ export default function MyDashboardPage(props: Props) {
|
||||||
});
|
});
|
||||||
|
|
||||||
const missingDocLabels = createMemo(() => {
|
const missingDocLabels = createMemo(() => {
|
||||||
const data = profileData();
|
const docs = documents();
|
||||||
if (!data) return [];
|
|
||||||
const docs = data.documents || data.documents_data || [];
|
|
||||||
return getDocFields(props.roleKey)
|
return getDocFields(props.roleKey)
|
||||||
.filter((doc) => doc.required)
|
.filter((doc) => doc.required)
|
||||||
.filter((doc) => !docs.some((d: any) => d?.doc_type === doc.key))
|
.filter((doc) => !docs.some((d: any) => d?.document_type === doc.key))
|
||||||
.map((doc) => doc.label);
|
.map((doc) => doc.label);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -178,14 +182,18 @@ export default function MyDashboardPage(props: Props) {
|
||||||
}
|
}
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
const res = await apiFetch("/api/profile/submit-for-verification", {
|
const data = profileData();
|
||||||
method: "POST",
|
const p = data.profile || data;
|
||||||
body: JSON.stringify({ roleKey: props.roleKey, document_urls: [] }),
|
const docUrls: Record<string, string> = {};
|
||||||
});
|
for (const d of documents()) {
|
||||||
if (res.ok || res.status === 200) {
|
if (d?.document_type && d?.file_url) docUrls[d.document_type] = d.file_url;
|
||||||
// Update verification status to PENDING
|
|
||||||
props.onVerificationStatusChange?.("PENDING");
|
|
||||||
}
|
}
|
||||||
|
// apiFetch() throws on a non-2xx response, so reaching this point means the submission succeeded.
|
||||||
|
await apiFetch("/api/profile/submit-for-verification", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ roleKey: props.roleKey, profile_data: { ...p, ...docUrls } }),
|
||||||
|
});
|
||||||
|
props.onVerificationStatusChange?.("PENDING");
|
||||||
} catch {
|
} catch {
|
||||||
// silently fail - the profile page handles submission errors
|
// silently fail - the profile page handles submission errors
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,11 @@ export async function saveProfile(rolePrefix: string, payload: any): Promise<any
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchDocuments(rolePrefix: string): Promise<any[]> {
|
||||||
|
const res = await apiFetch(`/api/${rolePrefix}/profile/documents`);
|
||||||
|
return res?.data ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
export async function submitProfileForVerification(rolePrefix: string): Promise<any> {
|
export async function submitProfileForVerification(rolePrefix: string): Promise<any> {
|
||||||
return apiFetch(`/api/${rolePrefix}/profile/submit`, {
|
return apiFetch(`/api/${rolePrefix}/profile/submit`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue