import React, { useState, useEffect, useRef } from 'react'; // Predefined equipment list based on user requirements const DEFAULT_EQUIPMENT = [ { id: '1', selected: true, rating: '580KW', name: 'Waari Solar Panel', quantity: 8, unit: 'Nos', make: 'Waari', warranty: '25 Years' }, { id: '2', selected: true, rating: '5KW', name: 'On-Grid Solar Inverter', quantity: 2, unit: 'Nos', make: 'Fujiyama (UTL)', warranty: '10 Years' }, { id: '3', selected: true, rating: '1 Phase', name: 'Net Meter', quantity: 1, unit: 'Nos', make: 'Secure Meters Limited', warranty: '' }, { id: '4', selected: true, rating: '', name: 'Alternating Current Distribution Box', quantity: 1, unit: 'Nos', make: '', warranty: '' }, { id: '5', selected: true, rating: '', name: 'Direct Current Distribution Box', quantity: 1, unit: 'Nos', make: '', warranty: '' }, { id: '6', selected: true, rating: '', name: 'G.I Structure', quantity: 1, unit: 'Lot', make: '', warranty: '' }, { id: '7', selected: true, rating: '', name: 'DC Wire', quantity: 1, unit: 'Lot', make: 'Polycab', warranty: '' }, { id: '8', selected: true, rating: '', name: 'Earthing', quantity: 3, unit: 'Nos', make: '', warranty: '' }, { id: '9', selected: true, rating: '', name: 'Pipe, Fitting & Other Accessories Etc.', quantity: 1, unit: 'Lot', make: '', warranty: '' } ]; export default function App() { const [formData, setFormData] = useState({ customerName: '', customerAddress: '', date: new Date().toISOString().split('T')[0], kwhLoad: '4', // Default to 4 as per original template cost: '255000' // Default to 255000 as per original template }); const [equipmentList, setEquipmentList] = useState(DEFAULT_EQUIPMENT); const [errors, setErrors] = useState({}); // Handle standard input changes const handleInputChange = (e) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value })); validateField(name, value); }; // Validation Logic const validateField = (name, value) => { let newErrors = { ...errors }; if (name === 'kwhLoad' || name === 'cost') { if (value === '') { delete newErrors[name]; // Allow empty while typing, but won't render in preview } else if (isNaN(parseFloat(value)) || !isFinite(value) || parseFloat(value) < 0) { newErrors[name] = 'Must be a valid positive number'; } else { delete newErrors[name]; } } setErrors(newErrors); }; // Handle Equipment Toggles const handleEquipmentToggle = (id) => { setEquipmentList(prev => prev.map(item => item.id === id ? { ...item, selected: !item.selected } : item )); }; // Handle Individual Equipment Field Changes const handleEquipmentChange = (id, field, value) => { setEquipmentList(prev => prev.map(item => item.id === id ? { ...item, [field]: value } : item )); }; const handleAddEquipment = () => { const newId = Date.now().toString(); setEquipmentList(prev => [...prev, { id: newId, selected: true, rating: '', name: '', quantity: 1, unit: 'Nos', make: '', warranty: '' }]); }; const handleRemoveEquipment = (id) => { setEquipmentList(prev => prev.filter(item => item.id !== id)); }; // Format currency for Indian Rupees const formatCurrency = (amount) => { const num = parseFloat(amount); if (isNaN(num)) return ''; return new Intl.NumberFormat('en-IN').format(num); }; // Format Date for letter const formatDate = (dateString) => { if (!dateString) return ''; const date = new Date(dateString); return date.toLocaleDateString('en-GB', { day: '2-digit', month: 'long', year: 'numeric' }); }; // Trigger browser print, relying on @media print CSS to isolate the document const handleDownloadPdf = () => { window.print(); }; const isFormValid = Object.keys(errors).length === 0; return (
{/* Print Styles */}
{/* LEFT COLUMN: Input Form (Hidden on Print) */}

Proposal Generator

{/* Customer Details */}
{errors.kwhLoad &&

{errors.kwhLoad}

}
{errors.cost &&

{errors.cost}

}

{/* Equipment Selection */}
{equipmentList.map((item) => (
handleEquipmentToggle(item.id)} className="mt-2 h-4 w-4 text-indigo-600 rounded cursor-pointer shrink-0" /> handleEquipmentChange(item.id, 'name', e.target.value)} placeholder="Equipment Name" disabled={!item.selected} className={`flex-1 p-1.5 text-sm font-medium border-b focus:outline-none bg-transparent ${item.selected ? 'border-gray-300 focus:border-indigo-500 text-gray-900' : 'border-transparent text-gray-400 line-through'}`} />
{item.selected && (
handleEquipmentChange(item.id, 'quantity', e.target.value)} className="w-full p-1.5 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-indigo-500 outline-none" min="0" />
handleEquipmentChange(item.id, 'unit', e.target.value)} placeholder="Nos/Lot" className="w-full p-1.5 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-indigo-500 outline-none" />
handleEquipmentChange(item.id, 'rating', e.target.value)} placeholder="e.g. 5KW" className="w-full p-1.5 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-indigo-500 outline-none" />
handleEquipmentChange(item.id, 'make', e.target.value)} placeholder="e.g. Waari" className="w-full p-1.5 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-indigo-500 outline-none" />
handleEquipmentChange(item.id, 'warranty', e.target.value)} placeholder="e.g. 25 Years" className="w-full p-1.5 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-indigo-500 outline-none" />
)}
))}
{/* RIGHT COLUMN: Live Document Preview */}
{/* Header */}

INDUJA

Engineering Services Pvt Ltd

{/* Ref and Date */}
SQ No. IESPL/HTS/2025-26/SQ87
Date: {formatDate(formData.date)}
{/* To Address */} {(formData.customerName || formData.customerAddress) && (

To,

{formData.customerName &&

{formData.customerName}

} {formData.customerAddress &&

Address: {formData.customerAddress}

}
)} {/* Subject */}

Subject: Technical offer for Rating- {formData.kwhLoad || '___'}kw On-Grid Rooftop Solar System

Dear Sir,

We acknowledge with thanks for your valued enquiry. We are pleased to submit our offer for your requirement of products as below.

{/* Annexure I - Price */}

Price Schedule - Annexure "I"

Cost of {formData.kwhLoad || '___'}kw Solar System - ₹ {formData.cost ? `${formatCurrency(formData.cost)}/-` : '______/-'}

{/* Annexure II - BOM */}

Bill of Material- Annexure "II"

    {equipmentList.filter(e => e.selected).map((item) => (
  • {item.rating ? `${item.rating} ` : ''}{item.name} - {item.quantity} {item.unit} {(item.make || item.warranty) && (
    {[ item.make ? `Make - ${item.make}` : '', item.warranty ? `${item.warranty} Warranty by Manufacturer` : '' ].filter(Boolean).join(', ')}
    )}
  • ))} {equipmentList.filter(e => e.selected).length === 0 && (
  • No equipment selected.
  • )}
{/* Annexure III - T&C */}

Commercial Terms & Conditions - Annexure "III"

  • Prices: Ex-Works Hathras basis.
  • GST: Inclusive in above Prices.
  • Freight: Inclusive in above Prices.
  • Installation & commissioning Charges: Inclusive in above Prices.
  • Payment Terms: 100% Advance against Proforma Invoice before dispatch of the solar panel, inverter and other BOS items to be delivered.
  • Validity of Quotation: Our Offer Is Valid For 7 Days.
  • Note: Any Civil work will be in client's Scope.
{/* Bank Details */}

Company's Bank Details

INDUJA ENGINEERING SERVICES PVT. LTD.

BANK A/C NO.: 50200087428646

BANK NAME: HDFC Bank

Swift Code: HDFCINBB

IFSC CODE: HDFC0000329

{/* Footer Signoff */}

We hope you will find above in line with your requirements. Should you require any further Information, please feel free to contact us.

Sincerely,

Nitin Prem Rajput

Induja Engineering Services Pvt Ltd

{/* Footer Address */}

Office Address: D-31, Sector-7, Noida-201301, Uttar Pradesh, India

www.indujagroup.com | indujaengineeringservices@gmail.com

Email: nitinpremrajput@indujagroup.com

); }