import { useCallback, useRef } from "react"; import { Box, Button, Chip, Paper, Stack, Typography } from "@mui/material"; import { useNavigate } from "react-router-dom"; import { api } from "../api"; import { useViewResource } from "../hooks/useViewResource"; import { useI18n } from "../i18n/I18nProvider"; import ViewStateNotice from "../components/ViewStateNotice"; import { PageHeader } from "../layout/PageLayout"; import type { JobApplication } from "../types"; type PagedJobs = { items: JobApplication[]; total: number; page: number; pageSize: number }; export default function OfferComparisonPage() { const navigate = useNavigate(); const { language, t } = useI18n(); const load = useCallback(() => api.get("/jobapplications", { params: { status: "Offer", page: 1, pageSize: 25, sortBy: "dateApplied", sortDir: "asc" } }).then((r) => r.data), []); const resource = useViewResource(load, { initialData: { items: [], total: 0, page: 1, pageSize: 25 }, errorMessage: "" }); const resultsRef = useRef(null); const retryPending = useRef(false); const loading = resource.loading || resource.refreshing; const locale = language === "nb" ? "nb-NO" : "en"; const date = (value?: string | null) => value ? new Date(value).toLocaleDateString(locale) : "—"; const periods = new Map([["year", t("salaryPeriodYear")], ["month", t("salaryPeriodMonth")], ["hour", t("salaryPeriodHour")]]); return ( 0 ? : null} /> { if (loading || retryPending.current) return; retryPending.current = true; resultsRef.current?.focus(); void resource.reload().finally(() => { retryPending.current = false; }); }} /> {!loading && !resource.error && resource.data.items.length === 0 ? ( {t("offerComparisonEmpty")} {t("offerComparisonEmptyHelp")} ) : null} {!loading && !resource.error && resource.data.items.length > 0 ? {t("offerComparisonSampleCount", { shown: resource.data.items.length, total: resource.data.total })} {resource.data.total > resource.data.items.length ? {t("offerComparisonSampleHelp")} : null} : null} {resource.data.items.map((offer) => ( {offer.jobTitle}{offer.company?.name} ))} ); } function Fact({ label, value, multiline = false }: { label: string; value: string; multiline?: boolean }) { return {label}{value}; } function formatSalary(job: JobApplication, fallback: string, locale: string, periods: Map) { if (job.salaryMin != null || job.salaryMax != null) { const range = [job.salaryMin, job.salaryMax].filter((value) => value != null).map((value) => Number(value).toLocaleString(locale)).join(" – "); const period = job.salaryPeriod ? periods.get(job.salaryPeriod.toLowerCase()) ?? job.salaryPeriod : null; return `${range} ${job.salaryCurrency || ""}${period ? ` / ${period}` : ""}`.trim(); } return job.salary || fallback; }