test preview
This commit is contained in:
146
server/index.js
Normal file
146
server/index.js
Normal file
@@ -0,0 +1,146 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import Stripe from 'stripe';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3001;
|
||||
|
||||
// Initialize Stripe
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
|
||||
|
||||
// Middleware
|
||||
app.use(cors({
|
||||
origin: process.env.FRONTEND_URL || 'http://localhost:5173',
|
||||
}));
|
||||
app.use(express.json());
|
||||
|
||||
// Health check
|
||||
app.get('/api/health', (req, res) => {
|
||||
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
||||
});
|
||||
|
||||
// Create Stripe Checkout Session
|
||||
app.post('/api/checkout', async (req, res) => {
|
||||
try {
|
||||
const { orderData } = req.body;
|
||||
|
||||
// Validate required fields
|
||||
if (!orderData?.contact?.email || !orderData?.contact?.name) {
|
||||
return res.status(400).json({ error: 'Name and email are required' });
|
||||
}
|
||||
|
||||
// Create Stripe Checkout Session
|
||||
const session = await stripe.checkout.sessions.create({
|
||||
payment_method_types: ['card'],
|
||||
mode: 'payment',
|
||||
customer_email: orderData.contact.email,
|
||||
line_items: [
|
||||
{
|
||||
price_data: {
|
||||
currency: 'eur',
|
||||
product_data: {
|
||||
name: 'Website in 48h',
|
||||
description: `${orderData.websiteType} | ${orderData.style} | ${orderData.theme === 'dark' ? 'Dunkel' : 'Hell'}`,
|
||||
images: ['https://webklar.de/og-image.png'], // Optional
|
||||
},
|
||||
unit_amount: 19900, // 199€ in cents
|
||||
},
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
metadata: {
|
||||
customerName: orderData.contact.name,
|
||||
customerCompany: orderData.contact.company || '',
|
||||
customerPhone: orderData.contact.phone || '',
|
||||
websiteType: orderData.websiteType,
|
||||
style: orderData.style,
|
||||
theme: orderData.theme,
|
||||
colorPrimary: orderData.colors?.primary || '#0A400C',
|
||||
colorSecondary: orderData.colors?.secondary || '#819067',
|
||||
colorAccent: orderData.colors?.accent || '#B1AB86',
|
||||
customReferenceUrl: orderData.customInput?.referenceUrl || '',
|
||||
customDescription: orderData.customInput?.description || '',
|
||||
},
|
||||
success_url: `${process.env.FRONTEND_URL || 'http://localhost:5173'}/success?session_id={CHECKOUT_SESSION_ID}`,
|
||||
cancel_url: `${process.env.FRONTEND_URL || 'http://localhost:5173'}/konfigurator`,
|
||||
});
|
||||
|
||||
res.json({
|
||||
sessionId: session.id,
|
||||
url: session.url
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Stripe error:', error);
|
||||
res.status(500).json({
|
||||
error: 'Failed to create checkout session',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Verify session (for success page)
|
||||
app.get('/api/session/:sessionId', async (req, res) => {
|
||||
try {
|
||||
const session = await stripe.checkout.sessions.retrieve(req.params.sessionId);
|
||||
|
||||
res.json({
|
||||
id: session.id,
|
||||
status: session.payment_status,
|
||||
customerEmail: session.customer_email,
|
||||
amountTotal: session.amount_total,
|
||||
metadata: session.metadata,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Session verification error:', error);
|
||||
res.status(404).json({ error: 'Session not found' });
|
||||
}
|
||||
});
|
||||
|
||||
// Stripe Webhook (for production)
|
||||
app.post('/api/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
|
||||
const sig = req.headers['stripe-signature'];
|
||||
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
|
||||
|
||||
if (!webhookSecret) {
|
||||
console.warn('Webhook secret not configured');
|
||||
return res.status(400).send('Webhook secret not configured');
|
||||
}
|
||||
|
||||
try {
|
||||
const event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
|
||||
|
||||
switch (event.type) {
|
||||
case 'checkout.session.completed':
|
||||
const session = event.data.object;
|
||||
console.log('✅ Payment successful:', session.id);
|
||||
// TODO: Save order to database, send confirmation email, etc.
|
||||
break;
|
||||
|
||||
case 'payment_intent.payment_failed':
|
||||
console.log('❌ Payment failed:', event.data.object.id);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(`Unhandled event type: ${event.type}`);
|
||||
}
|
||||
|
||||
res.json({ received: true });
|
||||
} catch (error) {
|
||||
console.error('Webhook error:', error.message);
|
||||
res.status(400).send(`Webhook Error: ${error.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`\n🚀 Server running on http://localhost:${port}`);
|
||||
console.log(`\n📋 Endpoints:`);
|
||||
console.log(` GET /api/health`);
|
||||
console.log(` POST /api/checkout`);
|
||||
console.log(` GET /api/session/:sessionId`);
|
||||
console.log(` POST /api/webhook\n`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user