diff --git a/src/app/(tabs)/my-bar.tsx b/src/app/(tabs)/my-bar.tsx index 731417c..f343456 100644 --- a/src/app/(tabs)/my-bar.tsx +++ b/src/app/(tabs)/my-bar.tsx @@ -1,5 +1,6 @@ +import { useIsFocused } from '@react-navigation/native' import { router } from 'expo-router' -import React, { useCallback, useEffect, useRef, useState } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import { ActivityIndicator, View, ViewStyle } from 'react-native' import Popover from 'react-native-popover-view' import { @@ -13,7 +14,7 @@ import { Tabs, Text, } from '~/components' -import { useAnalytics, useFetchMatchedRecipes, useSession } from '~/hooks' +import { useAnalytics, useFetchMatchedRecipes, useFetchMyBar, useSession } from '~/hooks' import { useDetailsModal, useStore } from '~/providers' export default function MyBarScreen() { @@ -23,6 +24,8 @@ export default function MyBarScreen() { const { capture } = useAnalytics() const [deleteingItemId, setDeleteingItemId] = useState('') + const isFocused = useIsFocused() + const handleIngredientPress = useCallback((ingredientId: string) => { setCurrentIngredientId(ingredientId) }, []) @@ -35,22 +38,28 @@ export default function MyBarScreen() { } }, [myBarPopoverDismissed]) + const { deleteFromMyBar, myBarRefetch, myBarLoading, sectionsData, sectionsHeader, myBarError } = + useFetchMyBar() + const { - deleteFromMyBar, getRecipeMatch, - myBarRefetch, - myBarLoading, partialMatchData, partialMatchRefetch, - sectionsData, - sectionsHeader, totalMatchData, totalMatchLoading, totalMatchRefetch, - myBarError, totalMatchError, } = useFetchMatchedRecipes() + useEffect(() => { + if (isFocused) { + // Refetch the data when the tab gains focus + myBarRefetch() + totalMatchRefetch() + partialMatchRefetch() + } + }, [isFocused, myBarRefetch]) + const renderIngredientItem = useCallback( ({ item }) => { if (!item.name) return diff --git a/src/graphql/queries/getIngredientsInMyBar.ts b/src/graphql/queries/getIngredientsInMyBar.ts deleted file mode 100644 index acf368a..0000000 --- a/src/graphql/queries/getIngredientsInMyBar.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { gql } from '~/__generated__/gql' - -export const GET_INGREDIENTS_IN_MY_BAR = gql(` - query getIngredientsInMyBar { - profilesIngredientsCollection(first: 1000) { - edges { - node { - ingredient { - id - name - ingredientsCategoriesCollection(first: 1000) { - edges { - node { - category { - id - name - } - } - } - } - } - } - } - } - } -`) diff --git a/src/graphql/queries/index.ts b/src/graphql/queries/index.ts index 733623e..5d3da37 100644 --- a/src/graphql/queries/index.ts +++ b/src/graphql/queries/index.ts @@ -5,7 +5,6 @@ export * from './getEquipmentDetails' export * from './getFavourites' export * from './getFilters' export * from './getIngredientDetails' -export * from './getIngredientsInMyBar' export * from './getIngtedientsByCategories' export * from './getMyBar' export * from './getPartialMatchRecipes' diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 879b16f..287a808 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -4,6 +4,7 @@ export * from './useFetchIngredients' export * from './useFetchMatchedRecipes' export * from './useFetchRecipeDetails' export * from './useFetchRecipes' +export * from './useFetchMybar' export * from './useHaptics' export * from './usePeristedState' export * from './useProtectedRouteListener' diff --git a/src/hooks/useFetchIngredientDetails.ts b/src/hooks/useFetchIngredientDetails.ts index c2b5d06..6b085fe 100644 --- a/src/hooks/useFetchIngredientDetails.ts +++ b/src/hooks/useFetchIngredientDetails.ts @@ -2,23 +2,21 @@ import { useMutation, useQuery } from '@apollo/client' import { router, useGlobalSearchParams } from 'expo-router' import { GetRecipesByIngredientQuery } from '~/__generated__/graphql' import { ADD_TO_MY_BAR, DELETE_FROM_MY_BAR } from '~/graphql/mutations' -import { - GET_INGREDIENTS_IN_MY_BAR, - GET_INGREDIENT_DETAILS, - GET_RECIPES_BY_INGREDIENT, -} from '~/graphql/queries' +import { GET_INGREDIENT_DETAILS, GET_RECIPES_BY_INGREDIENT } from '~/graphql/queries' import { useDetailsModal } from '~/providers' import { captureError } from '~/utils/captureError' +import { useFetchMyBar } from './useFetchMybar' import { useSession } from './useSession' export const useFetchIngredientDetails = (ingredientId: string, onClosed: () => void) => { try { + const { ingredientsInMyBar, myBarRefetch } = useFetchMyBar() const { recipeId } = useGlobalSearchParams() const { user } = useSession() const { data, loading } = useQuery(GET_INGREDIENT_DETAILS, { variables: { ingredientId }, }) - const { data: barIngredients, refetch: myBarRefetch } = useQuery(GET_INGREDIENTS_IN_MY_BAR) + const { data: relatedRecipes, loading: recipesLoading } = useQuery(GET_RECIPES_BY_INGREDIENT, { variables: { ingredientId }, fetchPolicy: 'cache-and-network', @@ -28,9 +26,8 @@ export const useFetchIngredientDetails = (ingredientId: string, onClosed: () => const [addToMyBar, { loading: addLoading }] = useMutation(ADD_TO_MY_BAR) const [deleteFromMyBar] = useMutation(DELETE_FROM_MY_BAR) - const myBar = - barIngredients?.profilesIngredientsCollection?.edges.map((e) => e.node?.ingredient?.id) ?? [] - const isInMyBar = myBar.includes(ingredientId) + + const isInMyBar = !!ingredientsInMyBar.find((i) => i.id === ingredientId) const ingredient = data?.ingredientsCollection?.edges[0]?.node const getAvailableRecipes = (relatedRecipes: GetRecipesByIngredientQuery) => { diff --git a/src/hooks/useFetchIngredients.ts b/src/hooks/useFetchIngredients.ts index 3304098..8273b72 100644 --- a/src/hooks/useFetchIngredients.ts +++ b/src/hooks/useFetchIngredients.ts @@ -2,17 +2,18 @@ import { useQuery } from '@apollo/client' import keyBy from 'lodash/keyBy' import { useEffect, useState } from 'react' import { SectionDataType, SectionHeaderType } from '~/components' -import { GET_INGREDIENTS_IN_MY_BAR } from '~/graphql/queries' import { GET_INGREDIENTS_BY_CATEGORIES } from '~/graphql/queries/getIngtedientsByCategories' import { useAppContent } from '~/providers' import { captureError } from '~/utils/captureError' import { api } from '../services/api' import { useAnalytics } from './useAnalytics' +import { useFetchMyBar } from './useFetchMybar' export type SelectedItems = Record export const useFetchIngredients = () => { try { + const { ingredientsInMyBar } = useFetchMyBar() const { capture } = useAnalytics() const { ingredient_categories } = useAppContent() const [searchQuery, setSearchQuery] = useState('') @@ -25,6 +26,10 @@ export const useFetchIngredients = () => { const [sectionsHeader, setSectionsHeader] = useState([]) const [initialSelectedItems, setInitialSelectedItems] = useState({}) + const { data: categories } = useQuery(GET_INGREDIENTS_BY_CATEGORIES, { + fetchPolicy: 'cache-and-network', + }) + /** * Search for ingredients that match the given search query. * @param searchQuery - The search query to match against ingredient names. @@ -64,14 +69,6 @@ export const useFetchIngredients = () => { searchIngredients(searchQuery) }, [searchQuery]) - const { data: categories } = useQuery(GET_INGREDIENTS_BY_CATEGORIES, { - fetchPolicy: 'cache-and-network', - }) - - const { data: selectedIngredients } = useQuery(GET_INGREDIENTS_IN_MY_BAR, { - fetchPolicy: 'cache-and-network', - }) - useEffect(() => { if (!categories) return const sectionsData: SectionDataType[][] = [] @@ -89,26 +86,17 @@ export const useFetchIngredients = () => { }, [categories]) useEffect(() => { - if (!selectedIngredients) return - const initialSelectedItems: SelectedItems = {} - selectedIngredients?.profilesIngredientsCollection?.edges - .filter(({ node }) => node?.ingredient) - .forEach( - ({ - node: { - ingredient: { id, name }, - }, - }) => { - initialSelectedItems[id] = { - name, - selected: true, - } - }, - ) + if (!ingredientsInMyBar) return + ingredientsInMyBar.forEach(({ name, id }) => { + initialSelectedItems[id] = { + name, + selected: true, + } + }) setInitialSelectedItems(initialSelectedItems) setSelectedItems(initialSelectedItems) - }, [selectedIngredients]) + }, [ingredientsInMyBar]) return { searchQuery, diff --git a/src/hooks/useFetchMatchedRecipes.ts b/src/hooks/useFetchMatchedRecipes.ts index 12341db..e9de6c2 100644 --- a/src/hooks/useFetchMatchedRecipes.ts +++ b/src/hooks/useFetchMatchedRecipes.ts @@ -1,29 +1,12 @@ -import { useMutation, useQuery } from '@apollo/client' -import { useIsFocused } from '@react-navigation/native' +import { useQuery } from '@apollo/client' import { router } from 'expo-router' -import { useEffect } from 'react' import { GetPartialMatchRecipesQuery, GetTotalmatchRecipesQuery } from '~/__generated__/graphql' -import { CardProps, SectionDataType, SectionHeaderType } from '~/components' -import { DELETE_FROM_MY_BAR } from '~/graphql/mutations/deleteFromMyBar' -import { - GET_INGREDIENTS_IN_MY_BAR, - GET_MY_BAR, - GET_PARTIAL_MATCH_RECIPES, - GET_TOTAL_MATCH_RECIPES, -} from '~/graphql/queries' -import { useAppContent } from '~/providers' +import { CardProps } from '~/components' +import { GET_PARTIAL_MATCH_RECIPES, GET_TOTAL_MATCH_RECIPES } from '~/graphql/queries' import { captureError } from '~/utils/captureError' export const useFetchMatchedRecipes = () => { try { - const { my_bar } = useAppContent() - const { - data: myBarData, - loading: myBarLoading, - refetch: myBarRefetch, - error: myBarError, - } = useQuery(GET_MY_BAR) - const { data: totalMatchData, refetch: totalMatchRefetch, @@ -38,17 +21,6 @@ export const useFetchMatchedRecipes = () => { error: partialMatchError, } = useQuery(GET_PARTIAL_MATCH_RECIPES) - const isFocused = useIsFocused() - - useEffect(() => { - if (isFocused) { - // Refetch the data when the tab gains focus - myBarRefetch() - totalMatchRefetch() - partialMatchRefetch() - } - }, [isFocused, myBarRefetch, totalMatchRefetch, partialMatchRefetch]) - const getRecipeMatch = ( matchedData: GetTotalmatchRecipesQuery | GetPartialMatchRecipesQuery, ): CardProps[] => { @@ -66,35 +38,12 @@ export const useFetchMatchedRecipes = () => { ) } - let sectionsData: SectionDataType[][] = [] - let sectionsHeader: SectionHeaderType[] = [] - - const categoriesdIngredients = - myBarData?.myBarCollection?.edges - ?.filter(({ node }) => !my_bar?.hidden_category_ids?.includes(node?.id)) - ?.map(({ node }) => node) ?? [] - - sectionsData = categoriesdIngredients.map((section) => JSON.parse(section?.data)) - sectionsHeader = categoriesdIngredients.map((section) => ({ - title: section?.title, - count: section?.count, - id: section?.title, - })) - - const [deleteFromMyBar] = useMutation(DELETE_FROM_MY_BAR) - return { - deleteFromMyBar, getRecipeMatch, - myBarError, - myBarLoading, - myBarRefetch, partialMatchData, partialMatchError, partialMatchLoading, partialMatchRefetch, - sectionsData, - sectionsHeader, totalMatchData, totalMatchError, totalMatchLoading, diff --git a/src/hooks/useFetchMybar.ts b/src/hooks/useFetchMybar.ts new file mode 100644 index 0000000..0495091 --- /dev/null +++ b/src/hooks/useFetchMybar.ts @@ -0,0 +1,70 @@ +import { useMutation, useQuery } from '@apollo/client' +import { useEffect, useState } from 'react' +import { SectionDataType, SectionHeaderType } from '~/components' +import { DELETE_FROM_MY_BAR } from '~/graphql/mutations/deleteFromMyBar' +import { GET_MY_BAR } from '~/graphql/queries' +import { useAppContent } from '~/providers' +import { captureError } from '~/utils/captureError' + +interface Ingredient { + id: string + name: string +} + +export const useFetchMyBar = () => { + try { + const { my_bar } = useAppContent() + const { + data: myBarData, + loading: myBarLoading, + refetch: myBarRefetch, + error: myBarError, + } = useQuery(GET_MY_BAR) + + const [sectionsData, setSectionsData] = useState([]) + const [sectionsHeader, setSectionsHeader] = useState([]) + const [ingredientsInMyBar, setIngredientsInMyBar] = useState([]) + + useEffect(() => { + if (!myBarData) return + + let newSectionsData = [] + let newSectionsHeader = [] + let newIngredientsInMyBar = [] + + for (let category of myBarData?.myBarCollection?.edges) { + const { node } = category + + if (!my_bar?.hidden_category_ids?.includes(node?.id)) { + const data = JSON.parse(node?.data) + + newIngredientsInMyBar = newIngredientsInMyBar.concat(data) + newSectionsData.push(data) + newSectionsHeader.push({ + title: node?.title, + count: node?.count, + id: node?.title, + }) + } + } + + setIngredientsInMyBar(newIngredientsInMyBar) + setSectionsData(newSectionsData) + setSectionsHeader(newSectionsHeader) + }, [myBarData, my_bar?.hidden_category_ids]) + + const [deleteFromMyBar] = useMutation(DELETE_FROM_MY_BAR) + + return { + deleteFromMyBar, + myBarError, + myBarLoading, + myBarRefetch, + sectionsData, + sectionsHeader, + ingredientsInMyBar, + } + } catch (error) { + captureError(error) + } +} diff --git a/src/hooks/useFetchRecipeDetails.ts b/src/hooks/useFetchRecipeDetails.ts index d5f5bfa..5e54625 100644 --- a/src/hooks/useFetchRecipeDetails.ts +++ b/src/hooks/useFetchRecipeDetails.ts @@ -1,14 +1,16 @@ import { useMutation, useQuery } from '@apollo/client' import { useLocalSearchParams } from 'expo-router' import { ADD_TO_FAVOURITES, DELETE_FROM_FAVOURITES } from '~/graphql/mutations' -import { GET_INGREDIENTS_IN_MY_BAR, GET_RECIPE_DETAILS } from '~/graphql/queries' +import { GET_RECIPE_DETAILS } from '~/graphql/queries' import { useAppContent } from '~/providers' import { captureError } from '~/utils/captureError' import { useAnalytics } from './useAnalytics' +import { useFetchMyBar } from './useFetchMybar' import { useSession } from './useSession' export const useFetchRecipeDetails = () => { try { + const { ingredientsInMyBar } = useFetchMyBar() const { capture } = useAnalytics() const { recipeId, recipeName } = useLocalSearchParams() const { recipe_attributes } = useAppContent() @@ -19,8 +21,6 @@ export const useFetchRecipeDetails = () => { fetchPolicy: 'cache-and-network', }) - const { data: barIngredients } = useQuery(GET_INGREDIENTS_IN_MY_BAR) - const firstTimeLoading = loading && !data && !error const recipe = data?.recipesCollection?.edges[0]?.node @@ -37,15 +37,10 @@ export const useFetchRecipeDetails = () => { (id: string) => categories.find((c) => c.parentId === id) ?? { id }, ) ?? [] - const myBar = - barIngredients?.profilesIngredientsCollection.edges - .filter((e) => e?.node?.ingredient) - .map((e) => e?.node?.ingredient?.id) ?? [] - const mergedRecipeIngredients = recipeIngredients .filter((recipeIngredient) => recipeIngredient?.ingredient) .map((recipeIngredient) => { - const inMyBar = myBar.includes(recipeIngredient?.ingredient?.id) + const inMyBar = !!ingredientsInMyBar.find((i) => i.id === recipeIngredient?.ingredient?.id) return { ...recipeIngredient, inMyBar,