Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | 'use client'; import { useMutation } from '@apollo/client/react'; import { ActionIcon, Tooltip } from '@mantine/core'; import { notifications } from '@mantine/notifications'; import { IconHeart, IconHeartFilled } from '@tabler/icons-react'; import { useSession } from 'next-auth/react'; import { useTranslations } from 'next-intl'; import { useCallback, useState } from 'react'; import { ADD_TO_FAVORITE_RECIPES, REMOVE_FROM_FAVORITE_RECIPES, } from '@/lib/graphql/mutations'; import { sizeMap } from '../consts'; import type { FavoriteButtonProps, FavoriteMutationData } from './types'; const FavoriteButton = ({ recipeId, isFavorite = false, size = 'md', }: FavoriteButtonProps) => { const { data: session } = useSession(); const translate = useTranslations('response'); const tFav = useTranslations('favorites'); const [optimisticFavorite, setOptimisticFavorite] = useState(isFavorite); const [addToFavorite, { loading: addLoading }] = useMutation<FavoriteMutationData>(ADD_TO_FAVORITE_RECIPES); const [removeFromFavorite, { loading: removeLoading }] = useMutation<FavoriteMutationData>(REMOVE_FROM_FAVORITE_RECIPES); const loading = addLoading || removeLoading; const userId = (session?.user as { id?: string })?.id; const handleToggle = useCallback( async (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); if (!userId || loading) return; const previousState = optimisticFavorite; setOptimisticFavorite(!previousState); try { const mutation = previousState ? removeFromFavorite : addToFavorite; const result = await mutation({ variables: { userId, recipeId }, refetchQueries: ['getFavoriteRecipes', 'getRecipeById'], }); const response = previousState ? result.data?.removeFromFavoriteRecipes : result.data?.addToFavoriteRecipes; if (response && !response.success) { setOptimisticFavorite(previousState); notifications.show({ title: translate('error'), message: translate( response.messageKey?.replace('response.', '') ?? 'unknownError', ), color: 'red', }); } } catch { setOptimisticFavorite(previousState); notifications.show({ title: translate('error'), message: translate('somethingWentWrong'), color: 'red', }); } }, [ userId, recipeId, optimisticFavorite, loading, addToFavorite, removeFromFavorite, translate, ], ); if (!userId) return null; const iconSize = sizeMap[size]; const HeartIcon = optimisticFavorite ? IconHeartFilled : IconHeart; return ( <Tooltip label={optimisticFavorite ? tFav('remove') : tFav('add')} withArrow > <ActionIcon variant="subtle" color={optimisticFavorite ? 'red' : 'gray'} onClick={handleToggle} loading={loading} aria-label={optimisticFavorite ? tFav('remove') : tFav('add')} size={size} > <HeartIcon size={iconSize} style={{ color: optimisticFavorite ? 'var(--mantine-color-red-6)' : undefined, }} /> </ActionIcon> </Tooltip> ); }; export default FavoriteButton; |