React + Vite + Tailwind frontend with Express backend. 3-step wizard (Operator, Ground Loops, Access Control) with PDF quote download and CAD pricing data.
52 lines
1.4 KiB
JavaScript
52 lines
1.4 KiB
JavaScript
const express = require('express');
|
|
const cors = require('cors');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 3001;
|
|
|
|
app.use(cors());
|
|
|
|
const pricingData = JSON.parse(
|
|
fs.readFileSync(path.join(__dirname, 'data', 'pricing.json'), 'utf-8')
|
|
);
|
|
|
|
app.get('/api/pricing', (req, res) => {
|
|
res.json(pricingData);
|
|
});
|
|
|
|
app.get('/api/pricing/:category', (req, res) => {
|
|
const { category } = req.params;
|
|
const validCategories = ['operators', 'groundLoopStyles', 'groundLoopTypes', 'accessControl'];
|
|
if (validCategories.includes(category)) {
|
|
return res.json(pricingData[category]);
|
|
}
|
|
res.status(400).json({ error: `Invalid category. Use: ${validCategories.join(', ')}` });
|
|
});
|
|
|
|
const clientDist = path.join(__dirname, '..', 'client', 'dist');
|
|
if (fs.existsSync(clientDist)) {
|
|
app.use(express.static(clientDist));
|
|
app.get('*', (req, res) => {
|
|
res.sendFile(path.join(clientDist, 'index.html'));
|
|
});
|
|
}
|
|
|
|
function getLocalIP() {
|
|
const ifaces = os.networkInterfaces();
|
|
for (const name of Object.keys(ifaces)) {
|
|
for (const iface of ifaces[name]) {
|
|
if (iface.family === 'IPv4' && !iface.internal) return iface.address;
|
|
}
|
|
}
|
|
return 'localhost';
|
|
}
|
|
|
|
app.listen(PORT, '0.0.0.0', () => {
|
|
const ip = getLocalIP();
|
|
console.log(`\n Local: http://localhost:${PORT}`);
|
|
console.log(` Network: http://${ip}:${PORT}\n`);
|
|
});
|