diff --git a/apps/admin/data/fitai.db b/apps/admin/data/fitai.db index d626798..f8a1bd1 100644 Binary files a/apps/admin/data/fitai.db and b/apps/admin/data/fitai.db differ diff --git a/apps/mobile/src/components/ScanFoodModal.tsx b/apps/mobile/src/components/ScanFoodModal.tsx index fbeffb9..a69d322 100644 --- a/apps/mobile/src/components/ScanFoodModal.tsx +++ b/apps/mobile/src/components/ScanFoodModal.tsx @@ -5,6 +5,7 @@ import { KeyboardAvoidingView, Modal, Platform, + ScrollView, StyleSheet, Text, TextInput, @@ -244,166 +245,184 @@ export function ScanFoodModal({ behavior={Platform.OS === "ios" ? "padding" : "height"} style={styles.resultContainer} > - - - - - - {notFound ? "Barcode Not Found" : "Food Details"} - - - - - - {!notFound && foodData ? ( - <> - - - - - - - {foodData.name} - {foodData.brand ? ( - {foodData.brand} - ) : null} - {foodData.servingSize} - - - - {foodData.caloriesPerServing} - - kcal per serving - - - - Number of Servings - - - setServings( - String( - Math.max(0.5, parseFloat(servings || "1") - 0.5), - ), - ) - } - style={styles.servingsButton} - > - - - - - setServings(String(parseFloat(servings || "1") + 0.5)) - } - style={styles.servingsButton} - > - - - - - - ) : ( - <> - - We could not find this product in OpenFoodFacts. - - - Food Name - + + + - - Calories - - - kcal - - - )} - - - Meal Type - - {MEAL_TYPES.map((type) => { - const active = mealType === type; - return ( - setMealType(type)} - style={[ - styles.mealTypeChip, - active && styles.mealTypeChipActive, - ]} - > - - {type.charAt(0).toUpperCase() + type.slice(1)} - - - ); - })} - + + + {notFound ? "Barcode Not Found" : "Food Details"} + + - + + + {!notFound && foodData ? ( + <> + + + + + + + {foodData.name} + + {[foodData.brand, foodData.servingSize] + .filter(Boolean) + .join(" • ")} + + + + + {foodData.caloriesPerServing} + + + kcal per serving + + + + + Servings + + + setServings( + String( + Math.max( + 0.5, + parseFloat(servings || "1") - 0.5, + ), + ), + ) + } + style={styles.servingsButton} + > + + + + + setServings( + String(parseFloat(servings || "1") + 0.5), + ) + } + style={styles.servingsButton} + > + + + + + + ) : ( + <> + + We could not find this product in OpenFoodFacts. + + + Food Name + + + Calories + + + kcal + + + )} + + + Meal Type + + {MEAL_TYPES.map((type) => { + const active = mealType === type; + return ( + setMealType(type)} + style={[ + styles.mealTypeChip, + active && styles.mealTypeChipActive, + ]} + > + + {type.charAt(0).toUpperCase() + type.slice(1)} + + + ); + })} + + + + + + Total Calories {getTotalCalories()} kcal - - - - Scan Again - + + + Reject + - - - - {notFound ? "Add Manual" : "Add to Diary"} - - - + + Add to Count + + + )} @@ -463,15 +482,32 @@ const styles = StyleSheet.create({ }, resultContainer: { flex: 1, + backgroundColor: "rgba(0, 0, 0, 0.35)", + justifyContent: "flex-end", + }, + resultSheet: { backgroundColor: theme.colors.background, + borderTopLeftRadius: 24, + borderTopRightRadius: 24, + maxHeight: "80%", }, resultHeader: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", - padding: 20, - paddingTop: 60, + paddingHorizontal: 20, + paddingVertical: 14, backgroundColor: "#fff", + borderTopLeftRadius: 24, + borderTopRightRadius: 24, + borderBottomWidth: 1, + borderBottomColor: theme.colors.gray100, + }, + resultScroll: { + flexGrow: 0, + }, + resultScrollContent: { + paddingBottom: 12, }, resultTitle: { fontSize: 18, @@ -479,46 +515,47 @@ const styles = StyleSheet.create({ color: theme.colors.gray900, }, foodCard: { - margin: 20, - padding: 24, + marginHorizontal: 16, + marginTop: 12, + padding: 16, backgroundColor: "#fff", - borderRadius: 24, + borderRadius: 16, alignItems: "center", ...theme.shadows.medium, }, foodIconContainer: { - marginBottom: 16, + marginBottom: 10, }, foodIcon: { - width: 80, - height: 80, - borderRadius: 40, + width: 64, + height: 64, + borderRadius: 32, justifyContent: "center", alignItems: "center", }, foodName: { - fontSize: 24, + fontSize: 20, fontWeight: "700", color: theme.colors.gray900, - marginBottom: 8, + marginBottom: 4, textAlign: "center", }, - servingSize: { - fontSize: 16, + servingMeta: { + fontSize: 14, color: theme.colors.gray600, - marginBottom: 16, + marginBottom: 12, textAlign: "center", }, caloriesBadge: { backgroundColor: theme.colors.gray50, - paddingHorizontal: 24, - paddingVertical: 16, - borderRadius: 16, + paddingHorizontal: 18, + paddingVertical: 10, + borderRadius: 12, alignItems: "center", - marginBottom: 24, + marginBottom: 14, }, caloriesValue: { - fontSize: 32, + fontSize: 26, fontWeight: "700", color: theme.colors.primary, }, @@ -529,11 +566,11 @@ const styles = StyleSheet.create({ }, servingsContainer: { width: "100%", - marginBottom: 24, + marginBottom: 14, }, mealTypeContainer: { width: "100%", - marginBottom: 24, + marginBottom: 6, }, mealTypeRow: { flexDirection: "row", @@ -615,13 +652,18 @@ const styles = StyleSheet.create({ color: theme.colors.gray500, }, totalCalories: { - width: "100%", + display: "none", + }, + footerSummary: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", - paddingTop: 24, + paddingHorizontal: 20, + paddingTop: 10, + paddingBottom: 10, borderTopWidth: 1, borderTopColor: theme.colors.gray200, + backgroundColor: "#fff", }, totalLabel: { fontSize: 16, @@ -635,17 +677,20 @@ const styles = StyleSheet.create({ }, buttonRow: { flexDirection: "row", - padding: 20, + paddingHorizontal: 20, + paddingTop: 8, + paddingBottom: 16, gap: 12, + backgroundColor: "#fff", }, - rescanButton: { + rejectButton: { flex: 1, paddingVertical: 16, borderRadius: 20, backgroundColor: theme.colors.gray100, alignItems: "center", }, - rescanButtonText: { + rejectButtonText: { fontSize: 16, fontWeight: "700", color: theme.colors.gray700,