Skip to content
Merged
63 changes: 63 additions & 0 deletions src/app/candidate/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { requireRoleCapability } from "@/modules/auth/session";
import { CandidateEditForm } from "@/modules/candidates/CandidateEditForm";
import { getCountryOptions, getUniversityOptions, getBankOptions } from "@/modules/candidates/actions";
import { getCandidateDetail } from "@/modules/workspace/data";
import { WorkspaceShell } from "@/modules/workspace/WorkspaceShell";

export const dynamic = "force-dynamic";

export default async function CandidateEditPage() {
const session = await requireRoleCapability("candidate", "candidate.read.own");
const [data, countries, universities, banks] = await Promise.all([
getCandidateDetail(Number(session.id), "/candidate/invitations"),
getCountryOptions(),
getUniversityOptions(),
getBankOptions(),
]);
const c = data.candidate;

return (
<WorkspaceShell
session={session}
eyebrow="Edit Profile"
title="Update your candidate profile"
metrics={data.metrics}
>
<CandidateEditForm
candidate={{
name: c?.candidate_name ?? "",
nameAr: c?.candidate_name_ar ?? "",
email: c?.candidate_email ?? "",
phone: c?.candidate_phone ?? "",
objective: c?.candidate_objective ?? "",
intro: c?.candidate_intro ?? "",
civilId: c?.candidate_civil_id ?? "",
profileUrl: c?.profile_url ?? "",
birthDate: c?.candidate_birth_date
? new Date(c.candidate_birth_date).toISOString().slice(0, 10)
: "",
address: c?.candidate_address_line1 ?? "",
countryId: c?.country_id ?? null,
universityId: c?.university_id ?? null,
bankId: c?.bank_id ?? null,
bankAccountName: c?.bank_account_name ?? "",
iban: c?.candidate_iban ?? "",
personalPhoto: c?.candidate_personal_photo ?? null,
resume: c?.candidate_resume ?? null,
video: c?.candidate_video ?? null,
civilPhotoFront: c?.candidate_civil_photo_front ?? null,
civilPhotoBack: c?.candidate_civil_photo_back ?? null,
}}
countries={countries}
universities={universities}
banks={banks}
skills={data.skills.map((s) => ({ id: Number(s.id), title: s.title }))}
experiences={data.experiences.map((e) => ({
id: Number(e.id),
title: e.title,
subtitle: e.subtitle,
}))}
/>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</WorkspaceShell>
);
}
25 changes: 17 additions & 8 deletions src/app/candidate/invitations/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CompactList, FactPanel } from "@/modules/workspace/DetailPanels";
import { WorkspaceShell } from "@/modules/workspace/WorkspaceShell";
import { getCandidateInvitationDetail } from "@/modules/workspace/data";
import { formatDate } from "@/modules/workspace/format";
import { InvitationRespondForm } from "@/modules/candidates/InvitationRespondForm";

export const dynamic = "force-dynamic";

