143 lines
6.6 KiB
TypeScript
143 lines
6.6 KiB
TypeScript
import express from 'express';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import { createServer as createViteServer } from 'vite';
|
|
import dotenv from 'dotenv';
|
|
|
|
dotenv.config();
|
|
|
|
async function startServer() {
|
|
const app = express();
|
|
const PORT = 3000;
|
|
|
|
app.use(express.json());
|
|
|
|
// API route to send email via SMTP (supporting both standard and PHP endpoint pathways)
|
|
app.post(['/api/send-email', '/send-email.php'], async (req, res) => {
|
|
const { name, email, phone, company, subject, message, isEstimate, estimateSummary } = req.body;
|
|
|
|
if (!name || !email) {
|
|
return res.status(400).json({ error: 'Missing name or email' });
|
|
}
|
|
|
|
// Generate Email Content
|
|
const emailSubject = isEstimate
|
|
? `LiteCharms Project Estimate Proposal: ${subject}`
|
|
: `LiteCharms General Service Inquiry: ${subject}`;
|
|
|
|
let breakdownHtml = '';
|
|
if (isEstimate && estimateSummary && Array.isArray(estimateSummary.breakdown)) {
|
|
breakdownHtml = estimateSummary.breakdown
|
|
.map((b: any) => `<li>${b.item}: ${b.price}</li>`)
|
|
.join('');
|
|
}
|
|
|
|
const emailHtml = `
|
|
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden; color: #1e293b;">
|
|
<div style="background-color: #020617; padding: 24px; text-align: center; border-bottom: 2px solid #00bcac;">
|
|
<h2 style="color: #ffffff; margin: 0; font-size: 22px; letter-spacing: -0.02em;">Lite<span style="color: #00bcac;">Charms</span></h2>
|
|
<p style="color: #94a3b8; margin: 4px 0 0 0; font-size: 12px; font-family: monospace;">MIDRAND, SOUTH AFRICA</p>
|
|
</div>
|
|
<div style="padding: 24px; background-color: #ffffff;">
|
|
<h3 style="color: #00bcac; margin-top: 0; margin-bottom: 16px; font-size: 18px;">${isEstimate ? 'New Project Estimate Inquiry' : 'New General Service Inquiry'}</h3>
|
|
|
|
<table style="width: 100%; border-collapse: collapse; margin-bottom: 24px;">
|
|
<tr style="border-bottom: 1px solid #f1f5f9;">
|
|
<td style="padding: 8px 0; font-weight: bold; width: 120px; font-size: 13px; color: #64748b;">Client Name:</td>
|
|
<td style="padding: 8px 0; font-size: 13px; color: #1e293b;">${name}</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #f1f5f9;">
|
|
<td style="padding: 8px 0; font-weight: bold; font-size: 13px; color: #64748b;">Email Address:</td>
|
|
<td style="padding: 8px 0; font-size: 13px; color: #1e293b;"><a href="mailto:${email}">${email}</a></td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #f1f5f9;">
|
|
<td style="padding: 8px 0; font-weight: bold; font-size: 13px; color: #64748b;">Phone Number:</td>
|
|
<td style="padding: 8px 0; font-size: 13px; color: #1e293b;">${phone || 'Not Provided'}</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #f1f5f9;">
|
|
<td style="padding: 8px 0; font-weight: bold; font-size: 13px; color: #64748b;">Company:</td>
|
|
<td style="padding: 8px 0; font-size: 13px; color: #1e293b;">${company || 'Not Provided'}</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #f1f5f9;">
|
|
<td style="padding: 8px 0; font-weight: bold; font-size: 13px; color: #64748b;">Subject:</td>
|
|
<td style="padding: 8px 0; font-size: 13px; color: #1e293b;">${subject}</td>
|
|
</tr>
|
|
</table>
|
|
|
|
${isEstimate && estimateSummary ? `
|
|
<div style="background-color: #f8fafc; border: 1px dashed #cbd5e1; padding: 16px; border-radius: 6px; margin-bottom: 24px;">
|
|
<h4 style="margin-top: 0; color: #020617; font-size: 14px; border-bottom: 1px solid #e2e8f0; padding-bottom: 6px;">Selected Scope & Custom Pricing Range</h4>
|
|
<div style="margin-top: 8px; font-size: 13px;">
|
|
<strong>Estimated Range:</strong> <span style="color: #00bcac; font-weight: bold;">R ${estimateSummary.totalMin?.toLocaleString('en-ZA')}</span> to <span style="color: #e11d48; font-weight: bold;">R ${estimateSummary.totalMax?.toLocaleString('en-ZA')}</span>
|
|
<br/><strong>Roadmap:</strong> ~${estimateSummary.timelineWeeks} Weeks
|
|
</div>
|
|
${breakdownHtml ? `
|
|
<div style="margin-top: 12px; font-size: 11px; color: #64748b;">
|
|
<strong>Breakdown items:</strong>
|
|
<ul style="margin: 4px 0 0 0; padding-left: 16px;">
|
|
${breakdownHtml}
|
|
</ul>
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
` : ''}
|
|
|
|
<div style="margin-bottom: 24px;">
|
|
<h4 style="margin-top: 0; margin-bottom: 8px; font-size: 14px; color: #020617;">Client Message / Brief:</h4>
|
|
<p style="background-color: #f8fafc; padding: 12px; border-radius: 6px; font-size: 13px; line-height: 1.5; color: #334155; white-space: pre-wrap; margin: 0;">${(message || 'No additional notes provided.').replace(/\n/g, '<br/>')}</p>
|
|
</div>
|
|
</div>
|
|
<div style="background-color: #f1f5f9; padding: 16px; text-align: center; font-size: 11px; color: #64748b; border-top: 1px solid #e2e8f0;">
|
|
This is an automated dispatch from the LiteCharms website server.
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
try {
|
|
const response = await fetch('https://messenger.api.khongisa.co.za/api/send-email', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
htmlBody: emailHtml,
|
|
from: 'contact@litecharms.co.za',
|
|
to: 'contact@litecharms.co.za',
|
|
subject: emailSubject,
|
|
}),
|
|
});
|
|
|
|
if (response.ok) {
|
|
return res.json({ success: true, message: 'Email sent successfully via Messenger API' });
|
|
} else {
|
|
const errorText = await response.text();
|
|
return res.status(500).json({ error: 'External API Error', details: errorText });
|
|
}
|
|
} catch (error: any) {
|
|
console.error('Server proxy email send error:', error);
|
|
return res.status(500).json({ error: 'Server error sending email', details: error.message });
|
|
}
|
|
});
|
|
|
|
// Vite middleware setup
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
const vite = await createViteServer({
|
|
server: { middlewareMode: true },
|
|
appType: 'spa',
|
|
});
|
|
app.use(vite.middlewares);
|
|
} else {
|
|
const distPath = path.join(process.cwd(), 'dist');
|
|
app.use(express.static(distPath));
|
|
app.get('*', (req, res) => {
|
|
res.sendFile(path.join(distPath, 'index.html'));
|
|
});
|
|
}
|
|
|
|
app.listen(PORT, '0.0.0.0', () => {
|
|
console.log(`LiteCharms full-stack application running on http://localhost:${PORT}`);
|
|
});
|
|
}
|
|
|
|
startServer();
|