florale-emotion/backend/server.js

301 lines
9.1 KiB
JavaScript

const express = require('express');
const cors = require('cors');
const nodemailer = require('nodemailer');
const axios = require('axios');
const path = require('path');
require('dotenv').config();
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(cors());
app.use(express.json());
app.use(express.static(path.join(__dirname, '../dist/florale-emotion')));
// Email configuration
const transporter = nodemailer.createTransport({
host: 'smtp.mailbox.org',
port: 587,
secure: false,
auth: {
user: process.env.EMAIL_USER || 'info@florale-emotion.de',
pass: process.env.EMAIL_PASS || 'your-email-password'
}
});
// Gitea configuration
const GITEA_CONFIG = {
url: process.env.GITEA_URL || 'https://your-gitea-instance.com',
token: process.env.GITEA_TOKEN || 'your-gitea-token',
owner: 'florale-emotion',
repo: 'tickets'
};
// Email templates
const getCustomerEmailTemplate = (formData) => {
const eventTypes = {
'wedding': 'Hochzeit',
'funeral': 'Beerdigung',
'corporate': 'Firmenevent',
'birthday': 'Geburtstag',
'anniversary': 'Jubiläum',
'other': 'Sonstiges'
};
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.header { background: linear-gradient(135deg, #ec4899, #22c55e); color: white; padding: 20px; text-align: center; }
.content { padding: 20px; }
.footer { background: #f8f9fa; padding: 15px; text-align: center; font-size: 12px; color: #666; }
</style>
</head>
<body>
<div class="header">
<h1>Florale Emotion</h1>
<p>Vielen Dank für Ihre Anfrage!</p>
</div>
<div class="content">
<p>Liebe/r ${formData.firstName} ${formData.lastName},</p>
<p>vielen Dank für Ihr Interesse an unseren floralen Services für Ihr/e ${eventTypes[formData.eventType] || formData.eventType}!</p>
<p>Wir haben Ihre Anfrage erhalten und werden uns schnellstmöglich bei Ihnen melden. In der Regel antworten wir innerhalb von 24 Stunden.</p>
<h3>Ihre Anfrage im Überblick:</h3>
<ul>
<li><strong>Event-Art:</strong> ${eventTypes[formData.eventType] || formData.eventType}</li>
${formData.eventDate ? `<li><strong>Gewünschtes Datum:</strong> ${new Date(formData.eventDate).toLocaleDateString('de-DE')}</li>` : ''}
${formData.guestCount ? `<li><strong>Anzahl Gäste:</strong> ${formData.guestCount}</li>` : ''}
${formData.budget ? `<li><strong>Budget:</strong> ${formData.budget}</li>` : ''}
</ul>
<p>Falls Sie noch Fragen haben oder zusätzliche Informationen benötigen, zögern Sie nicht, uns zu kontaktieren.</p>
<p>Mit floralen Grüßen,<br>
Ihr Team von Florale Emotion<br>
Veronika & Corinna</p>
</div>
<div class="footer">
<p>Florale Emotion | info@florale-emotion.de | www.florale-emotion.de</p>
</div>
</body>
</html>
`;
};
const getInternalEmailTemplate = (formData) => {
const eventTypes = {
'wedding': 'Hochzeit',
'funeral': 'Beerdigung',
'corporate': 'Firmenevent',
'birthday': 'Geburtstag',
'anniversary': 'Jubiläum',
'other': 'Sonstiges'
};
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.header { background: #1f2937; color: white; padding: 20px; }
.content { padding: 20px; }
.info-box { background: #f3f4f6; padding: 15px; margin: 10px 0; border-left: 4px solid #ec4899; }
</style>
</head>
<body>
<div class="header">
<h1>Neue Kundenanfrage - Florale Emotion</h1>
</div>
<div class="content">
<h2>Kundeninformationen</h2>
<div class="info-box">
<p><strong>Name:</strong> ${formData.firstName} ${formData.lastName}</p>
<p><strong>E-Mail:</strong> ${formData.email}</p>
<p><strong>Telefon:</strong> ${formData.phone || 'Nicht angegeben'}</p>
</div>
<h2>Event-Details</h2>
<div class="info-box">
<p><strong>Art des Events:</strong> ${eventTypes[formData.eventType] || formData.eventType}</p>
<p><strong>Gewünschtes Datum:</strong> ${formData.eventDate ? new Date(formData.eventDate).toLocaleDateString('de-DE') : 'Nicht angegeben'}</p>
<p><strong>Anzahl Gäste:</strong> ${formData.guestCount || 'Nicht angegeben'}</p>
<p><strong>Budget:</strong> ${formData.budget || 'Nicht angegeben'}</p>
</div>
<h2>Nachricht</h2>
<div class="info-box">
<p>${formData.message.replace(/\n/g, '<br>')}</p>
</div>
<p><em>Eingegangen am: ${new Date().toLocaleString('de-DE')}</em></p>
</div>
</body>
</html>
`;
};
// Create Gitea ticket
async function createGiteaTicket(formData) {
try {
const eventTypes = {
'wedding': 'Hochzeit',
'funeral': 'Beerdigung',
'corporate': 'Corporate Event',
'birthday': 'Geburtstag',
'anniversary': 'Jubiläum',
'other': 'Sonstiges'
};
const title = `Neue Anfrage: ${eventTypes[formData.eventType] || formData.eventType} - ${formData.firstName} ${formData.lastName}`;
const body = `## Kundeninformationen
- **Name:** ${formData.firstName} ${formData.lastName}
- **E-Mail:** ${formData.email}
- **Telefon:** ${formData.phone || 'Nicht angegeben'}
## Event-Details
- **Art des Events:** ${eventTypes[formData.eventType] || formData.eventType}
- **Gewünschtes Datum:** ${formData.eventDate || 'Nicht angegeben'}
- **Anzahl Gäste:** ${formData.guestCount || 'Nicht angegeben'}
- **Budget:** ${formData.budget || 'Nicht angegeben'}
## Nachricht
${formData.message}
---
*Automatisch erstellt am ${new Date().toLocaleString('de-DE')}*`;
const issue = {
title,
body,
labels: ['kunde-anfrage', eventTypes[formData.eventType]?.toLowerCase().replace(' ', '-') || 'sonstiges'],
assignees: ['veronika', 'corinna']
};
const response = await axios.post(
`${GITEA_CONFIG.url}/api/v1/repos/${GITEA_CONFIG.owner}/${GITEA_CONFIG.repo}/issues`,
issue,
{
headers: {
'Authorization': `token ${GITEA_CONFIG.token}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
} catch (error) {
console.error('Error creating Gitea ticket:', error.response?.data || error.message);
throw error;
}
}
// Routes
app.post('/api/contact', async (req, res) => {
try {
const formData = req.body;
// Send confirmation email to customer
const customerMailOptions = {
from: process.env.EMAIL_USER || 'info@florale-emotion.de',
to: formData.email,
subject: 'Bestätigung Ihrer Anfrage - Florale Emotion',
html: getCustomerEmailTemplate(formData)
};
// Send notification email to team
const teamMailOptions = {
from: process.env.EMAIL_USER || 'info@florale-emotion.de',
to: [
'veronika@florale-emotion.de',
'corinna@florale-emotion.de',
'info@florale-emotion.de'
],
subject: `Neue Kundenanfrage: ${formData.firstName} ${formData.lastName}`,
html: getInternalEmailTemplate(formData)
};
// Send emails
await Promise.all([
transporter.sendMail(customerMailOptions),
transporter.sendMail(teamMailOptions)
]);
// Create Gitea ticket
let ticketId = null;
try {
const ticket = await createGiteaTicket(formData);
ticketId = ticket.number;
} catch (ticketError) {
console.error('Failed to create Gitea ticket:', ticketError);
// Continue even if ticket creation fails
}
res.json({
success: true,
message: 'Anfrage erfolgreich gesendet',
ticketId
});
} catch (error) {
console.error('Error processing contact form:', error);
res.status(500).json({
success: false,
message: 'Fehler beim Senden der Anfrage'
});
}
});
app.post('/api/newsletter', async (req, res) => {
try {
const { email } = req.body;
const mailOptions = {
from: process.env.EMAIL_USER || 'info@florale-emotion.de',
to: email,
subject: 'Willkommen bei Florale Emotion Newsletter',
html: `
<h2>Willkommen bei unserem Newsletter!</h2>
<p>Vielen Dank für Ihr Interesse an Florale Emotion.</p>
<p>Sie erhalten ab sofort Updates über neue Projekte, Tipps und besondere Angebote.</p>
`
};
await transporter.sendMail(mailOptions);
res.json({
success: true,
message: 'Newsletter-Anmeldung erfolgreich'
});
} catch (error) {
console.error('Error processing newsletter signup:', error);
res.status(500).json({
success: false,
message: 'Fehler bei der Newsletter-Anmeldung'
});
}
});
// Health check
app.get('/api/health', (req, res) => {
res.json({ status: 'OK', timestamp: new Date().toISOString() });
});
// Serve Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '../dist/florale-emotion/index.html'));
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});