Passio Nutrition-AI
  • Nutrition-AI SDK Overview
  • Guides
    • Nutrition AI SDK
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Nutrition Facts scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
        • User created foods and reports
    • iOS SDK Docs
      • Before getting started
      • Getting the ml models to the device
      • Run the demos first
      • Adding Passio SDK into your project
      • Initialize and configure the SDK
      • Start/Stop food detection
      • Food Recognition Delegate
      • Migration from SDK 1.4.X to 2.x
      • SDK API
      • Quick Start Guide
        • Installation
        • Configure the SDK (UIKit)
        • Recognise food using image
        • Food Details
    • Android SDK Docs
      • Getting started
        • Include the library
        • Camera
        • SDK Initialization and Configuration
        • Food detection session
        • Visual, Barcode and Packaged Food detection
        • Nutritional Database
        • Sandbox app
      • Troubleshooting on Android
      • Migration from SDK version 1.4.x to 2.x
      • Quick Start Guide
        • Importing the Android SDK to a project
        • Configure SDK and handle the result
        • RecognizeImageRemote
        • Food Details
    • React Native SDK Docs
      • Getting Started
        • Installation
        • SDK Initialization and Configuration
      • API Reference
        • configure & requestCameraAuthorization
        • recognizeImageRemote
        • searchForFood & searchForFoodSemantic
        • startFoodDetection
          • FoodDetectionEvent
        • fetchFoodItemForProductCode
        • fetchFoodItemForRefCode
        • fetchFoodItemForDataInfo
        • startNutritionFactsDetection
        • fetchFoodItemForPassioID
        • recognizeSpeechRemote
        • Fetch Nutrients
        • onDowloadingPassioModelCallBacks
        • detectFoodFromImageURI
        • addToPersonalization
        • updateLanguage
        • fetchHiddenIngredients
        • fetchVisualAlternatives
        • fetchPossibleIngredients
      • Properties
        • PassioFoodItem
        • PassioFoodDataInfo
        • PassioFoodAmount
        • PassioIngredient
        • PassioNutrients
        • UnitMass
        • ServingUnit
        • ServingSize
        • PassioSearchResult
        • NutritionFacts
        • PassioNutritionPreview
        • PassioSpeechRecognitionModel
        • PassioLogAction
        • PassioAdvisorFoodInfo
        • FoodCandidates
        • FoodDetectionEvent
        • NutritionDetectionEvent
        • DetectedCandidate
        • BarcodeCandidate
        • PackagedFoodCode
        • AmountEstimate
        • ImagesInfo
        • PassioStatus
        • FoodDetectionEvent
        • NutritionFacts
        • PassioMealPlan
        • PassioMealPlanItem
      • Nutriton Advisor
        • initConversation
        • sendMessage
        • sendImage
        • Guide
          • useNutritionAdvisor
        • Properties
          • PassioAdvisorResponse
          • PassioAdvisorMessageResultStatus
          • PassioAdvisorResultStatus
      • Quick Start Guide
        • Installation
        • Configure the SDK
        • RecognizeImageRemote
        • Food Detail
      • Guide
        • Integrate SDK Setup
        • Integrate Quick Scan
        • Integrate Food Search
        • Integrate Food Editor with Recipe
        • Integrate MealPlan
        • Integrate Suggestions
        • Integrate recognizeImageRemote
      • Components
        • DetectionCameraView
        • PassioIconView
      • Changelog
      • More
        • Display Macro Chart
          • MockFood
          • Utils PassioNutrient
        • Display Micro Progress
        • Getting nutrition value for a FoodItem
        • Getting nutrition value for a Recipe
        • Recalculate the nutrition value based on serving size options.
      • Migrations
        • Migrating from SDK 2.X to version 3.X
        • Structure Migrations From SDK 3.X to SDK 2.X
        • [Deprecated] Migrating from SDK 1.X to version 2.X
        • [Deprecated] Getting Started (v1)
          • Installation
          • SDK Initialization and Configuration
          • Start food detection
          • FoodDetectionEvent
          • Nutritional Database
      • Troubleshooting on RN
      • V2
        • Getting Started
          • Installation
          • SDK Initialization and Configuration
          • Start food detection
          • FoodDetectionEvent
        • RN SDK API
          • Properties
            • PersonalizedAlternative
            • FoodSearchResult
            • PassioNutrient
            • FoodDetectionEvent
            • DownloadModelCallBack
            • UPCProduct
            • ServingUnit
            • PassioStatus
            • PassioIDAttributes
            • PassioIDEntityType
            • PassioFoodItem
            • PassioRecipe
            • ServingSize
            • Measurement
            • UnitMass
            • NutritionFacts
        • Food Image
        • Search Food Item
        • Quick Scan
        • Multi Scan
        • MealPlan
        • Recipe
      • How do I Integrate a Passio SDK in EXPO?
    • Flutter SDK Docs
      • Getting Started
    • Before You Continue
    • Setup For Android
    • Initialize and configure the SDK
  • Fundamentals
    • Nutrition-AI Developer FAQ
      • Nutrition Data
      • Supported Phones
      • Security
      • Testing Volume Estimation
      • Testing Nutrition-AI SDK
      • Nutrition-AI Test Methodology
    • Nutrition API - Mobile SDK interoperability
      • JSON Response parsing
  • Versions
    • 3.2.4
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Nutrition Facts scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
        • User created foods and reports
    • 3.2.2
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Nutrition Facts scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
        • User created foods and reports
    • 3.2.0
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Nutrition Facts scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
    • 3.1.4
      • SDK Key and minimum requirements
      • Installation
      • Configure the SDK
      • Use Cases
        • Food recognition
        • Nutrition data
        • Barcode scanning
        • Search, Food Icons, RefCode
        • Speech recognition
        • Nutrition Advisor
        • Suggestions and Meal Plans
