Extend useAppSettings with flightStatus and buyTicket button config
This commit is contained in:
@@ -6,6 +6,25 @@ export interface AppSettingsFilterOptions {
|
||||
timeStep?: string;
|
||||
}
|
||||
|
||||
export interface AppSettingsButtonsBuyTicketPeriod {
|
||||
min?: string;
|
||||
max?: string;
|
||||
}
|
||||
|
||||
export interface AppSettingsButtonsBuyTicket {
|
||||
period?: AppSettingsButtonsBuyTicketPeriod;
|
||||
}
|
||||
|
||||
export interface AppSettingsButtonsFlightStatus {
|
||||
availableFrom?: string;
|
||||
visible?: string;
|
||||
}
|
||||
|
||||
export interface AppSettingsButtons {
|
||||
flightStatus?: AppSettingsButtonsFlightStatus;
|
||||
buyTicket?: AppSettingsButtonsBuyTicket;
|
||||
}
|
||||
|
||||
export interface AppSettingsResponse {
|
||||
showDebugVersion?: string;
|
||||
uiOptions?: {
|
||||
@@ -14,7 +33,7 @@ export interface AppSettingsResponse {
|
||||
onlineboard?: AppSettingsFilterOptions;
|
||||
schedule?: AppSettingsFilterOptions;
|
||||
};
|
||||
buttons?: Record<string, unknown>;
|
||||
buttons?: AppSettingsButtons;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -82,4 +82,34 @@ describe("useAppSettings", () => {
|
||||
expect(result.current.error).toBe(err);
|
||||
expect(result.current.onlineboardSearchFrom).toBe(2);
|
||||
});
|
||||
|
||||
it("parses buttons config into hour numbers", async () => {
|
||||
const response: AppSettingsResponse = {
|
||||
uiOptions: {
|
||||
buttons: {
|
||||
flightStatus: { availableFrom: "24h" },
|
||||
buyTicket: { period: { min: "2h", max: "72h" } },
|
||||
},
|
||||
},
|
||||
};
|
||||
mockGetAppSettings.mockResolvedValue(response);
|
||||
|
||||
const { result } = renderHook(() => useAppSettings());
|
||||
|
||||
await waitFor(() => expect(result.current.loading).toBe(false));
|
||||
expect(result.current.flightStatusAvailableFromHours).toBe(24);
|
||||
expect(result.current.buyTicketMinHours).toBe(2);
|
||||
expect(result.current.buyTicketMaxHours).toBe(72);
|
||||
});
|
||||
|
||||
it("returns button-config defaults when fields are missing", async () => {
|
||||
mockGetAppSettings.mockResolvedValue({});
|
||||
|
||||
const { result } = renderHook(() => useAppSettings());
|
||||
|
||||
await waitFor(() => expect(result.current.loading).toBe(false));
|
||||
expect(result.current.flightStatusAvailableFromHours).toBe(24);
|
||||
expect(result.current.buyTicketMinHours).toBe(2);
|
||||
expect(result.current.buyTicketMaxHours).toBe(72);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,33 +3,52 @@ import { useApiClient } from "@/shared/api/provider.js";
|
||||
import { getAppSettings } from "@/shared/api/appSettings.js";
|
||||
|
||||
const DAYS_PATTERN = /^(\d+)d$/;
|
||||
const HOURS_PATTERN = /^(\d+)h$/;
|
||||
|
||||
const DEFAULTS = {
|
||||
onlineboardSearchFrom: 2,
|
||||
onlineboardSearchTo: 14,
|
||||
scheduleSearchFrom: 30,
|
||||
scheduleSearchTo: 30,
|
||||
flightStatusAvailableFromHours: 24,
|
||||
buyTicketMinHours: 2,
|
||||
buyTicketMaxHours: 72,
|
||||
} as const;
|
||||
|
||||
function parseDays(value: string | undefined, fallback: number): number {
|
||||
function parsePattern(
|
||||
value: string | undefined,
|
||||
pattern: RegExp,
|
||||
fallback: number,
|
||||
): number {
|
||||
if (!value) return fallback;
|
||||
const match = DAYS_PATTERN.exec(value);
|
||||
const match = pattern.exec(value);
|
||||
if (!match) return fallback;
|
||||
return parseInt(match[1]!, 10);
|
||||
}
|
||||
|
||||
function parseDays(value: string | undefined, fallback: number): number {
|
||||
return parsePattern(value, DAYS_PATTERN, fallback);
|
||||
}
|
||||
|
||||
function parseHours(value: string | undefined, fallback: number): number {
|
||||
return parsePattern(value, HOURS_PATTERN, fallback);
|
||||
}
|
||||
|
||||
export interface UseAppSettingsResult {
|
||||
onlineboardSearchFrom: number;
|
||||
onlineboardSearchTo: number;
|
||||
scheduleSearchFrom: number;
|
||||
scheduleSearchTo: number;
|
||||
flightStatusAvailableFromHours: number;
|
||||
buyTicketMinHours: number;
|
||||
buyTicketMaxHours: number;
|
||||
loading: boolean;
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the global app settings and exposes day-range numbers.
|
||||
* On error or parse failure, returns default values (2/14/30/30).
|
||||
* Fetches the global app settings and exposes day-range and button-config numbers.
|
||||
* On error or parse failure, returns defaults.
|
||||
*/
|
||||
export function useAppSettings(): UseAppSettingsResult {
|
||||
const client = useApiClient();
|
||||
@@ -45,11 +64,20 @@ export function useAppSettings(): UseAppSettingsResult {
|
||||
if (cancelled) return;
|
||||
const ob = response.uiOptions?.filter?.onlineboard;
|
||||
const sc = response.uiOptions?.filter?.schedule;
|
||||
const fs = response.uiOptions?.buttons?.flightStatus;
|
||||
const bt = response.uiOptions?.buttons?.buyTicket;
|
||||
|
||||
setState({
|
||||
onlineboardSearchFrom: parseDays(ob?.searchFrom, DEFAULTS.onlineboardSearchFrom),
|
||||
onlineboardSearchTo: parseDays(ob?.searchTo, DEFAULTS.onlineboardSearchTo),
|
||||
scheduleSearchFrom: parseDays(sc?.searchFrom, DEFAULTS.scheduleSearchFrom),
|
||||
scheduleSearchTo: parseDays(sc?.searchTo, DEFAULTS.scheduleSearchTo),
|
||||
flightStatusAvailableFromHours: parseHours(
|
||||
fs?.availableFrom,
|
||||
DEFAULTS.flightStatusAvailableFromHours,
|
||||
),
|
||||
buyTicketMinHours: parseHours(bt?.period?.min, DEFAULTS.buyTicketMinHours),
|
||||
buyTicketMaxHours: parseHours(bt?.period?.max, DEFAULTS.buyTicketMaxHours),
|
||||
});
|
||||
setLoading(false);
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user