Skip to main content
Version: 1.0

Recipe Card

Embed a single recipe card in search grids, shelves, or product pages. The card is an opaque WebView component (FeatureRoute.Recipe.Card).

Visual Overview​

displayVariant (1–3) and orientation (VERTICAL / HORIZONTAL) combine into six layouts:

VerticalHorizontal
Variant 1Variant 1 verticalVariant 1 horizontal
Variant 2Variant 2 verticalVariant 2 horizontal
Variant 3Variant 3 verticalVariant 3 horizontal

Parameters​

ParameterTypeRequiredDefaultWhat it does
displayRecipeDisplayRecipeyes—Which recipe to show (Mealz id or external id).
orientationRecipeCardOrientationnoVERTICALVERTICAL or HORIZONTAL layout.
dimensionsRecipeCardDimensions?noorientation defaultsPixel height (and optional width). Defaults: vertical height 360, horizontal height 188; width fills parent unless set.
displayVariantInt?nonullVisual variant of the card (SSR display_variant).
navigationCallbackRecipeCardNavigationCallbackyes—Open recipe details when the shopper taps the card.
modifierCompose Modifierno—Layout wrapper.
stateContentstate overlaysnolibrary defaultOptional loading UI.

DisplayRecipe​

VariantFieldsWhen to use
FromMealzRecipeId(id)Mealz recipe idYou know the Mealz id.
FromExternalRecipeId(id)Your / retailer recipe idRecipe mapped in Mealz under an external id.
Shelves / search

Do not pass surrounding product SKUs into DisplayRecipe anymore. Resolve shelf slots in batch with RecipeResolver.resolveRecipes(contexts), then render each non-null result with RecipeCard. Requires a store set via setSelectedStoreWithExternalId.

RecipeCardNavigationCallback​

CallbackRequiredWhat you must do
goToRecipeDetailsyes(DisplayRecipe, serves: Int?) -> Unit — open recipe details with optional guest count.

Base NavigationCallback redirects (redirectToLogIn, redirectToStoreLocator, redirectToCart, exit) default to no-ops on this component — only goToRecipeDetails matters.

Serves

Inside Mealz WebViews, SSR resolves portions automatically: if the recipe is already in the basket, the basket guest count wins over the recipe default. When you handle goToRecipeDetails, always forward the serves argument as-is into RecipeDetailsScreen / RecipeDetailsViewController — do not substitute your own default or the recipe's number-of-guests.

Inject​

RecipeCardViewController.companion.get(
    displayRecipe: DisplayRecipeFromMealzRecipeId(id: "12838"),
    dimensions: RecipeCardDimensions(height: 360, width: nil),
    orientation: .vertical,
    displayVariant: KotlinInt(int: Int32(1)),
    stateContent: nil,
    navigationCallback: RecipeCardNavigationCallback(
        goToRecipeDetails: { recipe, serves in
            // Forward serves as-is into RecipeDetailsViewController — do not substitute a default
            // serves is KotlinInt? — e.g. serves.map { Int(truncating: $0) }
        }
    )
)

iOS ViewControllers — Navigation & Sheet Refresh

Nested Kotlin types flatten in Swift (e.g. DisplayRecipe.FromMealzRecipeId → DisplayRecipeFromMealzRecipeId). Optional Int? parameters are often KotlinInt? — build with KotlinInt(int: Int32(…)).

In-WebView Back

Full-screen Mealz screens (CatalogViewController, RecipeDetailsViewController, …) keep their own WebView history. When you own the UINavigationController back button / interactive pop, prefer the WebView stack first:

if ScreenViewControllerCoordinator.shared.canGoBackInternally(viewController: mealzVC) {
    ScreenViewControllerCoordinator.shared.handleBackNavigation(viewController: mealzVC)
} else {
    // pop / dismiss your host screen
}

Recipe Card Under a Details Sheet

When you push recipe details, the card refreshes on return via the usual appear lifecycle. When you present details as a sheet (card stays visible underneath), post this notification on dismiss so RecipeCardViewController can refresh likes / basket state for that recipe:

NotificationCenter.default.post(
    name: Notification.Name("recipeDetailsDismissed"),
    object: nil,
    userInfo: [
        "recipeId": recipeId,           // Mealz or external id you opened
        "isMealzRecipe": true           // false for DisplayRecipeFromExternalRecipeId
    ]
)

The card listens for that notification automatically — you only need to post it when closing a sheet. No extra cleanup is required on the host side; the library tears down WebView / observers with the ViewController.

Shelves / Search — RecipeResolver​

When you show Mealz recipes between products on shelf or search pages:

  1. Build one RecipeContext(productIds, position) per slot.
  2. Call suspend RecipeResolver.resolveRecipes(contexts) once (or when contexts change).
  3. For each non-null DisplayRecipe in the result map, render a RecipeCard.
val resolved = RecipeResolver.resolveRecipes(
listOf(RecipeContext(productIds = nearbySkus, position = 0))
)
// resolved[0]?.let { RecipeCard(displayRecipe = it, …) }