Untitled
user_6004366
jsx
a year ago
31 kB
7
Indexable
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;
Editor is loading...
Leave a Comment