plan/react-rewrite #1

Merged
gnezim merged 138 commits from plan/react-rewrite into main 2026-04-15 12:21:16 +03:00
3 changed files with 200 additions and 0 deletions
Showing only changes of commit 0f5d7915be - Show all commits
+42
View File
@@ -0,0 +1,42 @@
/**
* JSON-LD schema builder for the Flights Map page.
*
* Produces a schema.org WebPage typed object ready for <JsonLdRenderer>.
*
* @module
*/
import type { WebPage } from "schema-dts";
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const SITE_NAME = "Aeroflot";
const PATH_WITHOUT_LOCALE = "/flights-map";
// ---------------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------------
/**
* Build a schema.org WebPage JSON-LD object for the flights map page.
*/
export function buildFlightsMapJsonLd(
locale: string,
canonicalOrigin: string,
): WebPage {
const url = `${canonicalOrigin}/${locale}${PATH_WITHOUT_LOCALE}`;
return {
"@type": "WebPage",
name: `${SITE_NAME} - Flight Map`,
url,
inLanguage: locale,
isPartOf: {
"@type": "WebSite",
name: SITE_NAME,
url: canonicalOrigin,
},
};
}
+93
View File
@@ -0,0 +1,93 @@
import { describe, expect, it } from "vitest";
import { buildFlightsMapSeo } from "./seo.js";
import { buildFlightsMapJsonLd } from "./json-ld.js";
/** Stub t() that returns the key for assertion. */
function stubT(key: string): string {
return key;
}
const CANONICAL = "https://www.aeroflot.ru";
// ---------------------------------------------------------------------------
// buildFlightsMapSeo
// ---------------------------------------------------------------------------
describe("buildFlightsMapSeo", () => {
it("uses FLIGHTS_MAP translation keys", () => {
const result = buildFlightsMapSeo(stubT, "ru", CANONICAL);
expect(result.title).toBe("SEO.FLIGHTS_MAP.TITLE");
expect(result.description).toBe("SEO.FLIGHTS_MAP.DESCRIPTION");
});
it("sets canonical to /{locale}/flights-map", () => {
const result = buildFlightsMapSeo(stubT, "en", CANONICAL);
expect(result.canonical).toBe("https://www.aeroflot.ru/en/flights-map");
});
it("includes hreflang with 10 entries", () => {
const result = buildFlightsMapSeo(stubT, "ru", CANONICAL);
expect(result.hreflang).toHaveLength(10);
});
it("sets og tags", () => {
const result = buildFlightsMapSeo(stubT, "ru", CANONICAL);
expect(result.og.title).toBe(result.title);
expect(result.og.type).toBe("website");
expect(result.og.locale).toBe("ru");
expect(result.og.siteName).toBe("Aeroflot");
expect(result.og.url).toBe("https://www.aeroflot.ru/ru/flights-map");
});
it("sets twitter card to summary", () => {
const result = buildFlightsMapSeo(stubT, "ru", CANONICAL);
expect(result.twitter).toBeDefined();
expect(result.twitter!.card).toBe("summary");
});
});
// ---------------------------------------------------------------------------
// buildFlightsMapJsonLd
// ---------------------------------------------------------------------------
describe("buildFlightsMapJsonLd", () => {
it("returns a WebPage schema", () => {
const result = buildFlightsMapJsonLd("ru", CANONICAL);
expect(result["@type"]).toBe("WebPage");
});
it("sets the correct URL with locale", () => {
const result = buildFlightsMapJsonLd("en", CANONICAL);
expect(result.url).toBe("https://www.aeroflot.ru/en/flights-map");
});
it("sets inLanguage to the locale", () => {
const result = buildFlightsMapJsonLd("ja", CANONICAL);
expect(result.inLanguage).toBe("ja");
});
it("includes isPartOf WebSite reference", () => {
const result = buildFlightsMapJsonLd("ru", CANONICAL);
expect(result.isPartOf).toBeDefined();
const site = result.isPartOf as { "@type": string; name: string; url: string };
expect(site["@type"]).toBe("WebSite");
expect(site.name).toBe("Aeroflot");
expect(site.url).toBe(CANONICAL);
});
it("sets name with site name prefix", () => {
const result = buildFlightsMapJsonLd("ru", CANONICAL);
expect(result.name).toContain("Aeroflot");
expect(result.name).toContain("Flight Map");
});
});
+65
View File
@@ -0,0 +1,65 @@
/**
* SEO builder functions for Flights Map route page.
*
* Pure function -- all data arrives via parameters, no hooks or side effects.
* Returns a SeoHeadProps object ready for <SeoHead>.
*
* @module
*/
import type { SeoHeadProps } from "@/ui/seo/SeoHead.js";
import { buildHreflangSet } from "@/shared/seo/hreflang.js";
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type TFunction = (key: string, opts?: any) => string;
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const OG_IMAGE = "https://www.aeroflot.ru/static/images/aeroflot-og-default.png";
const SITE_NAME = "Aeroflot";
const PATH_WITHOUT_LOCALE = "/flights-map";
// ---------------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------------
/**
* SEO props for the Flights Map start page.
*/
export function buildFlightsMapSeo(
t: TFunction,
locale: string,
canonicalOrigin: string,
): SeoHeadProps {
const title = t("SEO.FLIGHTS_MAP.TITLE");
const description = t("SEO.FLIGHTS_MAP.DESCRIPTION");
const canonical = `${canonicalOrigin}/${locale}${PATH_WITHOUT_LOCALE}`;
return {
title,
description,
canonical,
hreflang: buildHreflangSet({
canonicalOrigin,
pathWithoutLocale: PATH_WITHOUT_LOCALE,
}),
og: {
title,
description,
url: canonical,
image: OG_IMAGE,
type: "website",
locale,
siteName: SITE_NAME,
},
twitter: {
card: "summary",
},
};
}