diff --git a/src/features/online-board/components/details-panels/ServicesPanel.test.tsx b/src/features/online-board/components/details-panels/ServicesPanel.test.tsx new file mode 100644 index 00000000..692c179c --- /dev/null +++ b/src/features/online-board/components/details-panels/ServicesPanel.test.tsx @@ -0,0 +1,57 @@ +// @vitest-environment jsdom +import { describe, it, expect, vi } from "vitest"; +import { render, screen } from "@testing-library/react"; +import { ServicesPanel } from "./ServicesPanel.js"; +import type { IOnBoardService } from "../../types.js"; + +vi.mock("@/i18n/provider.js", () => ({ + useTranslation: () => ({ t: (k: string) => k }), +})); + +describe("ServicesPanel", () => { + it("renders an icon for each service", () => { + const services: IOnBoardService[] = [{ id: 1 }, { id: 4 }, { id: 8 }]; + render(); + expect(screen.getByTestId("service-icon-1")).toBeTruthy(); + expect(screen.getByTestId("service-icon-4")).toBeTruthy(); + expect(screen.getByTestId("service-icon-8")).toBeTruthy(); + }); + + it("maps service id 1 to shopping icon", () => { + render(); + const img = screen.getByTestId("service-icon-1") as HTMLImageElement; + expect(img.src).toContain("shopping"); + }); + + it("maps service id 4 to wifi icon", () => { + render(); + const img = screen.getByTestId("service-icon-4") as HTMLImageElement; + expect(img.src).toContain("wifi"); + }); + + it("uses fallback icon for unknown id", () => { + render(); + const img = screen.getByTestId("service-icon-99") as HTMLImageElement; + expect(img.src).toContain("comfort-plus"); + }); + + it("wraps icon in a link when service has url", () => { + const services: IOnBoardService[] = [ + { id: 4, url: "https://wifi.example" }, + ]; + render(); + const link = screen.getByTestId("service-icon-4").closest("a"); + expect(link?.getAttribute("href")).toBe("https://wifi.example"); + }); + + it("does not wrap icon in link when url is missing", () => { + render(); + const link = screen.getByTestId("service-icon-4").closest("a"); + expect(link).toBeNull(); + }); + + it("has panel data-testid", () => { + render(); + expect(screen.getByTestId("services-panel")).toBeTruthy(); + }); +}); diff --git a/src/features/online-board/components/details-panels/ServicesPanel.tsx b/src/features/online-board/components/details-panels/ServicesPanel.tsx new file mode 100644 index 00000000..bfad710f --- /dev/null +++ b/src/features/online-board/components/details-panels/ServicesPanel.tsx @@ -0,0 +1,67 @@ +import type { FC } from "react"; +import type { IOnBoardService } from "../../types.js"; +import { SERVICE_ICON_MAP, SERVICE_ICON_FALLBACK } from "./shared.js"; +import shoppingIcon from "./icons/shopping.svg"; +import spaceIcon from "./icons/space.svg"; +import taxiIcon from "./icons/taxi.svg"; +import wifiIcon from "./icons/wifi.svg"; +import gsmIcon from "./icons/gsm.svg"; +import entertainmentIcon from "./icons/entertaintment.svg"; +import seatReservationIcon from "./icons/seat_reservation.svg"; +import comfortPlusIcon from "./icons/comfort-plus.svg"; +import "./panels.scss"; + +const ICON_BY_NAME: Record = { + shopping: shoppingIcon, + space: spaceIcon, + taxi: taxiIcon, + wifi: wifiIcon, + gsm: gsmIcon, + entertaintment: entertainmentIcon, + seat_reservation: seatReservationIcon, + "comfort-plus": comfortPlusIcon, +}; + +export interface ServicesPanelProps { + services: IOnBoardService[]; +} + +export const ServicesPanel: FC = ({ services }) => { + return ( +
+
+ {services.map((svc) => { + const iconName = SERVICE_ICON_MAP[svc.id] ?? SERVICE_ICON_FALLBACK; + const iconSrc = + ICON_BY_NAME[iconName] ?? ICON_BY_NAME[SERVICE_ICON_FALLBACK]!; + const alt = svc.title ?? `service-${svc.id}`; + const img = ( + {alt} + ); + + return svc.url ? ( + + {img} + {svc.title && {svc.title}} + + ) : ( + + {img} + {svc.title && {svc.title}} + + ); + })} +
+
+ ); +};