The keyboard does not appear and I cannot add quantity.
View:
import React, { useState, useEffect } from "react";
import {
View,
Text,
TouchableOpacity,
ActivityIndicator,
Modal,
StyleSheet,
Alert
} from "react-native";
import { globalStyles } from "../globalStyles.js";
import { styles } from "./styles.js"; // Importamos los estilos desde styles.js
import * as RootNavigation from "../../utils/navigator/RootNavigation.js";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { PedidosComercialLogic } from "./PedidosComercialLogic";
import { Button } from "@rneui/themed";
import { FlashList } from "@shopify/flash-list";
import { SearchInput } from "../otros/SearchInput";
import { useGlobalContext } from "../../utils/context/GlobalContextProvider.js";
import { useInternetContext } from "../../utils/context/InternetContextProvider.js";
import { PdaUser } from "../../class/PdaUser.class";
import QuantitySelector from "../otros/QuantitySelector.jsx";
import { HOME } from "../../utils/const/navigatorConst.js";
import { getSecureStoreData } from "../../utils/gettersAndSetters/getters.js";
import { SHOW_PRICE_WITH_TAX } from "../../utils/const/secureStoreConst.js";
import PdfTabNavigator from "../otros/pdfView/PdfTabNavigator.jsx";
import ListadoPedidos from "../pedidos/ListadoPedidos.jsx";
const PedidosComercialScreenView = (props) => {
const [clientProducts, setClientProducts] = useState([]);
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
const [user, setUser] = useState(new PdaUser());
const [globalState, setGlobalState] = useGlobalContext();
const [searchText, setSearchText] = useState("");
const selectedClientId = props.cliente.client;
const [showAllProducts, setShowAllProducts] = useState(false);
const [showCobros, setShowCobros] = useState(false);
const [allProducts, setAllProducts] = useState([]);
const [quantities, setQuantities] = useState({});
const [isQuantityModalVisible, setQuantityModalVisible] = useState(false);
const [selectedProduct, setSelectedProduct] = useState(null);
const [isPurchaseModalVisible, setPurchaseModalVisible] = useState(false);
const [totalPurchase, setTotalPurchase] = useState(0);
const [showFinalizeOptionsModal, setShowFinalizeOptionsModal] =
useState(false);
const [internetState, setInternetState] = useInternetContext();
const [showPriceWithTax, setShowPriceWithTax] = useState(false);
const [visibleData, setVisibleData] = useState([]);
const [pdfUrls, setPdfUrls] = useState([]);
const [pendingPayments, setPendingPayments] = useState([]);
const [isPendingPaymentsModalVisible, setPendingPaymentsModalVisible] =
useState(false);
const itemsPerPage = 10;
const [page, setPage] = useState(1);
var DEV = new PedidosComercialLogic({
clientProducts,
setClientProducts,
products,
setProducts,
setLoading,
setUser,
user,
setGlobalState,
globalState,
selectedClientId,
});
useEffect(() => {
async function fetchData() {
const showPriceWithTax = await getSecureStoreData(SHOW_PRICE_WITH_TAX);
setShowPriceWithTax(showPriceWithTax === "true");
await DEV.init();
if (internetState.isConnected) {
try {
await DEV.getProductsByOrders(props.cliente.client);
await DEV.getProducts();
} catch (error) {
console.error("Error al cargar clientes:", error);
}
} else {
try {
await DEV.getLocalProductsByOrders();
await DEV.getLocalProducts();
} catch (error) {
console.error("Error al cargar clientes:", error);
}
}
try {
const totalDue = await DEV.getTotalDueByClient(props.cliente.client);
setPendingPayments(totalDue);
setPendingPaymentsModalVisible(true);
} catch (error) {
console.error("Error fetching total due:", error);
Alert.alert("Error", "Problemas al obtener los pagos pendientes.");
}
}
fetchData();
}, []);
useEffect(() => {
mergeProducts(clientProducts, products);
}, [products, clientProducts]);
useEffect(() => {
setVisibleData(filteredProducts.slice(0, itemsPerPage));
setPage(1);
}, [allProducts, showAllProducts, filteredProducts]);
useEffect(() => {
const filtered = allProducts.filter(
(product) =>
(product.label || "")
.toLowerCase()
.includes(searchText.toLowerCase()) &&
(showAllProducts ? product.client === 0 : product.client === 1)
);
setVisibleData(filtered.slice(0, itemsPerPage));
setPage(1);
}, [searchText, allProducts, showAllProducts]);
const loadMoreData = () => {
const filtered = allProducts.filter(
(product) =>
(product.label || "")
.toLowerCase()
.includes(searchText.toLowerCase()) &&
(showAllProducts ? product.client === 0 : product.client === 1)
);
const startIndex = page * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const newData = filtered.slice(startIndex, endIndex);
setPage(page + 1);
setVisibleData((prevData) => [...prevData, ...newData]);
};
const mergeProducts = async (clientProducts, products) => {
const productMap = new Map();
products.forEach((product) => {
if (product.fkProduct != null) {
productMap.set(product.fkProduct, {
...product,
client: 0,
quantity: 0,
productStock: product.productStock || 0,
});
}
});
clientProducts.forEach((product) => {
if (product.fkProduct != null) {
const existingProduct = productMap.get(product.fkProduct);
if (existingProduct) {
productMap.set(product.fkProduct, {
...existingProduct,
...product,
productStock:
product.productStock || existingProduct.productStock || 0,
client: 1,
});
} else {
productMap.set(product.fkProduct, {
...product,
client: 1,
productStock: product.productStock || 0,
});
}
}
});
const arrayMerge = Array.from(productMap.values());
setAllProducts(arrayMerge);
if (internetState.isConnected) {
await DEV.saveProductsLocal(arrayMerge);
}
setLoading(false);
};
const handleSearch = (text) => {
setSearchText(text);
};
const toggleProductList = () => {
setLoading(true);
setShowAllProducts(!showAllProducts);
setLoading(false);
};
const addProductToClient = (product) => {
setSelectedProduct(product);
setQuantityModalVisible(true);
};
const handleQuantitySave = (quantity, subprice, discount) => {
console.log("CANTIDAD", subprice)
setQuantities((prevQuantities) => ({
...prevQuantities,
[selectedProduct.fkProduct]: quantity,
}));
const updatedClientProducts = clientProducts.map((product) => {
if (product.fkProduct === selectedProduct.fkProduct) {
return {
...product,
quantity,
subprice: subprice,
remise_percent: discount,
client: 1,
};
}
return product;
});
if (
!updatedClientProducts.find(
(product) => product.fkProduct === selectedProduct.fkProduct
)
) {
updatedClientProducts.push({
...selectedProduct,
quantity,
subprice: subprice,
remise_percent: discount,
client: 1,
});
}
setClientProducts(updatedClientProducts);
mergeProducts(updatedClientProducts, products);
setQuantityModalVisible(false);
};
const removeProductFromClient = (fkProduct) => {
setLoading(true);
const remainingClientProducts = clientProducts.filter(
(product) => product.fkProduct !== fkProduct
);
const updatedProducts = products.map((product) => {
if (product.fkProduct === fkProduct) {
return { ...product, client: 0, quantity: 0 };
}
return product;
});
setClientProducts(remainingClientProducts);
setProducts(updatedProducts);
mergeProducts(remainingClientProducts, updatedProducts);
setLoading(false);
};
const handleQuantityChange = (fkProduct, newQuantity) => {
setQuantities((currentQuantities) => ({
...currentQuantities,
[fkProduct]: newQuantity,
}));
if (newQuantity === 0) {
removeProductFromClient(fkProduct);
} else {
const updatedClientProducts = clientProducts.map((product) =>
product.fkProduct === fkProduct
? { ...product, quantity: newQuantity }
: product
);
setClientProducts(updatedClientProducts);
mergeProducts(updatedClientProducts, products);
}
};
const filteredProducts = allProducts.filter(
(product) =>
(product.label || "").toLowerCase().includes(searchText.toLowerCase()) &&
(showAllProducts ? product.client === 0 : product.client === 1)
);
const countProductsWithQuantity = () => {
return allProducts.filter(
(product) => product.client === 1 && quantities[product.fkProduct] > 0
).length;
};
const calculateTotalPurchase = () => {
return allProducts
.reduce((acc, product) => {
if (product.client === 1 && quantities[product.fkProduct]) {
const priceWithDiscount =
product.subprice * (1 - product.remise_percent / 100);
return acc + priceWithDiscount * quantities[product.fkProduct];
}
return acc;
}, 0)
.toFixed(2);
};
const finalizePurchase = async () => {
let filteredProducts = allProducts.filter(
(product) =>
product.client === 1 &&
!Number.isNaN(parseInt(product.quantity)) &&
parseInt(product.quantity) > 0 &&
product.fkProduct != null
);
let pdfUrlsArray = [];
if (!internetState.isConnected) {
await DEV.saveOrderLocally(props.cliente.clientId, filteredProducts, 0);
success = true;
} else {
if (props.cliente.client != null) {
const totalPurchase = filteredProducts.reduce(
(acc, product) =>
acc + parseFloat(product.price) * parseInt(product.quantity),
0
);
setTotalPurchase(totalPurchase.toFixed(2));
const response = await DEV.createOrderFromClient(
props.cliente.client,
filteredProducts.map(product => ({
...product,
price: parseFloat(product.price) // Ensure the price is always multiprices["1"]
})),
0
);
if (response) {
pdfUrlsArray.push(response);
} else {
console.error(
"Error al realizar la compra:",
response.error
);
}
} else {
console.log("El ID del cliente es nulo.");
}
}
if (pdfUrlsArray.length > 0) {
setPdfUrls(pdfUrlsArray);
setPurchaseModalVisible(true);
}
};
const calculateProductPrice = (subprice_ttc, subprice, tva_tx, showPriceWithTax) => {
if (showPriceWithTax) {
return parseFloat(subprice_ttc).toFixed(2);
} else {
return parseFloat(subprice).toFixed(2);
}
};
if(showCobros){
return <ListadoPedidos cliente={props.cliente}/>
}
return (
<View style={[{ flex: 1, padding: 2 }, globalStyles.container]}>
<View style={styles.headerContainer}>
<View style={styles.headerContent}>
<Icon
name={showAllProducts ? "arrow-left" : "cart-plus"}
size={40}
onPress={toggleProductList}
/>
<View style={styles.headerTitle}>
<Text style={styles.headerTitleText}>{props.cliente.name}</Text>
<Text
style={styles.headerTitleText}
>{`TOTAL CARRITO SIN IVA: ${calculateTotalPurchase()} €`}</Text>
</View>
{!showAllProducts ? (
<Icon
name="content-save"
size={40}
onPress={() => setShowFinalizeOptionsModal(true)}
/>
) : (
<Icon
name="content-save"
size={40}
onPress={toggleProductList}
/>
)}
</View>
<View style={styles.buscarStyle}>
<SearchInput
placeholder="Buscar producto..."
onSearch={handleSearch}
/>
</View>
</View>
{loading ? (
<>
<ActivityIndicator size="large" />
</>
) : (
<FlashList
keyboardDismissMode="interactive"
keyboardShouldPersistTaps="handled"
data={visibleData}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => addProductToClient(item)}>
<View
style={[
styles.productContainer,
{
backgroundColor: item.client === 1 ? "#2271b3" : "#FDFD96",
},
]}
>
<View style={styles.productHeader}>
<View style={styles.productHeaderTitle}>
<Text style={styles.productHeaderText}>{item.label}</Text>
</View>
<Icon
name="calculator"
size={50}
onPress={() => addProductToClient(item)}
/>
</View>
<View style={styles.containerRow}>
<View style={styles.priceContainer}>
{!showAllProducts ? (
<>
<View style={styles.priceColumn}>
<Text style={styles.priceText}>
Precio histórico{" "}
{showPriceWithTax ? "IVA" : "SIN IVA"}:{" "}
{`${calculateProductPrice(
item.subprice,
item.subprice_ttc,
item.tva_tx,
showPriceWithTax
)} €`}
</Text>
</View>
<View style={styles.priceColumn}>
{item.realPrice !== 0 ? (
<Text style={styles.priceText}>
Precio {showPriceWithTax ? "IVA" : "SIN IVA"}:{" "}
{`${calculateProductPrice(
item.price,
item.subprice,
item.tva_tx,
showPriceWithTax
)} €`}
</Text>
) : null}
</View>
</>
) : (
<>
<Text style={styles.priceText}>
Precio venta {showPriceWithTax ? "IVA" : "SIN IVA"}:{" "}
{`${calculateProductPrice(
item.subprice,
item.subprice,
item.tva_tx,
showPriceWithTax
)} €`}
</Text>
</>
)}
<Text style={styles.priceText}>
Precio Total:{" "}
{`${
(
parseFloat(item.subprice || 0) *
(quantities[item.fkProduct] || 0) *
(1 - parseFloat(item.remise_percent || 0) / 100)
).toFixed(2) || 0
} €`}
</Text>
<Text style={styles.priceText}>
Stock actual: {item.productStock || 0}
</Text>
</View>
<View style={styles.stockContainer}>
<Text style={styles.stockText}>
Unidades/caja: {item.options_unidades || 0}
</Text>
<Text style={styles.stockText}>
Unidades : {quantities[item.fkProduct] || 0} uds
</Text>
{!showAllProducts ? (
<Text style={styles.stockText}>
Descuento: {item.remise_percent || 0}%
</Text>
) : (
<></>
)}
</View>
</View>
</View>
</TouchableOpacity>
)}
keyExtractor={(item) => item.fkProduct.toString()}
onEndReached={loadMoreData}
onEndReachedThreshold={0.1}
estimatedItemSize={200}
threshold={5}
/>
)}
<View style={styles.footerContainer}>
<Text
style={styles.footerText}
>{`Productos seleccionados: ${countProductsWithQuantity()}`}</Text>
</View>
<Modal
animationType="slide"
transparent={true}
visible={isQuantityModalVisible}
onRequestClose={() => setQuantityModalVisible(!isQuantityModalVisible)}
>
<QuantitySelector
isVisible={isQuantityModalVisible}
onClose={() => setQuantityModalVisible(false)}
onSave={handleQuantitySave}
product={selectedProduct}
showPriceWithTax={showPriceWithTax}
/>
</Modal>
<Modal
animationType="slide"
transparent={true}
visible={showFinalizeOptionsModal}
onRequestClose={() => setShowFinalizeOptionsModal(false)}
>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>
FINALIZACIÓN DEL PEDIDO
</Text>
<Button
buttonStyle={styles.buttonStyle}
title="Crear pedido completo"
onPress={() => {
finalizePurchase(false);
setShowFinalizeOptionsModal(false);
}}
/>
<Button
buttonStyle={styles.buttonStyle}
title="Cancelar"
onPress={() => setShowFinalizeOptionsModal(false)}
/>
</View>
</View>
</Modal>
<Modal
animationType="slide"
transparent={true}
visible={isPurchaseModalVisible}
onRequestClose={() => setPurchaseModalVisible(false)}
>
<View style={styles.modalContainer}>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>Pedido creado correctamente</Text>
<Text style={styles.modalSubTitle}>
Total: €{calculateTotalPurchase()}
</Text>
{/* {pdfUrls.length > 0 &&
(console.log("VEAMOS si hay pdfs o no", pdfUrls),
(<PdfTabNavigator pdfUrls={pdfUrls} />))} */}
<Button
buttonStyle={styles.buttonStyle}
title="Ver cobros"
onPress={() => {
setPurchaseModalVisible(false);
props.navigation.navigate("NuevaPantalla");
}}
/>
<Button
buttonStyle={styles.buttonStyle}
title="Home"
onPress={() => {
setPurchaseModalVisible(false);
RootNavigation.navigate(HOME);
}}
/>
</View>
</View>
</Modal>
<Modal
animationType="slide"
transparent={true}
visible={isPendingPaymentsModalVisible}
onRequestClose={() => setPendingPaymentsModalVisible(false)}
>
<View style={modalStyles.modalContainer}>
<View style={modalStyles.modalContent}>
<Text style={modalStyles.modalTitle}>PAGOS PENDIENTES</Text>
{pendingPayments.total_due > 0 ? (
<View>
<Text style={modalStyles.modalSubTitle}>
TOTAL : €{pendingPayments.total_due.toFixed(2) }
</Text>
</View>
) : (
<Text style={modalStyles.modalSubTitle}>
No hay pagos pendientes.
</Text>
)}
<Button
buttonStyle={modalStyles.buttonStyle}
title="Ver cobros"
onPress={() => setShowCobros(true)}
/>
<Button
buttonStyle={modalStyles.buttonStyle}
title="Cerrar"
onPress={() => setPendingPaymentsModalVisible(false)}
/>
</View>
</View>
</Modal>
</View>
);
};
export default PedidosComercialScreenView;
Quantity selector
import React, { useState, useEffect } from "react";
import {
View,
Text,
Button,
Modal,
StyleSheet,
TouchableOpacity,
TextInput,
KeyboardAvoidingView,
Platform,
TouchableWithoutFeedback,
Keyboard
} from "react-native";
import { getSecureStoreData } from "../../utils/gettersAndSetters/getters.js"; // Asegúrate de que la ruta sea correcta
import { SHOW_PRICE_WITH_TAX } from "../../utils/const/secureStoreConst.js";
const QuantitySelector = ({ isVisible, onClose, onSave, product }) => {
const [quantity, setQuantity] = useState("0");
const [unitType, setUnitType] = useState("units"); // 'units' or 'pack'
const [unitsPerPack, setUnitsPerPack] = useState(1);
const [price, setPrice] = useState('0.00');
const [discount, setDiscount] = useState("0");
const [showPriceWithTax, setShowPriceWithTax] = useState(false);
useEffect(() => {
const fetchShowPriceWithTax = async () => {
const showPriceWithTax = await getSecureStoreData(SHOW_PRICE_WITH_TAX);
setShowPriceWithTax(showPriceWithTax === "true");
};
fetchShowPriceWithTax();
if (product && product.options_unidades) {
setUnitsPerPack(product.options_unidades);
}
if (product) {
if (showPriceWithTax) {
setPrice(parseFloat(product.subprice_ttc).toFixed(2));
} else {
setPrice(parseFloat(product.subprice).toFixed(2));
}
}
}, [product, showPriceWithTax]);
const handleSave = () => {
const finalQuantity =
unitType === "pack"
? parseInt(quantity, 10) * unitsPerPack
: parseInt(quantity, 10);
const finalPrice = parseFloat(price).toFixed(2);
const finalDiscount = parseFloat(discount).toFixed(2);
onSave(finalQuantity, finalPrice, finalDiscount);
};
---
const handleNumberPress = (number) => {
setQuantity((prevQuantity) =>
prevQuantity === "0"
? number.toString()
: prevQuantity + number.toString()
);
};
const handleClear = () => {
setQuantity("0");
};
const handleBackspace = () => {
setQuantity((prevQuantity) =>
prevQuantity.length > 1 ? prevQuantity.slice(0, -1) : "0"
);
};
const handlePriceChange = (text) => {
const parsed = text.replace(/[^0-9.]/g, "");
setPrice(parsed);
};
const handleDiscountChange = (text) => {
const parsed = text.replace(/[^0-9.]/g, "");
setDiscount(parsed);
};
return (
<Modal visible={isVisible} transparent={true} animationType="slide">
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.modalContainer}
>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.modalContent}>
<Text style={styles.productText}>Producto {product?.label}</Text>
<View style={styles.switchContainer}>
<TouchableOpacity
style={[
styles.switchButton,
unitType === "units" ? styles.active : styles.inactive,
]}
onPress={() => setUnitType("units")}
>
<Text style={styles.switchText}>Unidades</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.switchButton,
unitType === "pack" ? styles.active : styles.inactive,
]}
onPress={() => setUnitType("pack")}
>
<Text style={styles.switchText}>Envases</Text>
</TouchableOpacity>
</View>
<Text style={styles.quantityDisplay}>{quantity}</Text>
<View style={styles.calculatorContainer}>
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map((number) => (
<TouchableOpacity
key={number}
style={styles.calculatorButton}
onPress={() => handleNumberPress(number)}
>
<Text style={styles.calculatorButtonText}>{number}</Text>
</TouchableOpacity>
))}
<TouchableOpacity
style={styles.calculatorButton}
onPress={handleBackspace}
>
<Text style={styles.calculatorButtonText}>⌫</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.calculatorButton}
onPress={handleClear}
>
<Text style={styles.calculatorButtonText}>CE</Text>
</TouchableOpacity>
</View>
<View style={styles.inputContainer}>
<Text style={styles.inputLabel}>
Precio de venta {showPriceWithTax ? "CON IVA" : "SIN IVA"}:
</Text>
<TextInput
style={styles.input}
keyboardType="numeric"
value={price}
onChangeText={handlePriceChange}
placeholder="0.00"
placeholderTextColor="#aaa"
clearButtonMode="always"
/>
</View>
<View style={styles.inputContainer}>
<Text style={styles.inputLabel}>Descuento (%):</Text>
<TextInput
style={styles.input}
keyboardType="numeric"
value={discount}
onChangeText={handleDiscountChange}
placeholder="0"
placeholderTextColor="#aaa"
clearButtonMode="always"
/>
</View>
<View style={styles.buttonContainer}>
<Button title="Guardar" onPress={handleSave} />
<Button title="Cancelar" onPress={onClose} />
</View>
</View>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
</Modal>
);
};
export default QuantitySelector;