first commit
This commit is contained in:
77
src/components/groceryComponents/GroceryListButtons.js
Normal file
77
src/components/groceryComponents/GroceryListButtons.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import React, { useState } from 'react';
|
||||
import { StyleSheet, TouchableOpacity, View, Text, TextInput } from 'react-native';
|
||||
//themes
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import { COLORS } from '../../themes/Colors';
|
||||
|
||||
//modals
|
||||
import AddItemModal from './modals/AddItemModal';
|
||||
|
||||
//redux
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { toggleVisibility } from '../../redux/slices/groceryList/toggleSlice';
|
||||
import { removeCheckedItems } from '../../redux/slices/groceryList/itemsSlice';
|
||||
|
||||
|
||||
export const AddItemButton = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={[styles.buttonContainer, styles.addItem]}
|
||||
onPress={()=>dispatch(toggleVisibility('addItemModalVisible'))}>
|
||||
<MaterialCommunityIcons name="cart-plus" color={COLORS.dp00} size={35} />
|
||||
{/* pop-up screen */}
|
||||
<AddItemModal/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
export const AddNewRecipeButton = () => {
|
||||
return (
|
||||
<TouchableOpacity style={[styles.buttonContainer, styles.AddNewProduct, { backgroundColor: COLORS.primaryVar2 }]}
|
||||
onPress={() => alert('hello')}>
|
||||
<MaterialCommunityIcons name="file-document-edit-outline" color={COLORS.dp00} size={40} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
export const PushItemsToStorageButton = () => {
|
||||
return (
|
||||
<TouchableOpacity style={[styles.buttonContainer, styles.AddNewRecipe, { backgroundColor: COLORS.actionSend }]}
|
||||
onPress={() => alert('lol')}>
|
||||
<MaterialCommunityIcons name="cloud-download-outline" color={COLORS.dp00} size={40} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
export const RemoveItemsButton = () => {
|
||||
const dispatch = useDispatch();
|
||||
return (
|
||||
<TouchableOpacity style={[styles.buttonContainer, styles.downloadList, { backgroundColor: COLORS.actionCancel }]}
|
||||
onPress={() => dispatch(removeCheckedItems())}>
|
||||
<MaterialCommunityIcons name="delete-forever-outline" color={COLORS.dp00} size={40} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
buttonContainer: {
|
||||
height: 60,
|
||||
width: 60,
|
||||
borderRadius: 60 / 2,
|
||||
elevation: 10,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
addItem: {
|
||||
backgroundColor: COLORS.primary,
|
||||
},
|
||||
AddNewProduct: {
|
||||
backgroundColor: COLORS.primary,
|
||||
},
|
||||
AddNewRecipe: {
|
||||
backgroundColor: COLORS.primary,
|
||||
|
||||
},
|
||||
downloadList: {
|
||||
backgroundColor: COLORS.primary,
|
||||
|
||||
},
|
||||
});
|
||||
219
src/components/groceryComponents/ListedItem.js
Normal file
219
src/components/groceryComponents/ListedItem.js
Normal file
@@ -0,0 +1,219 @@
|
||||
import React, { useRef, useEffect, useState } from 'react';
|
||||
import { StyleSheet, Text, TouchableOpacity, View, Animated } from 'react-native';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
//themes
|
||||
import { COLORS } from '../../themes/Colors';
|
||||
//redux
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { checkToggle } from '../.././redux/slices/groceryList/itemsSlice';
|
||||
|
||||
|
||||
export const ListedItem = (props) => {
|
||||
|
||||
//redux
|
||||
const dispatch = useDispatch()
|
||||
const products = useSelector(state => state.products)
|
||||
const items = useSelector(state => state.items)
|
||||
const tags = useSelector(state => state.tags)
|
||||
|
||||
|
||||
let product;
|
||||
const item = items.find((item) => item.productId === props.id);
|
||||
|
||||
if (products.find((product) => product.id === item.productId)) {
|
||||
product = products.find((product) => product.id === item.productId);
|
||||
}
|
||||
else {
|
||||
product = {
|
||||
productName: props.id,
|
||||
tag:'no-tag',
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const dispatchAnim = () => {
|
||||
dispatch(checkToggle(item.productId));
|
||||
}
|
||||
|
||||
const tag = tags.find((tag)=>tag.tagName === product.tag);
|
||||
|
||||
const scaleAnimValue = useRef(new Animated.Value(0)).current; // animation start value
|
||||
const colorAnimValue = useRef(new Animated.Value(0)).current; // animation start value
|
||||
const checkAnimValue = useRef(new Animated.Value(0)).current; // animation start value
|
||||
//animation:
|
||||
useEffect(() => {
|
||||
Animated.sequence([
|
||||
Animated.timing(scaleAnimValue, {
|
||||
toValue: 0.9,
|
||||
duration: 150,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
),
|
||||
Animated.spring(scaleAnimValue, {
|
||||
toValue: 1,
|
||||
friction: 4,
|
||||
useNativeDriver: false,
|
||||
},
|
||||
)
|
||||
]).start()
|
||||
|
||||
}, [item.checked])
|
||||
|
||||
//colors
|
||||
useEffect(() => {
|
||||
item.checked ? Animated.timing(colorAnimValue, {
|
||||
toValue: 1,
|
||||
duration: 200,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
).start()
|
||||
:
|
||||
Animated.timing(colorAnimValue, {
|
||||
toValue: 0,
|
||||
duration: 200,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
).start()
|
||||
|
||||
}, [item.checked])
|
||||
//checkmark
|
||||
useEffect(() => {
|
||||
item.checked ? Animated.sequence([
|
||||
Animated.delay(200),
|
||||
Animated.spring(checkAnimValue, {
|
||||
toValue: 1,
|
||||
friction: 4,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
|
||||
]).start()
|
||||
:
|
||||
Animated.sequence([
|
||||
Animated.delay(150),
|
||||
Animated.timing(checkAnimValue, {
|
||||
toValue: 0,
|
||||
duration: 150,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
]).start()
|
||||
|
||||
}, [item.checked])
|
||||
|
||||
const interpolateColor = colorAnimValue.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['rgb(22, 26, 30)', 'rgb(62, 131, 98)']
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, paddingLeft: 8, paddingRight: 8, flexDirection: 'row', alignItems: 'flex-start', justifyContent: 'space-between' }}>
|
||||
<Animated.View style={[styles.listedItemStyle, {backgroundColor: tag.color + '33'},item.checked ? styles.listedItemChecked : {}, {
|
||||
transform: [{
|
||||
scaleX: scaleAnimValue
|
||||
},
|
||||
{
|
||||
scaleY: scaleAnimValue
|
||||
}
|
||||
]
|
||||
}]} >
|
||||
<TouchableOpacity style={{}}
|
||||
onPress={() => console.log(item.checked)}
|
||||
onLongPress={() => dispatchAnim()}>
|
||||
<Text style={styles.textItem}>{product.productName}</Text>
|
||||
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'flex-end' }}>
|
||||
<Text style={styles.textAmount}>Amount: {item.amount}</Text>
|
||||
<Text style={styles.textPerson}>For: {item.person}</Text>
|
||||
</View>
|
||||
|
||||
{item.details ? <Text style={styles.textDetails}>Details: {item.details}</Text> : <View />}
|
||||
</TouchableOpacity>
|
||||
</Animated.View>
|
||||
<TouchableOpacity style={[styles.checkButton, { flex: 1 }]} onPress={() => dispatchAnim()}>
|
||||
<Animated.View style={[styles.checkmark, item.checked ? {
|
||||
borderWidth: 0,
|
||||
} : {}, {
|
||||
backgroundColor: interpolateColor,
|
||||
transform: [{
|
||||
scaleX: scaleAnimValue
|
||||
},
|
||||
{
|
||||
scaleY: scaleAnimValue
|
||||
}
|
||||
]
|
||||
},]} >
|
||||
<Animated.View style={[{
|
||||
transform: [{
|
||||
scaleX: checkAnimValue
|
||||
},
|
||||
{
|
||||
scaleY: checkAnimValue
|
||||
}
|
||||
]
|
||||
}]}>
|
||||
<MaterialCommunityIcons name="check" color={COLORS.dp00} size={25} />
|
||||
</Animated.View>
|
||||
|
||||
</Animated.View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
const height = 30;
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
listedItemStyle: {
|
||||
width: '90%',
|
||||
marginBottom: height / 7,
|
||||
|
||||
borderRadius: height / 2,
|
||||
padding: 2,
|
||||
paddingBottom: 3,
|
||||
backgroundColor: COLORS.dp03,
|
||||
},
|
||||
listedItemChecked: {
|
||||
backgroundColor: '#253f34',
|
||||
},
|
||||
textItem: {
|
||||
flex: 1,
|
||||
left: 8,
|
||||
fontFamily: 'Roboto',
|
||||
fontSize: height * 0.65,
|
||||
color: COLORS.textW0 + 'cc',
|
||||
},
|
||||
textAmount: {
|
||||
flex: 1,
|
||||
left: 30,
|
||||
fontFamily: 'Roboto',
|
||||
fontSize: height * 0.5,
|
||||
color: COLORS.textW1,
|
||||
},
|
||||
textPerson: {
|
||||
flex: 1,
|
||||
left: 25,
|
||||
fontFamily: 'Roboto',
|
||||
fontSize: height * 0.5,
|
||||
color: COLORS.textW1,
|
||||
},
|
||||
textDetails: {
|
||||
flex: 1,
|
||||
marginBottom: 3,
|
||||
left: 8,
|
||||
fontFamily: 'Roboto',
|
||||
fontSize: height * 0.5,
|
||||
color: COLORS.primary + 'aa',
|
||||
},
|
||||
checkmark: {
|
||||
height: 30,
|
||||
width: 30,
|
||||
borderRadius: 15,
|
||||
borderWidth: 1.5,
|
||||
borderColor: '#ffffff' + '12',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
checkButton: {
|
||||
height: '100%',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
});
|
||||
214
src/components/groceryComponents/ListedProduct.js
Normal file
214
src/components/groceryComponents/ListedProduct.js
Normal file
@@ -0,0 +1,214 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import { Image, StyleSheet, Text, TouchableOpacity, View, Animated } from 'react-native';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
//themes
|
||||
import { COLORS } from '../../themes/Colors';
|
||||
//redux
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { checkToggle } from '../.././redux/slices/groceryList/productsSlice';
|
||||
|
||||
|
||||
|
||||
export const ListedProduct = (props) => {
|
||||
|
||||
const products = useSelector(state => state.products)
|
||||
const product = products.find((product) => product.id === props.id);
|
||||
|
||||
const tags = useSelector(state => state.tags)
|
||||
const tag = tags.find((tag) => tag.tagName === product.tag);
|
||||
|
||||
const scaleAnimValue = useRef(new Animated.Value(0)).current; // animation start value
|
||||
const colorAnimValue = useRef(new Animated.Value(0)).current; // animation start value
|
||||
const checkAnimValue = useRef(new Animated.Value(0)).current; // animation start value
|
||||
//animation:
|
||||
useEffect(() => {
|
||||
Animated.sequence([
|
||||
Animated.timing(scaleAnimValue, {
|
||||
toValue: 0.9,
|
||||
duration: 150,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
),
|
||||
Animated.spring(scaleAnimValue, {
|
||||
toValue: 1,
|
||||
friction: 4,
|
||||
useNativeDriver: false,
|
||||
},
|
||||
)
|
||||
]).start()
|
||||
|
||||
}, [product.checked])
|
||||
|
||||
//colors
|
||||
useEffect(() => {
|
||||
product.checked ? Animated.timing(colorAnimValue, {
|
||||
toValue: 1,
|
||||
duration: 200,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
).start()
|
||||
:
|
||||
Animated.timing(colorAnimValue, {
|
||||
toValue: 0,
|
||||
duration: 200,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
).start()
|
||||
|
||||
}, [product.checked])
|
||||
//checkmark
|
||||
useEffect(() => {
|
||||
product.checked ? Animated.sequence([
|
||||
Animated.delay(200),
|
||||
Animated.spring(checkAnimValue, {
|
||||
toValue: 1,
|
||||
friction: 4,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
|
||||
]).start()
|
||||
:
|
||||
Animated.sequence([
|
||||
Animated.delay(150),
|
||||
Animated.timing(checkAnimValue, {
|
||||
toValue: 0,
|
||||
duration: 150,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
]).start()
|
||||
|
||||
}, [product.checked])
|
||||
//redux
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const dispatchAnim = () => {
|
||||
dispatch(checkToggle(product.id));
|
||||
}
|
||||
const interpolateColor = colorAnimValue.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['rgb(22, 26, 30)', 'rgb(62, 131, 98)']
|
||||
});
|
||||
return (
|
||||
<View style={{ flex: 1, paddingLeft: 8, paddingRight: 8, flexDirection: 'row', alignItems: 'flex-start', justifyContent: 'space-between' }}>
|
||||
<Animated.View style={[styles.listedItemStyle, { backgroundColor: tag.color + '33' }, product.checked ? styles.listedItemChecked : {}, {
|
||||
transform: [{
|
||||
scaleX: scaleAnimValue
|
||||
},
|
||||
{
|
||||
scaleY: scaleAnimValue
|
||||
}
|
||||
]
|
||||
}]} >
|
||||
<TouchableOpacity style={[styles.listedItemButton]}
|
||||
onPress={() => alert('Not ready yet!!')}
|
||||
onLongPress={() => dispatchAnim()}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={styles.textItem}>{product.productName}</Text>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
<Text style={[styles.textTags]}>Tag: </Text>
|
||||
<Text style={[styles.textTags, { color: tag.color, }]}>{tag.tagName}</Text>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
{product.price ? <Text style={styles.textPrice}>Price: </Text> : <View />}
|
||||
{product.price ? <Text style={[styles.textPrice, { color: '#C6A337', }]}>€{product.price}</Text> : <View />}
|
||||
</View>
|
||||
</View>
|
||||
<Image source={{ uri: product.image }} style={styles.image} />
|
||||
</TouchableOpacity>
|
||||
</Animated.View>
|
||||
<TouchableOpacity style={[styles.checkButton, { flex: 1 }]} onPress={() => dispatchAnim()}>
|
||||
<Animated.View style={[styles.checkmark, product.checked ? {
|
||||
borderWidth: 0,
|
||||
} : {}, {
|
||||
backgroundColor: interpolateColor,
|
||||
transform: [{
|
||||
scaleX: scaleAnimValue
|
||||
},
|
||||
{
|
||||
scaleY: scaleAnimValue
|
||||
}
|
||||
]
|
||||
},]} >
|
||||
<Animated.View style={[{
|
||||
transform: [{
|
||||
scaleX: checkAnimValue
|
||||
},
|
||||
{
|
||||
scaleY: checkAnimValue
|
||||
}
|
||||
]
|
||||
}]}>
|
||||
<MaterialCommunityIcons name="check" color={COLORS.dp00} size={25} />
|
||||
</Animated.View>
|
||||
|
||||
</Animated.View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const height = 30;
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
listedItemStyle: {
|
||||
width: '90%',
|
||||
marginBottom: height / 7,
|
||||
minHeight: 80,
|
||||
borderRadius: height / 2,
|
||||
backgroundColor: COLORS.dp03,
|
||||
},
|
||||
listedItemButton: {
|
||||
flex: 1,
|
||||
padding: 2,
|
||||
paddingBottom: 3,
|
||||
alignItems: 'flex-start',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
listedItemChecked: {
|
||||
backgroundColor: '#253f34',
|
||||
},
|
||||
textItem: {
|
||||
flex: 1,
|
||||
left: 8,
|
||||
width: '60%',
|
||||
fontFamily: 'Roboto',
|
||||
fontSize: height * 0.65,
|
||||
color: COLORS.textW0 + 'cc',
|
||||
},
|
||||
textTags: {
|
||||
left: 8,
|
||||
fontFamily: 'Roboto',
|
||||
fontSize: height * 0.5,
|
||||
color: COLORS.textW1,
|
||||
},
|
||||
textPrice: {
|
||||
left: 8,
|
||||
fontFamily: 'Roboto',
|
||||
fontSize: height * 0.5,
|
||||
color: COLORS.textW1,
|
||||
|
||||
},
|
||||
image: {
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom:0,
|
||||
width: 80,
|
||||
borderRadius: 15,
|
||||
opacity: 0.8,
|
||||
},
|
||||
checkmark: {
|
||||
height: 30,
|
||||
width: 30,
|
||||
borderRadius: 15,
|
||||
borderWidth: 1.5,
|
||||
borderColor: '#ffffff' + '12',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
checkButton: {
|
||||
height: '100%',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
});
|
||||
42
src/components/groceryComponents/ProductButtons.js
Normal file
42
src/components/groceryComponents/ProductButtons.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, TouchableOpacity, View, Text, TextInput, Image } from 'react-native';
|
||||
|
||||
//components
|
||||
import AddProductModal from './modals/AddProductModal';
|
||||
|
||||
//themes
|
||||
import { COLORS } from '../../themes/Colors';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
|
||||
//redux
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { toggleVisibility } from '../../redux/slices/groceryList/toggleSlice';
|
||||
|
||||
|
||||
export const AddProductButton = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={[styles.buttonContainer, styles.AddNewProduct]}
|
||||
onPress={() => dispatch(toggleVisibility('addProductModalVisible'))}>
|
||||
<MaterialCommunityIcons name="tag-plus-outline" color={COLORS.dp00} size={40} />
|
||||
{/* pop-up screen */}
|
||||
<AddProductModal/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
buttonContainer: {
|
||||
height: 60,
|
||||
width: 60,
|
||||
borderRadius: 60 / 2,
|
||||
elevation: 10,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
AddNewProduct: {
|
||||
backgroundColor: COLORS.primary,
|
||||
},
|
||||
|
||||
});
|
||||
246
src/components/groceryComponents/modals/AddItemModal.js
Normal file
246
src/components/groceryComponents/modals/AddItemModal.js
Normal file
@@ -0,0 +1,246 @@
|
||||
import React, { useState } from 'react';
|
||||
import { StyleSheet, TouchableOpacity, View, Text, TextInput, Image, ScrollView, TouchableOpacityComponent } from 'react-native';
|
||||
import Modal from 'react-native-modal';
|
||||
//themes
|
||||
import { COLORS } from '../../../themes/Colors';
|
||||
|
||||
//redux
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { itemAdded, amountUp } from '../../../redux/slices/groceryList/itemsSlice';
|
||||
import { toggleVisibility } from '../../../redux/slices/groceryList/toggleSlice';
|
||||
|
||||
export default AddItemModal = () => {
|
||||
//redux
|
||||
const modalVisible = useSelector(state => state.toggle.addItemModalVisible);
|
||||
|
||||
const products = useSelector(state => state.products);
|
||||
const items = useSelector(state => state.items);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
let newProductsList = [];
|
||||
for (let i = 0; i < products.length; i++) {
|
||||
newProductsList.push(products[i].productName);
|
||||
}
|
||||
|
||||
|
||||
const [item, setItem] = useState('');
|
||||
const [focussed, setFocussed] = useState(false);
|
||||
const [amount, setAmount] = useState('');
|
||||
const [person, setPerson] = useState('');
|
||||
const [details, setDetails] = useState('');
|
||||
|
||||
const [productsList, setProductsList] = useState(newProductsList);
|
||||
const filterProductsList = (text) => {
|
||||
let regex = new RegExp(text);
|
||||
|
||||
let newProductsList = products.filter((product) =>
|
||||
regex.test(product.productName)
|
||||
)
|
||||
text !== '' ? newProductsList = newProductsList.map((product) => product.productName) : newProductsList = products.map((product) => product.productName)
|
||||
if (newProductsList.length === 1 && newProductsList[0] === text) {
|
||||
setProductsList([]);
|
||||
}
|
||||
else {
|
||||
setProductsList(newProductsList);
|
||||
}
|
||||
setItem(text);
|
||||
};
|
||||
const toggleModal = () => {
|
||||
if (modalVisible && item !== '' && amount !== '') {
|
||||
if (products.find((product) => product.productName === item)) { //find if item is in products , else create unregistered item
|
||||
const productId = products.find((product) => product.productName === item).id;
|
||||
if(!items.find((itemObj) => itemObj.productId === productId)){ //check if amount up needed
|
||||
dispatch(itemAdded(productId, amount, person, details));
|
||||
}
|
||||
else{
|
||||
}
|
||||
}
|
||||
else if (!items.find((itemObj) => itemObj.productId === item)) //unregistered item check for amount up
|
||||
{
|
||||
dispatch(itemAdded(item, amount, person, details));
|
||||
}
|
||||
else{
|
||||
dispatch(amountUp(item,amount));
|
||||
}
|
||||
setItem('');
|
||||
setAmount();
|
||||
setPerson('');
|
||||
setDetails('');
|
||||
setProductsList(products.map((product) => product.productName));
|
||||
}
|
||||
|
||||
else {
|
||||
alert('You should give both a product and an amount');
|
||||
}
|
||||
dispatch(toggleVisibility('addItemModalVisible'));
|
||||
};
|
||||
const closeModal = () => {
|
||||
setItem('');
|
||||
setAmount();
|
||||
setPerson('');
|
||||
setDetails('');
|
||||
dispatch(toggleVisibility('addItemModalVisible'));
|
||||
setProductsList(products.map((product) => product.productName));
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isVisible={modalVisible} animationIn={'slideInUp'} animationOut={'slideOutDown'}
|
||||
onBackdropPress={closeModal}
|
||||
onBackButtonPress={closeModal}
|
||||
useNativeDriverForBackdrop
|
||||
style={styles.modalAddItem} >
|
||||
<View style={{
|
||||
borderRadius: 10,
|
||||
padding: 5,
|
||||
backgroundColor: COLORS.dp01,
|
||||
|
||||
}}>
|
||||
<Text style={styles.modalHeaderText}>Add item</Text>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<TextInput
|
||||
placeholder={'Product name'}
|
||||
placeholderTextColor={'grey'}
|
||||
style={styles.textInput}
|
||||
offFocus={() => setProductsList([])}
|
||||
onChangeText={text => filterProductsList(text)}
|
||||
value={item}
|
||||
onFocus={() => setFocussed(true)}
|
||||
onEndEditing={() => setFocussed(false)}
|
||||
/>
|
||||
|
||||
<ScrollView style={styles.dropdown} keyboardShouldPersistTaps={'always'}>
|
||||
|
||||
{focussed ? productsList.map((product, index) =>
|
||||
<TouchableOpacity key={index} onPress={() => filterProductsList(product)} style={styles.dropdownProduct}>
|
||||
<Text style={styles.dropdownText}>{product}</Text>
|
||||
</TouchableOpacity>
|
||||
) : <View />}
|
||||
|
||||
</ScrollView>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<TextInput
|
||||
placeholder={'Amount'}
|
||||
placeholderTextColor={'grey'}
|
||||
style={[styles.textInput]}
|
||||
onChangeText={text => setAmount(text)}
|
||||
value={amount}
|
||||
keyboardType={'number-pad'}
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<TextInput
|
||||
placeholder={'For'}
|
||||
placeholderTextColor={'grey'}
|
||||
style={styles.textInput}
|
||||
onChangeText={text => setPerson(text)}
|
||||
value={person}
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<TextInput
|
||||
placeholder={'Additional details'}
|
||||
placeholderTextColor={'grey'}
|
||||
style={styles.textInput}
|
||||
onChangeText={text => setDetails(text)}
|
||||
value={details}
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly', marginTop: 20, marginBottom: 10, }}>
|
||||
<TouchableOpacity title="Hide modal" style={styles.modalCloseButton} onPress={closeModal} >
|
||||
<Text style={styles.modalCloseButtonText}>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
<View style={{
|
||||
borderRadius: 10,
|
||||
backgroundColor: COLORS.dp01,
|
||||
borderLeftWidth: 1,
|
||||
borderColor: COLORS.dp08,
|
||||
height: '80%',
|
||||
|
||||
}} />
|
||||
<TouchableOpacity title="Hide modal" style={styles.modalAddButton} onPress={toggleModal} >
|
||||
<Text style={styles.modalAddButtonText}>Add item</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
//modals
|
||||
modalAddItem: {
|
||||
margin: 0,
|
||||
},
|
||||
modalHeaderText: {
|
||||
opacity: 0.9,
|
||||
fontSize: 23,
|
||||
alignSelf: 'center',
|
||||
color: COLORS.textW0 + 'de',
|
||||
},
|
||||
modalText: {
|
||||
left: 10,
|
||||
opacity: 0.9,
|
||||
fontSize: 18,
|
||||
color: COLORS.textB0,
|
||||
},
|
||||
modalAddButtonText: {
|
||||
opacity: 0.8,
|
||||
fontSize: 16,
|
||||
color: COLORS.primary,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
modalCloseButtonText: {
|
||||
opacity: 0.8,
|
||||
fontSize: 16,
|
||||
color: COLORS.primary,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
textInput: {
|
||||
|
||||
height: 25,
|
||||
width: '80%',
|
||||
left: 10,
|
||||
|
||||
borderBottomColor: COLORS.primary + 'aa',
|
||||
borderBottomWidth: 1,
|
||||
borderRadius: 3,
|
||||
marginTop: 10,
|
||||
padding: 0,
|
||||
paddingLeft: 5,
|
||||
paddingRight: 5,
|
||||
|
||||
color: COLORS.textW0,
|
||||
fontSize: 18
|
||||
|
||||
},
|
||||
dropdown: {
|
||||
|
||||
zIndex: 1,
|
||||
position: 'absolute',
|
||||
maxHeight: 100,
|
||||
width: 150,
|
||||
top: 40,
|
||||
left: 10,
|
||||
|
||||
borderRadius: 10,
|
||||
backgroundColor: COLORS.dp16 + 'ee',
|
||||
},
|
||||
dropdownProduct: {
|
||||
|
||||
zIndex: 1,
|
||||
width: 150,
|
||||
minHeight: 20,
|
||||
borderBottomWidth: 1.2,
|
||||
borderColor: '#666' + 'e',
|
||||
},
|
||||
dropdownText: {
|
||||
|
||||
zIndex: 1,
|
||||
left: 10,
|
||||
fontSize: 17,
|
||||
color: COLORS.textW0 + 'ee',
|
||||
|
||||
}
|
||||
});
|
||||
249
src/components/groceryComponents/modals/AddProductModal.js
Normal file
249
src/components/groceryComponents/modals/AddProductModal.js
Normal file
@@ -0,0 +1,249 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { StyleSheet, TouchableOpacity, View, Text, TextInput, Image, ScrollView } from 'react-native';
|
||||
import Modal from 'react-native-modal';
|
||||
|
||||
//themes
|
||||
import { COLORS } from '../../../themes/Colors';
|
||||
|
||||
//redux
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { productAdded } from '../../../redux/slices/groceryList/productsSlice';
|
||||
import { toggleVisibility } from '../../../redux/slices/groceryList/toggleSlice';
|
||||
|
||||
export default AddProductModal = () => {
|
||||
const modalVisible = useSelector(state => state.toggle.addProductModalVisible);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [product, setProduct] = useState('');
|
||||
const [tag, setTag] = useState('');
|
||||
const [price, setPrice] = useState('');
|
||||
const [image, setImage] = useState('https://icons-for-free.com/iconfiles/png/512/linecon+products+round+icon-1320165923260225670.png');
|
||||
|
||||
//tags
|
||||
const tags = useSelector(state => state.tags)
|
||||
let newTagsList = [];
|
||||
for (let i = 0; i < tags.length; i++) {
|
||||
newTagsList.push(tags[i].tagName);
|
||||
}
|
||||
const [tagsList, setTagsList] = useState(newTagsList);
|
||||
|
||||
const [focussed, setFocussed] = useState(false);
|
||||
|
||||
const filterTagsList = (text) => {
|
||||
let regex = new RegExp(text);
|
||||
|
||||
let newTagsList = tags.filter((tag) =>
|
||||
regex.test(tag.tagName)
|
||||
)
|
||||
text !== '' ? newTagsList = newTagsList.map((tag) => tag.tagName) : newTagsList = tags.map((tag) => tag.tagName)
|
||||
if (newTagsList.length === 1 && newTagsList[0] === text) {
|
||||
setTagsList([]);
|
||||
}
|
||||
else {
|
||||
setTagsList(newTagsList);
|
||||
}
|
||||
setTag(text);
|
||||
};
|
||||
//tags
|
||||
const toggleModal = () => {
|
||||
if (modalVisible) {
|
||||
if (product !== '' && tags.find((listTag) => listTag.tagName === tag)) {
|
||||
dispatch(productAdded(product, tag, price, image));
|
||||
}
|
||||
else {
|
||||
alert('You should give both a product name and a useable tag');
|
||||
}
|
||||
}
|
||||
setTagsList(tags.map((listTag) => listTag.tagName));
|
||||
dispatch(toggleVisibility('addProductModalVisible'));
|
||||
setProduct('');
|
||||
setTag('');
|
||||
setPrice();
|
||||
setImage('https://icons-for-free.com/iconfiles/png/512/linecon+products+round+icon-1320165923260225670.png');
|
||||
|
||||
};
|
||||
const closeModal = () => {
|
||||
setTagsList(tags.map((listTag) => listTag.tagName));
|
||||
setProduct('');
|
||||
setTag();
|
||||
setPrice();
|
||||
setImage('https://icons-for-free.com/iconfiles/png/512/linecon+products+round+icon-1320165923260225670.png');
|
||||
dispatch(toggleVisibility('addProductModalVisible'));
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isVisible={modalVisible} animationIn={'slideInUp'} animationOut={'slideOutDown'}
|
||||
onBackdropPress={closeModal}
|
||||
onBackButtonPress={closeModal}
|
||||
useNativeDriverForBackdrop
|
||||
style={styles.modalAddProduct} >
|
||||
<View style={{
|
||||
borderRadius: 10,
|
||||
padding: 5,
|
||||
backgroundColor: COLORS.dp01,
|
||||
|
||||
}}>
|
||||
<Text style={styles.modalHeaderText}>Add product</Text>
|
||||
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-start',
|
||||
}}>
|
||||
<View style={{
|
||||
width: '60%',
|
||||
}}>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<TextInput
|
||||
placeholder={'Product name'}
|
||||
placeholderTextColor={'grey'}
|
||||
style={styles.textInput}
|
||||
onChangeText={text => setProduct(text)}
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<TextInput
|
||||
placeholder={'Tag'}
|
||||
placeholderTextColor={'grey'}
|
||||
style={[styles.textInput]}
|
||||
value={tag}
|
||||
offFocus={() => setTagsList([])}
|
||||
onChangeText={text => filterTagsList(text)}
|
||||
onFocus={() => setFocussed(true)}
|
||||
onEndEditing={() => setFocussed(false)}
|
||||
/>
|
||||
<ScrollView style={styles.dropdown} keyboardShouldPersistTaps={'always'}>
|
||||
{focussed ? tagsList.map((newTag, index) =>
|
||||
<TouchableOpacity key={index} onPress={() => filterTagsList(newTag)} style={styles.dropdownProduct}>
|
||||
<Text style={styles.dropdownText}>{newTag}</Text>
|
||||
</TouchableOpacity>
|
||||
) : <View />}
|
||||
</ScrollView>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<Text style={styles.currencyPrefix}>€</Text>
|
||||
<TextInput
|
||||
placeholder={'Price'}
|
||||
placeholderTextColor={'grey'}
|
||||
style={[styles.textInput, { paddingLeft: 20 }]}
|
||||
onChangeText={text => setPrice(text)}
|
||||
keyboardType={'number-pad'}
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<TextInput
|
||||
placeholder={'Image url'}
|
||||
placeholderTextColor={'grey'}
|
||||
style={styles.textInput}
|
||||
onChangeText={text => { if (text !== '') { return setImage(text) } }}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Image source={{ uri: image }}
|
||||
style={{ width: 130, height: 130, marginTop: '5%', right: 10, borderRadius: 30, }} />
|
||||
</View>
|
||||
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-evenly', marginTop: 20, marginBottom: 10, }}>
|
||||
<TouchableOpacity title="Hide modal" style={styles.modalCloseButton} onPress={closeModal} >
|
||||
<Text style={styles.modalCloseButtonText}>Cancel </Text>
|
||||
</TouchableOpacity>
|
||||
<View style={{
|
||||
borderRadius: 10,
|
||||
backgroundColor: COLORS.dp01,
|
||||
borderLeftWidth: 1,
|
||||
borderColor: COLORS.dp08,
|
||||
height: '80%',
|
||||
|
||||
}} />
|
||||
<TouchableOpacity title="Hide modal" style={styles.modalAddButton} onPress={toggleModal} >
|
||||
<Text style={styles.modalAddButtonText}>Add product</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
//modals
|
||||
modalAddItem: {
|
||||
margin: 0,
|
||||
},
|
||||
modalHeaderText: {
|
||||
opacity: 0.9,
|
||||
fontSize: 23,
|
||||
alignSelf: 'center',
|
||||
color: COLORS.textW0 + 'de',
|
||||
},
|
||||
modalText: {
|
||||
left: 10,
|
||||
opacity: 0.9,
|
||||
fontSize: 18,
|
||||
color: COLORS.textB0,
|
||||
},
|
||||
modalAddButtonText: {
|
||||
opacity: 0.8,
|
||||
fontSize: 16,
|
||||
color: COLORS.primary,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
modalCloseButtonText: {
|
||||
opacity: 0.8,
|
||||
fontSize: 16,
|
||||
color: COLORS.primary,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
textInput: {
|
||||
|
||||
height: 25,
|
||||
width: '80%',
|
||||
left: 10,
|
||||
|
||||
borderBottomColor: COLORS.primary + 'aa',
|
||||
borderBottomWidth: 1,
|
||||
borderRadius: 3,
|
||||
marginTop: 10,
|
||||
padding: 0,
|
||||
paddingLeft: 5,
|
||||
paddingRight: 5,
|
||||
|
||||
color: COLORS.textW0,
|
||||
fontSize: 18
|
||||
|
||||
},
|
||||
currencyPrefix: {
|
||||
position: 'absolute',
|
||||
alignSelf: 'flex-end',
|
||||
left: 15,
|
||||
color: COLORS.primary + '99',
|
||||
fontSize: 18,
|
||||
},
|
||||
dropdown: {
|
||||
|
||||
zIndex: 1,
|
||||
position: 'absolute',
|
||||
maxHeight: 100,
|
||||
width: 150,
|
||||
top: 40,
|
||||
left: 10,
|
||||
|
||||
borderRadius: 10,
|
||||
backgroundColor: COLORS.dp16 + 'ee',
|
||||
},
|
||||
dropdownProduct: {
|
||||
|
||||
zIndex: 1,
|
||||
width: 150,
|
||||
minHeight: 20
|
||||
},
|
||||
dropdownText: {
|
||||
|
||||
zIndex: 1,
|
||||
left: 10,
|
||||
fontSize: 17,
|
||||
color: COLORS.textW0 + 'ee',
|
||||
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user