Files
flights_web/src/features/flights-map/api.ts
T
gnezim f61e050e8c Configure dev proxy to flights.test.aeroflot.ru and fix API endpoint paths
API functions now build the full localized path matching the Angular
EndpointService pattern (/api/flights/{version}/{locale}/{endpoint}).
The dev proxy forwards /api and /flights to the test backend.
2026-04-15 21:32:28 +03:00

119 lines
3.5 KiB
TypeScript

/**
* Flights Map API functions.
*
* Pure functions -- each takes an `ApiClient` as a parameter (dependency
* injection). No React hooks, no context, no side effects.
*
* @module
*/
import type { ApiClient } from "@/shared/api/client.js";
import type {
FlightsMapSearchParams,
FlightsMapCalendarParams,
IDestinationsResponse,
IFlightsMapDaysResponse,
} from "./types.js";
// ---------------------------------------------------------------------------
// API functions
// ---------------------------------------------------------------------------
/**
* Search flight destinations/routes on the map.
* Maps to: `GET destinations/1?departure=...&arrival=...&dateFrom=...&dateTo=...&connections=0`
*/
export async function searchDestinations(
client: ApiClient,
params: FlightsMapSearchParams,
): Promise<IDestinationsResponse> {
const query: Record<string, string> = {
departure: params.departure,
dateFrom: params.dateFrom,
dateTo: params.dateTo,
connections: String(params.connections ?? 0),
};
if (params.arrival) {
query["arrival"] = params.arrival;
}
return client.get<IDestinationsResponse>(`flights/1/${client.locale}/destinations`, query);
}
/**
* Get available calendar days for a flights-map route.
* Maps to: `GET days/{date}/200/{routeSegment}/flights-map/v1`
*
* The `days` response field is a binary string ("0110...") where each
* character represents one day starting from `date`. We parse it into
* an array of available date strings.
*/
export async function getFlightsMapCalendar(
client: ApiClient,
params: FlightsMapCalendarParams,
): Promise<string[]> {
const routeSegment = buildRouteSegment(params);
if (!routeSegment) return [];
const path = `flights/v1/${client.locale}/days/${params.date}/200/${routeSegment}/flights-map/`;
const response = await client.get<IFlightsMapDaysResponse>(path);
return parseBinaryDays(response.days, params.date);
}
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
function buildRouteSegment(params: FlightsMapCalendarParams): string | null {
if (params.departure && params.arrival) {
return params.connections
? `connections/${params.departure}-${params.arrival}-1`
: `route/${params.departure}-${params.arrival}`;
}
if (params.departure) {
return `departure/${params.departure}`;
}
return null;
}
/**
* Parse a binary days string ("01101...") into an array of ISO date strings
* representing the available (=1) days, starting from `startDate`.
*/
function parseBinaryDays(days: string, startDate: string): string[] {
if (!days) return [];
const result: string[] = [];
const start = parseYyyymmdd(startDate);
if (!start) return [];
for (let i = 0; i < days.length; i++) {
if (days[i] === "1") {
const d = new Date(start);
d.setDate(d.getDate() + i);
result.push(formatYyyymmdd(d));
}
}
return result;
}
function parseYyyymmdd(s: string): Date | null {
if (s.length !== 8) return null;
const year = Number(s.slice(0, 4));
const month = Number(s.slice(4, 6)) - 1;
const day = Number(s.slice(6, 8));
const d = new Date(year, month, day);
return Number.isNaN(d.getTime()) ? null : d;
}
function formatYyyymmdd(d: Date): string {
const y = d.getFullYear().toString();
const m = (d.getMonth() + 1).toString().padStart(2, "0");
const day = d.getDate().toString().padStart(2, "0");
return `${y}${m}${day}`;
}