Files
litecharms-site/server.ts
T
2026-07-14 12:14:23 +02:00

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();