diff --git a/frontend/src/screens/Jobs.jsx b/frontend/src/screens/Jobs.jsx
index be5b9ae..e7aae69 100644
--- a/frontend/src/screens/Jobs.jsx
+++ b/frontend/src/screens/Jobs.jsx
@@ -15,6 +15,7 @@ import AiFieldAssist from '../ui/AiFieldAssist'
import DataTable from '../ui/DataTable'
import Modal from '../ui/Modal'
import PageHeader from '../ui/PageHeader'
+import { Tabs } from '../ui/Tabs'
import { Badge, EmptyState, FieldError, Icon, SkeletonRows } from '../ui/primitives'
import { useToast } from '../ui/Toast'
import { useAuth } from '../auth/AuthContext'
@@ -981,17 +982,6 @@ function JobOwnership({ job, canEdit }) {
const managersQuery = useManagerDirectory()
const recruitersQuery = useRecruiterDirectory()
- const historyQuery = useQuery({
- queryKey: qk.assignments.job(job.id),
- queryFn: async () => {
- const res = await assignmentsApi.listJob(job.id, { currentOnly: false })
- const rows = Array.isArray(res?.data) ? res.data : []
- return rows.map((r) => assignmentsApi.toAssignmentView(r))
- },
- enabled: Boolean(job.id),
- retry: false,
- })
-
const patch = useMutation({
mutationFn: (body) => jobsApi.update(job.id, body),
onSuccess: () => {
@@ -1003,8 +993,6 @@ function JobOwnership({ job, canEdit }) {
onError: (err) => toast(friendlyAuthError(err, 'Could not update the assignment.'), 'error'),
})
- const history = historyQuery.data ?? []
-
return (
<>
@@ -1054,41 +1042,49 @@ function JobOwnership({ job, canEdit }) {
{canEdit && recruitersQuery.isError && (
The recruiter list needs the tasks.view permission.
)}
-
- Assignment history
- {historyQuery.isError ? (
-
- {friendlyAuthError(historyQuery.error, 'History did not load.')}
-
- ) : historyQuery.isPending ? (
- Loading…
- ) : history.length === 0 ? (
- No assignment history yet.
- ) : (
-
- {history.map((row) => (
-
-
-
{row.name || 'Unknown'}
-
- {[
- ROLE_LABEL[row.role] || row.role?.replace(/_/g, ' '),
- row.validFrom ? fmtShort(row.validFrom) : null,
- row.validTo ? `→ ${fmtShort(row.validTo)}` : 'current',
- row.assignedByName ? `by ${row.assignedByName}` : null,
- ].filter(Boolean).join(' · ')}
-
-
- {!row.validTo &&
Current}
-
- ))}
-
- )}
>
)
}
+function AssignmentHistory({ historyQuery }) {
+ const history = historyQuery.data ?? []
+
+ if (historyQuery.isError) {
+ return (
+
+ {friendlyAuthError(historyQuery.error, 'History did not load.')}
+
+ )
+ }
+ if (historyQuery.isPending) {
+ return Loading…
+ }
+ if (history.length === 0) {
+ return No assignment history yet.
+ }
+ return (
+
+ {history.map((row) => (
+
+
+
{row.name || 'Unknown'}
+
+ {[
+ ROLE_LABEL[row.role] || row.role?.replace(/_/g, ' '),
+ row.validFrom ? fmtShort(row.validFrom) : null,
+ row.validTo ? `→ ${fmtShort(row.validTo)}` : 'current',
+ row.assignedByName ? `by ${row.assignedByName}` : null,
+ ].filter(Boolean).join(' · ')}
+
+
+ {!row.validTo &&
Current}
+
+ ))}
+
+ )
+}
+
/* Cover image, when the post has one — fetched with the bearer token into an
object URL, because a bare
cannot carry auth headers. null (404)
simply renders nothing. */
@@ -1113,6 +1109,18 @@ function JobCover({ jobId }) {
function JobDetail({
job: j, canEdit, canDelete, statusBusy, deleteBusy, onClose, onPublish, onEdit, onStatus, onDelete,
}) {
+ const [tab, setTab] = useState('details')
+ const historyQuery = useQuery({
+ queryKey: qk.assignments.job(j.id),
+ queryFn: async () => {
+ const res = await assignmentsApi.listJob(j.id, { currentOnly: false })
+ const rows = Array.isArray(res?.data) ? res.data : []
+ return rows.map((r) => assignmentsApi.toAssignmentView(r))
+ },
+ enabled: Boolean(j.id),
+ retry: false,
+ })
+
return (
-
-
Department
{j.department || '—'}
-
Location
{j.location || '—'}
-
Employment Type
{j.type || '—'}
-
Platform
{platformLabel(j.platform) || '—'}
-
Vacancies
{j.vacancies ?? '—'}
-
Experience
{j.experience || '—'}
-
Created
{j.created ? fmtShort(j.created) : '—'}
-
Created by
{j.createdByName || '—'}
-
Hiring Manager
{j.hiringManager || '—'}
-
Assigned Recruiter
{j.recruiter || '—'}
-
Closed at
{j.closedAt ? fmtShort(j.closedAt) : '—'}
-
+
-
-
- {j.description && (
+ {tab === 'details' && (
<>
-
-
-
Description
-
{j.description}
+
+
Department
{j.department || '—'}
+
Location
{j.location || '—'}
+
Employment Type
{j.type || '—'}
+
Platform
{platformLabel(j.platform) || '—'}
+
Vacancies
{j.vacancies ?? '—'}
+
Experience
{j.experience || '—'}
+
Created
{j.created ? fmtShort(j.created) : '—'}
+
Created by
{j.createdByName || '—'}
+
Hiring Manager
{j.hiringManager || '—'}
+
Assigned Recruiter
{j.recruiter || '—'}
+
Closed at
{j.closedAt ? fmtShort(j.closedAt) : '—'}
+
+
+
+ {j.description && (
+ <>
+
+
+
Description
+
{j.description}
+
+ >
+ )}
+ {!!(j.skills && j.skills.length) && (
+
+
Required Skills
+
{j.skills.map((s) => {s})}
+
+ )}
>
)}
- {!!(j.skills && j.skills.length) && (
-
-
Required Skills
-
{j.skills.map((s) => {s})}
-
- )}
+
+ {tab === 'history' &&
}
)
}