import React, { useState, useEffect } from 'react'; import { Printer, Plus, Trash2, FileText, Briefcase, Hash, Calendar, Download, Image as ImageIcon } from 'lucide-react'; export default function App() { // State untuk jenis dokumen (quotation, invoice, receipt) const [docType, setDocType] = useState('quotation'); // State untuk status library html2canvas const [isLibraryLoaded, setIsLibraryLoaded] = useState(false); // Load html2canvas script useEffect(() => { const script = document.createElement('script'); script.src = "https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"; script.async = true; script.onload = () => setIsLibraryLoaded(true); document.body.appendChild(script); return () => { document.body.removeChild(script); }; }, []); // State untuk maklumat borang const [formData, setFormData] = useState({ companyName: 'Syarikat Maju Jaya Sdn Bhd', companyAddress: 'No. 123, Jalan Bisnes 1,\nTaman Usahawan,\n40000 Shah Alam, Selangor.', clientName: 'Encik Ali Bin Abu', clientAddress: 'Lot 45, Kampung Baru,\n50000 Kuala Lumpur.', docNumber: 'QT-2023-001', date: new Date().toISOString().split('T')[0], }); // State untuk senarai item const [items, setItems] = useState([ { id: 1, description: 'Perkhidmatan Reka Bentuk Web', quantity: 1, price: 1500 }, { id: 2, description: 'Domain & Hosting (1 Tahun)', quantity: 1, price: 300 }, ]); // Fungsi mengendalikan perubahan input teks const handleInputChange = (e) => { const { name, value } = e.target; setFormData({ ...formData, [name]: value }); }; // Fungsi mengendalikan perubahan item const handleItemChange = (id, field, value) => { const newItems = items.map((item) => { if (item.id === id) { return { ...item, [field]: value }; } return item; }); setItems(newItems); }; // Tambah item baru const addItem = () => { setItems([...items, { id: Date.now(), description: '', quantity: 1, price: 0 }]); }; // Hapus item const deleteItem = (id) => { setItems(items.filter((item) => item.id !== id)); }; // Kira jumlah total const calculateTotal = () => { return items.reduce((sum, item) => sum + (Number(item.quantity) * Number(item.price)), 0); }; // Format mata wang const formatCurrency = (amount) => { return new Intl.NumberFormat('ms-MY', { style: 'currency', currency: 'MYR' }).format(amount); }; // Dapatkan tajuk dokumen berdasarkan jenis const getDocTitle = () => { switch (docType) { case 'quotation': return 'SEBUTHARGA'; case 'invoice': return 'INVOIS'; case 'receipt': return 'RESIT'; default: return 'DOKUMEN'; } }; // Dapatkan label nombor rujukan const getRefLabel = () => { switch (docType) { case 'quotation': return 'No. Sebutharga'; case 'invoice': return 'No. Invois'; case 'receipt': return 'No. Resit'; default: return 'No. Rujukan'; } }; // Fungsi Simpan sebagai PNG const handleDownloadPNG = async () => { if (!isLibraryLoaded || typeof window.html2canvas === 'undefined') { alert("Sila tunggu sebentar, sistem sedang memuatkan fungsi imej..."); return; } const element = document.getElementById('document-preview'); try { const canvas = await window.html2canvas(element, { scale: 2, // Kualiti tinggi backgroundColor: '#ffffff', logging: false, useCORS: true }); const image = canvas.toDataURL("image/png"); const link = document.createElement('a'); link.href = image; link.download = `${getDocTitle()}_${formData.docNumber}.png`; document.body.appendChild(link); link.click(); document.body.removeChild(link); } catch (error) { console.error("Gagal menjana imej:", error); alert("Maaf, terdapat ralat semasa menjana imej."); } }; return (
{formData.companyAddress || "Alamat Syarikat..."}
| No. | Perkhidmatan / Produk | Kuantiti | Harga Unit | Jumlah |
|---|---|---|---|---|
| {index + 1} | {item.description} | {item.quantity} | {formatCurrency(item.price)} | {formatCurrency(item.quantity * item.price)} |
1. Pembayaran hendaklah dibuat dalam masa 30 hari dari tarikh invois.
2. Cek hendaklah ditulis atas nama {formData.companyName}.
3. Terima kasih atas sokongan anda.
Tandatangan Penerima
Tandatangan Syarikat