style(ui): flatten activity and offer comparison sections

61 selected tests and build/lint pass. Wider rendered qualification remains in progress; this local checkpoint does not establish visual acceptance.
This commit is contained in:
cesnimda
2026-11-04 00:41:27 +01:00
parent 2218659ecf
commit 69621788ee
43 changed files with 80 additions and 11 deletions
+2 -2
View File
@@ -102,7 +102,7 @@ test("shows the first 25 of the real total in server application-date order with
expect(await screen.findByText(copy("offerComparisonSampleCount", "en", { shown: 25, total: 61 }))).toBeInTheDocument();
expect(screen.getByText(copy("offerComparisonSampleHelp"))).toBeInTheDocument();
expect(screen.getAllByRole("article")).toHaveLength(25);
expect(screen.getAllByRole("heading", { level: 3 }).map((heading) => heading.textContent)).toEqual(items.map((item) => item.jobTitle));
expect(screen.getAllByRole("heading", { level: 2 }).map((heading) => heading.textContent)).toEqual(items.map((item) => item.jobTitle));
expect(screen.queryByText("Offer role 26")).not.toBeInTheDocument();
expect(mockedApi.get).toHaveBeenCalledTimes(1);
expect(mockedApi.get).toHaveBeenCalledWith("/jobapplications", request);
@@ -150,7 +150,7 @@ test("a live locale change translates loaded offer chrome and preserves recorded
renderPage();
expect(await screen.findByText(notes)).toBeInTheDocument();
changeLanguage("nb");
expect(screen.getByRole("heading", { level: 2, name: translations.nb.offerComparisonTitle })).toBeInTheDocument();
expect(screen.getByRole("region", { name: translations.nb.offerComparisonTitle })).toBeInTheDocument();
const article = screen.getByRole("article", { name: "English source title" });
expect(within(article).getByText(notes)).toBeInTheDocument();
expect(within(article).getByText("GBP package as recorded")).toBeInTheDocument();
@@ -5,7 +5,6 @@ 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 };
@@ -24,8 +23,10 @@ export default function OfferComparisonPage() {
return (
<Stack spacing={2} sx={{ minWidth: 0 }}>
<PageHeader level="h2" title={t("offerComparisonTitle")} description={t("offerComparisonHelp")}
actions={!loading && !resource.error && resource.data.items.length > 0 ? <Button variant="outlined" onClick={() => navigate("/jobs?status=Offer&sortBy=dateApplied&sortDir=asc")}>{t("offerComparisonAllOffers")}</Button> : null} />
<Stack direction={{ xs: "column", md: "row" }} alignItems={{ xs: "flex-start", md: "center" }} gap={1.5}>
<Typography color="text.secondary" sx={{ flex: 1 }}>{t("offerComparisonHelp")}</Typography>
{!loading && !resource.error && resource.data.items.length > 0 ? <Button variant="outlined" onClick={() => navigate("/jobs?status=Offer&sortBy=dateApplied&sortDir=asc")}>{t("offerComparisonAllOffers")}</Button> : null}
</Stack>
<Box ref={resultsRef} role="region" aria-label={t("offerComparisonTitle")} tabIndex={-1} aria-busy={loading} sx={{ minWidth: 0 }}>
<ViewStateNotice compact loading={loading} title={t("offerComparisonLoadFailed")}
error={resource.error ? { ...resource.error, message: resource.error.message || t("offerComparisonLoadFailed") } : null}
@@ -37,7 +38,7 @@ export default function OfferComparisonPage() {
}} />
{!loading && !resource.error && resource.data.items.length === 0 ? (
<Paper variant="outlined" sx={{ p: "var(--app-card-padding)", textAlign: "center" }}>
<Typography component="h3" variant="sectionTitle">{t("offerComparisonEmpty")}</Typography>
<Typography component="h2" variant="sectionTitle">{t("offerComparisonEmpty")}</Typography>
<Typography color="text.secondary" sx={{ mt: 0.5, mb: 2 }}>{t("offerComparisonEmptyHelp")}</Typography>
<Button variant="contained" onClick={() => navigate("/jobs")}>{t("jobApplications")}</Button>
</Paper>
@@ -50,7 +51,7 @@ export default function OfferComparisonPage() {
{resource.data.items.map((offer) => (
<Paper key={offer.id} component="article" aria-label={offer.jobTitle} variant="outlined" sx={{ p: "var(--app-card-padding)", display: "flex", flexDirection: "column", minWidth: 0 }}>
<Stack direction="row" justifyContent="space-between" spacing={1} alignItems="flex-start">
<Box sx={{ minWidth: 0 }}><Typography component="h3" variant="sectionTitle" sx={{ overflowWrap: "anywhere" }}>{offer.jobTitle}</Typography><Typography color="text.secondary" sx={{ overflowWrap: "anywhere" }}>{offer.company?.name}</Typography></Box>
<Box sx={{ minWidth: 0 }}><Typography component="h2" variant="sectionTitle" sx={{ overflowWrap: "anywhere" }}>{offer.jobTitle}</Typography><Typography color="text.secondary" sx={{ overflowWrap: "anywhere" }}>{offer.company?.name}</Typography></Box>
<Chip size="small" color="success" label={t("statusOffer")} sx={{ flexShrink: 0 }} />
</Stack>
<Stack spacing={1.25} sx={{ my: 2 }}>
+2 -2
View File
@@ -137,7 +137,7 @@ export default function OperationsPage() {
{errorDetail !== errorTitle ? <Typography variant="body2">{errorDetail}</Typography> : null}
</Alert> : null}
{loading ? <LinearProgress aria-label={t("operationsLoading")} /> : null}
<PageSection surface title={t("notifications")}>
<PageSection title={t("notifications")}>
{hasLoaded && notifications.length === 0 ? <Typography color="text.secondary">{t("operationsNoNotifications")}</Typography> : null}
<Stack spacing={1.5}>{notifications.map(notification => <Paper key={notification.id} component="article" aria-label={notification.title} variant="outlined" sx={{ p: "var(--app-card-padding)", borderRadius: 1, minWidth: 0, overflowWrap: "anywhere" }}>
<Typography component="h3" variant="sectionTitle">{notification.title}</Typography>
@@ -150,7 +150,7 @@ export default function OperationsPage() {
</Stack>
</Paper>)}</Stack>
</PageSection>
<PageSection surface title={t("operations")}>
<PageSection title={t("operations")}>
{hasLoaded && operations.length === 0 ? <Typography color="text.secondary">{t("operationsEmpty")}</Typography> : null}
<Stack spacing={1.5}>{operations.map(operation => <Paper key={operation.id} component="article" aria-label={taskLabel(operation.taskType)} data-operation-id={operation.id} variant="outlined" sx={{ p: "var(--app-card-padding)", borderRadius: 1, minWidth: 0, overflowWrap: "anywhere" }}>
<Box sx={{ display: "flex", justifyContent: "space-between", gap: 1, flexWrap: "wrap", minWidth: 0 }}>