Powered by GitBook
On this page
  • Example
  • useMealPlan
  • MealPlan
Export as PDF
  1. Guides
  2. React Native SDK Docs
  3. Guide

Integrate MealPlan

PreviousIntegrate Food Editor with RecipeNextIntegrate Suggestions

Last updated 1 year ago

The API below is used for food search.

  /**
   * fetch list of all meal Plans
   * @returns A `Promise` resolving to a `PassioMealPlan` array if the record exists in the database or `null` if not.
   */
  fetchMealPlans(): Promise<PassioMealPlan[] | null>
  
  /**
   * fetch list of all meal Plan item
   * @param mealPlanLabel - query for type of mealPlan.
   * @param day - for which day meal plan is needed
   * @returns A `Promise` resolving to a `PassioMealPlanItem` array if the record exists in the database or `null` if not.
   */
  fetchMealPlanForDay(
    mealPlanLabel: string,
    day: number
  ): Promise<PassioMealPlanItem[] | null>

Example

useMealPlan

import { useState, useCallback, useEffect, useMemo } from 'react'
import {
  PassioSDK,
  type PassioFoodDataInfo,
  PassioMealPlan,
  PassioMealPlanItem,
} from '@passiolife/nutritionai-react-native-sdk-v3'
import type { Props } from './MealPlan'

