From cab192d946390b647a8b161904967d1d2a576488 Mon Sep 17 00:00:00 2001
From: Ashwin Kumar Sivakumar
Date: Mon, 27 Jul 2026 18:07:37 +0530
Subject: [PATCH] Fix job seeker document submission: hide raw storage URL, fix
error masking
Two issues in the job seeker (and shared profile) dashboard:
- The uploaded document's full Backblaze URL was rendered as visible text
and linked directly; view-document now resolves a short-lived signed
URL on demand instead of exposing the permanent storage link.
- "Submit for Verification" always showed a generic "Network error"
message on any failure because request() throws on non-2xx responses,
making the destructured status/data unreachable in the catch-free path
(e.g. a 409 "verification already in progress" looked identical to a
network failure). Now surfaces the real backend error message.
Co-Authored-By: Claude Sonnet 5
---
src/components/dashboard/ProfilePage.tsx | 16 ++++++++--------
.../dashboard/VerificationStatusPage.tsx | 19 +++++++++++++------
src/lib/api.ts | 13 +++++++++++++
3 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/src/components/dashboard/ProfilePage.tsx b/src/components/dashboard/ProfilePage.tsx
index eff635a..a9b7f55 100644
--- a/src/components/dashboard/ProfilePage.tsx
+++ b/src/components/dashboard/ProfilePage.tsx
@@ -859,7 +859,7 @@ export default function ProfilePage(props: Props) {
setSubmitting(true);
setSubmitMsg("");
try {
- const { data, status } = await request("/api/profile/submit-for-verification", {
+ const { status } = await request("/api/profile/submit-for-verification", {
method: "POST",
body: { roleKey: props.roleKey, profile_data: { ...form(), ...docUrls() } },
});
@@ -867,13 +867,13 @@ export default function ProfilePage(props: Props) {
setVerificationStatus("PENDING");
props.onVerificationStatusChange?.("PENDING");
setSubmitMsg("Submitted! We will review your profile and notify you.");
- } else if (status === 409) {
- setSubmitMsg(data?.error ?? "A verification is already in progress.");
- } else {
- setSubmitMsg(data?.error ?? "Submission failed. Please try again.");
}
- } catch {
- setSubmitMsg("Network error. Please try again.");
+ } catch (err: any) {
+ // request() throws on any non-2xx response with the backend's actual error
+ // message (e.g. "A verification is already in progress...") — surface that
+ // instead of a generic message, otherwise every failure looks identical and
+ // unactionable regardless of cause.
+ setSubmitMsg(err?.message || "Submission failed. Please try again.");
} finally {
setSubmitting(false);
}
@@ -1241,7 +1241,7 @@ export default function ProfilePage(props: Props) {
"border-radius": "6px",
}}
>
- ✓ {docUrls()[doc.key]}
+ ✓ Uploaded
}
>
- {
+ const signed = await presignDocumentUrl(url()!);
+ window.open(signed, '_blank', 'noopener,noreferrer');
+ }}
+ style={{
+ margin: '4px 0 0', 'font-size': '12px', color: '#FF5E13',
+ 'text-decoration': 'underline', display: 'inline-block',
+ background: 'none', border: 'none', padding: '0', cursor: 'pointer',
+ }}
>
View document
-
+
{
return res?.data ?? [];
}
+/**
+ * Resolve a stored document reference into a short-lived, signed view URL.
+ * Never render a stored document URL directly (e.g. as an or
)
+ * — always exchange it for a fresh one through this endpoint first.
+ */
+export async function presignDocumentUrl(url: string): Promise {
+ const res = await apiFetch('/api/profile/documents/presign', {
+ method: 'POST',
+ body: JSON.stringify({ url }),
+ });
+ return res?.url ?? url;
+}
+
export async function submitProfileForVerification(rolePrefix: string): Promise {
return apiFetch(`/api/${rolePrefix}/profile/submit`, {
method: 'POST',