Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 5x 10x 10x 8x 2x 3x 14x 39x 18x | import type { MarketplaceCity } from "@interioring/api-types";
/**
* Public city directory for pages that must follow the live rule.
* The API is the authority (`GET /api/marketplace/seo/cities`). When that
* call fails or returns nothing, Hyderabad is the fallback — it is pinned
* live, so the footer and sitemap never go blank during an API blip.
*/
/** `MarketplaceCity` with `state` and `publishedProCount` optional, so the
* hard-coded fallback and older payloads still fit. */
export type PublicCity = Omit<MarketplaceCity, "state" | "publishedProCount"> &
Partial<Pick<MarketplaceCity, "state" | "publishedProCount">>;
export const HYDERABAD_FALLBACK: PublicCity = {
id: "hyderabad",
slug: "hyderabad",
publicName: "Hyderabad",
state: "Telangana",
sortOrder: 1,
marketplaceStatus: "live",
publishedProCount: 0,
pricesApproved: true,
wikidataId: "Q1361",
};
type CitiesClient = {
getSeoCities: () => Promise<{ cities: PublicCity[] }>;
};
export async function loadPublicCities(
api: CitiesClient,
): Promise<PublicCity[]> {
try {
const res = await api.getSeoCities();
if (res.cities?.length) return res.cities;
} catch (err) {
console.error("[cities] getSeoCities failed:", err);
}
return [HYDERABAD_FALLBACK];
}
export function liveCities(cities: PublicCity[]): PublicCity[] {
return cities
.filter((city) => city.marketplaceStatus === "live")
.sort(
(a, b) =>
a.sortOrder - b.sortOrder || a.publicName.localeCompare(b.publicName),
);
}
|