const useMealPlan = ({ onFoodDetail }: Props) => {
  // State variables
  const [passioMealPlan, setPassioMealPlan] = useState<PassioMealPlan>()
  const [selectedDay, setSelectedDay] = useState<number>(0)
  const [passioMealPlans, setPassioMealPlans] = useState<PassioMealPlan[]>()
  const [loading, setLoading] = useState<boolean>(false)
  const [passioMealPlanItem, setPassioMealPlanItem] = useState<
    PassioMealPlanItem[] | null
  >()

  const generateDaysData = useMemo(() => {
    const days = []
    for (let i = 1; i <= 14; i++) {
      days.push(`Day ${i}`)
    }

    return days
  }, [])

  const onChangeDay = useCallback((day: number) => {
    setSelectedDay(day)
  }, [])

  // Effect for handling debounced search term changes
  useEffect(() => {
    async function init() {
      try {
        setLoading(true)
        setPassioMealPlanItem([])
        setPassioMealPlans([])
        // Fetch food results from the PassioSDK based on the query
        const mealPlans = await PassioSDK.fetchMealPlans()
        if (mealPlans) {
          setPassioMealPlans(mealPlans)
          const initial = mealPlans[0]
          if (initial) {
            setPassioMealPlan(initial)
          }
        }
      } catch (error) {
        setPassioMealPlans([])
        setPassioMealPlanItem([])
      } finally {
        // Reset loading state to indicate the end of the search
        setLoading(false)
      }
    }
    init()
  }, [])
  // Effect for handling debounced search term changes
  useEffect(() => {
    async function init() {
      try {
        setLoading(true)
        setPassioMealPlanItem([])
        if (passioMealPlan?.mealPlanLabel) {
          const mealPlans = await PassioSDK.fetchMealPlanForDay(
            passioMealPlan?.mealPlanLabel,
            selectedDay + 1
          )
          setPassioMealPlanItem(mealPlans)
        }
      } catch (error) {
        // Handle errors, e.g., network issues or API failures
        setPassioMealPlanItem([])
      } finally {
        // Reset loading state to indicate the end of the search
        setLoading(false)
      }
    }
    init()
  }, [passioMealPlan, passioMealPlan?.mealPlanLabel, selectedDay])

  const onResultItemPress = useCallback(
    async (foodSearchResult: PassioFoodDataInfo) => {
      let result = await PassioSDK.fetchFoodItemForDataInfo(foodSearchResult)

      if (result) {
        if (foodSearchResult.nutritionPreview?.weightUnit) {
          result.amount.weight = {
            unit: foodSearchResult.nutritionPreview?.weightUnit,
            value: foodSearchResult.nutritionPreview?.weightQuantity ?? 0,
          }
          result.amount.selectedUnit =
            foodSearchResult.nutritionPreview?.servingUnit
          result.amount.selectedQuantity =
            foodSearchResult.nutritionPreview?.servingQuantity ?? 0
        }

        console.log(JSON.stringify(result))

        onFoodDetail(result)
      }
    },
    [onFoodDetail]
  )

  const onChangeMeal = (plan: PassioMealPlan) => {
    setPassioMealPlan(plan)
  }

  return {
    passioMealPlanItem,
    passioMealPlans,
    onChangeMeal,
    loading,
    onResultItemPress,
    passioMealPlan,
    generateDaysData,
    onChangeDay,
    selectedDay,
  }
}

export default useMealPlan

MealPlan

import React from 'react'
import {
  ActivityIndicator,
  FlatList,
  SafeAreaView,
  StyleSheet,
  Text,
  TouchableOpacity,
  Image,
  View,
} from 'react-native'
import {
  PassioIconView,
  IconSize,
  PassioFoodItem,
  PassioMealPlan,
  PassioMealPlanItem,
} from '@passiolife/nutritionai-react-native-sdk-v3'
import useMealPlan from './useMealPlan'

export interface Props {
  onClose: () => void
  onFoodDetail: (passioFoodItem: PassioFoodItem) => void
}

