import { Ingredient } from "@/components/Nutrition/models/Ingredient"; import { API_RESULTS_PAGE_SIZE, ApiPath, LANGUAGE_SHORT_ENGLISH } from "@/core/lib/consts"; import { fetchPaginated } from "@/core/lib/requests"; import { makeHeader, makeUrl } from "@/core/lib/url"; import { SearchLanguageFilter } from '@/core/ui/Widgets/SearchLanguageFilter'; import { ApiIngredientType, NutriScoreValue } from '@/types'; import axios from 'axios'; import { memoize } from "lodash"; export type IngredientLanguageFilter = SearchLanguageFilter; export interface IngredientSearchFilters { languageCode: string; languageFilter?: IngredientLanguageFilter; isVegan?: boolean; isVegetarian?: boolean; /** Worst acceptable Nutri-Score grade; sent as `nutriscore__lte`. */ nutriscoreMax?: NutriScoreValue; } /* * Memoized version of getIngredient. This caches results in memory for the duration * of the app session, which avoids multiple requests for the same ingredient. */ export const getIngredient = memoize(async (id: number): Promise => { const { data: receivedIngredient } = await axios.get( makeUrl(ApiPath.INGREDIENTINFO_PATH, { id: id }), { headers: makeHeader() }, ); return Ingredient.fromJson(receivedIngredient); }); export const getIngredients = async (ids: number[]): Promise => { // If IDs is an empty list, return. Otherwise, the resulting empty id__in will // cause the API to not filter at all if (ids.length === 0) { return []; } const url = makeUrl(ApiPath.INGREDIENTINFO_PATH, { query: { id__in: ids.join(',') } }); const out: Ingredient[] = []; // Collect all the ingredients for await (const page of fetchPaginated(url, makeHeader())) { for (const logData of page) { out.push(Ingredient.fromJson(logData)); } } return out; }; export const searchIngredient = async ( name: string, filters: IngredientSearchFilters, ): Promise => { const { languageCode, languageFilter = "current_english", isVegan, isVegetarian, nutriscoreMax, } = filters; const languages = languageFilter === "all" ? null : [languageCode]; if (languages && languageFilter === "current_english" && languageCode !== LANGUAGE_SHORT_ENGLISH) { languages.push(LANGUAGE_SHORT_ENGLISH); } const query: Record = { 'name__search': name, 'limit': API_RESULTS_PAGE_SIZE, }; if (languages) { query['language__code'] = languages.join(','); } if (isVegan !== undefined) { query['is_vegan'] = String(isVegan); } if (isVegetarian !== undefined) { query['is_vegetarian'] = String(isVegetarian); } if (nutriscoreMax !== undefined) { query['nutriscore__lte'] = nutriscoreMax; } const url = makeUrl(ApiPath.INGREDIENTINFO_PATH, { query }); const { data } = await axios.get(url, { headers: makeHeader() },); return data.results.map((entry: ApiIngredientType) => Ingredient.fromJson(entry)); };