Files
web/server/routers/hotels/utils.ts
2024-09-24 09:47:31 +02:00

203 lines
5.0 KiB
TypeScript

import { IconName } from "@/types/components/icon"
import deepmerge from "deepmerge"
import { unstable_cache } from "next/cache"
import * as api from "@/lib/api"
import {
apiCitiesByCountrySchema,
apiCitySchema,
apiCountriesSchema,
apiLocationsSchema,
type CitiesGroupedByCountry,
type Countries,
} from "./output"
import type { RequestOptionsWithOutBody } from "@/types/fetch"
import type { Lang } from "@/constants/languages"
import type { Endpoint } from "@/lib/api/endpoints"
export function getIconByPoiCategory(category: string) {
switch (category) {
case "Transportations":
return IconName.Train
case "Shopping":
return IconName.Shopping
case "Museum":
return IconName.Museum
case "Tourist":
return IconName.Cultural
case "Restaurant":
return IconName.Restaurant
default:
return null
}
}
export const locationsAffix = "locations"
export const TWENTYFOUR_HOURS = 60 * 60 * 24
export async function getCity(
cityUrl: string,
options: RequestOptionsWithOutBody
) {
const url = new URL(cityUrl)
const cityResponse = await api.get(
url.pathname as Endpoint,
options,
url.searchParams
)
if (!cityResponse.ok) {
return null
}
const cityJson = await cityResponse.json()
const city = apiCitySchema.safeParse(cityJson)
if (!city.success) {
console.info(`Validation of city failed`)
console.info(`cityUrl: ${cityUrl}`)
console.error(city.error)
return null
}
return city.data
}
export async function getCountries(
options: RequestOptionsWithOutBody,
params: URLSearchParams
) {
const countryResponse = await api.get(
api.endpoints.v1.countries,
options,
params
)
if (!countryResponse.ok) {
return null
}
const countriesJson = await countryResponse.json()
const countries = apiCountriesSchema.safeParse(countriesJson)
if (!countries.success) {
console.info(`Validation for countries failed`)
console.error(countries.error)
return null
}
return countries.data
}
export async function getCitiesByCountry(
countries: Countries,
options: RequestOptionsWithOutBody,
params: URLSearchParams
) {
const citiesGroupedByCountry: CitiesGroupedByCountry = {}
await Promise.all(
countries.data.map(async (country) => {
const countryResponse = await api.get(
`${api.endpoints.v1.citiesCountry}/${country.name}`,
options,
params
)
if (!countryResponse.ok) {
return null
}
const countryJson = await countryResponse.json()
const citiesByCountry = apiCitiesByCountrySchema.safeParse(countryJson)
if (!citiesByCountry.success) {
console.info(`Failed to validate Cities by Country payload`)
console.error(citiesByCountry.error)
return null
}
citiesGroupedByCountry[country.name] = citiesByCountry.data.data
return true
})
)
return citiesGroupedByCountry
}
export async function getLocations(
lang: Lang,
options: RequestOptionsWithOutBody,
params: URLSearchParams,
citiesByCountry: CitiesGroupedByCountry | null
) {
const apiResponse = await api.get(api.endpoints.v1.locations, options, params)
if (!apiResponse.ok) {
if (apiResponse.status === 401) {
return { error: true, cause: "unauthorized" } as const
} else if (apiResponse.status === 403) {
return { error: true, cause: "forbidden" } as const
}
return null
}
const apiJson = await apiResponse.json()
const verifiedLocations = apiLocationsSchema.safeParse(apiJson)
if (!verifiedLocations.success) {
console.info(`Locations Verification Failed`)
console.error(verifiedLocations.error)
return null
}
return await Promise.all(
verifiedLocations.data.data.map(async (location) => {
if (location.type === "cities") {
if (citiesByCountry) {
const country = Object.keys(citiesByCountry).find((country) => {
if (
citiesByCountry[country].find((loc) => loc.name === location.name)
) {
return true
}
return false
})
if (country) {
return {
...location,
country,
}
} else {
console.info(
`Location cannot be found in any of the countries cities`
)
console.info(location)
}
}
} else if (location.type === "hotels") {
if (location.relationships.city?.url) {
const getCachedCity = unstable_cache(
getCity,
[`${lang}:${location.relationships.city}`],
{ revalidate: TWENTYFOUR_HOURS }
)
const city = await getCachedCity(
location.relationships.city.url,
options
)
if (city) {
return deepmerge(location, {
relationships: {
city,
},
})
}
}
}
return location
})
)
}