// FoodSearchScreen component
export const MealPlan = (props: Props) => {
  // Get styles object from the searchStyle function
  const styles = searchStyle()

  // Destructure values from the custom hook
  const {
    passioMealPlanItem,
    passioMealPlans,
    onChangeMeal,
    loading,
    onResultItemPress,
    passioMealPlan,
    generateDaysData,
    onChangeDay,
    selectedDay,
  } = useMealPlan(props)

  // Function to render each item in the FlatList
  const renderSearchItem = ({ item }: { item: PassioMealPlanItem }) => {
    return (
      <TouchableOpacity
        style={styles.itemContainer}
        onPress={() => onResultItemPress(item.meal)}
      >
        <View style={styles.itemIconContainer}>
          <PassioIconView
            style={styles.itemIcon}
            config={{
              passioID: item.meal.iconID,
              iconSize: IconSize.PX360,
            }}
          />
        </View>
        <View>
          <Text style={styles.itemFoodName}>{item.meal.foodName}</Text>
          <Text style={styles.itemBrandName}>
            {item.meal.nutritionPreview?.servingUnit + ' '}
            {item.meal.nutritionPreview?.servingQuantity + ' | '}
            {Math.round(item.meal.nutritionPreview?.calories ?? 0) + ' kcal'}
            {item.meal.brandName ? ', ' + item.meal.brandName : ''}
          </Text>
        </View>
      </TouchableOpacity>
    )
  }
  const renderMealTime = ({ item }: { item: PassioMealPlan }) => {
    return (
      <TouchableOpacity
        style={styles.mealTimeContainer}
        onPress={() => onChangeMeal(item)}
      >
        <Text
          style={[
            styles.mealTime,
            item.mealPlanLabel === passioMealPlan?.mealPlanLabel &&
              styles.selectedMealTime,
          ]}
        >
          {item.mealPlanLabel}
        </Text>
      </TouchableOpacity>
    )
  }

  const renderDays = ({ item, index }: { item: string; index: number }) => {
    return (
      <TouchableOpacity
        style={styles.mealTimeContainer}
        onPress={() => {
          onChangeDay(index)
        }}
      >
        <Text
          style={[
            styles.mealTime,
            index === selectedDay && styles.selectedMealTime,
          ]}
        >
          {item}
        </Text>
      </TouchableOpacity>
    )
  }

  // Display loading indicator when results are empty and loading is true
  const renderLoading = () => {
    return (
      <>{loading ? <ActivityIndicator style={{ marginTop: 100 }} /> : null}</>
    )
  }

  // Render the component
  return (
    <SafeAreaView style={styles.body}>
      <View style={styles.closeButton}>
        <TouchableOpacity onPress={props.onClose}>
          <Image
            style={styles.closeText}
            source={require('../assets/back.png')}
          />
        </TouchableOpacity>
      </View>

      <FlatList
        data={passioMealPlanItem}
        contentContainerStyle={styles.list}
        renderItem={renderSearchItem}
        ListEmptyComponent={renderLoading}
        ListHeaderComponent={() => {
          return (
            <View>
              <FlatList
                data={generateDaysData}
                renderItem={renderDays}
                horizontal
              />
              <FlatList
                data={passioMealPlans}
                renderItem={renderMealTime}
                horizontal
              />
            </View>
          )
        }}
        keyExtractor={(item, index) => item.meal.foodName.toString() + index}
      />
    </SafeAreaView>
  )
}

// Styles for the component
const searchStyle = () =>
  StyleSheet.create({
    closeButton: {},
    list: {
      marginTop: 16,
    },
    closeText: {
      margin: 16,
      height: 24,
      width: 24,
    },
    itemContainer: {
      padding: 12,
      flex: 1,
      marginVertical: 4,
      marginHorizontal: 16,
      backgroundColor: 'white',
      flexDirection: 'row',
      borderRadius: 24,
    },
    mealTimeContainer: {
      marginStart: 16,
      backgroundColor: 'white',
      flexDirection: 'row',
      borderRadius: 24,
      marginBottom: 16,
      overflow: 'hidden',
    },
    mealTime: {
      textTransform: 'capitalize',
      paddingVertical: 12,
      paddingHorizontal: 12,
      fontSize: 16,
    },
    itemFoodName: {
      flex: 1,
      textTransform: 'capitalize',
      marginHorizontal: 8,
      fontSize: 16,
    },

    selectedMealTime: {
      color: 'white',
      backgroundColor: 'blue',
    },
    itemBrandName: {
      flex: 1,
      textTransform: 'capitalize',
      marginHorizontal: 8,
      fontSize: 12,
    },

    itemAlternativeContainer: {
      overflow: 'hidden',
    },
    alternativeContainer: {
      marginStart: 16,
      alignItems: 'center',
      overflow: 'hidden',
      alignSelf: 'center',
      backgroundColor: 'rgba(238, 242, 255, 1)',
      shadowColor: '#000',
      shadowOffset: { width: 0, height: 0.1 },
      shadowOpacity: 0.5,
      shadowRadius: 0.5,
      marginVertical: 2,
      marginBottom: 14,
      elevation: 5,
      borderRadius: 24,
    },
    itemAlternativeName: {
      textTransform: 'capitalize',
      paddingVertical: 8,
      paddingHorizontal: 16,
    },
    itemIconContainer: {
      height: 46,
      width: 46,
      borderRadius: 30,
      overflow: 'hidden',
    },
    itemIcon: {
      height: 46,
      width: 46,
    },
    textInput: {
      backgroundColor: 'white',
      paddingHorizontal: 16,
      padding: 12,
      color: 'black',
      fontWeight: '500',
      fontSize: 16,
      marginHorizontal: 16,
    },
    body: {
      backgroundColor: 'rgba(242, 245, 251, 1)',
      flex: 1,
    },
  })