Expand All @@ -16,26 +17,34 @@ export default async function CandidateInvitationDetailPage({ params }: { params
notFound();
}

const inv = data.invitation;

return (
<WorkspaceShell
session={session}
eyebrow="Candidate / Invitation"
title={data.invitation.request.request_position_title ?? "Invitation"}
title={inv.request.request_position_title ?? "Invitation"}
metrics={data.metrics}
primary={{ title: "Notes", rows: data.notes }}
>
<FactPanel
title="Invitation Brief"
facts={[
{ label: "Company", value: data.invitation.request.company?.company_name },
{ label: "Compensation", value: data.invitation.request.request_compensation },
{ label: "Location", value: data.invitation.request.request_location },
{ label: "Seats", value: data.invitation.request.request_number_of_employees },
{ label: "Staff Owner", value: data.invitation.request.staff?.staff_name },
{ label: "Created", value: formatDate(data.invitation.invitation_created_at) },
{ label: "Updated", value: formatDate(data.invitation.invitation_updated_at) }
{ label: "Company", value: inv.request.company?.company_name },
{ label: "Compensation", value: inv.request.request_compensation },
{ label: "Location", value: inv.request.request_location },
{ label: "Seats", value: inv.request.request_number_of_employees },
{ label: "Staff Owner", value: inv.request.staff?.staff_name },
{ label: "Status", value: `Status ${inv.invitation_status ?? 0}` },
{ label: "Created", value: formatDate(inv.invitation_created_at) },
{ label: "Updated", value: formatDate(inv.invitation_updated_at) },
]}
/>

<InvitationRespondForm
invitationUuid={inv.invitation_uuid}
currentStatus={inv.invitation_status ?? 0}
/>
</WorkspaceShell>
);
}
2 changes: 2 additions & 0 deletions src/app/candidate/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ export default async function CandidatePage() {
<CandidateProfile
detail={data}
actions={[
{ label: "Edit profile", href: "/candidate/edit" },
{ label: "Invitations", href: "/candidate/invitations" },
{ label: "Work logs", href: "/candidate/work-logs" },
{ label: "Payments", href: "/candidate/payments" },
data.candidate?.candidate_email ? { label: "Email support", href: `mailto:${data.candidate.candidate_email}` } : null
].filter((action): action is { label: string; href: string } => Boolean(action))}
/>
Expand Down
32 changes: 32 additions & 0 deletions src/app/candidate/payments/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { requireRoleCapability } from "@/modules/auth/session";
import { DataTable } from "@/modules/workspace/DataTable";
import { WorkspaceShell } from "@/modules/workspace/WorkspaceShell";
import { getCandidateTransferRows } from "@/modules/workspace/data";

export const dynamic = "force-dynamic";

export default async function CandidatePaymentsPage() {
const session = await requireRoleCapability("candidate", "candidate.read.own");
const rows = await getCandidateTransferRows(Number(session.id));

return (
<WorkspaceShell session={session} eyebrow="Candidate" title="Payment History" metrics={[]}>
<DataTable
title="Transfer & Payment History"
description="Payout rows linked to your candidate account. Paid status, amounts, and payment dates are from the imported production data."
rows={rows}
columns={[
{ key: "company", label: "Company / Store", render: (row) => <strong>{row.company}</strong> },
{ key: "period", label: "Period", render: (row) => row.period },
{ key: "hours", label: "Hours", render: (row) => row.hours },
{ key: "candidateTotal", label: "Your Total", render: (row) => row.candidateTotal },
{ key: "companyTotal", label: "Company Total", render: (row) => row.companyTotal },
{ key: "cost", label: "Transfer Cost", render: (row) => row.cost },
{ key: "paid", label: "Paid", render: (row) => row.paid },
{ key: "paymentDate", label: "Payment Date", render: (row) => row.paymentDate },
{ key: "updated", label: "Updated", render: (row) => row.updated },
]}
/>
</WorkspaceShell>
);
}
5 changes: 4 additions & 1 deletion src/app/candidate/work-logs/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CompactList, FactPanel } from "@/modules/workspace/DetailPanels";
import { WorkspaceShell } from "@/modules/workspace/WorkspaceShell";
import { getCandidateWorkLogDetail } from "@/modules/workspace/data";
import { formatDate } from "@/modules/workspace/format";
import { WorkLogAppealForm } from "@/modules/candidates/WorkLogAppealForm";

export const dynamic = "force-dynamic";

Expand Down Expand Up @@ -33,9 +34,11 @@ export default async function CandidateWorkLogDetailPage({ params }: { params: P
{ label: "Store Location", value: data.workLog.store?.store_location },
{ label: "Start", value: formatDate(data.workLog.start_time) },
{ label: "End", value: formatDate(data.workLog.end_time) },
{ label: "Note", value: data.workLog.note }
{ label: "Note", value: data.workLog.note },
]}
/>

<WorkLogAppealForm workLogUuid={data.workLog.candidate_working_hour_uuid} />
</WorkspaceShell>
);
}
Loading
Loading