Untitled
user_6004366
jsx
a month ago
31 kB
1
Indexable
Never
import React, { useState, useEffect, useRef } from "react"; import AddCustomermodal from "../../components/AddCustomermodal"; import { useNavigate } from "react-router-dom"; import { pdf } from "@react-pdf/renderer"; import axiosInstance from "../../utils/axiosInstance"; import BarcodeCheckerPDF from "./SellProductPdf"; import ConfirmationModal from "./ConfirmationModal"; import { toast, ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; const convertToEnglishNumbers = (str) => { const persianNumbers = ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"]; const arabicNumbers = ["٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"]; const englishNumbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]; return str .split("") .map((c) => { const persianIndex = persianNumbers.indexOf(c); const arabicIndex = arabicNumbers.indexOf(c); if (persianIndex !== -1) return englishNumbers[persianIndex]; if (arabicIndex !== -1) return englishNumbers[arabicIndex]; return c; }) .join(""); }; const BarcodeChecker = () => { const navigate = useNavigate(); const [barcode, setBarcode] = useState(""); const [id, setId] = useState(""); const [items, setItems] = useState([]); const [customerName, setCustomerName] = useState(null); const [clientName, setClientName] = useState(null); const [customerDetails, setCustomerDetails] = useState(null); const [loading, setLoading] = useState(false); const [errors, setErrors] = useState({}); const [quantity, setQuantity] = useState(); const [name, setName] = useState(""); const [price, setPrice] = useState(0); const [payment, setPayment] = useState(0); const [paidAmount, setPaidAmount] = useState(0); const [remainingAmount, setRemainingAmount] = useState(0); const [suggestions, setSuggestions] = useState([]); const [customers, setCustomers] = useState([]); const [debt, setDebt] = useState(0); const [availableQuantity, setAvailableQuantity] = useState(0); const [selectedSuggestionIndex, setSelectedSuggestionIndex] = useState(-1); const [editIndex, setEditIndex] = useState(null); const [editQuantity, setEditQuantity] = useState(0); const [editPrice, setEditPrice] = useState(0); // const [discount, setDiscount] = useState(0); const [showModal, setShowModal] = useState(false); const [deleteIndex, setDeleteIndex] = useState(null); const [enterKeyPressCount, setEnterKeyPressCount] = useState(0); const [showNewCustomerModal, setShowNewCustomerModal] = useState(false); const barcodeRef = useRef(null); const [currentSaleId, setCurrentSaleId] = useState(null); useEffect(() => { if (enterKeyPressCount === 1) { // Focus the button document.getElementById("add-button").focus(); handleAddItem(); setEnterKeyPressCount(0); if (barcodeRef.current) { barcodeRef.current.focus(); } } else if (enterKeyPressCount === 2) { // Click the button // Reset the count } }, [enterKeyPressCount]); useEffect(() => { const fetchCustomers = async () => { setLoading(true); try { const response = await axiosInstance.get("/customers?perPage=100"); setCustomers(response.data); } catch (error) { console.error("Error fetching customers:", error); } finally { setLoading(false); } }; fetchCustomers(); }, []); useEffect(() => { if (barcode) { const fetchItem = async () => { setLoading(true); try { const response = await axiosInstance.get(`/items/${barcode}`); const item = response.data.data; setName(item.name); setPrice(item.salePrice); setId(item.id); setAvailableQuantity(item.quantity); } catch (error) { console.error("Error fetching item:", error); setName(""); setPrice(0); setId(null); setAvailableQuantity(0); } finally { setLoading(false); } }; fetchItem(); } }, [barcode]); useEffect(() => { if (customerName) { const filteredSuggestions = customers.data.filter((customer) => customer.username.toLowerCase().startsWith(customerName.toLowerCase()) ); setSuggestions(filteredSuggestions); } else { setSuggestions([]); } }, [customerName, customers]); useEffect(() => { if (customerDetails && customerDetails.id) { const fetchDebt = async () => { setLoading(true); try { const response = await axiosInstance.get( `/debts/${customerDetails.id}` ); const debt = response.data.data.total; setDebt(debt); } catch (error) { console.error("Error fetching customer debt:", error); } finally { setLoading(false); } }; fetchDebt(); } }, [customerDetails]); const handleNewInvoice = () => { setItems([]); setCustomerDetails(null); setCustomerName(null); setPaidAmount(0); setRemainingAmount(0); setPayment(0); setCurrentSaleId(null); }; const validate = () => { const newErrors = {}; if (!barcode) newErrors.barcode = "بارکۆد پێویستە"; if (!name) newErrors.name = "ناوی بەرهەم پێویستە"; if (!price) newErrors.price = "نرخ پێویستە"; if (!quantity) newErrors.quantity = "دانە پێویستە"; return newErrors; }; const formatPhoneNumber = (phone) => { const part1 = phone.slice(7, 11); const part2 = phone.slice(4, 7); const part3 = phone.slice(0, 4); return `${part1} ${part2} ${part3}`; }; const formatNumber = (value) => { if (!value) return ""; const parts = value.toString().split("."); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); return parts.join("."); }; const handlePaymentChange = (e) => { const inputValue = e.target.value; const englishNumbers = convertToEnglishNumbers(inputValue); const value = englishNumbers.replace(/,/g, ""); // Remove commas for parsing setPayment(value ? parseFloat(value) : 0); // Update state with numeric value }; const handlePriceChange = (e) => { const value = e.target.value.replace(/,/g, ""); // Remove commas for parsing setPrice(value ? parseFloat(value) : 0); // Update state with numeric value }; // const handleDiscountChange = (e) => { // const value = e.target.value.replace(/,/g, ""); // Remove commas for parsing // setDiscount(value ? parseFloat(value) : 0); // Update state with numeric value // }; const handleEditPriceChange = (e) => { const value = e.target.value.replace(/,/g, ""); // Remove commas for parsing setEditPrice(value ? parseFloat(value) : 0); // Update state with numeric value }; const handleBarcodeKeyDown = (e) => { if (e.key === "Enter") { e.preventDefault(); handleAddItem(); } }; const handleAddItem = () => { const validationErrors = validate(); if (Object.keys(validationErrors).length > 0) { setErrors(validationErrors); return; } setErrors({}); const newItem = { barcode, name, price: parseFloat(price), quantity: parseInt(quantity, 10), // Ensure it's a number id, availableQuantity, }; setItems([...items, newItem]); setBarcode(""); setName(""); setPrice(0); setQuantity(""); // Refocus on the barcode input if (barcodeRef.current) { barcodeRef.current.focus(); } }; const handleDeleteItem = () => { const newItems = items.filter((_, i) => i !== deleteIndex); setItems(newItems); setShowModal(false); }; useEffect(() => { console.log("am here"); console.log(customerName); if (customerName == "") { console.log("true true"); setClientName(() => null); } }, [customerName]); const handleShowModal = (index) => { setDeleteIndex(index); setShowModal(true); }; const handleSearchCustomer = (customer) => { const selectedCustomer = customers.data.find( (c) => c.username === customer ); if (selectedCustomer) { setCustomerDetails(selectedCustomer); setCustomerName(selectedCustomer.username); setSuggestions([]); setPaidAmount(0); setRemainingAmount(totalPriceAfterDiscount); } else { setCustomerDetails(null); setErrors({ customerName: "Customer not found" }); } }; const handleSuggestionClick = (customer) => { handleSearchCustomer(customer.username); setCustomerName(customer.username); setClientName(customer.username); }; const handleKeyDown = (e) => { if (e.key === "ArrowDown") { setSelectedSuggestionIndex((prevIndex) => prevIndex < suggestions.length - 1 ? prevIndex + 1 : 0 ); } else if (e.key === "ArrowUp") { setSelectedSuggestionIndex((prevIndex) => prevIndex > 0 ? prevIndex - 1 : suggestions.length - 1 ); } else if (e.key === "Enter" && selectedSuggestionIndex >= 0) { handleSuggestionClick(suggestions[selectedSuggestionIndex]); } }; const totalPrice = items.reduce( (sum, item) => sum + item.price * item.quantity, 0 ); const handleQuantityChange = (e) => { const inputValue = e.target.value; const englishNumbers = convertToEnglishNumbers(inputValue); setQuantity(englishNumbers === "" ? "" : parseInt(englishNumbers, 10)); }; // const totalPriceAfterDiscount = totalPrice - discount; const totalPriceAfterDiscount = totalPrice; const handlePayment = async () => { const newPaidAmount = paidAmount + payment; const newRemainingAmount = totalPriceAfterDiscount - newPaidAmount; const newAmountLent = customerDetails.amountLent + newRemainingAmount; setPaidAmount(newPaidAmount); setRemainingAmount(newRemainingAmount > 0 ? newRemainingAmount : 0); setCustomerDetails((prevDetails) => ({ ...prevDetails, amountLent: newAmountLent, })); try { let response; let paymentData; let message; if (currentSaleId) { // Update existing sale paymentData = { paidAmount: newPaidAmount, soldItems: items.map((item) => ({ item_id: item.id, quantity: item.quantity, salePrice: parseFloat(item.price), })), }; response = await axiosInstance.put( `/sales/${currentSaleId}`, paymentData ); message = "!وەسڵەکە بە سەرکەوتوویی نوێ کرایەوە"; console.log("Sale updated successfully"); } else { // Create new sale paymentData = { customer_id: customerDetails.id, paidAmount: newPaidAmount, soldItems: items.map((item) => ({ item_id: item.id, quantity: item.quantity, salePrice: parseFloat(item.price), })), }; response = await axiosInstance.post("/sales", paymentData); console.log("New sale created successfully"); setCurrentSaleId(response.data.data.id); message = "!وەسڵەکە بە سەرکەوتوویی تۆمارکرا"; } // const paymentData = { // customer_id: customerDetails.id, // paidAmount: newPaidAmount, // soldItems: items.map((item) => ({ // item_id: item.id, // quantity: item.quantity, // salePrice: parseFloat(item.price), // })), // totalPrice: totalPriceAfterDiscount, // }; // if (currentSaleId) { // // Update existing sale // response = await axiosInstance.patch( // `/sales/${currentSaleId}`, // paymentData // ); // console.log("Sale updated successfully"); // } else { // // Create new sale // response = await axiosInstance.post("/sales", paymentData); // console.log("New sale created successfully"); // setCurrentSaleId(response.data.data.id); // } toast.success(message, { position: "top-right", autoClose: 2000, }); } catch (error) { console.error("Error recording payment:", error); toast.error("هەڵەیەک ڕویدا لە تۆمارکردنی وەسڵەکە."); } setPayment(0); }; // const handleQuantityKeyPress = (e) => { // if (e.key === "Enter") { // setEnterKeyPressCount((prevCount) => prevCount + 1); // } // }; const handlePrint = async () => { const doc = ( <BarcodeCheckerPDF customerDetails={customerDetails} items={items} totalPrice={totalPriceAfterDiscount} paidAmount={paidAmount} remainingAmount={remainingAmount} // discount={discount} customers={customers} /> ); const blob = await pdf(doc).toBlob(); const url = URL.createObjectURL(blob); const printWindow = window.open(url); if (printWindow) { printWindow.onload = () => { printWindow.print(); }; } else { console.error("Failed to open new window for printing."); } }; const handleEditRow = (index) => { setEditIndex(index); setEditQuantity(items[index].quantity); setEditPrice(items[index].price); }; const handleSaveEdit = (index) => { const updatedItems = items.map((item, i) => { if (i === index) { return { ...item, quantity: editQuantity, price: parseFloat(editPrice), }; } return item; }); setItems(updatedItems); // Reset editing state setEditIndex(null); setEditQuantity(0); setEditPrice(0); }; const handleCancelEdit = () => { setEditIndex(null); setEditQuantity(0); setEditPrice(0); }; return ( <div className="flex items-center justify-center min-h-screen overflow-hidden bg-secondary"> <ToastContainer /> <div className="flex flex-col w-full p-8 m-2 border-2 rounded-lg shadow-lg bg-accent border-primary"> <button className="flex px-4 py-2 mb-4 text-lg text-center border rounded-md text-invert border-primary w-fit" onClick={() => { navigate("/"); }} > گەڕانەوە </button> <div className="relative flex mb-4"> <input type="text" value={customerName} onChange={(e) => setCustomerName(e.target.value)} placeholder="ناوی کڕیار" onKeyDown={handleKeyDown} className={`flex-grow px-4 py-2 text-xl border rounded-md bg-secondary text-invert text-right focus:outline-none focus:ring focus:ring-primary ${ errors.customerName ? "border-red-500" : "border-primary" }`} /> {!customerDetails && ( <button className="p-4 mx-4 rounded-sm bg-primary" onClick={() => setShowNewCustomerModal(true)} > کڕیاری نوێ </button> )} <AddCustomermodal isOpen={showNewCustomerModal} onClose={() => setShowNewCustomerModal(false)} onSubmit={(data) => { // Handle form submission setShowNewCustomerModal(false); // Close modal after submit }} /> {/* <button onClick={() => handleSearchCustomer(customerName)} disabled={loading} className="px-10 py-[10px] mr-4 bg-primary text-invert rounded-md hover:bg-primary focus:outline-none focus:ring-2 focus:ring-invert focus:ring-opacity-75 text-xl font-medium" > گەڕان </button> */} {suggestions.length > 0 && clientName === null && ( <ul className="absolute z-10 w-full mt-1 text-xl rounded-md shadow-lg top-full bg-accent"> {suggestions.map((suggestion, index) => ( <li key={suggestion.id} onClick={() => handleSuggestionClick(suggestion)} className={`px-4 py-2 text-xl text-right cursor-pointer hover:bg-primary text-invert ${ selectedSuggestionIndex === index ? " bg-primary" : "" }`} > <div className="" onClick={() => handleSuggestionClick(suggestion)} > {" "} {suggestion.username} - {suggestion.city} -{" "} {suggestion.phone} </div> </li> ))} </ul> )} </div> {errors.customerName && ( <p className="mt-1 text-sm text-right text-red-500"> {errors.customerName} </p> )} {/* <h2 className="mb-6 text-2xl font-bold text-center text-invert"> زانیاری بەرهەم </h2> */} <div className="grid grid-cols-1 gap-4 mb-4 text-2xl md:grid-cols-2 lg:grid-cols-7"> <div className="flex flex-col col-span-2"> <label className="mb-2 text-invert">بارکۆد</label> <input type="text" ref={barcodeRef} value={barcode} onChange={(e) => setBarcode(e.target.value)} className={`px-4 py-2 border rounded-md text-xl bg-secondary text-invert text-right focus:outline-none focus:ring focus:ring-primary ${ errors.barcode ? "border-red-500" : "border-primary" }`} /> </div> <div className="flex flex-col col-span-2"> <label className="mb-2 text-invert">ناوی بەرهەم</label> <input type="text" value={name} readOnly className={` w-92 px-4 py-2 border rounded-md text-xl bg-secondary text-invert text-right focus:outline-none focus:ring focus:ring-primary ${ errors.name ? "border-red-500" : "border-primary" }`} /> </div> <div className="flex flex-col"> <label className="mb-2 text-invert">نرخ</label> <input type="text" value={formatNumber(price)} onChange={handlePriceChange} className={`w-44 px-4 py-2 border rounded-md text-xl bg-secondary text-invert text-right focus:outline-none focus:ring focus:ring-primary ${ errors.price ? "border-red-500" : "border-primary" }`} /> </div> <div className="flex flex-col"> <label className="mb-2 text-invert">عدد</label> <input type="text" value={quantity} onChange={handleQuantityChange} onKeyDown={handleBarcodeKeyDown} className={`w-28 p-2 border rounded-md text-xl bg-secondary text-invert text-right focus:outline-none focus:ring focus:ring-primary ${ errors.quantity ? "border-red-500" : "border-primary" }`} /> </div> <div className="flex items-center justify-center w-1/3 "> <button id="add-button" onClick={handleAddItem} disabled={quantity === 0} className="w-24 px-4 py-2 text-4xl rounded-md bg-primary disabled:bg-gray-900 disabled:cursor-not-allowed text-invert hover:bg-primary focus:outline-none focus:ring-2 focus:ring-invert focus:ring-opacity-75" > + </button> </div> </div> {errors.barcode && ( <p className="mt-1 text-xl text-right text-red-500"> {errors.barcode} </p> )} <div className="flex flex-1"> <div className="w-1/4 pl-4"> {customerDetails && ( <div className="w-full"> <h3 className="text-2xl font-semibold text-right text-invert"> زانیاری کڕیار </h3> <div className="w-full p-4 px-2 my-4 border-2 rounded-lg shadow bg-secondary border-primary"> <div className="grid grid-cols-1 "> <p className="w-full px-2 text-xl text-invert"> {customerDetails.username} </p> <br /> <p className="px-2 text-xl text-invert"> {customerDetails.province} _ {customerDetails.city} _{" "} {customerDetails.address} </p> <br /> {/* <p className={`px-2 ${ customerDetails.amountLent <= 1500 ? "text-green-500 text-xl" : "text-red-500 text-xl" }`} > قەرز : ${debt?.toLocaleString("en-US")} </p> */} {/* <br /> */} <p className="px-2 text-xl text-invert"> {customerDetails.phone1 && formatPhoneNumber(customerDetails.phone1)} </p> </div> </div> </div> )} {customerDetails && ( <> {" "} {/* <div className="flex items-center justify-center w-full gap-4 mb-4 text-2xl"> <label className="w-3/5 ml-4 mr-2 text-sm font-semibold text-invert"> بڕی داشکاندن </label> <input type="text" value={formatNumber(discount)} onChange={handleDiscountChange} placeholder="(دینار)" className={`px-4 py-2 border rounded-md text-xl w-full bg-secondary text-invert text-right focus:outline-none focus:ring focus:ring-primary ${ errors.discount ? "border-red-500" : "border-primary" }`} /> </div> */} <div className="w-full p-4 ml-auto text-right border-2 rounded-lg shadow bg-secondary border-primary"> <div className="flex items-center mb-2 text-right"> <label className="ml-4 mr-2 text-xl font-semibold text-invert"> بڕی پارە </label> <input type="text" value={formatNumber(payment)} onChange={handlePaymentChange} className="w-40 p-4 py-2 text-2xl text-right border rounded-md border-primary bg-secondary text-invert focus:outline-none focus:ring focus:ring-primary" /> </div> <button onClick={handlePayment} disabled={loading} className="w-full px-4 py-2 mt-2 mb-4 text-xl font-semibold rounded-md bg-primary text-invert hover:bg-primary focus:outline-none focus:ring-2 focus:ring-invert focus:ring-opacity-75" > پارەدان </button> </div> </> )} </div> <div className="flex flex-col w-3/4 pr-4"> {items.length > 0 && ( <> <div className="flex-1 "> <h3 className="text-2xl font-semibold text-right text-invert"> زانیاری بەرهەمەکان </h3> <div className="mt-[23px] overflow-y-auto max-h-96 text-xl flex-1 border-1 border-primary rounded-md"> <table className="min-w-full border-2 bg-secondary text-invert border-primary"> <thead> <tr> <th className="w-1/12 px-4 py-2 text-xl text-right border-2 border-primary"> # </th> <th className="w-3/12 px-4 py-2 text-xl text-right border-2 border-primary"> بەرهەم </th> <th className="w-2/12 px-4 py-2 text-xl text-right border-2 border-primary"> دانە </th> <th className="w-2/12 px-4 py-2 text-xl text-right border-2 border-primary"> نرخ </th> <th className="w-2/12 px-4 py-2 text-xl text-right border-2 border-primary"> کۆ </th> <th className="w-2/12 px-4 py-2 text-xl text-right border-2 border-primary"> گۆرانکاری{" "} </th> </tr> </thead> <tbody> {items.map((item, index) => ( <tr key={index}> <td className="px-4 py-2 text-xl text-right border"> {index + 1} </td> <td className="px-4 py-2 text-xl text-right border"> {item.name} </td> <td className="px-4 py-2 text-xl text-right border"> {editIndex === index ? ( <input type="number" value={editQuantity} onChange={(e) => setEditQuantity(parseInt(e.target.value)) } className="w-full p-2 text-right text-black rounded-md" /> ) : ( item.quantity )} </td> <td className="px-4 py-2 text-xl text-right border"> {editIndex === index ? ( <input type="text" value={formatNumber(editPrice)} onChange={handleEditPriceChange} className="w-full p-2 text-right text-black rounded-md" /> ) : ( formatNumber(item.price) // Ensure the price is formatted correctly )} </td> <td className="px-4 py-2 text-xl text-right border"> {formatNumber(item.price * item.quantity)} </td> <td className="px-4 py-2 text-xl text-right border"> {editIndex === index ? ( <div className="flex justify-end gap-2"> <button onClick={() => handleSaveEdit(index)} className="px-2 py-1 text-white rounded bg-primary" > نوێکردنەوە </button> <button onClick={handleCancelEdit} className="px-2 py-1 text-white bg-red-600 rounded" > هەڵوەشاندنەوە </button> </div> ) : ( <div className="flex justify-center gap-2"> <button onClick={() => handleEditRow(index)} className="px-2 py-1 text-white rounded bg-primary/20" > 🖋️ </button> <button onClick={() => handleShowModal(index)} className="px-2 py-1 text-white rounded bg-red-600/20" > ❌ </button> </div> )} </td> </tr> ))} </tbody> </table> </div> <h3 className="mt-4 text-2xl font-semibold text-right text-invert"> کۆی نرخ: {totalPrice.toLocaleString("en-US")} </h3> <div className="p-2 mb-4 border-primary"> <p className="py-2 text-xl text-invert"> پارەی دراو: {paidAmount.toLocaleString("en-US")} $ </p> <p className="py-2 text-xl text-invert"> ماوە: {remainingAmount.toLocaleString("en-US")} $ </p> </div> {/* <h3 className="mt-4 text-2xl font-semibold text-right text-invert"> بڕی داشکاندن: {discount.toLocaleString("en-US")} </h3> */} {/* <h3 className="mt-4 text-2xl font-semibold text-right text-invert"> کۆی نرخ دوای داشکاندن:{" "} {totalPriceAfterDiscount.toLocaleString("en-US")} </h3> */} </div> </> )} </div> </div> <button onClick={handlePrint} className="flex justify-center w-full px-4 py-2 mt-8 text-2xl rounded-md bg-primary text-invert hover:bg-primary focus:outline-none focus:ring-2 focus:ring-invert focus:ring-opacity-75" > پرینت کردن </button> <button onClick={() => window.location.reload()} className="w-full px-4 py-2 mt-20 mb-4 text-xl font-semibold rounded-md bg-primary text-invert hover:bg-primary focus:outline-none focus:ring-2 focus:ring-invert focus:ring-opacity-75" > وەصڵی نوێ </button> </div> <ConfirmationModal show={showModal} onClose={() => setShowModal(false)} onConfirm={handleDeleteItem} /> </div> ); }; export default BarcodeChecker;
Leave a Comment