From ec2da1a20e715e9dd95490d77d179fc17214b59c Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Mon, 1 Jun 2026 19:19:28 +0200 Subject: [PATCH 01/11] feat(356): add dish detail modal page --- app/(main)/(authenticated)/create-trip/_layout.tsx | 1 + .../(authenticated)/create-trip/dish-details-modal.tsx | 7 +++++++ .../core/navigation/data/services/NavigationService.ts | 7 +++++-- features/core/navigation/domain/entities/Modals.ts | 1 + .../domain/entities/services/INavigationService.ts | 1 + features/trips/pages.ts | 1 + .../FoodCard/components/DishItem/DishItem.tsx | 10 +++++----- .../components/TypicalDishesList/TypicalDishesList.tsx | 5 +++-- .../DishDetailsModalPage/DishDetailsModalPage.logic.ts | 10 ++++++++++ .../DishDetailsModalPage/DishDetailsModalPage.tsx | 8 ++++++++ .../TypicalDishesModalPage.logic.ts | 3 ++- .../TypicalDishesModalPage/TypicalDishesModalPage.tsx | 4 ++-- 12 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 app/(main)/(authenticated)/create-trip/dish-details-modal.tsx create mode 100644 features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts create mode 100644 features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx diff --git a/app/(main)/(authenticated)/create-trip/_layout.tsx b/app/(main)/(authenticated)/create-trip/_layout.tsx index d7dd19b..b700a45 100644 --- a/app/(main)/(authenticated)/create-trip/_layout.tsx +++ b/app/(main)/(authenticated)/create-trip/_layout.tsx @@ -73,6 +73,7 @@ export default function CreateTripLayout() { }} /> + ); } diff --git a/app/(main)/(authenticated)/create-trip/dish-details-modal.tsx b/app/(main)/(authenticated)/create-trip/dish-details-modal.tsx new file mode 100644 index 0000000..3652a94 --- /dev/null +++ b/app/(main)/(authenticated)/create-trip/dish-details-modal.tsx @@ -0,0 +1,7 @@ +import { DishDetailsModalPage } from '@/features/trips/pages'; + +const DishDetailsModal = () => { + return ; +}; + +export default DishDetailsModal; diff --git a/features/core/navigation/data/services/NavigationService.ts b/features/core/navigation/data/services/NavigationService.ts index 612ab21..550563a 100644 --- a/features/core/navigation/data/services/NavigationService.ts +++ b/features/core/navigation/data/services/NavigationService.ts @@ -61,8 +61,11 @@ export class NavigationService implements INavigationService { toChangeLanguage() { this.client.push(`/${Stacks.Profile}/${Routes.ChangeLanguage}`); } - toTypicalDishesModal({ tripId }: { tripId: string }) { - this.client.push({ pathname: `/${Stacks.CreateTrip}/${Modals.TypicalDishes}`, params: { tripId } }); + toTypicalDishesModal(params: { tripId: string }) { + this.client.push({ pathname: `/${Stacks.CreateTrip}/${Modals.TypicalDishes}`, params }); + } + toDishDetailsModal(params: { tripId: string; searchTerm: string }) { + this.client.push({ pathname: `/${Stacks.CreateTrip}/${Modals.DishDetails}`, params }); } back() { diff --git a/features/core/navigation/domain/entities/Modals.ts b/features/core/navigation/domain/entities/Modals.ts index 5356b1a..bcd73e0 100644 --- a/features/core/navigation/domain/entities/Modals.ts +++ b/features/core/navigation/domain/entities/Modals.ts @@ -1,5 +1,6 @@ export const Modals = { TypicalDishes: 'typical-dishes-modal', + DishDetails: 'dish-details-modal', } as const; export type Modals = (typeof Modals)[keyof typeof Modals]; diff --git a/features/core/navigation/domain/entities/services/INavigationService.ts b/features/core/navigation/domain/entities/services/INavigationService.ts index 64a3b28..c559fc3 100644 --- a/features/core/navigation/domain/entities/services/INavigationService.ts +++ b/features/core/navigation/domain/entities/services/INavigationService.ts @@ -25,6 +25,7 @@ export interface INavigationService { toTripList(): void; toChangeLanguage(): void; toTypicalDishesModal(params: { tripId: string }): void; + toDishDetailsModal(params: { tripId: string; searchTerm: string }): void; back(): void; diff --git a/features/trips/pages.ts b/features/trips/pages.ts index 32d8177..c043fac 100644 --- a/features/trips/pages.ts +++ b/features/trips/pages.ts @@ -1,4 +1,5 @@ export { ActivityDetailsPage } from '@/features/trips/ui/pages/ActivityDetailsPage/ActivityDetailsPage'; +export { DishDetailsModalPage } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage'; export { TripDetailsPage } from '@/features/trips/ui/pages/TripDetailsPage/TripDetailsPage'; export { TripListPage } from '@/features/trips/ui/pages/TripListPage/TripListPage'; export { TypicalDishesModalPage } from '@/features/trips/ui/pages/TypicalDishesModalPage/TypicalDishesModalPage'; diff --git a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx index 3262bfa..477706c 100644 --- a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx +++ b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx @@ -3,15 +3,15 @@ import type { TypicalDish } from '@/features/trips/domain/entities/TypicalDish'; import { useDishItemLogic } from '@/features/trips/ui/components/FoodCard/components/DishItem/DishItem.logic'; import { styles } from '@/features/trips/ui/components/FoodCard/components/DishItem/DishItem.style'; import type { FC } from 'react'; -import { View } from 'react-native'; +import { Pressable, View } from 'react-native'; -type DishItemProps = { dish: TypicalDish }; +type DishItemProps = { dish: TypicalDish; onPress: () => void }; -export const DishItem: FC = ({ dish }) => { +export const DishItem: FC = ({ dish, onPress }) => { const { image, isLoading } = useDishItemLogic(dish.searchTerm); return ( - + {isLoading ? ( @@ -23,6 +23,6 @@ export const DishItem: FC = ({ dish }) => { - + ); }; diff --git a/features/trips/ui/components/TypicalDishesList/TypicalDishesList.tsx b/features/trips/ui/components/TypicalDishesList/TypicalDishesList.tsx index b3348f8..f7d4eed 100644 --- a/features/trips/ui/components/TypicalDishesList/TypicalDishesList.tsx +++ b/features/trips/ui/components/TypicalDishesList/TypicalDishesList.tsx @@ -7,16 +7,17 @@ import { View } from 'react-native'; type TypicalDishesListProps = { dishItems: TypicalDish[] | undefined; + onDishPress: (searchTerm: string) => void; }; const Separator = () => ; -export const TypicalDishesList: FC = ({ dishItems }) => ( +export const TypicalDishesList: FC = ({ dishItems, onDishPress }) => ( <> {dishItems?.map((item, index) => ( {index > 0 && } - + onDishPress(item.searchTerm)} /> ))} diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts new file mode 100644 index 0000000..d05644b --- /dev/null +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts @@ -0,0 +1,10 @@ +import { navigationService } from '@/features/core/navigation'; +import { useLocalSearchParams } from 'expo-router'; + +export const useDishDetailsModalPageLogic = () => { + const { tripId, searchTerm } = useLocalSearchParams<{ tripId: string; searchTerm: string }>(); + + const handleClose = () => navigationService.back(); + + return { tripId, searchTerm, handleClose }; +}; diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx new file mode 100644 index 0000000..aba4da5 --- /dev/null +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx @@ -0,0 +1,8 @@ +import { useDishDetailsModalPageLogic } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic'; +import { View } from 'react-native'; + +export const DishDetailsModalPage = () => { + useDishDetailsModalPageLogic(); + + return ; +}; diff --git a/features/trips/ui/pages/TypicalDishesModalPage/TypicalDishesModalPage.logic.ts b/features/trips/ui/pages/TypicalDishesModalPage/TypicalDishesModalPage.logic.ts index 5b21d14..2ed7cf4 100644 --- a/features/trips/ui/pages/TypicalDishesModalPage/TypicalDishesModalPage.logic.ts +++ b/features/trips/ui/pages/TypicalDishesModalPage/TypicalDishesModalPage.logic.ts @@ -11,6 +11,7 @@ export const useTypicalDishesModalPageLogic = () => { const dishNumber = food?.typicalDishes.length ?? 0; const handleClose = () => navigationService.back(); + const handleDishPress = (searchTerm: string) => navigationService.toDishDetailsModal({ tripId, searchTerm }); - return { handleClose, location, dishNumber, dishItems: food?.typicalDishes }; + return { handleClose, handleDishPress, location, dishNumber, dishItems: food?.typicalDishes }; }; diff --git a/features/trips/ui/pages/TypicalDishesModalPage/TypicalDishesModalPage.tsx b/features/trips/ui/pages/TypicalDishesModalPage/TypicalDishesModalPage.tsx index 1438b31..c306cfc 100644 --- a/features/trips/ui/pages/TypicalDishesModalPage/TypicalDishesModalPage.tsx +++ b/features/trips/ui/pages/TypicalDishesModalPage/TypicalDishesModalPage.tsx @@ -5,12 +5,12 @@ import { styles } from '@/features/trips/ui/pages/TypicalDishesModalPage/Typical import { ScrollView } from 'react-native'; export const TypicalDishesModalPage = () => { - const { handleClose, location, dishNumber, dishItems } = useTypicalDishesModalPageLogic(); + const { handleClose, handleDishPress, location, dishNumber, dishItems } = useTypicalDishesModalPageLogic(); return ( - + ); }; From 2bad097ae2d75fbe29cc372cfdee084bf443debd Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Tue, 2 Jun 2026 12:12:55 +0200 Subject: [PATCH 02/11] feat(356): add image and description body --- .../BottomSheetHeader.style.ts | 18 ++++++++++ .../BottomSheetHeader/BottomSheetHeader.tsx | 19 +++++++++++ features/core/ui/index.ts | 1 + features/core/ui/style/dimensions/images.ts | 1 + .../DishDetailsModalPage.logic.ts | 10 +++++- .../DishDetailsModalPage.style.ts | 33 +++++++++++++++++++ .../DishDetailsModalPage.tsx | 22 +++++++++++-- 7 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.style.ts create mode 100644 features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.tsx create mode 100644 features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts diff --git a/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.style.ts b/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.style.ts new file mode 100644 index 0000000..429ba7e --- /dev/null +++ b/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.style.ts @@ -0,0 +1,18 @@ +import { fontSize } from '@/features/core/ui/style/dimensions/fontSize'; +import { spacing } from '@/features/core/ui/style/dimensions/spacing'; +import { fontFamily } from '@/features/core/ui/style/fontFamily'; +import { StyleSheet } from 'react-native'; + +export const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingBottom: spacing.Double, + marginBottom: spacing.Fourfold, + }, + title: { + fontFamily: fontFamily.interExtraBold, + fontSize: fontSize.XL2, + }, +}); diff --git a/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.tsx b/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.tsx new file mode 100644 index 0000000..c686c64 --- /dev/null +++ b/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.tsx @@ -0,0 +1,19 @@ +import { ButtonType } from '@/features/core/ui/components/basic/CustomButton/CustomButton.logic'; +import { CustomIconButtonMedium } from '@/features/core/ui/components/basic/CustomIconButton/CustomIconButtonMedium'; +import { CustomText } from '@/features/core/ui/components/basic/CustomText/CustomText'; +import { styles } from '@/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.style'; +import { icons } from '@/features/core/ui/style/icons'; +import type { FC } from 'react'; +import { View } from 'react-native'; + +type BottomSheetHeaderProps = { + title: string; + onClose: () => void; +}; + +export const BottomSheetHeader: FC = ({ title, onClose }) => ( + + + + +); diff --git a/features/core/ui/index.ts b/features/core/ui/index.ts index fb161d6..8aaae08 100644 --- a/features/core/ui/index.ts +++ b/features/core/ui/index.ts @@ -41,6 +41,7 @@ export * from '@/features/core/ui/components/basic/LinearGradientText/LinearGrad export * from '@/features/core/ui/components/basic/LottieAnimation/LottieAnimation'; // Composite components +export * from '@/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader'; export * from '@/features/core/ui/components/composite/AnimatedHeaderImage/AnimatedHeaderImage'; export * from '@/features/core/ui/components/composite/CardWithImage/CardWithImage'; export * from '@/features/core/ui/components/composite/CustomHeader/CustomHeader'; diff --git a/features/core/ui/style/dimensions/images.ts b/features/core/ui/style/dimensions/images.ts index fa95a72..55a9017 100644 --- a/features/core/ui/style/dimensions/images.ts +++ b/features/core/ui/style/dimensions/images.ts @@ -5,4 +5,5 @@ export const images = { logoRoundHeight: 80, logoRoundWidth: 80, dishImageSize: 80, + dishFullImageSize: 150, }; diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts index d05644b..44a35f5 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts @@ -1,10 +1,18 @@ +import { useGetWikimediaDishImage } from '@/features/core/images/facades/useGetWikimediaDishImage'; import { navigationService } from '@/features/core/navigation'; +import { useGetTripById } from '@/features/trips/facades/useGetTripById'; import { useLocalSearchParams } from 'expo-router'; export const useDishDetailsModalPageLogic = () => { const { tripId, searchTerm } = useLocalSearchParams<{ tripId: string; searchTerm: string }>(); + const { data, isLoading } = useGetWikimediaDishImage(searchTerm); + const { trip } = useGetTripById(tripId); + + const dish = trip?.tripAiResp?.food?.typicalDishes.find(d => d.searchTerm === searchTerm); + const dishName = dish?.name ?? ''; + const dishDescription = dish?.description ?? ''; const handleClose = () => navigationService.back(); - return { tripId, searchTerm, handleClose }; + return { dishName, dishDescription, handleClose, image: data?.url, imageIsLoading: isLoading }; }; diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts new file mode 100644 index 0000000..4490860 --- /dev/null +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts @@ -0,0 +1,33 @@ +import { colors, fontFamily, fontSize, images, shadows, spacing } from '@/features/core/ui'; +import { StyleSheet } from 'react-native'; + +export const styles = StyleSheet.create({ + contentContainer: { + paddingVertical: spacing.Quintuple, + paddingHorizontal: spacing.Quintuple, + }, + container: { + backgroundColor: colors.primaryWhite, + }, + imageWrapper: { + width: images.dishFullImageSize, + height: images.dishFullImageSize, + borderRadius: images.dishFullImageSize, + boxShadow: shadows.highShadow, + }, + image: { + width: images.dishFullImageSize, + height: images.dishFullImageSize, + borderRadius: images.dishFullImageSize, + }, + bodyContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + columnGap: spacing.Fourfold, + }, + description: { + flex: 1, + fontFamily: fontFamily.interRegular, + fontSize: fontSize.MD, + }, +}); diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx index aba4da5..a8e3e45 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx @@ -1,8 +1,24 @@ +import { BaseSkeleton, BottomSheetHeader, CustomImage, CustomText } from '@/features/core/ui'; import { useDishDetailsModalPageLogic } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic'; -import { View } from 'react-native'; +import { styles } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style'; +import { ScrollView, View } from 'react-native'; export const DishDetailsModalPage = () => { - useDishDetailsModalPageLogic(); + const { dishName, dishDescription, handleClose, image, imageIsLoading } = useDishDetailsModalPageLogic(); - return ; + return ( + + + + + {imageIsLoading ? ( + + ) : ( + + )} + + + + + ); }; From 597e36cb425a2920191cc37b69f0c114b9ac1615 Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Tue, 2 Jun 2026 19:10:49 +0200 Subject: [PATCH 03/11] feat(256): add dish description --- .../core/ui/components/basic/Cheap/Cheap.tsx | 6 +++-- features/core/ui/style/dimensions/images.ts | 2 +- features/core/ui/style/icons.ts | 1 + .../components/DishItem/DishItem.style.ts | 10 ++++++- .../FoodCard/components/DishItem/DishItem.tsx | 2 +- .../IngredientsList/IngredientsList.style.ts | 20 ++++++++++++++ .../IngredientsList/IngredientsList.tsx | 26 +++++++++++++++++++ .../TypicalDishesList.style.ts | 4 +-- .../TypicalDishesModalHeader.style.ts | 3 --- .../DishDetailsModalPage.logic.ts | 3 ++- .../DishDetailsModalPage.style.ts | 13 ++++------ .../DishDetailsModalPage.tsx | 19 +++++++------- 12 files changed, 81 insertions(+), 28 deletions(-) create mode 100644 features/trips/ui/components/IngredientsList/IngredientsList.style.ts create mode 100644 features/trips/ui/components/IngredientsList/IngredientsList.tsx diff --git a/features/core/ui/components/basic/Cheap/Cheap.tsx b/features/core/ui/components/basic/Cheap/Cheap.tsx index 5920d65..01ee667 100644 --- a/features/core/ui/components/basic/Cheap/Cheap.tsx +++ b/features/core/ui/components/basic/Cheap/Cheap.tsx @@ -10,14 +10,16 @@ type CheapProps = { title: string; color: string; icon?: IoniconsName; + uppercase?: boolean; }; -export const Cheap: FC = ({ title, color, icon }) => { +export const Cheap: FC = ({ title, color, icon, uppercase = true }) => { const styles = cheapStyles(color); + return ( {icon && } - + ); }; diff --git a/features/core/ui/style/dimensions/images.ts b/features/core/ui/style/dimensions/images.ts index 55a9017..3a309ce 100644 --- a/features/core/ui/style/dimensions/images.ts +++ b/features/core/ui/style/dimensions/images.ts @@ -5,5 +5,5 @@ export const images = { logoRoundHeight: 80, logoRoundWidth: 80, dishImageSize: 80, - dishFullImageSize: 150, + dishFullImageSize: 110, }; diff --git a/features/core/ui/style/icons.ts b/features/core/ui/style/icons.ts index 0190c46..d57ce4a 100644 --- a/features/core/ui/style/icons.ts +++ b/features/core/ui/style/icons.ts @@ -5,6 +5,7 @@ export const icons: Record = { location: 'location', locationOutline: 'location-outline', globeOutline: 'globe-outline', + checkmark: 'checkmark', personCircleOutline: 'person-circle-outline', arrowBack: 'arrow-back', arrowRight: 'chevron-forward', diff --git a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.style.ts b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.style.ts index 08c9dc5..78b909f 100644 --- a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.style.ts +++ b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.style.ts @@ -1,4 +1,4 @@ -import { colors, fontFamily, images, spacing } from '@/features/core/ui'; +import { colors, fontFamily, images, opacity, spacing } from '@/features/core/ui'; import { StyleSheet } from 'react-native'; export const styles = StyleSheet.create({ @@ -6,11 +6,16 @@ export const styles = StyleSheet.create({ flexDirection: 'row', alignItems: 'center', gap: spacing.Double, + backgroundColor: colors.secondaryGrey, + padding: spacing.Double, + borderRadius: spacing.Fourfold, }, image: { width: images.dishImageSize, height: images.dishImageSize, borderRadius: images.dishImageSize, + borderWidth: spacing.Minimal, + borderColor: colors.primaryBlack, }, skeleton: { width: images.dishImageSize, @@ -31,4 +36,7 @@ export const styles = StyleSheet.create({ flex: 1, alignItems: 'flex-start', }, + pressed: { + opacity: opacity.default, + }, }); diff --git a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx index 477706c..2d08c1d 100644 --- a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx +++ b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx @@ -11,7 +11,7 @@ export const DishItem: FC = ({ dish, onPress }) => { const { image, isLoading } = useDishItemLogic(dish.searchTerm); return ( - + [styles.container, pressed && styles.pressed]} onPress={onPress}> {isLoading ? ( diff --git a/features/trips/ui/components/IngredientsList/IngredientsList.style.ts b/features/trips/ui/components/IngredientsList/IngredientsList.style.ts new file mode 100644 index 0000000..2632914 --- /dev/null +++ b/features/trips/ui/components/IngredientsList/IngredientsList.style.ts @@ -0,0 +1,20 @@ +import { colors, fontFamily, fontSize, spacing } from '@/features/core/ui'; +import { StyleSheet } from 'react-native'; + +export const styles = StyleSheet.create({ + container: { + flex: 1, + gap: spacing.Double, + }, + title: { + fontFamily: fontFamily.interBold, + fontSize: fontSize.SM, + color: colors.primaryGrey, + }, + chipsRow: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: spacing.SingleAndHalf, + width: '100%', + }, +}); diff --git a/features/trips/ui/components/IngredientsList/IngredientsList.tsx b/features/trips/ui/components/IngredientsList/IngredientsList.tsx new file mode 100644 index 0000000..8842c99 --- /dev/null +++ b/features/trips/ui/components/IngredientsList/IngredientsList.tsx @@ -0,0 +1,26 @@ +import { Cheap, CustomText, colors, icons } from '@/features/core/ui'; +import { styles } from '@/features/trips/ui/components/IngredientsList/IngredientsList.style'; +import type { FC } from 'react'; +import { View } from 'react-native'; + +type IngredientsListProps = { + title: string; + ingredients: string[]; +}; + +export const IngredientsList: FC = ({ title, ingredients }) => ( + + + + {ingredients.map(ingredient => ( + + ))} + + +); diff --git a/features/trips/ui/components/TypicalDishesList/TypicalDishesList.style.ts b/features/trips/ui/components/TypicalDishesList/TypicalDishesList.style.ts index a350883..b8c00ac 100644 --- a/features/trips/ui/components/TypicalDishesList/TypicalDishesList.style.ts +++ b/features/trips/ui/components/TypicalDishesList/TypicalDishesList.style.ts @@ -4,7 +4,7 @@ import { StyleSheet } from 'react-native'; export const styles = StyleSheet.create({ separator: { height: 1, - backgroundColor: colors.secondaryGreen, - marginVertical: spacing.Fourfold, + backgroundColor: colors.secondaryGrey, + marginVertical: spacing.Double, }, }); diff --git a/features/trips/ui/components/TypicalDishesModalHeader/TypicalDishesModalHeader.style.ts b/features/trips/ui/components/TypicalDishesModalHeader/TypicalDishesModalHeader.style.ts index 072e1af..3d26e90 100644 --- a/features/trips/ui/components/TypicalDishesModalHeader/TypicalDishesModalHeader.style.ts +++ b/features/trips/ui/components/TypicalDishesModalHeader/TypicalDishesModalHeader.style.ts @@ -7,9 +7,6 @@ export const styles = StyleSheet.create({ justifyContent: 'space-between', alignItems: 'center', marginBottom: spacing.Quintuple, - borderBottomWidth: 1, - borderBottomColor: colors.secondaryGreen, - paddingBottom: spacing.Double, }, headerContent: { gap: spacing.Single, diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts index 44a35f5..5580c4f 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts @@ -11,8 +11,9 @@ export const useDishDetailsModalPageLogic = () => { const dish = trip?.tripAiResp?.food?.typicalDishes.find(d => d.searchTerm === searchTerm); const dishName = dish?.name ?? ''; const dishDescription = dish?.description ?? ''; + const dishIngredients = dish?.ingredients ?? []; const handleClose = () => navigationService.back(); - return { dishName, dishDescription, handleClose, image: data?.url, imageIsLoading: isLoading }; + return { dishName, dishDescription, dishIngredients, handleClose, image: data?.url, imageIsLoading: isLoading }; }; diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts index 4490860..e8af112 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts @@ -1,4 +1,4 @@ -import { colors, fontFamily, fontSize, images, shadows, spacing } from '@/features/core/ui'; +import { colors, fontFamily, fontSize, images, spacing } from '@/features/core/ui'; import { StyleSheet } from 'react-native'; export const styles = StyleSheet.create({ @@ -9,21 +9,18 @@ export const styles = StyleSheet.create({ container: { backgroundColor: colors.primaryWhite, }, - imageWrapper: { - width: images.dishFullImageSize, - height: images.dishFullImageSize, - borderRadius: images.dishFullImageSize, - boxShadow: shadows.highShadow, - }, image: { width: images.dishFullImageSize, height: images.dishFullImageSize, borderRadius: images.dishFullImageSize, + borderWidth: spacing.MinimalDouble, + borderColor: colors.primaryBlack, }, bodyContainer: { flexDirection: 'row', justifyContent: 'space-between', - columnGap: spacing.Fourfold, + columnGap: spacing.Double, + marginBottom: spacing.Triple, }, description: { flex: 1, diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx index a8e3e45..a0b7019 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx @@ -1,24 +1,25 @@ import { BaseSkeleton, BottomSheetHeader, CustomImage, CustomText } from '@/features/core/ui'; +import { IngredientsList } from '@/features/trips/ui/components/IngredientsList/IngredientsList'; import { useDishDetailsModalPageLogic } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic'; import { styles } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style'; import { ScrollView, View } from 'react-native'; export const DishDetailsModalPage = () => { - const { dishName, dishDescription, handleClose, image, imageIsLoading } = useDishDetailsModalPageLogic(); + const { dishName, dishDescription, dishIngredients, handleClose, image, imageIsLoading } = + useDishDetailsModalPageLogic(); return ( - - {imageIsLoading ? ( - - ) : ( - - )} - - + {imageIsLoading ? ( + + ) : ( + + )} + + ); }; From f4a2bfe6d39afc8d5f779af0e02238c20333c798 Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Wed, 3 Jun 2026 16:16:10 +0200 Subject: [PATCH 04/11] feat(356): badge components --- .../translations/libraries/locales/en.json | 3 +- .../translations/libraries/locales/it.json | 3 +- .../components/composite/Badge/Badge.style.ts | 43 +++++++++++++++++++ .../ui/components/composite/Badge/Badge.tsx | 37 ++++++++++++++++ features/core/ui/index.ts | 1 + features/core/ui/style/colors.ts | 1 + .../core/ui/style/dimensions/components.ts | 2 + .../ui/components/FoodCard/FoodCard.style.ts | 29 ++++++++++++- .../trips/ui/components/FoodCard/FoodCard.tsx | 17 +++++--- .../DishDetailsModalPage.style.ts | 10 +++++ .../DishDetailsModalPage.tsx | 7 ++- 11 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 features/core/ui/components/composite/Badge/Badge.style.ts create mode 100644 features/core/ui/components/composite/Badge/Badge.tsx diff --git a/features/core/translations/libraries/locales/en.json b/features/core/translations/libraries/locales/en.json index 8fd3086..ac89d0a 100644 --- a/features/core/translations/libraries/locales/en.json +++ b/features/core/translations/libraries/locales/en.json @@ -38,7 +38,8 @@ "PROFILE": "Profile", "MY_TRIPS": "My Trips", "LOGO": "HolidAI", - "UPCOMING_TRIP": "Upcoming trip:" + "UPCOMING_TRIP": "Upcoming trip:", + "MORE_DETAILS": "More details" }, "ACTIVITY_DETAILS": { "USEFUL_TIPS": "Useful Tips", diff --git a/features/core/translations/libraries/locales/it.json b/features/core/translations/libraries/locales/it.json index c1e8ff4..e761014 100644 --- a/features/core/translations/libraries/locales/it.json +++ b/features/core/translations/libraries/locales/it.json @@ -38,7 +38,8 @@ "PROFILE": "Profilo", "MY_TRIPS": "Viaggi", "LOGO": "HolidAI", - "UPCOMING_TRIP": "Prossimo viaggio:" + "UPCOMING_TRIP": "Prossimo viaggio:", + "MORE_DETAILS": "Più dettagli" }, "ACTIVITY_DETAILS": { "USEFUL_TIPS": "Consigli utili", diff --git a/features/core/ui/components/composite/Badge/Badge.style.ts b/features/core/ui/components/composite/Badge/Badge.style.ts new file mode 100644 index 0000000..9569312 --- /dev/null +++ b/features/core/ui/components/composite/Badge/Badge.style.ts @@ -0,0 +1,43 @@ +import { colors } from '@/features/core/ui/style/colors'; +import { components } from '@/features/core/ui/style/dimensions/components'; +import { fontSize } from '@/features/core/ui/style/dimensions/fontSize'; +import { spacing } from '@/features/core/ui/style/dimensions/spacing'; +import { fontFamily } from '@/features/core/ui/style/fontFamily'; +import { StyleSheet } from 'react-native'; + +export const styles = (active: boolean, backgroundColor: string) => + StyleSheet.create({ + container: { + alignItems: 'center', + gap: spacing.Single, + backgroundColor: active ? backgroundColor : colors.secondaryGrey, + }, + circleWrapper: { + width: components.badgeCircleSize, + height: components.badgeCircleSize, + }, + circle: { + width: components.badgeCircleSize, + height: components.badgeCircleSize, + borderRadius: components.badgeCircleSize / 2, + alignItems: 'center', + justifyContent: 'center', + }, + checkBadge: { + position: 'absolute', + bottom: 0, + right: 0, + width: components.badgeCheckSize, + height: components.badgeCheckSize, + borderRadius: components.badgeCheckSize / 2, + backgroundColor: colors.primaryWhite, + alignItems: 'center', + justifyContent: 'center', + }, + label: { + fontSize: fontSize.XS, + fontFamily: fontFamily.interBold, + color: colors.primaryBlack, + textAlign: 'center', + }, + }); diff --git a/features/core/ui/components/composite/Badge/Badge.tsx b/features/core/ui/components/composite/Badge/Badge.tsx new file mode 100644 index 0000000..b633762 --- /dev/null +++ b/features/core/ui/components/composite/Badge/Badge.tsx @@ -0,0 +1,37 @@ +import { CustomIcon, type IoniconsName } from '@/features/core/ui/components/basic/CustomIcon/CustomIcon'; +import { CustomText } from '@/features/core/ui/components/basic/CustomText/CustomText'; +import { styles as badgeStyle } from '@/features/core/ui/components/composite/Badge/Badge.style'; +import { colors } from '@/features/core/ui/style/colors'; +import { spacing } from '@/features/core/ui/style/dimensions/spacing'; +import { icons } from '@/features/core/ui/style/icons'; +import type { FC } from 'react'; +import { View } from 'react-native'; + +type BadgeProps = { + label: string; + icon: IoniconsName; + backgroundColor: string; + active: boolean; +}; + +export const Badge: FC = ({ label, icon, backgroundColor, active }) => { + const styles = badgeStyle(active, backgroundColor); + + return ( + + + + + + + + + + + + ); +}; diff --git a/features/core/ui/index.ts b/features/core/ui/index.ts index 8aaae08..8f8bda6 100644 --- a/features/core/ui/index.ts +++ b/features/core/ui/index.ts @@ -41,6 +41,7 @@ export * from '@/features/core/ui/components/basic/LinearGradientText/LinearGrad export * from '@/features/core/ui/components/basic/LottieAnimation/LottieAnimation'; // Composite components +export * from '@/features/core/ui/components/composite/Badge/Badge'; export * from '@/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader'; export * from '@/features/core/ui/components/composite/AnimatedHeaderImage/AnimatedHeaderImage'; export * from '@/features/core/ui/components/composite/CardWithImage/CardWithImage'; diff --git a/features/core/ui/style/colors.ts b/features/core/ui/style/colors.ts index cc226c4..2ba4741 100644 --- a/features/core/ui/style/colors.ts +++ b/features/core/ui/style/colors.ts @@ -19,4 +19,5 @@ export const colors = { tertiaryBlue: '#63b3ff', primaryRed: '#FFD9D9', secondaryGreen: '#8AFF8A', + tertiaryGreen: '#57C17B', } as const; diff --git a/features/core/ui/style/dimensions/components.ts b/features/core/ui/style/dimensions/components.ts index 1f9b583..9460c44 100644 --- a/features/core/ui/style/dimensions/components.ts +++ b/features/core/ui/style/dimensions/components.ts @@ -26,6 +26,8 @@ export const components = { buttonNumberHeight: 30, animatedWordsHeight: 30, carouselImageSize: 200, + badgeCircleSize: 80, + badgeCheckSize: 22, welcomeCardHeightSmall: 130, welcomeCardHeightMedium: 180, welcomeCardHeightLarge: 230, diff --git a/features/trips/ui/components/FoodCard/FoodCard.style.ts b/features/trips/ui/components/FoodCard/FoodCard.style.ts index 93a7bfe..3db5914 100644 --- a/features/trips/ui/components/FoodCard/FoodCard.style.ts +++ b/features/trips/ui/components/FoodCard/FoodCard.style.ts @@ -1,4 +1,4 @@ -import { colors, fontFamily, fontSize, spacing } from '@/features/core/ui'; +import { colors, fontFamily, fontSize, opacity, spacing } from '@/features/core/ui'; import { StyleSheet } from 'react-native'; export const styles = StyleSheet.create({ @@ -56,4 +56,31 @@ export const styles = StyleSheet.create({ marginTop: spacing.Double, paddingHorizontal: spacing.Double, }, + titleContainer: { + flexDirection: 'row', + alignItems: 'center', + gap: spacing.Single, + }, + typicalDishesBox: { + padding: spacing.Double, + backgroundColor: colors.secondaryGrey, + borderRadius: spacing.Double, + marginTop: spacing.Double, + marginHorizontal: spacing.Double, + }, + pressed: { + opacity: opacity.default, + }, + boxText: { + fontFamily: fontFamily.interMedium, + color: colors.primaryBlack, + }, + boxButton: { + marginTop: spacing.Single, + fontFamily: fontFamily.interBold, + alignSelf: 'flex-end', + backgroundColor: colors.primaryWhite, + padding: spacing.Single, + borderRadius: spacing.Double, + }, }); diff --git a/features/trips/ui/components/FoodCard/FoodCard.tsx b/features/trips/ui/components/FoodCard/FoodCard.tsx index 6037c92..3430d22 100644 --- a/features/trips/ui/components/FoodCard/FoodCard.tsx +++ b/features/trips/ui/components/FoodCard/FoodCard.tsx @@ -1,10 +1,10 @@ -import { CustomButtonMedium, CustomIcon, CustomText, colors, icons, spacing } from '@/features/core/ui'; +import { CustomIcon, CustomText, colors, icons, spacing } from '@/features/core/ui'; import type { Food } from '@/features/trips/domain/entities/Food'; import { useFoodCardLogic } from '@/features/trips/ui/components/FoodCard/FoodCard.logic'; import { styles } from '@/features/trips/ui/components/FoodCard/FoodCard.style'; import { LinearGradient } from 'expo-linear-gradient'; import type { FC } from 'react'; -import { View } from 'react-native'; +import { Pressable, View } from 'react-native'; type FoodCardProps = { food: Food; @@ -36,9 +36,16 @@ export const FoodCard: FC = ({ food, tripId }) => { - - - + [styles.typicalDishesBox, pressed && styles.pressed]} + onPress={handleOpenModal} + > + + + + + + ); diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts index e8af112..cfccfa6 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style.ts @@ -21,10 +21,20 @@ export const styles = StyleSheet.create({ justifyContent: 'space-between', columnGap: spacing.Double, marginBottom: spacing.Triple, + alignItems: 'center', }, description: { flex: 1, fontFamily: fontFamily.interRegular, fontSize: fontSize.MD, + lineHeight: fontSize.MD * 1.5, + }, + badgesContainer: { + flexDirection: 'row', + gap: spacing.Single, + marginTop: spacing.Double, + justifyContent: 'space-between', + paddingHorizontal: spacing.Double, + paddingVertical: spacing.Single, }, }); diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx index a0b7019..08ad810 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx @@ -1,4 +1,4 @@ -import { BaseSkeleton, BottomSheetHeader, CustomImage, CustomText } from '@/features/core/ui'; +import { Badge, BaseSkeleton, BottomSheetHeader, CustomImage, CustomText, colors, icons } from '@/features/core/ui'; import { IngredientsList } from '@/features/trips/ui/components/IngredientsList/IngredientsList'; import { useDishDetailsModalPageLogic } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic'; import { styles } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style'; @@ -20,6 +20,11 @@ export const DishDetailsModalPage = () => { + + + + + ); }; From c1affe48551ecf2914949ccf9a3b45efe57e7073 Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Thu, 4 Jun 2026 10:56:06 +0200 Subject: [PATCH 05/11] feat(356): add food badges --- convex/validators/Trips.ts | 1 + .../translations/libraries/locales/en.json | 3 ++ .../translations/libraries/locales/it.json | 3 ++ .../core/ui/assets/images/gluten_free.png | Bin 0 -> 22326 bytes features/core/ui/assets/images/vegan.png | Bin 0 -> 24255 bytes features/core/ui/assets/images/vegetarian.png | Bin 0 -> 22765 bytes .../components/composite/Badge/Badge.style.ts | 6 +++- .../ui/components/composite/Badge/Badge.tsx | 18 +++++----- .../BottomSheetHeader.style.ts | 1 + .../BottomSheetHeader/BottomSheetHeader.tsx | 2 +- features/core/ui/style/icons.ts | 1 + .../domain/schemas/GenerateTripSchema.ts | 1 + features/trips/domain/entities/TypicalDish.ts | 1 + .../DishDetailsModalPage.logic.ts | 22 +++++++++--- .../DishDetailsModalPage.tsx | 34 ++++++++++++++---- 15 files changed, 73 insertions(+), 20 deletions(-) create mode 100644 features/core/ui/assets/images/gluten_free.png create mode 100644 features/core/ui/assets/images/vegan.png create mode 100644 features/core/ui/assets/images/vegetarian.png diff --git a/convex/validators/Trips.ts b/convex/validators/Trips.ts index 3b1fc37..2ab054c 100644 --- a/convex/validators/Trips.ts +++ b/convex/validators/Trips.ts @@ -54,6 +54,7 @@ export const TypicalDish = v.object({ ingredients: v.array(v.string()), isGlutenFree: v.boolean(), isVegetarian: v.boolean(), + isVegan: v.boolean(), }); export const Food = v.object({ diff --git a/features/core/translations/libraries/locales/en.json b/features/core/translations/libraries/locales/en.json index ac89d0a..fc47cac 100644 --- a/features/core/translations/libraries/locales/en.json +++ b/features/core/translations/libraries/locales/en.json @@ -35,6 +35,9 @@ "DISHES_one": "dish", "DISHES_other": "dishes", "TYPICAL_DISHES": "Typical Dishes", + "GLUTEN_FREE": "GLUTEN-FREE", + "VEGAN": "VEGAN", + "VEGETARIAN": "VEGETARIAN", "PROFILE": "Profile", "MY_TRIPS": "My Trips", "LOGO": "HolidAI", diff --git a/features/core/translations/libraries/locales/it.json b/features/core/translations/libraries/locales/it.json index e761014..39cb3bc 100644 --- a/features/core/translations/libraries/locales/it.json +++ b/features/core/translations/libraries/locales/it.json @@ -35,6 +35,9 @@ "DISHES_one": "piatto", "DISHES_other": "piatti", "TYPICAL_DISHES": "Piatti tipici", + "GLUTEN_FREE": "SENZA GLUTINE", + "VEGAN": "VEGANO", + "VEGETARIAN": "VEGETARIANO", "PROFILE": "Profilo", "MY_TRIPS": "Viaggi", "LOGO": "HolidAI", diff --git a/features/core/ui/assets/images/gluten_free.png b/features/core/ui/assets/images/gluten_free.png new file mode 100644 index 0000000000000000000000000000000000000000..9d8686adab3e47562074b53f0f2e4da0badcdb37 GIT binary patch literal 22326 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 literal 0 HcmV?d00001 diff --git a/features/core/ui/assets/images/vegan.png b/features/core/ui/assets/images/vegan.png new file mode 100644 index 0000000000000000000000000000000000000000..d9b007e331c5b99eb6033c599d7eaf5aec1abc72 GIT binary patch literal 24255 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 literal 0 HcmV?d00001 diff --git a/features/core/ui/components/composite/Badge/Badge.style.ts b/features/core/ui/components/composite/Badge/Badge.style.ts index 9569312..d954a2a 100644 --- a/features/core/ui/components/composite/Badge/Badge.style.ts +++ b/features/core/ui/components/composite/Badge/Badge.style.ts @@ -10,7 +10,6 @@ export const styles = (active: boolean, backgroundColor: string) => container: { alignItems: 'center', gap: spacing.Single, - backgroundColor: active ? backgroundColor : colors.secondaryGrey, }, circleWrapper: { width: components.badgeCircleSize, @@ -22,6 +21,7 @@ export const styles = (active: boolean, backgroundColor: string) => borderRadius: components.badgeCircleSize / 2, alignItems: 'center', justifyContent: 'center', + backgroundColor: active ? backgroundColor : colors.primaryRed, }, checkBadge: { position: 'absolute', @@ -34,6 +34,10 @@ export const styles = (active: boolean, backgroundColor: string) => alignItems: 'center', justifyContent: 'center', }, + badgeImage: { + width: components.badgeCircleSize * 0.6, + height: components.badgeCircleSize * 0.6, + }, label: { fontSize: fontSize.XS, fontFamily: fontFamily.interBold, diff --git a/features/core/ui/components/composite/Badge/Badge.tsx b/features/core/ui/components/composite/Badge/Badge.tsx index b633762..6136ae9 100644 --- a/features/core/ui/components/composite/Badge/Badge.tsx +++ b/features/core/ui/components/composite/Badge/Badge.tsx @@ -1,37 +1,39 @@ -import { CustomIcon, type IoniconsName } from '@/features/core/ui/components/basic/CustomIcon/CustomIcon'; +import { CustomIcon } from '@/features/core/ui/components/basic/CustomIcon/CustomIcon'; +import { CustomImage } from '@/features/core/ui/components/basic/CustomImage/CustomImage'; import { CustomText } from '@/features/core/ui/components/basic/CustomText/CustomText'; import { styles as badgeStyle } from '@/features/core/ui/components/composite/Badge/Badge.style'; import { colors } from '@/features/core/ui/style/colors'; import { spacing } from '@/features/core/ui/style/dimensions/spacing'; import { icons } from '@/features/core/ui/style/icons'; import type { FC } from 'react'; +import type { ImageSourcePropType } from 'react-native'; import { View } from 'react-native'; type BadgeProps = { label: string; - icon: IoniconsName; + image: ImageSourcePropType; backgroundColor: string; active: boolean; }; -export const Badge: FC = ({ label, icon, backgroundColor, active }) => { +export const Badge: FC = ({ label, image, backgroundColor, active }) => { const styles = badgeStyle(active, backgroundColor); return ( - - + + - + ); }; diff --git a/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.style.ts b/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.style.ts index 429ba7e..578ef2c 100644 --- a/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.style.ts +++ b/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.style.ts @@ -14,5 +14,6 @@ export const styles = StyleSheet.create({ title: { fontFamily: fontFamily.interExtraBold, fontSize: fontSize.XL2, + maxWidth: '90%', }, }); diff --git a/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.tsx b/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.tsx index c686c64..a28d2d1 100644 --- a/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.tsx +++ b/features/core/ui/components/composite/BottomSheetHeader/BottomSheetHeader.tsx @@ -13,7 +13,7 @@ type BottomSheetHeaderProps = { export const BottomSheetHeader: FC = ({ title, onClose }) => ( - + ); diff --git a/features/core/ui/style/icons.ts b/features/core/ui/style/icons.ts index d57ce4a..4f75651 100644 --- a/features/core/ui/style/icons.ts +++ b/features/core/ui/style/icons.ts @@ -2,6 +2,7 @@ import type { Ionicons } from '@expo/vector-icons'; export const icons: Record = { close: 'close', + closeCircle: 'close-circle', location: 'location', locationOutline: 'location-outline', globeOutline: 'globe-outline', diff --git a/features/trip-generation/domain/schemas/GenerateTripSchema.ts b/features/trip-generation/domain/schemas/GenerateTripSchema.ts index f44c3b5..174c5d4 100644 --- a/features/trip-generation/domain/schemas/GenerateTripSchema.ts +++ b/features/trip-generation/domain/schemas/GenerateTripSchema.ts @@ -78,6 +78,7 @@ export const generatedTripSchema = z.object({ ingredients: z.array(z.string()).describe('Main ingredients of the dish.'), isGlutenFree: z.boolean().describe('Whether the dish is gluten free.'), isVegetarian: z.boolean().describe('Whether the dish is vegetarian.'), + isVegan: z.boolean().describe('Whether the dish is vegan.'), }), ), }), diff --git a/features/trips/domain/entities/TypicalDish.ts b/features/trips/domain/entities/TypicalDish.ts index 502a0f4..ba6af8a 100644 --- a/features/trips/domain/entities/TypicalDish.ts +++ b/features/trips/domain/entities/TypicalDish.ts @@ -5,4 +5,5 @@ export interface TypicalDish { ingredients: string[]; isGlutenFree: boolean; isVegetarian: boolean; + isVegan: boolean; } diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts index 5580c4f..e6cdcd6 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts @@ -3,17 +3,31 @@ import { navigationService } from '@/features/core/navigation'; import { useGetTripById } from '@/features/trips/facades/useGetTripById'; import { useLocalSearchParams } from 'expo-router'; +const glutenFreeImage = require('@/features/core/ui/assets/images/gluten_free.png'); +const veganImage = require('@/features/core/ui/assets/images/vegan.png'); +const vegetarianImage = require('@/features/core/ui/assets/images/vegetarian.png'); + export const useDishDetailsModalPageLogic = () => { const { tripId, searchTerm } = useLocalSearchParams<{ tripId: string; searchTerm: string }>(); const { data, isLoading } = useGetWikimediaDishImage(searchTerm); const { trip } = useGetTripById(tripId); const dish = trip?.tripAiResp?.food?.typicalDishes.find(d => d.searchTerm === searchTerm); - const dishName = dish?.name ?? ''; - const dishDescription = dish?.description ?? ''; - const dishIngredients = dish?.ingredients ?? []; const handleClose = () => navigationService.back(); - return { dishName, dishDescription, dishIngredients, handleClose, image: data?.url, imageIsLoading: isLoading }; + return { + dishName: dish?.name ?? '', + dishDescription: dish?.description ?? '', + dishIngredients: dish?.ingredients ?? [], + handleClose, + image: data?.url, + imageIsLoading: isLoading, + isVegetarian: dish?.isVegetarian ?? false, + isGlutenFree: dish?.isGlutenFree ?? false, + isVegan: dish?.isVegan ?? false, + glutenFreeImage, + veganImage, + vegetarianImage, + }; }; diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx index 08ad810..050d7e9 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx @@ -1,12 +1,24 @@ -import { Badge, BaseSkeleton, BottomSheetHeader, CustomImage, CustomText, colors, icons } from '@/features/core/ui'; +import { Badge, BaseSkeleton, BottomSheetHeader, CustomImage, CustomText, colors } from '@/features/core/ui'; import { IngredientsList } from '@/features/trips/ui/components/IngredientsList/IngredientsList'; import { useDishDetailsModalPageLogic } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic'; import { styles } from '@/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.style'; import { ScrollView, View } from 'react-native'; export const DishDetailsModalPage = () => { - const { dishName, dishDescription, dishIngredients, handleClose, image, imageIsLoading } = - useDishDetailsModalPageLogic(); + const { + dishName, + dishDescription, + dishIngredients, + handleClose, + image, + imageIsLoading, + isVegetarian, + isGlutenFree, + isVegan, + glutenFreeImage, + veganImage, + vegetarianImage, + } = useDishDetailsModalPageLogic(); return ( @@ -21,9 +33,19 @@ export const DishDetailsModalPage = () => { - - - + + + ); From fc83f8cd367b99ea7743549f7bfa0d0b3d8c2ce2 Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Thu, 4 Jun 2026 11:13:04 +0200 Subject: [PATCH 06/11] fix(356): add in line badges --- .../components/DishItem/DishItem.logic.ts | 23 +++++++++++++--- .../components/DishItem/DishItem.style.ts | 9 +++++++ .../FoodCard/components/DishItem/DishItem.tsx | 26 +++++++++++++++++-- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.logic.ts b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.logic.ts index d060e70..e9e3018 100644 --- a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.logic.ts +++ b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.logic.ts @@ -1,6 +1,23 @@ import { useGetWikimediaDishImage } from '@/features/core/images'; +import type { TypicalDish } from '@/features/trips'; -export const useDishItemLogic = (searchTerm: string) => { - const { data, isLoading } = useGetWikimediaDishImage(searchTerm); - return { image: data?.url, isLoading }; +const glutenFreeImage = require('@/features/core/ui/assets/images/gluten_free.png'); +const veganImage = require('@/features/core/ui/assets/images/vegan.png'); +const vegetarianImage = require('@/features/core/ui/assets/images/vegetarian.png'); + +export const useDishItemLogic = (dish: TypicalDish) => { + const { data, isLoading } = useGetWikimediaDishImage(dish.searchTerm); + const hasBadge = dish.isGlutenFree || dish.isVegan || dish.isVegetarian; + + return { + image: data?.url, + isLoading, + glutenFreeImage, + veganImage, + vegetarianImage, + hasBadge, + isGlutenFree: dish.isGlutenFree, + isVegan: dish.isVegan, + isVegetarian: dish.isVegetarian, + }; }; diff --git a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.style.ts b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.style.ts index 78b909f..384793b 100644 --- a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.style.ts +++ b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.style.ts @@ -39,4 +39,13 @@ export const styles = StyleSheet.create({ pressed: { opacity: opacity.default, }, + badge: { + width: spacing.FourfoldAndHalf, + height: spacing.FourfoldAndHalf, + }, + badgeContainer: { + flexDirection: 'row', + columnGap: spacing.Minimal, + left: -spacing.MinimalDouble, + }, }); diff --git a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx index 2d08c1d..7c92c05 100644 --- a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx +++ b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx @@ -8,7 +8,17 @@ import { Pressable, View } from 'react-native'; type DishItemProps = { dish: TypicalDish; onPress: () => void }; export const DishItem: FC = ({ dish, onPress }) => { - const { image, isLoading } = useDishItemLogic(dish.searchTerm); + const { + image, + isLoading, + glutenFreeImage, + veganImage, + vegetarianImage, + hasBadge, + isGlutenFree, + isVegan, + isVegetarian, + } = useDishItemLogic(dish); return ( [styles.container, pressed && styles.pressed]} onPress={onPress}> @@ -21,7 +31,19 @@ export const DishItem: FC = ({ dish, onPress }) => { - + + {hasBadge && ( + + {isGlutenFree && } + {isVegan && } + {isVegetarian && } + + )} ); From 62cc72bdad1ddb11b6c58f8223173fc0ea6da790 Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Fri, 5 Jun 2026 11:45:41 +0200 Subject: [PATCH 07/11] fix(356): architecture rule violation --- .../ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts index e6cdcd6..0f655a6 100644 --- a/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts +++ b/features/trips/ui/pages/DishDetailsModalPage/DishDetailsModalPage.logic.ts @@ -1,4 +1,4 @@ -import { useGetWikimediaDishImage } from '@/features/core/images/facades/useGetWikimediaDishImage'; +import { useGetWikimediaDishImage } from '@/features/core/images'; import { navigationService } from '@/features/core/navigation'; import { useGetTripById } from '@/features/trips/facades/useGetTripById'; import { useLocalSearchParams } from 'expo-router'; From 5291d026abf2a02ae556054aacff8cad1904fe1e Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Fri, 5 Jun 2026 11:53:45 +0200 Subject: [PATCH 08/11] fix(356): use i18n key for ingredients list title Co-Authored-By: Claude Sonnet 4.6 --- features/core/translations/libraries/locales/en.json | 1 + features/core/translations/libraries/locales/it.json | 1 + .../trips/ui/components/IngredientsList/IngredientsList.tsx | 2 +- .../ui/pages/DishDetailsModalPage/DishDetailsModalPage.tsx | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/features/core/translations/libraries/locales/en.json b/features/core/translations/libraries/locales/en.json index fc47cac..f544eeb 100644 --- a/features/core/translations/libraries/locales/en.json +++ b/features/core/translations/libraries/locales/en.json @@ -35,6 +35,7 @@ "DISHES_one": "dish", "DISHES_other": "dishes", "TYPICAL_DISHES": "Typical Dishes", + "INGREDIENTS": "INGREDIENTS", "GLUTEN_FREE": "GLUTEN-FREE", "VEGAN": "VEGAN", "VEGETARIAN": "VEGETARIAN", diff --git a/features/core/translations/libraries/locales/it.json b/features/core/translations/libraries/locales/it.json index 39cb3bc..1997724 100644 --- a/features/core/translations/libraries/locales/it.json +++ b/features/core/translations/libraries/locales/it.json @@ -35,6 +35,7 @@ "DISHES_one": "piatto", "DISHES_other": "piatti", "TYPICAL_DISHES": "Piatti tipici", + "INGREDIENTS": "INGREDIENTI", "GLUTEN_FREE": "SENZA GLUTINE", "VEGAN": "VEGANO", "VEGETARIAN": "VEGETARIANO", diff --git a/features/trips/ui/components/IngredientsList/IngredientsList.tsx b/features/trips/ui/components/IngredientsList/IngredientsList.tsx index 8842c99..980719f 100644 --- a/features/trips/ui/components/IngredientsList/IngredientsList.tsx +++ b/features/trips/ui/components/IngredientsList/IngredientsList.tsx @@ -10,7 +10,7 @@ type IngredientsListProps = { export const IngredientsList: FC = ({ title, ingredients }) => ( - + {ingredients.map(ingredient => ( { ) : ( )} - + From 8296e93b6b113fad9c34aa933690a3bf5a0339c5 Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Fri, 5 Jun 2026 12:04:24 +0200 Subject: [PATCH 09/11] fix(356): add accessibilityLabel to badge image for screen readers Co-Authored-By: Claude Sonnet 4.6 --- features/core/ui/components/composite/Badge/Badge.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/core/ui/components/composite/Badge/Badge.tsx b/features/core/ui/components/composite/Badge/Badge.tsx index 6136ae9..c743e81 100644 --- a/features/core/ui/components/composite/Badge/Badge.tsx +++ b/features/core/ui/components/composite/Badge/Badge.tsx @@ -23,7 +23,7 @@ export const Badge: FC = ({ label, image, backgroundColor, active }) - + Date: Fri, 5 Jun 2026 18:25:44 +0200 Subject: [PATCH 10/11] fix(356): add accessibility role and label to dish item pressable Co-Authored-By: Claude Sonnet 4.6 --- .../components/FoodCard/components/DishItem/DishItem.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx index 7c92c05..23eebac 100644 --- a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx +++ b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx @@ -21,7 +21,12 @@ export const DishItem: FC = ({ dish, onPress }) => { } = useDishItemLogic(dish); return ( - [styles.container, pressed && styles.pressed]} onPress={onPress}> + [styles.container, pressed && styles.pressed]} + onPress={onPress} + accessibilityRole="button" + accessibilityLabel={dish.name} + > {isLoading ? ( From 77b8e9742666d357ee064b031c4e5c9e00979383 Mon Sep 17 00:00:00 2001 From: Timothy Russo Date: Fri, 5 Jun 2026 23:28:39 +0200 Subject: [PATCH 11/11] fix(356): add accessibilityLabel to dietary badge images in dish item Co-Authored-By: Claude Sonnet 4.6 --- .../FoodCard/components/DishItem/DishItem.logic.ts | 3 +++ .../FoodCard/components/DishItem/DishItem.tsx | 13 ++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.logic.ts b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.logic.ts index e9e3018..ba1857c 100644 --- a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.logic.ts +++ b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.logic.ts @@ -19,5 +19,8 @@ export const useDishItemLogic = (dish: TypicalDish) => { isGlutenFree: dish.isGlutenFree, isVegan: dish.isVegan, isVegetarian: dish.isVegetarian, + glutenFreeLabel: 'MY_TRIP.GLUTEN_FREE', + veganLabel: 'MY_TRIP.VEGAN', + vegetarianLabel: 'MY_TRIP.VEGETARIAN', }; }; diff --git a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx index 23eebac..e867e51 100644 --- a/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx +++ b/features/trips/ui/components/FoodCard/components/DishItem/DishItem.tsx @@ -18,6 +18,9 @@ export const DishItem: FC = ({ dish, onPress }) => { isGlutenFree, isVegan, isVegetarian, + glutenFreeLabel, + veganLabel, + vegetarianLabel, } = useDishItemLogic(dish); return ( @@ -44,9 +47,13 @@ export const DishItem: FC = ({ dish, onPress }) => { /> {hasBadge && ( - {isGlutenFree && } - {isVegan && } - {isVegetarian && } + {isGlutenFree && ( + + )} + {isVegan && } + {isVegetarian && ( + + )} )}