diff --git a/example/ios/NutritionUxExample.xcodeproj/xcshareddata/xcschemes/NutritionUxExample.xcscheme b/example/ios/NutritionUxExample.xcodeproj/xcshareddata/xcschemes/NutritionUxExample.xcscheme
index 4042878..30f6f00 100644
--- a/example/ios/NutritionUxExample.xcodeproj/xcshareddata/xcschemes/NutritionUxExample.xcscheme
+++ b/example/ios/NutritionUxExample.xcodeproj/xcshareddata/xcschemes/NutritionUxExample.xcscheme
@@ -50,6 +50,8 @@
ReferencedContainer = "container:NutritionUxExample.xcodeproj">
+
+
void;
+ isColum?: boolean;
+ isCenter?: boolean;
+}
+export interface FiledSelectionViewRef {
+ value: () => string | undefined;
+ errorCheck: () => boolean | undefined;
+}
+
+export const FiledSelectionView = React.forwardRef<
+ FiledSelectionViewRef,
+ Props
+>(
+ (
+ {
+ name,
+ lists,
+ labelList,
+ label,
+ onChange,
+ value: defaultValue,
+ isColum = false,
+ isCenter = false,
+ }: Props,
+ ref: React.Ref
+ ) => {
+ const branding = useBranding();
+
+ const styles = requireNutritionFactStyle(branding);
+ const [value, setValue] = useState(defaultValue);
+ const [error, setError] = useState();
+
+ useImperativeHandle(
+ ref,
+ () => ({
+ value: () => {
+ return value;
+ },
+ errorCheck: () => {
+ if (value === undefined || value?.length === 0) {
+ setError('please enter value');
+ } else {
+ setError(undefined);
+ }
+ return value?.length === 0;
+ },
+ }),
+ [value]
+ );
+
+ const renderFiled = () => {
+ return (
+
+
+ {name}
+
+ {
+ onChange?.(item);
+ setError(undefined);
+ setValue(item);
+ }}
+ lists={lists ?? []}
+ label={label}
+ labelList={labelList}
+ style={styles.pickerTextInput}
+ error={error ?? ''}
+ />
+
+ );
+ };
+
+ return {renderFiled()};
+ }
+);
+
+const requireNutritionFactStyle = ({}: Branding) =>
+ StyleSheet.create({
+ formRow: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginBottom: 10,
+ },
+ formColum: {
+ flexDirection: 'column',
+ justifyContent: 'space-between',
+ marginBottom: 10,
+ },
+ label: {
+ flex: 1,
+ },
+ labelMargin: {
+ marginTop: 10,
+ },
+ pickerTextInput: {
+ flexWrap: 'wrap',
+ textAlign: 'right',
+ },
+ });
diff --git a/src/components/filed/FiledView.tsx b/src/components/filed/FiledView.tsx
new file mode 100644
index 0000000..c182f24
--- /dev/null
+++ b/src/components/filed/FiledView.tsx
@@ -0,0 +1,138 @@
+import React, { useImperativeHandle, useState } from 'react';
+import { Text, TextInput } from '..';
+import {
+ Image,
+ KeyboardTypeOptions,
+ StyleSheet,
+ TouchableOpacity,
+ View,
+} from 'react-native';
+import { Branding, useBranding } from '../../contexts';
+import { scaleHeight } from '../../utils';
+import { ICONS } from '../../assets';
+
+interface Props {
+ name: string;
+ value?: string;
+ label?: string;
+ keyboardType?: KeyboardTypeOptions;
+ isColum?: boolean;
+ onDelete?: () => void;
+}
+
+export interface FiledViewRef {
+ value: () => string | undefined;
+ errorCheck: () => boolean | undefined;
+}
+
+export const FiledView = React.forwardRef(
+ (
+ {
+ name,
+ value: defaultValue,
+ keyboardType = 'decimal-pad',
+ label = 'value',
+ isColum = false,
+ onDelete,
+ }: Props,
+ ref: React.Ref
+ ) => {
+ const branding = useBranding();
+ const [value, setValue] = useState(defaultValue);
+ const [error, setError] = useState();
+
+ const styles = requireNutritionFactStyle(branding);
+
+ useImperativeHandle(
+ ref,
+ () => ({
+ value: () => {
+ return value;
+ },
+ errorCheck: () => {
+ if (value === undefined || value?.length === 0) {
+ setError('please enter value');
+ } else {
+ setError(undefined);
+ }
+ return value?.length === 0;
+ },
+ }),
+ [value]
+ );
+
+ const renderFiled = () => {
+ return (
+
+
+ {name}
+
+ {
+ setValue(text);
+ setError(undefined);
+ }}
+ value={defaultValue}
+ containerStyle={styles.containerTextInput}
+ placeholder={label}
+ error={error}
+ enterKeyHint="next"
+ keyboardType={keyboardType}
+ />
+ {onDelete && (
+
+
+
+ )}
+
+ );
+ };
+
+ return {renderFiled()};
+ }
+);
+
+const requireNutritionFactStyle = ({ white, gray300 }: Branding) =>
+ StyleSheet.create({
+ formRow: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ marginBottom: 10,
+ },
+ formColum: {
+ flexDirection: 'column',
+ justifyContent: 'space-between',
+ marginBottom: 10,
+ },
+ label: {
+ flex: 1,
+ },
+ labelMargin: {
+ marginTop: 10,
+ },
+ delete: {
+ height: 24,
+ width: 24,
+ marginHorizontal: 6,
+ },
+ textInput: {
+ textAlign: 'left',
+ flex: 1,
+ fontWeight: '400',
+ fontSize: 14,
+ backgroundColor: white,
+ borderColor: gray300,
+ paddingVertical: scaleHeight(8),
+ borderRadius: scaleHeight(4),
+ },
+ containerTextInput: {
+ flex: 1,
+ },
+ });
diff --git a/src/components/filed/index.ts b/src/components/filed/index.ts
new file mode 100644
index 0000000..3f64981
--- /dev/null
+++ b/src/components/filed/index.ts
@@ -0,0 +1,2 @@
+export * from './FiledSelectionView';
+export * from './FiledView';
diff --git a/src/components/index.ts b/src/components/index.ts
index 356ce32..ec6124e 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -41,6 +41,8 @@ export * from './weeklyAddhernce';
export * from './progressBard';
export * from './timeStamp';
export * from './mealPlan';
+export * from './tab';
+export * from './filed';
import ActionSheet from './actionSheets/ActionSheet';
export { ActionSheet };
diff --git a/src/components/listPickers/ListPicker.tsx b/src/components/listPickers/ListPicker.tsx
index 399ca81..5fad0e1 100644
--- a/src/components/listPickers/ListPicker.tsx
+++ b/src/components/listPickers/ListPicker.tsx
@@ -18,11 +18,12 @@ interface Props {
labelList?: string[];
value: string;
title: string;
- error: string;
+ error?: string;
style: StyleProp;
label?: string;
extraWidth?: number;
onChange: (size: T) => void;
+ isCenter?: boolean;
}
export const ListPicker: React.FC> = ({
@@ -32,6 +33,8 @@ export const ListPicker: React.FC> = ({
extraWidth,
value,
onChange,
+ isCenter,
+ error,
}) => {
const branding = useBranding();
const styles = menuStyle(branding);
@@ -49,6 +52,8 @@ export const ListPicker: React.FC> = ({
}}
>
> = ({
return (
> = ({
}
>
- {label ?? value}
+
+ {label ?? value}
+
+ {error && (
+
+ {error}
+
+ )}
);
};
diff --git a/src/components/listPickers/menu.styles.tsx b/src/components/listPickers/menu.styles.tsx
index 95d4c7a..6a19ad5 100644
--- a/src/components/listPickers/menu.styles.tsx
+++ b/src/components/listPickers/menu.styles.tsx
@@ -2,11 +2,11 @@ import { StyleSheet } from 'react-native';
import type { Branding } from '../../contexts';
import { scaleHeight, scaleWidth } from '../../utils';
-const menuStyle = ({ white, border }: Branding) =>
+const menuStyle = ({ white, gray300, border, error }: Branding) =>
StyleSheet.create({
main: {
backgroundColor: white,
- borderColor: border,
+ borderColor: gray300,
flexDirection: 'row',
borderRadius: 4,
paddingVertical: 8,
@@ -17,13 +17,16 @@ const menuStyle = ({ white, border }: Branding) =>
mainTitle: {
flex: 1,
marginStart: 12,
- textTransform: 'capitalize',
},
icon: {
marginEnd: 12,
height: scaleHeight(20),
width: scaleWidth(20),
},
+ error: {
+ color: error,
+ },
+
optionContainer: {
backgroundColor: white,
paddingVertical: scaleHeight(16),
@@ -33,7 +36,6 @@ const menuStyle = ({ white, border }: Branding) =>
},
optionTitle: {
marginStart: scaleWidth(12),
- textTransform: 'capitalize',
},
optionIcon: {
height: scaleHeight(20),
diff --git a/src/components/logOptions/LogOptions.tsx b/src/components/logOptions/LogOptions.tsx
index ea92f92..418ee3f 100644
--- a/src/components/logOptions/LogOptions.tsx
+++ b/src/components/logOptions/LogOptions.tsx
@@ -13,6 +13,7 @@ interface Props {
onTakePicture: () => void;
onTakeCamera: () => void;
onAiAdvisor: () => void;
+ onMyFoods: () => void;
}
type Type = 'All' | 'UseImage';
@@ -45,6 +46,7 @@ export const LogOptions = ({
{type === 'All' ? (
<>
+ {/* {renderItem(ICONS.logOptionFavorite, 'My Foods', onMyFoods)} */}
{renderItem(ICONS.logOptionFavorite, 'Favorites', onFavorite)}
{renderItem(ICONS.Mic, 'Voice Logging', onVoiceLogging)}
{renderItem(ICONS.AIAdvisor, 'AI Advisor', onAiAdvisor)}
diff --git a/src/components/picker/Picker.tsx b/src/components/picker/Picker.tsx
index 5a998c9..af7c92e 100644
--- a/src/components/picker/Picker.tsx
+++ b/src/components/picker/Picker.tsx
@@ -3,13 +3,14 @@ import { View, Modal, Pressable, Platform } from 'react-native';
import { useBranding } from '../../contexts';
import tutorialStyle from './picker.styles';
import { Card } from '../cards';
-import { scaleWidth } from '../../utils';
+import { scaleWidth, screenHeight } from '../../utils';
interface PickerProps extends React.PropsWithChildren {
top?: boolean;
bottom?: boolean;
options: React.JSX.Element;
extraWidth?: number;
+ isCenter?: boolean;
}
export interface PickerRef {
onClose: () => void;
@@ -46,7 +47,7 @@ export const Picker = React.forwardRef(
(fx: number, fy: number, width: number, height: number) => {
const newMeasure: Matrix = {
x: fx,
- y: fy,
+ y: props.isCenter ? screenHeight / 2 : fy,
width: width,
height: height,
};
diff --git a/src/components/tab/TabBar.tsx b/src/components/tab/TabBar.tsx
new file mode 100644
index 0000000..228b399
--- /dev/null
+++ b/src/components/tab/TabBar.tsx
@@ -0,0 +1,91 @@
+import React, { useState } from 'react';
+import { StyleSheet, TouchableOpacity, View } from 'react-native';
+import { Text } from '../../components';
+import { Branding, useBranding } from '../../contexts';
+import { scaleHeight } from '../../utils';
+
+export interface TabBarProps {
+ list: string[];
+ onTabSelect: (value: string) => void;
+}
+
+export const TabBar = ({ list, onTabSelect }: TabBarProps) => {
+ const styles = tabStyles(useBranding());
+ const [tab, setTab] = useState(list[0]);
+
+ return (
+
+
+ {
+ setTab(list[0]);
+ onTabSelect(list[0]);
+ }}
+ >
+
+ {list[0]}
+
+
+ {
+ setTab(list[1]);
+ onTabSelect(list[1]);
+ }}
+ >
+
+ {list[1]}
+
+
+
+
+
+
+
+
+ );
+};
+
+const tabStyles = ({ primaryColor, text }: Branding) =>
+ StyleSheet.create({
+ tabContainer: {
+ flexDirection: 'row',
+ paddingVertical: scaleHeight(12),
+ },
+ touchableTab: {
+ flex: 1,
+ },
+ tabTex: {
+ fontSize: 18,
+ fontWeight: '400',
+ textAlign: 'center',
+ color: text,
+ },
+ tabSelectText: {
+ fontWeight: '600',
+ color: primaryColor,
+ },
+ lineContainer: {
+ flexDirection: 'row',
+ },
+ tabLine: {
+ height: 2,
+ borderRadius: 24,
+ flex: 1,
+ },
+ tabSelectLine: {
+ backgroundColor: primaryColor,
+ },
+ });
diff --git a/src/components/tab/index.ts b/src/components/tab/index.ts
new file mode 100644
index 0000000..832e14a
--- /dev/null
+++ b/src/components/tab/index.ts
@@ -0,0 +1 @@
+export * from './TabBar';
diff --git a/src/constants/colors.ts b/src/constants/colors.ts
index a4d66c4..a077578 100644
--- a/src/constants/colors.ts
+++ b/src/constants/colors.ts
@@ -20,7 +20,7 @@ export const COLORS = {
grayscale: '#6E7191',
grayscaleAsh: '#262338',
grayscaleBody: '#4E4B66',
- grayscaleLine: '#D9DBE9',
+ grayscaleLine: '#D1D5DB',
grayscaleInput: '#EFF0F6',
grey9: '#D0D3DA',
monochrome: '#6E7191',
diff --git a/src/navigaitons/BottomTabNavigations.tsx b/src/navigaitons/BottomTabNavigations.tsx
index 39db9ec..ce0f537 100644
--- a/src/navigaitons/BottomTabNavigations.tsx
+++ b/src/navigaitons/BottomTabNavigations.tsx
@@ -23,6 +23,7 @@ export interface TabBarProps extends BottomTabBarProps {
onTakePicture: () => void;
onTakeCamera: () => void;
onAiAdvisor: () => void;
+ onMyFoods: () => void;
}
export const renderTabBarIcons = (
diff --git a/src/navigaitons/HomeBottomNavigations.tsx b/src/navigaitons/HomeBottomNavigations.tsx
index 64c52fa..bcea557 100644
--- a/src/navigaitons/HomeBottomNavigations.tsx
+++ b/src/navigaitons/HomeBottomNavigations.tsx
@@ -144,6 +144,12 @@ export const HomeBottomNavigation = React.memo(() => {
logToMeal: undefined,
});
}}
+ onMyFoods={() => {
+ navigation.navigate('MyFoodsScreen', {
+ logToDate: mealLogDateRef.current,
+ logToMeal: undefined,
+ });
+ }}
onTakePicture={onTakePicture}
{...props}
items={menu}
diff --git a/src/navigaitons/Nutrition-Navigator.tsx b/src/navigaitons/Nutrition-Navigator.tsx
index dcfec6f..a9fd3f7 100644
--- a/src/navigaitons/Nutrition-Navigator.tsx
+++ b/src/navigaitons/Nutrition-Navigator.tsx
@@ -19,6 +19,8 @@ import {
TakePictureScreen,
AdvisorScreen,
ImagePickerScreen,
+ MyFoodsScreen,
+ FoodCreatorScreen,
} from '../screens';
import {
DashboardScreenRoute,
@@ -44,6 +46,8 @@ import {
TakePictureScreenRoute,
AdvisorScreenRoute,
ImagePickerScreenRoute,
+ MyFoodsScreenRoute,
+ FoodCreatorScreenRoute,
} from './Route';
import MyPlanScreen from '../screens/myPlans/MyPlanScreen';
import { HomeBottomNavigation } from './HomeBottomNavigations';
@@ -201,6 +205,16 @@ export const NutritionNavigator = () => {
name={ImagePickerScreenRoute}
component={ImagePickerScreen}
/>
+
+
{
floatingRef.current?.onClose();
props.onAiAdvisor();
}}
+ onMyFoods={() => {
+ floatingRef.current?.onClose();
+ props.onMyFoods();
+ }}
/>
}
/>
diff --git a/src/navigaitons/params/NutritionNavigatorParam.ts b/src/navigaitons/params/NutritionNavigatorParam.ts
index c0f4a90..0229789 100644
--- a/src/navigaitons/params/NutritionNavigatorParam.ts
+++ b/src/navigaitons/params/NutritionNavigatorParam.ts
@@ -60,6 +60,14 @@ export interface AdvisorScreenProps {
logToDate?: Date | undefined;
logToMeal?: MealLabel | undefined;
}
+export interface FoodCreatorNavProps {
+ logToDate?: Date | undefined;
+ logToMeal?: MealLabel | undefined;
+}
+export interface MyFoodsScreenNavProps {
+ logToDate?: Date | undefined;
+ logToMeal?: MealLabel | undefined;
+}
export type ParamList = {
MealLogScreen: MealLogScreenProps;
@@ -89,4 +97,6 @@ export type ParamList = {
TakePictureScreen: TakePictureScreenProps;
AdvisorScreen: AdvisorScreenProps;
ImagePickerScreen: ImagePickerProps;
+ FoodCreatorScreen: FoodCreatorNavProps;
+ MyFoodsScreen: MyFoodsScreenNavProps;
};
diff --git a/src/screens/advisor/AdvisorScreen.tsx b/src/screens/advisor/AdvisorScreen.tsx
index 996f961..1c80766 100644
--- a/src/screens/advisor/AdvisorScreen.tsx
+++ b/src/screens/advisor/AdvisorScreen.tsx
@@ -110,6 +110,7 @@ export const AdvisorScreen = () => {
keyExtractor={(_item, index) => index.toString()}
renderItem={renderItem}
showsVerticalScrollIndicator={false}
+ contentContainerStyle={{ flexGrow: 1 }}
style={styles.flatListStyle}
// onContentSizeChange={() => listRef.current?.scrollToEnd()}
// onLayout={() => listRef.current?.scrollToEnd()}
diff --git a/src/screens/advisor/view/BottomBar.tsx b/src/screens/advisor/view/BottomBar.tsx
index ec5862d..6daa06f 100644
--- a/src/screens/advisor/view/BottomBar.tsx
+++ b/src/screens/advisor/view/BottomBar.tsx
@@ -35,44 +35,55 @@ export const BottomBar = ({
return (
- {isOptionShow ? (
-
-
-
-
+ {inputValue.length === 0 && (
+ <>
+ {isOptionShow ? (
+
+
+
+
-
-
-
-
- ) : (
-
-
-
+
+
+
+
+ ) : (
+
+
+
+ )}
+ >
)}
- {renderText()}
+
+
+ {renderText()}
+
{tools && tools?.length > 0 && (
)}
-
+
);
};
@@ -98,7 +105,6 @@ const ResponseViewStyle = () =>
},
receivedMsgView: {
backgroundColor: '#6366F1',
- alignSelf: 'flex-start',
borderBottomRightRadius: 8,
borderBottomLeftRadius: 0,
},
diff --git a/src/screens/foodCreator/FoodCreator.styles.ts b/src/screens/foodCreator/FoodCreator.styles.ts
new file mode 100644
index 0000000..ba70ec2
--- /dev/null
+++ b/src/screens/foodCreator/FoodCreator.styles.ts
@@ -0,0 +1,15 @@
+import { StyleSheet } from 'react-native';
+import { getStatusBarHeight } from 'react-native-status-bar-height';
+import type { Branding } from '../../contexts';
+
+export const foodCreatorStyle = ({ searchBody }: Branding) =>
+ StyleSheet.create({
+ statusBarLayout: {
+ height: getStatusBarHeight(),
+ backgroundColor: searchBody,
+ },
+ body: {
+ backgroundColor: searchBody,
+ flex: 1,
+ },
+ });
diff --git a/src/screens/foodCreator/FoodCreatorScreen.tsx b/src/screens/foodCreator/FoodCreatorScreen.tsx
new file mode 100644
index 0000000..73b287c
--- /dev/null
+++ b/src/screens/foodCreator/FoodCreatorScreen.tsx
@@ -0,0 +1,63 @@
+import { ScrollView, View } from 'react-native';
+
+import React from 'react';
+import { foodCreatorStyle } from './FoodCreator.styles';
+import { useFoodCreator } from './useFoodCreator';
+import { BackNavigation, BasicButton } from '../../components';
+import { FoodCreatorFoodDetail } from './views/FoodCreatorFoodDetail';
+import { RequireNutritionFacts } from './views/RequireNutritionFacts';
+import { OtherNutritionFacts } from './views/OtherNutritionFacts';
+
+export const FoodCreatorScreen = () => {
+ const {
+ branding,
+ otherNutritionFactsRef,
+ requireNutritionFactsRef,
+ foodCreatorFoodDetailRef,
+ onSavePress,
+ } = useFoodCreator();
+
+ const styles = foodCreatorStyle(branding);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/screens/foodCreator/data.ts b/src/screens/foodCreator/data.ts
new file mode 100644
index 0000000..1316467
--- /dev/null
+++ b/src/screens/foodCreator/data.ts
@@ -0,0 +1,34 @@
+import type { NutrientType } from '../../models';
+
+export const Units = [
+ 'Servings',
+ 'Piece',
+ 'cup',
+ 'oz',
+ 'g',
+ 'ml',
+ 'handful',
+ 'scoop',
+ 'tbsp',
+ 'tsp',
+ 'slice',
+ 'can',
+ 'bottle',
+ 'bar',
+ 'packet',
+];
+
+export const OtherNutrients: NutrientType[] = [
+ 'satFat',
+ 'transFat',
+ 'cholesterol',
+ 'sodium',
+ 'fiber',
+ 'sugars',
+ 'sugarAdded',
+ 'vitaminD',
+ 'calcium',
+ 'iron',
+ 'potassium',
+];
+export const Weights = ['grams', 'ml'];
diff --git a/src/screens/foodCreator/index.tsx b/src/screens/foodCreator/index.tsx
new file mode 100644
index 0000000..df80ca5
--- /dev/null
+++ b/src/screens/foodCreator/index.tsx
@@ -0,0 +1 @@
+export * from './FoodCreatorScreen';
diff --git a/src/screens/foodCreator/useFoodCreator.ts b/src/screens/foodCreator/useFoodCreator.ts
new file mode 100644
index 0000000..8f8bf77
--- /dev/null
+++ b/src/screens/foodCreator/useFoodCreator.ts
@@ -0,0 +1,36 @@
+import { useRef } from 'react';
+import { useBranding } from '../../contexts';
+import type { OtherNutritionFactsRef } from './views/OtherNutritionFacts';
+import type { RequireNutritionFactsRef } from './views/RequireNutritionFacts';
+import type { FoodCreatorFoodDetailRef } from './views/FoodCreatorFoodDetail';
+
+export const useFoodCreator = () => {
+ const branding = useBranding();
+ const otherNutritionFactsRef = useRef(null);
+ const requireNutritionFactsRef = useRef(null);
+ const foodCreatorFoodDetailRef = useRef(null);
+
+ const onSavePress = () => {
+ const info = foodCreatorFoodDetailRef.current?.getValue();
+ const requireNutritionFact = requireNutritionFactsRef.current?.getValue();
+ const otherNutritionFact = otherNutritionFactsRef.current?.getValue();
+
+ if (info?.isNotValid) {
+ return;
+ }
+ if (requireNutritionFact?.isNotValid) {
+ return;
+ }
+ if (otherNutritionFact?.isNotValid) {
+ return;
+ }
+ };
+
+ return {
+ branding,
+ otherNutritionFactsRef,
+ requireNutritionFactsRef,
+ foodCreatorFoodDetailRef,
+ onSavePress,
+ };
+};
diff --git a/src/screens/foodCreator/views/FoodCreatorFoodDetail.tsx b/src/screens/foodCreator/views/FoodCreatorFoodDetail.tsx
new file mode 100644
index 0000000..8715dbc
--- /dev/null
+++ b/src/screens/foodCreator/views/FoodCreatorFoodDetail.tsx
@@ -0,0 +1,151 @@
+import React, { useImperativeHandle, useMemo, useRef } from 'react';
+import { Card, Text } from '../../../components';
+import { Image, StyleSheet, View } from 'react-native';
+import { Branding, useBranding } from '../../../contexts';
+import { FiledView, FiledViewRef } from '../../../components/filed/FiledView';
+import {
+ FiledSelectionView,
+ FiledSelectionViewRef,
+} from '../../../components/filed/FiledSelectionView';
+import { Units } from '../data';
+import { ICONS } from '../../../assets';
+
+interface Props {}
+
+export type FoodCreatorFoodDetailType = 'name' | 'brand' | 'barcode';
+
+interface Value {
+ records: Record;
+ isNotValid?: boolean;
+}
+
+export interface FoodCreatorFoodDetailRef {
+ getValue: () => Value;
+}
+
+export const FoodCreatorFoodDetail = React.forwardRef<
+ FoodCreatorFoodDetailRef,
+ Props
+>(({}: Props, ref: React.Ref) => {
+ const branding = useBranding();
+
+ const styles = requireNutritionFactStyle(branding);
+
+ const nameRef = useRef(null);
+ const brandNameRef = useRef(null);
+ const barcodeRef = useRef(null);
+
+ const refs = useMemo(
+ () => ({
+ name: nameRef,
+ brand: brandNameRef,
+ barcode: barcodeRef,
+ }),
+ []
+ );
+
+ useImperativeHandle(
+ ref,
+ () => ({
+ getValue: () => {
+ let record: Record = {} as Record<
+ FoodCreatorFoodDetailType,
+ string
+ >;
+ let isNotValid = false;
+
+ (Object.keys(refs) as FoodCreatorFoodDetailType[]).forEach((key) => {
+ const currentRef = refs[key].current;
+ const value = currentRef?.value();
+ currentRef?.errorCheck();
+ if (value === undefined || value.length === 0) {
+ isNotValid = true;
+ }
+ record[key] = value ?? '';
+ });
+
+ return {
+ records: record,
+ isNotValid,
+ };
+ },
+ }),
+ [refs]
+ );
+
+ return (
+
+ {
+
+ {'Scan Description'}
+
+
+
+
+ {'Edit Image'}
+
+
+
+
+
+
+
+
+
+ }
+
+ );
+});
+
+const requireNutritionFactStyle = ({}: Branding) =>
+ StyleSheet.create({
+ card: {
+ marginHorizontal: 16,
+ marginVertical: 16,
+ padding: 16,
+ },
+ title: {
+ marginBottom: 16,
+ },
+ container: {
+ flexDirection: 'row',
+ alignContent: 'space-around',
+ justifyContent: 'space-between',
+ },
+ left: {
+ flex: 1,
+ alignContent: 'center',
+ alignItems: 'center',
+ alignSelf: 'center',
+ },
+ right: {
+ flex: 1.5,
+ },
+ editImage: {
+ marginVertical: 4,
+ fontSize: 10,
+ },
+ icon: {
+ height: 80,
+ width: 80,
+ alignItems: 'center',
+ alignSelf: 'center',
+ justifyContent: 'center',
+ alignContent: 'center',
+ },
+ });
diff --git a/src/screens/foodCreator/views/OtherNutritionFacts.tsx b/src/screens/foodCreator/views/OtherNutritionFacts.tsx
new file mode 100644
index 0000000..8328df4
--- /dev/null
+++ b/src/screens/foodCreator/views/OtherNutritionFacts.tsx
@@ -0,0 +1,130 @@
+import React, { useImperativeHandle, useRef, useState } from 'react';
+import { Card, Text } from '../../../components';
+import { StyleSheet, View } from 'react-native';
+import { Branding, useBranding } from '../../../contexts';
+import { FiledView, FiledViewRef } from '../../../components/filed/FiledView';
+import { FiledSelectionView } from '../../../components/filed/FiledSelectionView';
+import { OtherNutrients } from '../data';
+import { FlatList } from 'react-native';
+import { nutrientName, type NutrientType } from '../../../models';
+
+interface Props {}
+
+interface Value {
+ records: Record;
+ isNotValid?: boolean;
+}
+export interface OtherNutritionFactsRef {
+ getValue: () => Value;
+}
+
+export const OtherNutritionFacts = React.forwardRef<
+ OtherNutritionFactsRef,
+ Props
+>(({}: Props, ref: React.Ref) => {
+ const branding = useBranding();
+
+ const styles = requireNutritionFactStyle(branding);
+ const [defaultList, setDefaultList] =
+ useState(OtherNutrients);
+ const [list, setList] = useState([]);
+ const labelList = defaultList.map((i) => {
+ return nutrientName[i].toString() ?? '';
+ });
+
+ const refs = useRef>>({});
+
+ useImperativeHandle(
+ ref,
+ () => ({
+ getValue: () => {
+ let record: Record = {} as Record<
+ NutrientType,
+ string
+ >;
+ let isNotValid = false;
+ list.forEach((item) => {
+ const sleetedRef = refs.current[item];
+ if (sleetedRef && sleetedRef.current) {
+ if (sleetedRef.current.errorCheck()) {
+ isNotValid = true;
+ }
+ record[item as NutrientType] = sleetedRef.current.value() ?? '';
+ }
+ });
+
+ return {
+ records: record,
+ isNotValid: isNotValid,
+ };
+ },
+ }),
+ [list]
+ );
+
+ // Initialize refs for each item in the list
+ list.forEach((item) => {
+ if (!refs.current[item]) {
+ refs.current[item] = React.createRef();
+ }
+ });
+
+ return (
+
+ {
+
+ {'Other Nutrition Facts'}
+ item}
+ renderItem={({ item }) => {
+ return (
+ {
+ setList((i) => [...i.filter((o) => item !== o)]);
+ setDefaultList((i) => [...i, item as NutrientType]);
+ }}
+ />
+ );
+ }}
+ />
+ {defaultList.length > 0 && (
+ {
+ setList((i) => [...i, item]);
+ setDefaultList((i) => [...i.filter((o) => item !== o)]);
+ }}
+ />
+ )}
+
+ }
+
+ );
+});
+
+const requireNutritionFactStyle = ({}: Branding) =>
+ StyleSheet.create({
+ card: {
+ marginHorizontal: 16,
+ marginVertical: 16,
+ padding: 16,
+ },
+ title: {
+ marginBottom: 16,
+ },
+ container: {
+ flexDirection: 'row',
+ alignContent: 'space-around',
+ justifyContent: 'space-between',
+ },
+ });
diff --git a/src/screens/foodCreator/views/RequireNutritionFacts.tsx b/src/screens/foodCreator/views/RequireNutritionFacts.tsx
new file mode 100644
index 0000000..0d5c47c
--- /dev/null
+++ b/src/screens/foodCreator/views/RequireNutritionFacts.tsx
@@ -0,0 +1,124 @@
+import React, { useImperativeHandle, useRef, useState, useMemo } from 'react';
+import { Card, FiledViewRef, Text } from '../../../components';
+import { StyleSheet, View } from 'react-native';
+import { Branding, useBranding } from '../../../contexts';
+import { FiledView } from '../../../components';
+import {
+ FiledSelectionView,
+ FiledSelectionViewRef,
+} from '../../../components/filed/FiledSelectionView';
+import { Units, Weights } from '../data';
+
+interface Props {}
+
+export type RequireNutritionFactsType =
+ | 'calories'
+ | 'ServingSize'
+ | 'Units'
+ | 'Weight'
+ | 'Fat'
+ | 'Carbs'
+ | 'Protein';
+
+interface Value {
+ records: Record;
+ isNotValid?: boolean;
+}
+
+export interface RequireNutritionFactsRef {
+ getValue: () => Value;
+}
+
+export const RequireNutritionFacts = React.forwardRef<
+ RequireNutritionFactsRef,
+ Props
+>(({}: Props, ref: React.Ref) => {
+ const branding = useBranding();
+ const styles = requireNutritionFactStyle(branding);
+
+ const [units, setUnits] = useState('');
+
+ const servingSizeRef = useRef(null);
+ const caloriesRef = useRef(null);
+ const fatRef = useRef(null);
+ const carbsRef = useRef(null);
+ const proteinRef = useRef(null);
+ const unitRef = useRef(null);
+ const weightRef = useRef(null);
+
+ const refs = useMemo(
+ () => ({
+ ServingSize: servingSizeRef,
+ Units: unitRef,
+ Weight: weightRef,
+ calories: caloriesRef,
+ Fat: fatRef,
+ Carbs: carbsRef,
+ Protein: proteinRef,
+ }),
+ []
+ );
+
+ useImperativeHandle(
+ ref,
+ () => ({
+ getValue: () => {
+ let record: Record = {} as Record<
+ RequireNutritionFactsType,
+ string
+ >;
+ let isNotValid = false;
+
+ (Object.keys(refs) as RequireNutritionFactsType[]).forEach((key) => {
+ const currentRef = refs[key].current;
+ const value = currentRef?.value();
+ currentRef?.errorCheck();
+ if (value === undefined || value.length === 0) {
+ isNotValid = true;
+ }
+ record[key] = value ?? '';
+ });
+
+ return {
+ records: record,
+ isNotValid,
+ };
+ },
+ }),
+ [refs]
+ );
+
+ return (
+
+
+ {'Required Nutrition Facts'}
+
+ setUnits(value)}
+ />
+ {units === 'g' || units === 'ml' ? null : (
+
+ )}
+
+
+
+
+
+
+ );
+});
+
+const requireNutritionFactStyle = ({}: Branding) =>
+ StyleSheet.create({
+ card: {
+ marginHorizontal: 16,
+ marginVertical: 16,
+ padding: 16,
+ },
+ title: {
+ marginBottom: 16,
+ },
+ });
diff --git a/src/screens/index.tsx b/src/screens/index.tsx
index a3b32e3..a296d0d 100644
--- a/src/screens/index.tsx
+++ b/src/screens/index.tsx
@@ -21,3 +21,5 @@ export * from './voiceLogging';
export * from './takePicture';
export * from './advisor';
export * from './imagePicker';
+export * from './foodCreator';
+export * from './myFoods';
diff --git a/src/screens/myFoods/MyFoodsScreen.styles.ts b/src/screens/myFoods/MyFoodsScreen.styles.ts
new file mode 100644
index 0000000..299e27b
--- /dev/null
+++ b/src/screens/myFoods/MyFoodsScreen.styles.ts
@@ -0,0 +1,22 @@
+import { StyleSheet } from 'react-native';
+import { getStatusBarHeight } from 'react-native-status-bar-height';
+import type { Branding } from '../../contexts';
+
+export const myFoodScreenStyle = ({ searchBody }: Branding) =>
+ StyleSheet.create({
+ statusBarLayout: {
+ height: getStatusBarHeight(),
+ backgroundColor: searchBody,
+ },
+ body: {
+ backgroundColor: searchBody,
+ flex: 1,
+ },
+ container: {
+ flex: 1,
+ },
+ button: {
+ marginVertical: 24,
+ marginHorizontal: 16,
+ },
+ });
diff --git a/src/screens/myFoods/MyFoodsScreen.tsx b/src/screens/myFoods/MyFoodsScreen.tsx
new file mode 100644
index 0000000..306a2af
--- /dev/null
+++ b/src/screens/myFoods/MyFoodsScreen.tsx
@@ -0,0 +1,47 @@
+import { View } from 'react-native';
+
+import React from 'react';
+import { myFoodScreenStyle } from './MyFoodsScreen.styles';
+import { useMyFoodScreen } from './useMyFoodScreen';
+import { BackNavigation, BasicButton, TabBar } from '../../components';
+import { useNavigation } from '@react-navigation/native';
+import type { StackNavigationProp } from '@react-navigation/stack';
+import type { ParamList } from '../../navigaitons';
+import { useSharedValue } from 'react-native-reanimated';
+
+type ScreenNavigationProps = StackNavigationProp;
+
+const TabList = ['Custom Foods', 'Recipe'];
+
+export const MyFoodsScreen = () => {
+ const { branding } = useMyFoodScreen();
+ const navigation = useNavigation();
+ const tab = useSharedValue(TabList[0]);
+
+ const styles = myFoodScreenStyle(branding);
+
+ const renderTab = () => {
+ return (
+ {
+ tab.value = value;
+ }}
+ />
+ );
+ };
+
+ return (
+
+
+
+ {
+ navigation.navigate('FoodCreatorScreen', {});
+ }}
+ />
+
+ );
+};
diff --git a/src/screens/myFoods/index.tsx b/src/screens/myFoods/index.tsx
new file mode 100644
index 0000000..25009ff
--- /dev/null
+++ b/src/screens/myFoods/index.tsx
@@ -0,0 +1 @@
+export * from './MyFoodsScreen';
diff --git a/src/screens/myFoods/useMyFoodScreen.ts b/src/screens/myFoods/useMyFoodScreen.ts
new file mode 100644
index 0000000..d4cb24d
--- /dev/null
+++ b/src/screens/myFoods/useMyFoodScreen.ts
@@ -0,0 +1,9 @@
+import { useBranding } from '../../contexts';
+
+export const useMyFoodScreen = () => {
+ const branding = useBranding();
+
+ return {
+ branding,
+ };
+};