Skip to content

Instantly share code, notes, and snippets.

@amritmaurya1504
Created February 22, 2025 09:33
Show Gist options
  • Select an option

  • Save amritmaurya1504/b6846836a67cc0fb483b5d5c7222893d to your computer and use it in GitHub Desktop.

Select an option

Save amritmaurya1504/b6846836a67cc0fb483b5d5c7222893d to your computer and use it in GitHub Desktop.
// INVOICE COMPONENT
import React, { useRef } from "react";
import { motion } from "framer-motion";
import { FaCheck } from "react-icons/fa6";
const Invoice = ({ orderInfo, setShowInvoice }) => {
const invoiceRef = useRef(null);
const handlePrint = () => {
const printContent = invoiceRef.current.innerHTML;
const WinPrint = window.open("", "", "width=900,height=650");
WinPrint.document.write(`
<html>
<head>
<title>Order Receipt</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.receipt-container { width: 300px; border: 1px solid #ddd; padding: 10px; }
h2 { text-align: center; }
</style>
</head>
<body>
${printContent}
</body>
</html>
`);
WinPrint.document.close();
WinPrint.focus();
setTimeout(() => {
WinPrint.print();
WinPrint.close();
}, 1000);
};
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center">
<div className="bg-white p-4 rounded-lg shadow-lg w-[400px]">
{/* Receipt Content for Printing */}
<div ref={invoiceRef} className="p-4">
{/* Receipt Header */}
<div className="flex justify-center mb-4">
<motion.div
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1.2, opacity: 1 }}
transition={{ duration: 0.5, type: "spring", stiffness: 150 }}
className="w-12 h-12 border-8 border-green-500 rounded-full flex items-center justify-center shadow-lg bg-green-500"
>
<motion.span
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ delay: 0.3, duration: 0.3 }}
className="text-2xl"
>
<FaCheck className="text-white" />
</motion.span>
</motion.div>
</div>
<h2 className="text-xl font-bold text-center mb-2">Order Receipt</h2>
<p className="text-gray-600 text-center">Thank you for your order!</p>
{/* Order Details */}
<div className="mt-4 border-t pt-4 text-sm text-gray-700">
<p>
<strong>Order ID:</strong>{" "}
{Math.floor(new Date(orderInfo.orderDate).getTime())}
</p>
<p>
<strong>Name:</strong> {orderInfo.customerDetails.name}
</p>
<p>
<strong>Phone:</strong> {orderInfo.customerDetails.phone}
</p>
<p>
<strong>Guests:</strong> {orderInfo.customerDetails.guests}
</p>
</div>
{/* Items Summary */}
<div className="mt-4 border-t pt-4">
<h3 className="text-sm font-semibold">Items Ordered</h3>
<ul className="text-sm text-gray-700">
{orderInfo.items.map((item, index) => (
<li
key={index}
className="flex justify-between items-center text-xs"
>
<span>
{item.name} x{item.quantity}
</span>
<span>₹{item.price.toFixed(2)}</span>
</li>
))}
</ul>
</div>
{/* Bills Summary */}
<div className="mt-4 border-t pt-4 text-sm">
<p>
<strong>Subtotal:</strong> ₹{orderInfo.bills.total.toFixed(2)}
</p>
<p>
<strong>Tax:</strong> ₹{orderInfo.bills.tax.toFixed(2)}
</p>
<p className="text-md font-semibold">
<strong>Grand Total:</strong> ₹
{orderInfo.bills.totalWithTax.toFixed(2)}
</p>
</div>
{/* Payment Details */}
<div className="mb-2 mt-2 text-xs">
{orderInfo.paymentMethod === "Cash" ? (
<p>
<strong>Payment Method:</strong> {orderInfo.paymentMethod}
</p>
) : (
<>
<p>
<strong>Payment Method:</strong> {orderInfo.paymentMethod}
</p>
<p>
<strong>Razorpay Order ID:</strong>{" "}
{orderInfo.paymentData?.razorpay_order_id}
</p>
<p>
<strong>Razorpay Payment ID:</strong>{" "}
{orderInfo.paymentData?.razorpay_payment_id}
</p>
</>
)}
</div>
</div>
{/* Buttons */}
<div className="flex justify-between mt-4">
<button
onClick={handlePrint}
className="text-blue-500 hover:underline text-xs px-4 py-2 rounded-lg"
>
Print Receipt
</button>
<button
onClick={() => setShowInvoice(false)}
className="text-red-500 hover:underline text-xs px-4 py-2 rounded-lg"
>
Close
</button>
</div>
</div>
</div>
);
};
export default Invoice;
// BILL COMPONENT
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getTotalPrice } from "../../redux/slices/cartSlice";
import {
addOrder,
createOrderRazorpay,
updateTable,
verifyPaymentRazorpay,
} from "../../https/index";
import { enqueueSnackbar } from "notistack";
import { useMutation } from "@tanstack/react-query";
import { removeAllItems } from "../../redux/slices/cartSlice";
import { removeCustomer } from "../../redux/slices/customerSlice";
import Invoice from "../invoice/Invoice";
function loadScript(src) {
return new Promise((resolve) => {
const script = document.createElement("script");
script.src = src;
script.onload = () => {
resolve(true);
};
script.onerror = () => {
resolve(false);
};
document.body.appendChild(script);
});
}
const Bill = () => {
const dispatch = useDispatch();
const customerData = useSelector((state) => state.customer);
const cartData = useSelector((state) => state.cart);
const total = useSelector(getTotalPrice);
const taxRate = 5.25;
const tax = (total * taxRate) / 100;
const totalPriceWithTax = total + tax;
const [paymentMethod, setPaymentMethod] = useState();
const [showInvoice, setShowInvoice] = useState(false);
const [orderInfo, setOrderInfo] = useState();
const handlePlaceOrder = async () => {
if (!paymentMethod) {
enqueueSnackbar("Please select a payment method!", {
variant: "warning",
});
return;
}
if (paymentMethod === "Online") {
// load the script
try {
const res = await loadScript(
"https://checkout.razorpay.com/v1/checkout.js"
);
if (!res) {
enqueueSnackbar("Razorpay SDK failed to load. Are you online?", {
variant: "warning",
});
return;
}
// create order
const reqData = {
amount: totalPriceWithTax.toFixed(2),
};
const { data } = await createOrderRazorpay(reqData);
const options = {
key: `${import.meta.env.VITE_RAZORPAY_KEY_ID}`,
amount: data.order.amount,
currency: data.order.currency,
name: "RESTRO",
description: "Secure Payment for Your Meal",
order_id: data.order.id,
handler: async function (response) {
const verification = await verifyPaymentRazorpay(response);
console.log(verification);
enqueueSnackbar(verification.data.message, { variant: "success" });
// Place the order
const orderData = {
customerDetails: {
name: customerData.customerName,
phone: customerData.customerPhone,
guests: customerData.guests,
},
orderStatus: "In Progress",
bills: {
total: total,
tax: tax,
totalWithTax: totalPriceWithTax,
},
items: cartData,
table: customerData.table.tableId,
paymentMethod: paymentMethod,
paymentData: {
razorpay_order_id: response.razorpay_order_id,
razorpay_payment_id: response.razorpay_payment_id,
},
};
setTimeout(() => {
orderMutation.mutate(orderData);
}, 1500);
},
prefill: {
name: customerData.name,
email: "",
contact: customerData.phone,
},
theme: { color: "#025cca" },
};
const rzp = new window.Razorpay(options);
rzp.open();
} catch (error) {
console.log(error);
enqueueSnackbar("Payment Failed!", {
variant: "error",
});
}
} else {
// Place the order
const orderData = {
customerDetails: {
name: customerData.customerName,
phone: customerData.customerPhone,
guests: customerData.guests,
},
orderStatus: "In Progress",
bills: {
total: total,
tax: tax,
totalWithTax: totalPriceWithTax,
},
items: cartData,
table: customerData.table.tableId,
paymentMethod: paymentMethod,
};
orderMutation.mutate(orderData);
}
};
const orderMutation = useMutation({
mutationFn: (reqData) => addOrder(reqData),
onSuccess: (resData) => {
const { data } = resData.data;
console.log(data);
setOrderInfo(data);
// Update Table
const tableData = {
status: "Booked",
orderId: data._id,
tableId: data.table,
};
setTimeout(() => {
tableUpdateMutation.mutate(tableData);
}, 1500);
enqueueSnackbar("Order Placed!", {
variant: "success",
});
setShowInvoice(true);
},
onError: (error) => {
console.log(error);
},
});
const tableUpdateMutation = useMutation({
mutationFn: (reqData) => updateTable(reqData),
onSuccess: (resData) => {
console.log(resData);
dispatch(removeCustomer());
dispatch(removeAllItems());
},
onError: (error) => {
console.log(error);
},
});
return (
<>
<div className="flex items-center justify-between px-5 mt-2">
<p className="text-xs text-[#ababab] font-medium mt-2">
Items({cartData.lenght})
</p>
<h1 className="text-[#f5f5f5] text-md font-bold">
₹{total.toFixed(2)}
</h1>
</div>
<div className="flex items-center justify-between px-5 mt-2">
<p className="text-xs text-[#ababab] font-medium mt-2">Tax(5.25%)</p>
<h1 className="text-[#f5f5f5] text-md font-bold">₹{tax.toFixed(2)}</h1>
</div>
<div className="flex items-center justify-between px-5 mt-2">
<p className="text-xs text-[#ababab] font-medium mt-2">
Total With Tax
</p>
<h1 className="text-[#f5f5f5] text-md font-bold">
₹{totalPriceWithTax.toFixed(2)}
</h1>
</div>
<div className="flex items-center gap-3 px-5 mt-4">
<button
onClick={() => setPaymentMethod("Cash")}
className={`bg-[#1f1f1f] px-4 py-3 w-full rounded-lg text-[#ababab] font-semibold ${
paymentMethod === "Cash" ? "bg-[#383737]" : ""
}`}
>
Cash
</button>
<button
onClick={() => setPaymentMethod("Online")}
className={`bg-[#1f1f1f] px-4 py-3 w-full rounded-lg text-[#ababab] font-semibold ${
paymentMethod === "Online" ? "bg-[#383737]" : ""
}`}
>
Online
</button>
</div>
<div className="flex items-center gap-3 px-5 mt-4">
<button className="bg-[#025cca] px-4 py-3 w-full rounded-lg text-[#f5f5f5] font-semibold text-lg">
Print Receipt
</button>
<button
onClick={handlePlaceOrder}
className="bg-[#f6b100] px-4 py-3 w-full rounded-lg text-[#1f1f1f] font-semibold text-lg"
>
Place Order
</button>
</div>
{showInvoice && (
<Invoice orderInfo={orderInfo} setShowInvoice={setShowInvoice} />
)}
</>
);
};
export default Bill;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment