Add LastUpdate component with timestamp and mobile share
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
// @vitest-environment jsdom
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { LastUpdate } from "./LastUpdate.js";
|
||||
import type { ISimpleFlight, IFlightLeg } from "../../types.js";
|
||||
|
||||
vi.mock("@/i18n/provider.js", () => ({ useTranslation: () => ({ t: (k: string) => k }) }));
|
||||
|
||||
function makeLeg(updated: string): IFlightLeg {
|
||||
return {
|
||||
arrival: {
|
||||
scheduled: { airport: "", airportCode: "LED", city: "", cityCode: "", countryCode: "" },
|
||||
latest: { airport: "", airportCode: "LED", city: "", cityCode: "", countryCode: "" },
|
||||
dispatch: "",
|
||||
gate: "",
|
||||
terminal: "",
|
||||
times: {
|
||||
scheduledArrival: {
|
||||
dayChange: { value: 0, title: "" },
|
||||
local: "",
|
||||
localTime: "",
|
||||
tzOffset: 0,
|
||||
utc: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
dayChange: 0,
|
||||
departure: {
|
||||
scheduled: { airport: "", airportCode: "SVO", city: "", cityCode: "", countryCode: "" },
|
||||
latest: { airport: "", airportCode: "SVO", city: "", cityCode: "", countryCode: "" },
|
||||
dispatch: "",
|
||||
gate: "",
|
||||
terminal: "",
|
||||
checkingStatus: "Scheduled",
|
||||
parkingStand: "",
|
||||
times: {
|
||||
scheduledDeparture: {
|
||||
dayChange: { value: 0, title: "" },
|
||||
local: "",
|
||||
localTime: "",
|
||||
tzOffset: 0,
|
||||
utc: "2026-04-20T10:00:00Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
equipment: {},
|
||||
flags: { checkinAvailable: false, returnToAirport: false, routeChanged: false },
|
||||
flyingTime: "1h",
|
||||
index: 0,
|
||||
operatingBy: {},
|
||||
status: "Scheduled",
|
||||
updated,
|
||||
} as IFlightLeg;
|
||||
}
|
||||
|
||||
function makeFlight(updated: string): ISimpleFlight {
|
||||
return {
|
||||
id: "X",
|
||||
routeType: "Direct",
|
||||
flyingTime: "1h",
|
||||
status: "Scheduled",
|
||||
flightId: { carrier: "SU", flightNumber: "0022", suffix: "", date: "20260417" },
|
||||
operatingBy: { carrier: "SU", flightNumber: "0022" },
|
||||
leg: makeLeg(updated),
|
||||
} as ISimpleFlight;
|
||||
}
|
||||
|
||||
describe("LastUpdate", () => {
|
||||
it("renders LAST-UPDATE label", () => {
|
||||
render(<LastUpdate flight={makeFlight("2026-04-20T12:34:00Z")} locale="ru" />);
|
||||
expect(screen.getByText(/SHARED\.LAST-UPDATE/)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders timestamp in HH:mm dd.MM.yyyy format", () => {
|
||||
render(<LastUpdate flight={makeFlight("2026-04-20T12:34:00Z")} locale="ru" />);
|
||||
const ts = screen.getByTestId("last-update-timestamp");
|
||||
expect(ts.textContent).toMatch(/\d{2}:\d{2}\s+\d{2}\.\d{2}\.\d{4}/);
|
||||
});
|
||||
|
||||
it("renders empty timestamp when leg.updated is empty", () => {
|
||||
render(<LastUpdate flight={makeFlight("")} locale="ru" />);
|
||||
const ts = screen.getByTestId("last-update-timestamp");
|
||||
expect(ts.textContent?.trim()).toBe("");
|
||||
});
|
||||
|
||||
it("renders share button", () => {
|
||||
render(<LastUpdate flight={makeFlight("2026-04-20T12:34:00Z")} locale="ru" />);
|
||||
expect(screen.getByTestId("share-button")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { FC } from "react";
|
||||
import { parseISO, format, isValid } from "date-fns";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import type { ISimpleFlight } from "../../types.js";
|
||||
import { ShareButton } from "./ShareButton.js";
|
||||
|
||||
export interface LastUpdateProps {
|
||||
flight: ISimpleFlight;
|
||||
locale: string;
|
||||
}
|
||||
|
||||
function getUpdated(flight: ISimpleFlight): string | undefined {
|
||||
const leg = flight.routeType === "Direct" ? flight.leg : flight.legs[0];
|
||||
return leg?.updated;
|
||||
}
|
||||
|
||||
function formatUpdated(updated: string | undefined): string {
|
||||
if (!updated) return "";
|
||||
const d = parseISO(updated);
|
||||
if (!isValid(d)) return "";
|
||||
return format(d, "HH:mm dd.MM.yyyy");
|
||||
}
|
||||
|
||||
export const LastUpdate: FC<LastUpdateProps> = ({ flight, locale }) => {
|
||||
const { t } = useTranslation();
|
||||
const timestamp = formatUpdated(getUpdated(flight));
|
||||
const shareUrl = typeof window !== "undefined" ? window.location.href : "";
|
||||
|
||||
return (
|
||||
<div className="last-update">
|
||||
<ShareButton url={shareUrl} locale={locale} />
|
||||
<span className="last-update__description">
|
||||
<span>{t("SHARED.LAST-UPDATE")}:</span>
|
||||
<span className="last-update__time" data-testid="last-update-timestamp">
|
||||
{timestamp}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user