diff --git a/package.json b/package.json index 260d484..234e932 100644 --- a/package.json +++ b/package.json @@ -15,13 +15,14 @@ "@react-navigation/stack": "^6.0.11", "@reduxjs/toolkit": "^1.6.2", "expo": "~43.0.0", + "expo-image-picker": "^11.0.3", "expo-status-bar": "~1.1.0", "react": "17.0.1", "react-dom": "17.0.1", "react-native": "0.64.2", + "react-native-animatable": "^1.3.3", "react-native-gesture-handler": "~1.10.2", "react-native-modal": "^13.0.0", - "react-native-reanimated": "~2.2.0", "react-native-safe-area-context": "3.3.2", "react-native-screens": "~3.8.0", "react-native-vector-icons": "^9.0.0", diff --git a/src/App.js b/src/App.js index d8d7f4b..1d50e07 100644 --- a/src/App.js +++ b/src/App.js @@ -54,6 +54,7 @@ function App() { + ); diff --git a/src/components/Dropdown.js b/src/components/Dropdown.js index ea33f89..e36dcd4 100644 --- a/src/components/Dropdown.js +++ b/src/components/Dropdown.js @@ -48,7 +48,7 @@ const Dropdown = (props) => { ) }) return ( - + {dropdownList} ) diff --git a/src/components/GroceryList/groceries/List.js b/src/components/GroceryList/groceries/List.js index e6454c9..41dfbd6 100644 --- a/src/components/GroceryList/groceries/List.js +++ b/src/components/GroceryList/groceries/List.js @@ -88,7 +88,7 @@ export default React.memo((props) => { < WrapperList listLength={items.length} onLayout={(event) => { HandleAnimation(event) }}> {list.open && Add a grocery} data={filteredItems} diff --git a/src/components/GroceryList/groceries/ListedItem.js b/src/components/GroceryList/groceries/ListedItem.js index 1f9581e..e7d5775 100644 --- a/src/components/GroceryList/groceries/ListedItem.js +++ b/src/components/GroceryList/groceries/ListedItem.js @@ -7,18 +7,19 @@ import { CheckButton } from '../../../styles/componentBlueprints'; import { useSelector, useDispatch, shallowEqual } from 'react-redux'; import { selectItemById, checkToggle, modalToggle } from '../../../redux/slices/groceryList/itemsSlice' import { findTag } from '../../../redux/slices/groceryList/tagsSlice' +import { toggleOffAnim, toggleOnAnim } from '../../../styles/animations'; const ListedItem = React.memo((props) => { const dispatch = useDispatch() const item = useSelector(state => selectItemById(state, props.item._id), shallowEqual) const tag = useSelector(state => findTag(state, item.tag)) return ( - - + + { props.setVisible(true); return dispatch(modalToggle(item._id)) }}> {item.productName} {item.details != "" && {item.details}} - {item.amount.am}{item.amount.qt && " " + item.amount.qt} + {item.amount.am}{item.amount.qt && " x (" + item.amount.qt + ")"} {item.person != "" && {item.person}} diff --git a/src/components/GroceryList/groceries/styles/listedItem.js b/src/components/GroceryList/groceries/styles/listedItem.js index 7ea14b4..6431951 100644 --- a/src/components/GroceryList/groceries/styles/listedItem.js +++ b/src/components/GroceryList/groceries/styles/listedItem.js @@ -1,4 +1,7 @@ +import * as Animatable from 'react-native-animatable'; + import { Text, View, Image, TouchableOpacity} from 'react-native' + import styled, { css } from 'styled-components' export const Wrapper = styled(View)` @@ -8,7 +11,7 @@ export const Wrapper = styled(View)` justify-content: flex-start; width: 100%; ` -export const DarkLayer = styled(View)` +export const DarkLayer = styled(Animatable.View)` background-color: ${({ theme }) => theme.colors.dp00}; display: flex; flex: 1; @@ -31,7 +34,7 @@ export const WrapperItem = styled(TouchableOpacity)` background-color: ${props => props.checked ? props.theme.colors.itemSelected : props.color + '66'}; ` export const WrapperButton = styled(TouchableOpacity)` - height: 30px; + min-height: 40px; width: 40px; ` export const TextProductName = styled(Text)` diff --git a/src/components/GroceryList/products/ListedProduct.js b/src/components/GroceryList/products/ListedProduct.js index 75bd39f..69a43d9 100644 --- a/src/components/GroceryList/products/ListedProduct.js +++ b/src/components/GroceryList/products/ListedProduct.js @@ -1,4 +1,5 @@ import React from 'react' +import * as Animatable from 'react-native-animatable'; //components //styling import { Wrapper, WrapperProduct, WrapperButton, WrapperText, TextProductName, TextTag, TextPrice, StyledImage, IconCheck } from './styles/listedProduct' @@ -7,6 +8,7 @@ import { useSelector, useDispatch, shallowEqual } from 'react-redux'; import { selectProductById, checkToggle, modalToggle } from '../../../redux/slices/groceryList/productsSlice' import { findTag } from '../../../redux/slices/groceryList/tagsSlice' import { CheckButton } from '../../../styles/componentBlueprints'; +import { toggleOffAnim, toggleOnAnim } from '../../../styles/animations'; const ListedProduct = React.memo((props) => { const dispatch = useDispatch() @@ -14,14 +16,16 @@ const ListedProduct = React.memo((props) => { const tag = useSelector(state => findTag(state, product.tag)) return ( - { props.setVisible(true); return dispatch(modalToggle(product._id)) }}> - - {product.productName} - {tag.tagName} - {product.price !== 0 && € {product.price}} - - {product.image != "" && } - + + { props.setVisible(true); return dispatch(modalToggle(product._id)) }}> + + {product.productName} + {tag.tagName} + {product.price !== 0 && € {product.price}} + + {product.image != "" && } + + dispatch(checkToggle(product._id))} > diff --git a/src/components/GroceryList/products/styles/listedProduct.js b/src/components/GroceryList/products/styles/listedProduct.js index accdc14..be9082f 100644 --- a/src/components/GroceryList/products/styles/listedProduct.js +++ b/src/components/GroceryList/products/styles/listedProduct.js @@ -17,8 +17,7 @@ export const Wrapper = styled(View)` export const WrapperProduct = styled(TouchableOpacity)` box-shadow: ${({theme})=> theme.colors.shadow}; display: flex; - flex: 1; - width: 100%; + width: 98%; min-height: 70px; position: relative; flex-direction: row; @@ -30,7 +29,7 @@ export const WrapperProduct = styled(TouchableOpacity)` background-color: ${props => props.checked ? props.theme.colors.itemSelected : props.color + '66'}; ` export const WrapperButton = styled(TouchableOpacity)` - height: 60px; + height: 70px; width: 40px; ` diff --git a/src/components/Header.js b/src/components/Header.js index dc35a46..3879047 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -5,7 +5,7 @@ import { useHeaderHeight } from '@react-navigation/elements'; const HeaderPadding = (props) => { const headerHeight = useHeaderHeight(); return ( - + ) } export default HeaderPadding; \ No newline at end of file diff --git a/src/components/modals/groceries/ModalAddItem.js b/src/components/modals/groceries/ModalAddItem.js index b847253..fb4cd06 100644 --- a/src/components/modals/groceries/ModalAddItem.js +++ b/src/components/modals/groceries/ModalAddItem.js @@ -61,7 +61,7 @@ const ModalAddItem = (props) => { let product = products.find((product) => product.productName === pName); setProductName(product.productName) setTag(product.tag) - setPrice(product.price) + setPrice(product.price && product.price.toString()) } return ( { } - setPrice(text)} placeholder="Price" /> diff --git a/src/components/modals/recipes/ModalAddIngredients.js b/src/components/modals/recipes/ModalAddIngredients.js index 50b5608..bbfb1bf 100644 --- a/src/components/modals/recipes/ModalAddIngredients.js +++ b/src/components/modals/recipes/ModalAddIngredients.js @@ -84,7 +84,7 @@ const ModalAddIngredients = (props) => { setServings(text)} min={amountOfServings} diff --git a/src/components/modals/styles/modal.js b/src/components/modals/styles/modal.js index f0e5914..e2198bd 100644 --- a/src/components/modals/styles/modal.js +++ b/src/components/modals/styles/modal.js @@ -22,7 +22,7 @@ export const WrapperInput = styled(View)` margin-bottom:5px; ` export const WrapperDropdown = styled(View)` - margin-left: 16px; + margin-left: 42px; margin-top: -5px; margin-bottom: 5px; ` @@ -68,7 +68,7 @@ export const Button = styled(TouchableOpacity)` export const ButtonText = styled(Text)` color: ${props => props.theme.colors.primary}; font-weight: bold; - font-size: ${({ theme }) => theme.fontSizes.fontS}px; + font-size: ${({ theme }) => theme.fontSizes.fontM}px; ` export const ModalHeader = styled(Text)` diff --git a/src/components/recipes/Ingredient&Button.js b/src/components/recipes/Ingredient&Button.js index c0347cb..2d3e8dd 100644 --- a/src/components/recipes/Ingredient&Button.js +++ b/src/components/recipes/Ingredient&Button.js @@ -1,5 +1,5 @@ import React from 'react'; -import { View } from 'react-native' +import { TouchableOpacity, View } from 'react-native' import styled from "styled-components" import { Ingredient } from "./addRecipe/Ingredient" @@ -14,7 +14,7 @@ export const Wrapper = styled(View)` border-bottom-color: ${props => props.theme.colors.dp01}; border-bottom-width: 1px; border-radius: 20px; - ${props => props.checked === true && css`background-color: ` + props.theme.colors.selected + '33'}; + ${props => props.checked === true && "background-color:" + props.theme.colors.selected + '33'}; ` const IngredientButton = (props) => { @@ -23,9 +23,9 @@ const IngredientButton = (props) => { return ( - dispatch(ingredientCheckToggle({ id: props.recipeId, productName: ingredient.productName }))} > + dispatch(ingredientCheckToggle({ id: props.recipeId, productName: ingredient.productName }))} > - + ) } diff --git a/src/components/recipes/addRecipe/Buttons.js b/src/components/recipes/addRecipe/Buttons.js index 1e3f2c6..61d31f4 100644 --- a/src/components/recipes/addRecipe/Buttons.js +++ b/src/components/recipes/addRecipe/Buttons.js @@ -11,22 +11,22 @@ import { removeRecipe } from "../../../redux/slices/recipesSlice" import { PlusIcon, WrapperAddItem } from "../../GroceryList/groceries/styles/buttons" import ModalAddIngredients from "../../modals/recipes/ModalAddIngredients" import { Alert } from "react-native" +import { useNavigation } from "@react-navigation/core"; +import { TouchableOpacity } from "react-native-gesture-handler"; export const AddRecipeButton = () => { - + let navigation = useNavigation() return ( - // < Link to="/recipes/addRecipe"> - - - - // + navigation.navigate('AddRecipe', {id: ""})}> + + ) } export const AddIngredientsButton = (props) => { const [visible, setVisible] = useState(false) return (<> - setVisible(true)}> + setVisible(true)}> setVisible(false)} /> @@ -37,6 +37,7 @@ export const AddIngredientsButton = (props) => { export const OptionsButtonRecipe = (props) => { const dispatch = useDispatch() const [toggled, setToggled] = useState(false) + const navigation = useNavigation() const handleRemove = () => { Alert.alert( "Warning", @@ -45,6 +46,7 @@ export const OptionsButtonRecipe = (props) => { { text: "Cancel", }, { text: "Remove", onPress: () => { + navigation.goBack() dispatch(removeRecipe(props.id)) } } @@ -54,11 +56,12 @@ export const OptionsButtonRecipe = (props) => { } return ( - setToggled(!toggled)} /> - - handleRemove()} /> - history.push("/recipes/addRecipe/" + props.id)} /> - + handleRemove()} > + + + navigation.navigate("AddRecipe", { id: props.id })} > + + ) } \ No newline at end of file diff --git a/src/components/recipes/addRecipe/Ingredient.js b/src/components/recipes/addRecipe/Ingredient.js index d7f352f..5481a5f 100644 --- a/src/components/recipes/addRecipe/Ingredient.js +++ b/src/components/recipes/addRecipe/Ingredient.js @@ -1,5 +1,5 @@ import React from 'react'; -import { View } from "react-native" +import { TouchableOpacity, View } from "react-native" import { useSelector } from "react-redux" import { WrapperIngredient, WrapperIngredientLeft, TagCircle, IngredientName, IngredientPortion, IngredientAmount, IconEdit, IconRemove } from './styles/ingredient' @@ -12,12 +12,11 @@ export const Ingredient = (props) => { - {ingredient.portion} + {ingredient.amount * multiplier} x ({ingredient.portion}) {ingredient.productName} - {ingredient.amount*multiplier} - {props.EditIngredient && props.EditIngredient(props.index)} />} - {props.RemoveIngredient && props.RemoveIngredient(props.index)} />} + {props.EditIngredient && props.EditIngredient(props.index)} >} + {props.RemoveIngredient && props.RemoveIngredient(props.index)} >} ) } \ No newline at end of file diff --git a/src/components/recipes/addRecipe/Inputs.js b/src/components/recipes/addRecipe/Inputs.js index fc649e4..aa9c89b 100644 --- a/src/components/recipes/addRecipe/Inputs.js +++ b/src/components/recipes/addRecipe/Inputs.js @@ -1,13 +1,13 @@ import React from 'react'; import { useState } from "react" -import { View } from "react-native" +import { Text, View } from "react-native" import { useSelector } from "react-redux" import { selectAllProducts } from "../../../redux/slices/groceryList/productsSlice" import Dropdown from "../../Dropdown" -import { Input } from "../../modals/styles/modal" +import { ButtonText, Input } from "../../modals/styles/modal" import { Ingredient } from "./Ingredient" import { - WrapperIngredients, InputIngredientName, InputAmount, InputPortion, Button + WrapperIngredients, InputIngredientName, InputAmount, InputPortion, Button, Row, TitleIngredients, WrapperDropdown } from "./styles/inputs" export const Ingredients = (props) => { let ingredients = props.ingredients @@ -67,54 +67,56 @@ export const Ingredients = (props) => { let product = products.find((product) => product.productName === pName); setIngredientName(product.productName) setTag(product.tag) - setPrice(product.price) + setPrice(product.price && product.price.toString()) } return ( -

Ingredients

- + Ingredients + {IngredientList} - setFocused(true)} onBlur={() => { setTimeout(() => { setFocused(false) }, 100) }} - type="text" + setFocused(true)} onEndEditing={() => setFocused(false)} value={ingredientName} - onChange={(text) => setIngredientName(text.target.value)} + onChangeText={(text) => setIngredientName(text)} placeholder="Name ingredient" /> - {focused && - product.productName)} text={ingredientName} setElement={handleDropdownPress} />} - - - setFocusedTag(true)} onBlur={() => { setTimeout(() => { setFocusedTag(false) }, 100) }} - style={{ marginLeft: 0 }} - type="text" - value={tag} - onChange={(text) => setTag(text.target.value)} - placeholder="tag" /> - {focusedTag && - t.tagName)} text={tag} setElement={setTag} />} - + + + {focused && + product.productName)} text={ingredientName} setElement={handleDropdownPress} />} + + setFocusedTag(true)} onEndEditing={() => setFocusedTag(false)} + style={{ marginLeft: 0 }} + type="text" + value={tag} + onChangeText={(text) => setTag(text)} + placeholder="tag" /> + setPrice(text.target.value)} + onChangeText={(text) => setPrice(text)} placeholder="Price" /> + + + {focusedTag && + t.tagName)} text={tag} setElement={setTag} />} - + setAmount(text.target.value)} + onChangeText={(text) => setAmount(text)} placeholder="amt." /> setPortion(text.target.value)} + onChangeText={(text) => setPortion(text)} placeholder="Portion (1/2 teaspoon, ...)" /> - - + + - -
+ + ) } \ No newline at end of file diff --git a/src/components/recipes/addRecipe/styles/buttons.js b/src/components/recipes/addRecipe/styles/buttons.js index 0abf77c..2326ade 100644 --- a/src/components/recipes/addRecipe/styles/buttons.js +++ b/src/components/recipes/addRecipe/styles/buttons.js @@ -15,30 +15,8 @@ export const WrapperAddRecipe = styled(Button)` export const IconPlus = () => export const WrapperOptions = styled(View)` - position: absolute; - top: 0px; - right: 0px; -` - -export const WrapperOptionButtons = styled(View)` display: flex; - flex-direction: column; - position: absolute; - align-items: center; - top: 60px; - width: 55px; - right: 0px; - height: ${props => props.toggled ? css`100px` : css`0px` }; - background-color: ${({theme}) => theme.colors.dp00 +'bb'}; - border-bottom-left-radius: 8px; - overflow: hidden; -` -const Options = () => - -export const IconOptions = styled(Options)` - margin-right: 5px; - margin-top: 10px; - transform: rotate(${props => props.toggled ? css`135deg` : css`0deg` }); + flex-direction: row; ` const Remove = () => diff --git a/src/components/recipes/addRecipe/styles/ingredient.js b/src/components/recipes/addRecipe/styles/ingredient.js index 6384cb4..7d1d2f5 100644 --- a/src/components/recipes/addRecipe/styles/ingredient.js +++ b/src/components/recipes/addRecipe/styles/ingredient.js @@ -1,3 +1,4 @@ +import React from 'react'; import { Text, View } from "react-native" import styled from 'styled-components' @@ -9,7 +10,7 @@ export const WrapperIngredient = styled(View)` display: flex; flex: 1; flex-direction: row; - justify-content: center; + justify-content: space-between; align-items: center; ` export const WrapperIngredientLeft = styled(View)` @@ -29,32 +30,25 @@ export const TagCircle = styled(View)` export const IngredientName = styled(Text)` margin-left: 10px; width: 60%; - font-size: ${({ theme }) => theme.fontSizes.fontS}px; + font-size: 18px; /* overflow-wrap: break-word; */ color: ${props => props.theme.colors.textW4}; ` export const IngredientPortion = styled(Text)` width: 35%; - font-size: ${({ theme }) => theme.fontSizes.fontS}px; + font-size: 18px; font-weight: 900; /* word-break: break-all; */ /* overflow-wrap: break-word; */ color: ${props => props.theme.colors.textW5}; ` -export const IngredientAmount = styled(Text)` - max-width: 12%; - margin-right: 48px; - font-size: ${({theme}) => theme.fontSizes.fontS}px; - /* overflow-wrap: break-word; */ - color: ${props => props.theme.colors.textW5}; -` -const Remove = () => +const Remove = () => export const IconRemove = styled(Remove)` position:absolute; right: 0px; ` -const Edit = () => +const Edit = () => export const IconEdit = styled(Edit)` position:absolute; diff --git a/src/components/recipes/addRecipe/styles/inputs.js b/src/components/recipes/addRecipe/styles/inputs.js index 0c07c00..10c891e 100644 --- a/src/components/recipes/addRecipe/styles/inputs.js +++ b/src/components/recipes/addRecipe/styles/inputs.js @@ -1,34 +1,49 @@ import { Text, TextInput, View } from "react-native" import styled from "styled-components" +import { Input } from "../../../modals/styles/modal" export const WrapperIngredients = styled(View)` margin-top: 10px; width:100%; - border-left: solid ${props => props.theme.colors.primary + '55'} 1px; + border-left-color: ${props => props.theme.colors.primary + '55'} ; + border-left-width: 1px; padding-left: 5px; - /* #row{ - position: relative; - display: flex; - flex-direction: row; - flex:1; - width:100%; - } */ ` -export const InputIngredientName = styled(TextInput)` - margin-top: 10px; - font-size: ${({theme}) => theme.fontSizes.fontS}px; - border-bottom-color: ${props => props.theme.colors.primary + 'aa'}; +export const Row = styled(View)` + position: relative; + display: flex; + flex-direction: row; + width:100%; +` +export const WrapperDropdown = styled(View)` + margin-top: -10px; + margin-bottom: 10px; +` +export const TitleIngredients = styled(Text)` + font-size: 30px; + font-weight: bold; + color: ${props => props.theme.colors.textW2}; +` +export const InputIngredientName = styled(Input)` + margin-left: 0px; + padding-right: 0px; + + margin: 10px 0px; border-bottom-width: 1px; width:100%; ` -export const InputAmount = styled(TextInput)` - font-size: ${({theme}) => theme.fontSizes.fontS}px; - border-bottom-color: ${props => props.theme.colors.primary + 'aa'}; +export const InputAmount = styled(Input)` + margin-left: 0px; + padding-right: 0px; + margin-top: 10px; + border-bottom-width: 1px; width: 50px; ` -export const InputPortion = styled(TextInput)` - font-size: ${({theme}) => theme.fontSizes.fontS}px; - border-bottom-color: ${props => props.theme.colors.primary + 'aa'}; +export const InputPortion = styled(Input)` + margin-left: 0px; + padding-right: 0px; + margin-top: 10px; + border-bottom-width: 1px; width: 60%; margin-left: 10px; @@ -39,5 +54,5 @@ export const Button = styled(Text)` bottom: -8px; color: ${props => props.theme.colors.primary + 'bb'}; font-weight: bold; - font-size: ${({theme}) => theme.fontSizes.fontS}px; + font-size: ${({ theme }) => theme.fontSizes.fontS}px; ` \ No newline at end of file diff --git a/src/components/recipes/styles/recipeCard.js b/src/components/recipes/styles/recipeCard.js index 18e587a..661bede 100644 --- a/src/components/recipes/styles/recipeCard.js +++ b/src/components/recipes/styles/recipeCard.js @@ -13,6 +13,7 @@ export const WrapperRecipeCard = styled(TouchableOpacity)` width: 48%; background-color: ${props => props.theme.colors.dp01 + 'dd'}; border-radius: 20px; + margin-bottom: 4px; ` export const RecipeName = styled(Text)` diff --git a/src/pages/recipes/AddRecipe.js b/src/pages/recipes/AddRecipe.js index 2ee143d..b89bf5b 100644 --- a/src/pages/recipes/AddRecipe.js +++ b/src/pages/recipes/AddRecipe.js @@ -1,57 +1,66 @@ import React from 'react'; -import { Text, View } from 'react-native' +import { Button, ScrollView, Text, View } from 'react-native' +import * as ImagePicker from 'expo-image-picker'; //components import Header from "../../components/Header" import { ArrowBack } from "../styles/page"; import { Ingredients } from "../../components/recipes/addRecipe/Inputs"; //styling -import { Wrapper, WrapperRecipe, Input, InputInstructions, IconRecipe, IconPot, IconMeal, IconImage, IconCheck } from "./styles/addRecipe" +import { Wrapper, WrapperRecipe, Input, InputInstructions, IconRecipe, IconPot, IconMeal, IconImage, IconCheck, AddImageButton, ButtonText, SubmitButton } from "./styles/addRecipe" import { useState } from "react"; import { addRecipe, findRecipeById, updateRecipe } from "../../redux/slices/recipesSlice"; import { useDispatch, useSelector } from "react-redux"; import { StyledImage } from "./styles/recipe"; import HeaderPadding from '../../components/Header'; +import { Row } from '../../components/recipes/addRecipe/styles/inputs'; +import { useNavigation } from '@react-navigation/core'; + +const AddRecipe = (props) => { + const id = props.route.params.id + + const navigation = useNavigation() -const AddRecipe = () => { - let { id } = useParams() const foundRecipe = useSelector(state => findRecipeById(state, id)) let recipe = foundRecipe ? foundRecipe : { name: '', prepTime: '', servings: '', image: '', ingredients: [], instructions: '' } const dispatch = useDispatch() + const [name, setName] = useState(recipe.name) - const [prepTime, setPrepTime] = useState(recipe.prepTime) - const [servings, setServings] = useState(recipe.servings) + const [prepTime, setPrepTime] = useState(recipe.prepTime && recipe.prepTime.toString()) + const [servings, setServings] = useState(recipe.servings && recipe.servings.toString()) const [image, setImage] = useState(recipe.image) const [ingredients, setIngredients] = useState(recipe.ingredients) const [instructions, setInstructions] = useState(recipe.instructions) - const handleImageInput = (input) => { - if (input.target.files && input.target.files[0] && input.target.files[0].size < 1000000) { - let reader = new FileReader() - reader.onload = function (e) { - setImage(e.target.result) - }; - reader.readAsDataURL(input.target.files[0]) + const pickImage = async () => { + let result = await ImagePicker.launchImageLibraryAsync({ + mediaTypes: ImagePicker.MediaTypeOptions.All, + allowsEditing: true, + aspect: [4, 3], + quality: 1, + }); + + console.log(result); + + if (!result.cancelled) { + setImage(result.uri); } - else { - alert("That file is too big! Choose an image with a size lower than 1MB") - } - } + }; const submitRecipe = () => { if (name && ingredients && instructions) { foundRecipe ? dispatch(updateRecipe({ _id: foundRecipe._id, name, prepTime: Number(prepTime), servings: Number(servings), image, ingredients, instructions })) : dispatch(addRecipe({ name, prepTime: Number(prepTime), servings: Number(servings), image, ingredients, instructions })) - console.log(typeof (image)) + navigation.goBack() } else { alert("You should add a name, at least one ingredient and the instructions") } } - const handleInput = (event) => { - let lastChar = event.target.value.substr(-1).charCodeAt(0); - let penultimateChar = event.target.value.substr(-2).charCodeAt(0); + const handleInput = (text) => { + let lastChar = text.substr(-1).charCodeAt(0); + let penultimateChar = text.substr(-2).charCodeAt(0); if (instructions === '') { - setInstructions("- " + event.target.value) + setInstructions("- " + text) return } else if (penultimateChar === 10 && lastChar === 45) { @@ -59,55 +68,56 @@ const AddRecipe = () => { return } else if (lastChar === 10) { - setInstructions(event.target.value + "- ") + setInstructions(text + "- ") return } - setInstructions(event.target.value) + setInstructions(text) } - return ( - <> - + return (<> + + + {image != "" && } - {image && } - + setName(text.target.value)} + onChangeText={(text) => setName(text)} placeholder="Recipe name" /> - - + + setPrepTime(text.target.value)} + onChangeText={(text) => setPrepTime(text)} placeholder="Prep time (min)" /> setServings(text.target.value)} + onChangeText={(text) => setServings(text)} placeholder="Servings" /> - - - - handleImageInput(input)} /> - + + + Add Image + handleInput(text)} + onChangeText={(text) => handleInput(text)} placeholder='Instructions' /> - + + {name != "" && ingredients != "" && instructions != "" && + + } + ) } diff --git a/src/pages/recipes/Recipe.js b/src/pages/recipes/Recipe.js index 35fc378..296f766 100644 --- a/src/pages/recipes/Recipe.js +++ b/src/pages/recipes/Recipe.js @@ -10,8 +10,8 @@ import { OptionsButtonRecipe, AddIngredientsButton } from "../../components/reci import { ScrollView, Text, View } from "react-native" import HeaderPadding from "../../components/Header" -const Recipe = (props) => { - const id = props.route.params.id +const Recipe = ({route, navigation}) => { + const id = route.params.id const recipe = useSelector(state => findRecipeById(state, id)) const IngredientList = recipe.ingredients.map((ingredient, index) => { return () @@ -25,12 +25,21 @@ const Recipe = (props) => { {instruction} ) }) + + React.useLayoutEffect(() => { + navigation.setOptions({ + headerRight: () => ( + + ), + }); + }, [navigation]); + return ( <> + + {recipe.image != "" && } - - {recipe.image != "" && } {recipe.name}
diff --git a/src/pages/recipes/styles/addRecipe.js b/src/pages/recipes/styles/addRecipe.js index 9fd5e0f..b9e9dd9 100644 --- a/src/pages/recipes/styles/addRecipe.js +++ b/src/pages/recipes/styles/addRecipe.js @@ -1,8 +1,9 @@ import React from 'react'; -import { Image, Text, TextInput, View } from "react-native" +import { Image, Text, TextInput, TouchableOpacity, View } from "react-native" import styled from 'styled-components' import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import theme from "../../../styles/theme"; +import { Button } from '../../../styles/componentBlueprints'; export const Wrapper = styled(View)` display: flex; @@ -38,35 +39,49 @@ export const Input = styled(TextInput)` color: ${props => props.theme.colors.textW1}; border-bottom-color: ${props => props.theme.colors.primary + 'aa'}; border-bottom-width: 1px; - font-size: ${({theme}) => theme.fontSizes.fontS}px; + font-size: ${({theme}) => theme.fontSizes.fontM}px; width: 100%; ` -export const InputInstructions = styled(Text)` +export const InputInstructions = styled(TextInput)` margin-top: 30px; padding: 5px; color: ${props => props.theme.colors.textW1}; border-bottom-color: ${props => props.theme.colors.primary + 'aa'}; border-bottom-width: 1px; - font-size: ${({theme}) => theme.fontSizes.fontS}px; - min-height: 600px; + font-size: ${({theme}) => theme.fontSizes.fontM}px; width: 100%; ` -export const StyledImage = styled(Image)` - width: 100px; - height: 100px; +export const AddImageButton = styled(TouchableOpacity)` + justify-content: center; + align-items: center; + align-self: center; + margin: 10px; + width: 140px; + height: 40px; + background-color:${props => props.theme.colors.primary}; + border-radius: 15px; ` -export const IconRecipe = () => +export const ButtonText = styled(Text)` + color: ${props => props.theme.colors.textB1}; + font-weight: bold; + font-size: 20px; +` +export const SubmitButton = styled(Button)` + position: absolute; + right: 10px; + bottom: 10px; + background-color: ${({theme}) => theme.colors.primary}; +` +export const IconRecipe = () => -export const IconPot = () => +export const IconPot = () => -export const IconMeal = () => +export const IconMeal = () => -export const IconImage = () => - -const Check = () => +const Check = () => export const IconCheck = styled(Check)` margin-right: 10px; diff --git a/src/pages/recipes/styles/recipe.js b/src/pages/recipes/styles/recipe.js index 9cdd278..3964660 100644 --- a/src/pages/recipes/styles/recipe.js +++ b/src/pages/recipes/styles/recipe.js @@ -47,6 +47,7 @@ export const InstructionNumber = styled(Text)` ` export const StyledImage = styled(Image)` + margin-top: -110px; height: 200px; width: 100%; ` diff --git a/src/redux/slices/recipesSlice.js b/src/redux/slices/recipesSlice.js index a204600..967c759 100644 --- a/src/redux/slices/recipesSlice.js +++ b/src/redux/slices/recipesSlice.js @@ -14,8 +14,8 @@ export const fetchRecipes = createAsyncThunk('recipes/fetchRecipes', async () => }) export const addRecipe = createAsyncThunk('recipes/addRecipe', async (payload) => { - const size = new TextEncoder().encode(JSON.stringify(payload)).length - console.log(size) + // const size = new TextEncoder().encode(JSON.stringify(payload)).length + // console.log(size) const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json' }, diff --git a/src/styles/animations.js b/src/styles/animations.js new file mode 100644 index 0000000..90b4cb2 --- /dev/null +++ b/src/styles/animations.js @@ -0,0 +1,40 @@ +export const toggleOnAnim = { + 0.0: { + scale: 1 + }, + 0.2: { + scale: 0.94 + }, + 0.4: { + scale: 1.02 + }, + 0.6: { + scale: 0.99 + }, + 0.8: { + scale: 1.005 + }, + 1: { + scale: 1 + } +}; +export const toggleOffAnim = { + 0.0: { + scale: 1 + }, + 0.2: { + scale: 0.94 + }, + 0.4: { + scale: 1.02 + }, + 0.6: { + scale: 0.99 + }, + 0.8: { + scale: 1.0051 + }, + 1: { + scale: 1 + } +}; \ No newline at end of file diff --git a/src/styles/componentBlueprints.js b/src/styles/componentBlueprints.js index a78217f..c8f6256 100644 --- a/src/styles/componentBlueprints.js +++ b/src/styles/componentBlueprints.js @@ -5,6 +5,8 @@ import styled, { css } from 'styled-components' import LightenDarken from '../functions' import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import theme from "./theme"; +import * as Animatable from 'react-native-animatable' +import { toggleOffAnim, toggleOnAnim } from "./animations"; //standard button layout export const Button = styled(TouchableOpacity)` box-shadow: ${({ theme }) => theme.colors.shadow}; @@ -15,7 +17,7 @@ export const Button = styled(TouchableOpacity)` width: 65px; border-radius: 35px; ` -const CheckButtonWrapper = styled(View)` +const CheckButtonWrapper = styled(Animatable.View)` display:flex; justify-content: center; align-items: center; @@ -29,14 +31,14 @@ const CheckButtonWrapper = styled(View)` ` export const CheckButton = (props) => { - return ( - + return ( + - - ) + + ) } //load anim export const LoadAnimation = () => { - return () + return () } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 6f16b89..738b3c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -719,7 +719,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-object-assign@^7.0.0", "@babel/plugin-transform-object-assign@^7.10.4": +"@babel/plugin-transform-object-assign@^7.0.0": version "7.14.5" resolved "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.14.5.tgz" integrity sha512-lvhjk4UN9xJJYB1mI5KC0/o1D5EcJXdbhVe+4fSk08D6ZN+iuAIs7LJC+71h8av9Ew4+uRq9452v9R93SFmQlQ== @@ -2605,6 +2605,15 @@ expo-font@~10.0.3: expo-modules-core "~0.4.4" fontfaceobserver "^2.1.0" +expo-image-picker@^11.0.3: + version "11.0.3" + resolved "https://registry.yarnpkg.com/expo-image-picker/-/expo-image-picker-11.0.3.tgz#c0b6cb9b5fa027f1bd1879a879fe13157f31ac94" + integrity sha512-s7nXB+hop5htcETlSvtPhEGE6RM4BX0G2e6mhr2SjJdJPAFn+hY7R3vCGBFMtxV11Gjzr0D1w2y9gDqhOj0GKg== + dependencies: + "@expo/config-plugins" "^4.0.2" + expo-modules-core "~0.4.4" + uuid "7.0.2" + expo-keep-awake@~10.0.0: version "10.0.0" resolved "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-10.0.0.tgz" @@ -4147,11 +4156,6 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.5" -mockdate@^3.0.2: - version "3.0.5" - resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb" - integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ== - ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" @@ -4662,6 +4666,13 @@ react-native-animatable@1.3.3: dependencies: prop-types "^15.7.2" +react-native-animatable@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/react-native-animatable/-/react-native-animatable-1.3.3.tgz#a13a4af8258e3bb14d0a9d839917e9bb9274ec8a" + integrity sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w== + dependencies: + prop-types "^15.7.2" + react-native-codegen@^0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.0.6.tgz" @@ -4690,16 +4701,6 @@ react-native-modal@^13.0.0: prop-types "^15.6.2" react-native-animatable "1.3.3" -react-native-reanimated@~2.2.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.2.3.tgz#edecfe477ad9efac6f006f7e1194e8c9aa4fc6d5" - integrity sha512-d+BV39Jp4Om0ZkgVjop672/004ytlTfDT01EloO3HFZs9wR2QTuCjekq8yi3xl0G2xGZKd4DXhvqabIa7OnMYA== - dependencies: - "@babel/plugin-transform-object-assign" "^7.10.4" - fbjs "^3.0.0" - mockdate "^3.0.2" - string-hash-64 "^1.0.3" - react-native-safe-area-context@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.3.2.tgz#9549a2ce580f2374edb05e49d661258d1b8bcaed" @@ -5357,11 +5358,6 @@ strict-uri-encode@^2.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz" integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= -string-hash-64@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string-hash-64/-/string-hash-64-1.0.3.tgz#0deb56df58678640db5c479ccbbb597aaa0de322" - integrity sha512-D5OKWKvDhyVWWn2x5Y9b+37NUllks34q1dCDhk/vYcso9fmhs+Tl3KR/gE4v5UNj2UA35cnX4KdVVGkG1deKqw== - string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -5667,6 +5663,11 @@ utils-merge@1.0.1: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uuid@7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.2.tgz#7ff5c203467e91f5e0d85cfcbaaf7d2ebbca9be6" + integrity sha512-vy9V/+pKG+5ZTYKf+VcphF5Oc6EFiu3W8Nv3P3zIh0EqVI80ZxOzuPfe9EHjkFNvf8+xuTHVeei4Drydlx4zjw== + uuid@^3.3.2, uuid@^3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz"