function SecondsSalesView({ salesUrl, token, id }) { const [entry, setEntry] = React.useState(null); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(''); React.useEffect(() => { let mounted = true; async function load() { try { setLoading(true); const res = await fetch((salesUrl || '') + '/api/seconds-sales', { headers: { Authorization: token ? ('Bearer ' + token) : '' } }); const data = await res.json(); if (!res.ok) throw new Error(data.message || 'Failed to load'); const found = (data.rows || []).find(r => String(r._id) === String(id)); if (mounted) setEntry(found || null); } catch (err) { if (mounted) setError(err.message || 'Failed'); } finally { if (mounted) setLoading(false); } } load(); return () => { mounted = false; }; }, [id]); // Purchase modal state (hooks before returns) const [showPurchase, setShowPurchase] = React.useState(false); const [purchaseForm, setPurchaseForm] = React.useState({ customerName: '', phone: '', price: '', bankId: '' }); const [purchaseImages, setPurchaseImages] = React.useState([]); const [purchaseDocs, setPurchaseDocs] = React.useState([]); const [banks, setBanks] = React.useState([]); const [purchaseLoading, setPurchaseLoading] = React.useState(false); // load banks React.useEffect(() => { let mounted = true; (async () => { try { const res = await fetch((salesUrl || '') + '/api/banks', { headers: { Authorization: token ? ('Bearer ' + token) : '' } }); const data = await res.json(); if (res.ok && mounted) setBanks(Array.isArray(data.banks) ? data.banks : []); } catch (err) { console.error('load banks', err); } })(); return () => { mounted = false; }; }, []); function purchaseOnChange(e) { const { name, value } = e.target; setPurchaseForm(f => ({ ...f, [name]: value })); } function filesToBase64(fileList, setter) { const files = Array.from(fileList || []); if (!files.length) return; const promises = files.map(f => new Promise((res, rej) => { const reader = new FileReader(); reader.onload = () => res({ name: f.name, base64: reader.result }); reader.onerror = rej; reader.readAsDataURL(f); })); Promise.all(promises).then(arr => setter(prev => [...prev, ...arr])).catch(err => console.error('file read', err)); } async function submitPurchase(e) { e.preventDefault(); const amount = Number(purchaseForm.price || 0); const bankId = purchaseForm.bankId || ''; if (!amount || amount <= 0) return alert('Enter valid price'); setPurchaseLoading(true); try { const payload = { customerName: purchaseForm.customerName || '', phone: purchaseForm.phone || '', price: amount, bank_id: bankId || undefined, images: purchaseImages || [], documents: purchaseDocs || [] }; const res = await fetch((salesUrl || '') + '/api/seconds-sales/' + encodeURIComponent(entry._id) + '/purchase', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: token ? ('Bearer ' + token) : '' }, body: JSON.stringify(payload) }); const data = await res.json(); if (!res.ok) throw new Error(data.message || 'Purchase API failed'); // server returns updated entry (with purchases) if (data.entry) setEntry(data.entry); setShowPurchase(false); setPurchaseForm({ customerName: '', phone: '', price: '', bankId: '' }); setPurchaseImages([]); setPurchaseDocs([]); } catch (err) { alert(err.message || 'Purchase failed'); } finally { setPurchaseLoading(false); } } // Helpers to prepare WhatsApp message and printable bill function decodeJwt(tk) { try { const theToken = tk || token || localStorage.getItem('branch_token') || localStorage.getItem('sales_token') || ''; const parts = theToken.split('.'); if (parts.length < 2) return {}; const base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/'); const json = decodeURIComponent(atob(base64).split('').map(function(c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); return JSON.parse(json); } catch (e) { return {}; } } async function getBranchInfo() { let shopName = ''; let shopContact = ''; try { const url = new URL((salesUrl || '') + '/api/branches'); const res = await fetch(url, { headers: { Authorization: token ? ('Bearer ' + token) : '' } }); const data = await res.json(); if (res.ok && Array.isArray(data.branches) && data.branches.length > 0) { const payload = decodeJwt(); const branchId = payload?.branch_id || payload?._id || ''; let found = null; if (branchId) found = data.branches.find(b => String(b._id) === String(branchId)); if (!found) found = data.branches[0]; shopName = found?.name || ''; shopContact = found?.phoneNumber || found?.phone || ''; } } catch (e) { /* ignore */ } if (!shopName || !shopContact) { const payload = decodeJwt(); shopName = shopName || payload.shopName || payload.name || payload.branchName || ''; shopContact = shopContact || payload.phone || payload.phoneNumber || payload.branchPhone || ''; } return { shopName, shopContact }; } function normalizePhone(raw) { let digits = (raw || '').toString().replace(/[^0-9]/g, ''); if (digits.length === 11 && digits.startsWith('0')) digits = digits.slice(1); if (digits.length === 10) digits = '91' + digits; return digits; } async function handleWhatsAppLastPurchase() { const p = (entry.purchases || [])[((entry.purchases||[]).length - 1)]; if (!p) return alert('No purchase found'); const { shopName, shopContact } = await getBranchInfo(); const productName = `${entry.mobileName || ''}${entry.model ? (' — ' + entry.model) : ''}`.trim(); const date = new Date(p.createdAt || Date.now()).toLocaleString(); const message = `Shop: ${shopName}\nContact: ${shopContact}\n\nProduct: ${productName}\nPrice: ₹ ${Number(p.price||0).toFixed(2)}\nDate: ${date}\nCustomer: ${p.customerName || '-'} — ${p.phone || '-'}\n\nThanks,\n${shopName}`; const cust = normalizePhone(p.phone || ''); try { // Open WhatsApp web with prefilled message to customer number const whatsappUrl = window.ENV_CONFIG?.WHATSAPP_WEB_URL || 'https://web.whatsapp.com'; if (cust) window.open(`${whatsappUrl}/send?phone=${cust}&text=${encodeURIComponent(message)}`, '_blank'); else window.open(whatsappUrl + '/', '_blank'); } catch (e) { console.error('open whatsapp', e); } } function handlePrintLastPurchase() { const p = (entry.purchases || [])[((entry.purchases||[]).length - 1)]; if (!p) return alert('No purchase found'); (async () => { const { shopName, shopContact } = await getBranchInfo(); const productName = `${entry.mobileName || ''}${entry.model ? (' — ' + entry.model) : ''}`.trim(); const date = new Date(p.createdAt || Date.now()).toLocaleString(); const total = Number(p.price || 0).toFixed(2); const html = `Receipt` + `

TAX INVOICE

${shopName || 'Shop'}
${shopContact || ''}
` + `
Date: ${date}
` + `` + `` + `
ItemQtyUnitLine
${productName}1${Number(p.price||0).toFixed(2)}${Number(p.price||0).toFixed(2)}
` + `
Thanks for your purchase!
`; const w = window.open('', '_blank'); if (!w) { setError('Popup blocked: allow popups to print directly'); return; } w.document.open(); w.document.write(html); w.document.close(); w.focus(); setTimeout(() => { try { w.print(); } catch (e) { /* ignore */ } }, 300); })(); } if (loading) return (

Loading Entry Details

Please wait while we fetch the information...

); if (error) return (
⚠️

Error Loading Entry

{error}

); if (!entry) return (
📱

Entry Not Found

The requested mobile entry could not be found.

); // Enhanced helper to render file links with better styling const fileLinks = (arr) => (arr || []).map((f, i) => { const filename = f.filename || (f.path ? f.path.split(/[\\/]/).pop() : null); const base = (salesUrl || '').replace(/\/+$/, '') || ''; const url = filename ? `${base}/uploads/seconds-sales/${filename}` : (f.path || '#'); const isPdf = (filename || '').toLowerCase().endsWith('.pdf'); const isImage = /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(filename || ''); const getFileIcon = () => { if (isPdf) return '📄'; if (isImage) return '🖼️'; return '📁'; }; return (
{ e.target.style.backgroundColor = '#e5e7eb'; e.target.style.borderColor = '#9ca3af'; e.target.style.transform = 'translateY(-1px)'; }} onMouseLeave={(e) => { e.target.style.backgroundColor = '#f3f4f6'; e.target.style.borderColor = '#d1d5db'; e.target.style.transform = 'translateY(0px)'; }} > {getFileIcon()} {f.originalName || filename || 'file'}
); }); // Helper to render file links for purchases const purchaseFileLinks = fileLinks; return (

📱 {entry.mobileName || 'Mobile Entry'} Details

Complete information and purchase history

{/* Mobile Device Information */}

📋 Device Information

Model
{entry.model || 'Not specified'}
IMEI Number
{entry.imeNo || 'Not available'}
Specification
{entry.specification || 'Not specified'}
Condition
{entry.mobileCondition || 'Not specified'}
{/* Seller Information */}

👤 Seller Information

Seller Name
{entry.sellerName || 'Not provided'}
Address
{entry.sellerAddress || 'Not provided'}
Reference Contact
{(entry.referenceName || 'Not provided') + (entry.referenceNumber ? (' — ' + entry.referenceNumber) : '')}
Reason for Sale
{entry.reasonForSale || 'Not provided'}
{/* Payment & Proof */}

💰 Payment & Verification

Proof Details
{(entry.proofType || 'Not provided') + (entry.proofNo ? (' — ' + entry.proofNo) : '')}
Purchase Value
₹{Number(entry.valueOfProduct || 0).toFixed(2)}
{/* Attachments */}

📎 Attached Files

📸 Images ({(entry.images || []).length})
{(entry.images || []).length > 0 ? fileLinks(entry.images) : (
No images attached
)}
📄 Documents ({(entry.documents || []).length})
{(entry.documents || []).length > 0 ? fileLinks(entry.documents) : (
No documents attached
)}
✍️ Signatures ({(entry.signatures || []).length})
{(entry.signatures || []).length > 0 ? fileLinks(entry.signatures) : (
No signatures attached
)}
{/* Purchases Section */}

🧾 Purchase History

Track all sales for this mobile device

{(entry.purchases || []).length} Record{(entry.purchases || []).length !== 1 ? 's' : ''}
{(entry.purchases || []).length === 0 ? (
🧾

No Purchases Yet

This mobile device is still available for sale. Use the "Record Purchase" button above to add a sale.

) : (
{(entry.purchases || []).map((p, idx) => (
{/* Purchase Header */}
SOLD #{idx + 1}
{p.customerName || 'Unknown Customer'}
{p.phone || 'No phone number'}
₹{Number(p.price || 0).toFixed(2)}
{/* Purchase Details */}
📄 Documents ({(p.documents || []).length})
{(p.documents || []).length > 0 ? purchaseFileLinks(p.documents) : (
No documents
)}
📸 Images ({(p.images || []).length})
{(p.images || []).length > 0 ? purchaseFileLinks(p.images) : (
No images
)}
Sold on {new Date(p.createdAt || Date.now()).toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' })}
))}
)} {/* Action Buttons */} {(entry.purchases || []).length > 0 ? (
) : null}
{/* Enhanced Purchase Modal */} {showPurchase ? (
{/* Modal Header */}

💰 Record New Purchase

Enter customer details and sale information

{/* Customer Information */}
👤 Customer Information
e.target.style.borderColor = '#16a34a'} onBlur={(e) => e.target.style.borderColor = '#e2e8f0'} />
e.target.style.borderColor = '#16a34a'} onBlur={(e) => e.target.style.borderColor = '#e2e8f0'} />
{/* Payment Information */}
💳 Payment Details
e.target.style.borderColor = '#16a34a'} onBlur={(e) => e.target.style.borderColor = '#e2e8f0'} />
{/* File Attachments */}
📎 Attachments (Optional)
filesToBase64(e.target.files, setPurchaseDocs)} style={{ width: '100%', padding: '12px', border: '2px dashed #d1d5db', borderRadius: '8px', fontSize: '14px', backgroundColor: '#f9fafb', cursor: 'pointer' }} /> {purchaseDocs.length > 0 && (
✓ {purchaseDocs.length} document{purchaseDocs.length !== 1 ? 's' : ''} selected
)}
filesToBase64(e.target.files, setPurchaseImages)} style={{ width: '100%', padding: '12px', border: '2px dashed #d1d5db', borderRadius: '8px', fontSize: '14px', backgroundColor: '#f9fafb', cursor: 'pointer' }} /> {purchaseImages.length > 0 && (
✓ {purchaseImages.length} image{purchaseImages.length !== 1 ? 's' : ''} selected
)}
{/* Modal Actions */}
) : null}
); } window.SecondsSalesView = SecondsSalesView;