import { PlausibleProps } from 'mealz-shared-analytics'; import { DocumentCollection } from 'miam-jsonapi'; import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs'; import { Basket, BasketEntry, Ingredient, Item, Menu, MenuRecipe, PointOfSale, Recipe, RecipeLike, SponsorBlock, Supplier } from '../../_models'; import { RecipePricing } from '../../_models/recipe-pricing'; import { Tag } from '../../_models/tag'; import { ProductCategory, ProductPrice, RecipeDisplay } from '../../_services'; import { RecipeInBasketPreview } from '../../_services/basket-utils.service'; import { Product } from '../../_services/new-recipe-details.service'; import { BasicPreference } from '../../_services/preferences.service'; import { ProductPlanner, ProductPlannerCategory } from '../../_services/recipe-details-products-planner.service'; import { BasketEntryToReplace } from '../../_services/replace-item.service'; import { EventJourney } from '../event-journey.enum'; import { EventTrace } from '../event-trace'; export interface MealzInternalInterface { analytics: { /** * Sends an analytics event via mealz-shared-analytics */ sendEvent: (name: string, path: string, props: PlausibleProps, journey?: EventJourney) => void; /** * Defines the `journey` property for mealz-shared-analytics * * Set to true if we currently are in a mealz dedicated page */ setIsMealzPage: (isMealzPage: boolean) => void; }; // --------------------------------------------------------------------------------------------------- basket: { /** * Emits the list of recipe IDs when recipes are added to the basket. */ recipesAddedToBasket$: () => Observable; /** * Emits the pricing information for recipes in the basket. */ recipePricesInBasket$: () => Observable<{ id: string; price: string }[]>; /** * Gets the guests count for a recipe * @param recipeId */ guestsForRecipe: (recipeId: string) => number; /** * Removes a recipe from the basket. */ removeRecipe: (recipeId: string, analyticsPath: string) => void; /** * Emits the preview of recipes in the basket. */ buildPreview: () => Observable; /** * Observable that emits the full state of the basket preview including open state and active tab */ basketPreviewState$: Observable<{ isOpen: boolean; activeTabIndex?: number }>; /** * Emits the list of recipes in the basket. */ waitForBasketEntries: () => Observable; /** * Emits the list of basket-entries in the basket each time it changes. */ entries$: () => Observable; /** * Refresh the current basket state and emit updated basket */ refreshCurrentBasket: () => Observable; /** * if false, don't show the product section in the basket preview */ displayProductsInBasket: () => boolean; /** * Emits the list of basket-entries to add to retailer cart */ updateRetailerBasketFromPlanner: () => void; }; basketTransfer: { /** * Exposes the transfer-in-progress state */ basketIsBeingTransferred: BehaviorSubject; /** * Abort the transfer (reloads basket) */ abortTransfer: () => Observable; /** * Navigate to the transfer URL stored in session */ navigateToTransferUrl: () => void; /** * transfer basket to supplier */ transfer: () => void; }; // --------------------------------------------------------------------------------------------------- catalog: { loadMoreRecipes: (packageId: string, page: number, pageSize: number, guests: number) => Observable; }; // --------------------------------------------------------------------------------------------------- config: { logLevel: Observable; }; // --------------------------------------------------------------------------------------------------- planner: { /** * Emits the item to replace from recipe details view */ itemToReplace$: BehaviorSubject<{ ingredient: Ingredient; item: Item }>; /** * Emits the list of items with prices */ itemsWithPricesList$: BehaviorSubject; /** * Emits if items are getting fetched */ fetchingItemLoading$: BehaviorSubject; /** * Emits an observable with the total price of the menu in the planner */ menuPrice$: BehaviorSubject; /** * Emits an observable with the price of the recipe currently displayed in the planner */ plannerRecipePrice$: BehaviorSubject; /** * creates a menu */ createMenu: () => Observable; /** * Deletes a menu from its id * @param menuId */ deleteMenu: (menuId: string) => Observable; /** * Updates a menu with its id * @param menuId * @param toUpdate */ updateMenu: (menuId: string, toUpdate: Partial) => Observable; /** * Add a recipe to a menu with its id * @param recipeId * @param guests * @param autocomplete */ addRecipeToMenu: (recipeId: string, guests: number, hasPos?: boolean, toPickProducts?: ProductPlanner[]) => Observable; /** * Removes a recipe from a menu with its id * @param recipeId */ removeRecipeFromMenu: (recipeId: string) => Observable; /** * Fetches the title of the menu */ fetchMenuTitle: () => Observable; /** * Transfers the menu to the basket * @param basketId */ menuToBasket: (basketId: string) => Observable; /** * Gets the menu recipe id for a recipe * @param recipeId */ getMenuRecipeId: (recipeId: string) => Observable; /** * Checks if a recipe is in the menu * @param recipeId */ isRecipeInMenu$: (recipeId: string) => Observable; /** * Rejects a recipe suggestion to prevent it to be suggested again * @param recipeId */ rejectRecipe: (recipeId: string) => Observable; /** * Selects a product in the planner * @param itemId * @param ingredientsDefinitionId */ selectProduct: (itemId: number, ingredientsDefinitionId: string) => void; /** * Unselects a product in the planner * @param itemId * @param ingredientsDefinitionId */ unselectProduct: (itemId: number, ingredientsDefinitionId: string) => void; /** * Replaces a product in the planner from the replace item modal * @param product */ replaceProduct: (product: ProductPlanner) => void; /** * Opens replace item view * @param product */ openReplaceItemView: (product: ProductPlanner) => void; /** * Searches for an item from replace item modal * @param searchString * @param ingredient * @param item */ searchItem(searchString: string, ingredient: Ingredient, item: Item): Observable; /** * Gets suggested recipes */ getSuggestedRecipes: () => Observable; /** * Updates the guests count * @param guests * @param eventTrace */ updateGuests: (guests: number, eventTrace: EventTrace) => void; /** * Gets the guests count for a recipe * @param recipeId */ getGuestsForRecipe: (recipeId: string) => Observable; }; // --------------------------------------------------------------------------------------------------- recipes: { /** * Opens the recipe details by calling the `openRecipeDetails` method of the `recipesService`. */ openDetails: ( recipeId: string, guests: number, initialTabIndex?: number, analyticsPath?: string, plannerOrCategoryId?: boolean | string, categoryId?: string ) => void; /** * Loads and setups a recipe */ loadAndSetupRecipe: (recipeId: string, guests?: number) => Observable; /** * Method to open replace item view */ replaceBasketEntry: (basketEntry: BasketEntry, ignoreSelected: boolean) => void; /** * Method to update guest number */ updateGuests: (eventTrace: EventTrace, guests?: number) => void; /** * Method to add all ingredients from recipe to basket */ addAllIngredientsToBasket: (eventTrace: EventTrace) => void; /** * Method to add a product to the basket */ addToBasket: (product: Product, eventTrace: EventTrace) => void; /** * Method to remove an ingredient */ ingredientRemoved: (ingredient: Ingredient, eventTrace: EventTrace) => void; /** * Method to update the quantity of a product */ updateProductQuantity: (basketEntry: BasketEntry, newQuantity: number, eventTrace: EventTrace) => void; /** * Method to ignore a product */ ignoreProduct: (product: Product) => void; /** * Method to check if a product is being added */ productIsBeingAdded: (basketEntry: BasketEntry) => Observable; /** * Emits the loading state of the `addAllIngredientsToBasket` method */ allIngredientsToBasketLoading$: BehaviorSubject; /** * Emits the loading state of the `addToBasket` method */ ingredientToBasketLoading$: BehaviorSubject; /** * Emits the loading state of the `ingredientRemoved` or `updateIngredientFromBasket` method */ updateIngredientFromBasketLoading$: BehaviorSubject; /** * Emits the loading state of products */ productsLoading$: BehaviorSubject; /** * Emits the currently displayed recipe */ displayedRecipe$: BehaviorSubject; /** * Emits the products by category */ productsByCategory$: BehaviorSubject; /** * Emits the products by category in planner view */ productsPlannerByCategory$: BehaviorSubject; /** * Emits if recipeDetails should display the noPos view */ noPosDisplay$: BehaviorSubject; /** * Emits if recipeDetails should display the invalidPos view */ invalidPosDisplay$: BehaviorSubject; /** * Emits an observable containing the recipe's basket entries that have not yet been added to the basket. */ remainingBasketEntries$: BehaviorSubject; /** * Emits an observable with the price of a recipe displayed, from what is already in the basket and what is remaining */ recipePrice$: BehaviorSubject<{ remaining: number; inBasket: number }>; /** * Emits an observable with the date of the last order */ orderHistoryDate$: BehaviorSubject; /** * Updates or creates a recipe like entry. * If `recipeLikeId` is provided, it updates the existing like; otherwise, it creates a new one. * It also sets the `isPast` status and tracks the update event. */ updateRecipeLike: (recipeLikeId: string, recipeId: string, isPast: boolean, path?: string, categoryId?: string) => void; /** * Emits an observable that notifies subscribers when a recipe like has been updated. */ recipeLikeUpdated: () => Observable<{ id: string; isPast: boolean }>; /** * Emits an observable that notifies subscribers when the number of guests of a recipe has been updated from recipe details. */ guestsUpdated: () => Observable<{ guests: number; recipeId: string }>; /** * Emits an observable that notifies subscribers when a recipe price has been updated. */ recipePriceUpdated: () => Observable<{ remaining: number; inBasket: number; recipeId: string }>; /** * Fetches the pricing information for a specific recipe based on the provided parameters. */ fetchPricing: (recipeId: string, posId: string, serves: number) => Observable; /** * Updates the state to indicate whether the recipe details is being accessed from planner. */ setIsRecipeDetailsFromPlanner: (isSSR: boolean) => void; /** * Checks if a recipe is in the basket * @param recipeId */ isRecipeInBasket: (recipeId: string) => Observable; /** * Gets the recipe like for a specific recipe * @param recipeId */ getRecipeLike: (recipeId: string) => Observable; }; // --------------------------------------------------------------------------------------------------- replaceItem: { /** * Emits the basket entry to replace from recipe details view */ basketEntryToReplace$: BehaviorSubject; /** * Emits if the replace item modal should be displayed from basket preview */ replaceProductFromPreviewOpen$: BehaviorSubject; /** * Emits if the replace item modal should be displayed from the product addition */ additionModalOpen$: BehaviorSubject; /** * Method to call when adding an item from the replace item modal */ onSelectItem: (item: Item, searchString: string, onComplete?: (itemId?: string) => void, eventTrace?: EventTrace) => void; /** * Variable with the list of items with prices */ itemsWithPricesList$: BehaviorSubject<{ item: Item; price: ProductPrice }[]>; /** * Emits if items are getting fetched */ fetchingItemLoading$: BehaviorSubject; /** * Emits the item that is being replaced */ replaceItemLoading$: BehaviorSubject; /** * method to call to retrieve item from query */ searchItem: (searchString: string) => Observable; }; // --------------------------------------------------------------------------------------------------- router: { /** * Retrieve retailer cart url */ getRetailerCartUrl: () => string; /** * Retrieve catalog url */ getCatalogUrl: () => string; }; // --------------------------------------------------------------------------------------------------- products: { /** * Changes the quantity of a product or removes it from the basket if quantity is equal to 0 */ changeQuantity: (basketEntry: BasketEntry, quantity: number, path: string) => void; /** * Removes a product from the basket */ removeProduct: (basketEntry: BasketEntry, path: string) => void; /** * Checks if a product is being updated */ entryIsBeingUpdated: (entryId: string) => Observable; }; // --------------------------------------------------------------------------------------------------- pos: { /** * Fetches the current point of sale */ currentPos: () => Observable; /** * Checks if the point of sale has been initialized */ posWasInitialized: () => Observable; /** * Loads the point of sale data for the given pos id */ loadPos: (posId: string) => Observable; /** * Retrieves the updated basket after a new POS has been selected */ basketLoadedForNewPos: () => Observable; }; // --------------------------------------------------------------------------------------------------- sponsor: { /** * Checks if a sponsor has storytelling content available */ hasStorytelling: (sponsorId: string) => Observable; /** * Retrieves all sponsor blocks associated with a given sponsor, sorted by position */ getSponsorBlocks: (sponsorId: string) => Observable; }; // --------------------------------------------------------------------------------------------------- supplier: { /** * Retrieves the token from the suppliers service */ getToken: () => string; /** * Fetches the current supplier */ currentSupplier: () => Observable; /** * Retrieves if the retailer is not a supplier */ isNoSupplier: () => boolean; /** * Emits once the no-supplier mode has been resolved from `setupWithToken`. */ noSupplier$: ReplaySubject; }; // --------------------------------------------------------------------------------------------------- user: { /** * Retrieve user language as an ISO 639-1 code or custom code */ getLanguage: () => string; /** * Retrieves the current authentication status of the user. */ isAuthenticated: () => Observable; /** * BehaviorSubject containing the user's geolocation coordinates */ userCoordinates$: BehaviorSubject; /** * Updates the SDK's session ID to ensure consistency with SSR. */ setSessionId: (sessionId: string) => void; }; // --------------------------------------------------------------------------------------------------- storeLocator: { /** * Opens the store locator */ open: () => void; /** * Opens the store locator / indicator warning modal */ openWarning: () => void; /** * Closes the store locator */ close: () => void; /** * Method to call to configure new pos and supplier */ changePosAndSupplier: (e: CustomEvent, eventTrace: EventTrace) => void; /** * Notifies subscribers that a new store has been selected */ newStoreSelected: () => void; }; // --------------------------------------------------------------------------------------------------- productAddition: { /** * Opens the product addition modal */ open: () => void; /** * Closes the product addition modal */ close: () => void; /** * Emits an observable that notifies subscribers when a product has been added. */ productAdded$: Observable; }; productReplacement: { /** * Opens the product replacement modal * @param product the product to replace */ open: (product: BasketEntry) => void; }; html: { /** * method that returns Like button HTML from SSR */ like: (recipeId: string, path?: string, categoryId?: string) => Observable; }; getStickyHeaderHeight: () => Observable; preferences: { /** * Returns the current number of preferences */ preferencesCount: () => Observable; /** * BehaviorSubject containing the current number of guests */ guests$: BehaviorSubject; /** * Resets the tags actions */ resetTagsActions: () => void; /** * Checks if a tag should be checked based on its state */ tagShouldBeChecked: (tag: Tag, isWithout: boolean) => boolean; /** * Resets all preferences to default values */ resetPreferences: () => void; /** * Sends a cache request to the server */ sendCacheRequest: (action: 'set' | 'remove', key: string, value?: any) => Observable; /** * Current preferences stored in local storage */ preferencesInStorage: () => { with: BasicPreference[]; without: BasicPreference[] }; /** * Array of tags to be added */ tagsToAdd: { tag: Tag; checked: boolean; without: boolean }[]; /** * Adds a tag to preferences */ addTag: (tag: { tag: Tag; checked: boolean; without: boolean }) => void; /** * Removes a tag from preferences */ removeTag: (tag: { tag: Tag; checked: boolean; without: boolean }) => void; /** * Updates the preferences */ updatePreferences: () => void; /** * Notifies that preferences have changed */ preferencesChanged$: () => Observable; /** * Emits an observable that notifies subscribers when the preferences have changed */ preferencesChanged: () => void; /** * Adds preferences to remote filters */ addPreferencesToRemoteFilters: (filters: object, includeGuests: boolean) => { include_tags?: string; exclude_tags?: string }; /** * Adds a new tag from search to preferences */ newTagFromSearch: (tag: Tag) => void; }; tags: { all: (params: { remotefilter: { tag_type: string; for_supplier: string } }) => Observable>; autocomplete: (query: string) => Observable>; }; /** * Set up a callback which Mealz will call before adding a recipe to the user's cart * * @param needLogin if true, Mealz will ask for login * @param needPos if true, Mealz will ask for a pos * @returns Observable true if the operation can continue, false otherwise */ hook: { hookCallback: (needLogin?: boolean, needPos?: boolean) => Observable; }; noSupplier: { addRecipeToBasketFromIdAndOpenPreview: (recipeId: string) => Observable; displaySupplierSelector$: BehaviorSubject; }; }