diff --git a/src/features/online-board/components/details-panels/RegistrationPanel.test.tsx b/src/features/online-board/components/details-panels/RegistrationPanel.test.tsx new file mode 100644 index 00000000..2e8b2f1b --- /dev/null +++ b/src/features/online-board/components/details-panels/RegistrationPanel.test.tsx @@ -0,0 +1,62 @@ +// @vitest-environment jsdom +import { describe, it, expect, vi } from "vitest"; +import { render, screen } from "@testing-library/react"; +import { RegistrationPanel } from "./RegistrationPanel.js"; +import type { IFlightTransitionItem } from "../../types.js"; + +vi.mock("@/i18n/provider.js", () => ({ + useTranslation: () => ({ t: (k: string) => k }), +})); + +const baseItem: IFlightTransitionItem = { + start: { + dayChange: { value: 0, title: "" }, + local: "10:00", + localTime: "10:00", + tzOffset: 3, + utc: "07:00", + }, + end: { + dayChange: { value: 0, title: "" }, + local: "10:30", + localTime: "10:30", + tzOffset: 3, + utc: "07:30", + }, + status: "InProgress", + isActual: true, +}; + +describe("RegistrationPanel", () => { + it("renders start and end times", () => { + render(); + expect(screen.getByText("10:00")).toBeTruthy(); + expect(screen.getByText("10:30")).toBeTruthy(); + }); + + it("renders status label", () => { + render(); + expect(screen.getByText("DETAILS.STATUS_IN_PROGRESS")).toBeTruthy(); + }); + + it("renders only start time when end is missing", () => { + const noEnd: IFlightTransitionItem = { + ...baseItem, + end: { + dayChange: { value: 0, title: "" }, + local: "", + localTime: "", + tzOffset: 0, + utc: "", + }, + }; + render(); + expect(screen.getByText("10:00")).toBeTruthy(); + expect(screen.queryByText("10:30")).toBeNull(); + }); + + it("has data-testid for targeting in integration tests", () => { + render(); + expect(screen.getByTestId("registration-panel")).toBeTruthy(); + }); +}); diff --git a/src/features/online-board/components/details-panels/RegistrationPanel.tsx b/src/features/online-board/components/details-panels/RegistrationPanel.tsx new file mode 100644 index 00000000..19d9c41e --- /dev/null +++ b/src/features/online-board/components/details-panels/RegistrationPanel.tsx @@ -0,0 +1,40 @@ +import type { FC } from "react"; +import { useTranslation } from "@/i18n/provider.js"; +import type { IFlightTransitionItem, FlightTransitionStatus } from "../../types.js"; +import "./panels.scss"; + +const STATUS_KEYS: Record = { + Finished: "DETAILS.STATUS_FINISHED", + Expected: "DETAILS.STATUS_EXPECTED", + InProgress: "DETAILS.STATUS_IN_PROGRESS", + Specified: "DETAILS.STATUS_SPECIFIED", + Scheduled: "DETAILS.STATUS_SCHEDULED", +}; + +export interface RegistrationPanelProps { + item: IFlightTransitionItem; +} + +export const RegistrationPanel: FC = ({ item }) => { + const { t } = useTranslation(); + const hasEnd = Boolean(item.end?.local); + + return ( +
+
+ {t("DETAILS.STATUS")} + {t(STATUS_KEYS[item.status])} +
+
+ {t("DETAILS.SCHEDULED")} + {item.start.local} +
+ {hasEnd && ( +
+ {t("DETAILS.ACTUAL")} + {item.end.local} +
+ )} +
+ ); +}; diff --git a/src/features/online-board/components/details-panels/panels.scss b/src/features/online-board/components/details-panels/panels.scss new file mode 100644 index 00000000..8589f762 --- /dev/null +++ b/src/features/online-board/components/details-panels/panels.scss @@ -0,0 +1,53 @@ +.details-panel { + padding: 12px 0; + font-size: 14px; + line-height: 1.5; +} + +.details-panel__row { + display: flex; + justify-content: space-between; + padding: 6px 0; + border-bottom: 1px solid #eee; + + &:last-child { + border-bottom: none; + } +} + +.details-panel__label { + color: #666; +} + +.details-panel__value { + color: #000; + font-weight: 500; +} + +.details-panel__status { + display: inline-block; + padding: 2px 8px; + border-radius: 4px; + background: #f0f4f8; + color: #2060c0; + font-size: 12px; +} + +.details-panel__icons { + display: flex; + gap: 12px; + flex-wrap: wrap; +} + +.details-panel__icon { + display: inline-flex; + align-items: center; + gap: 6px; + text-decoration: none; + color: inherit; + + img { + width: 24px; + height: 24px; + } +}