- Removed old socket handling code and replaced it with a new implementation in `app/api/socketio/route.js`. - Added MySQL database integration for managing active sessions and queue entries. - Implemented event retrieval and ticket purchasing APIs in `app/api/events/route.js` and `app/api/purchase/route.js`. - Created database schema for events, tickets, active sessions, and orders in `database/schema.sql`. - Updated front-end to handle event data fetching and ticket purchasing with improved UI components. - Removed unused SVG files from the public directory.
107 lines
3.1 KiB
JavaScript
107 lines
3.1 KiB
JavaScript
import mysql from 'mysql2/promise'
|
|
import jwt from 'jsonwebtoken'
|
|
|
|
async function getDbConnection() {
|
|
if (!process.env.MYSQL_HOST) return null
|
|
return await mysql.createConnection({
|
|
host: process.env.MYSQL_HOST,
|
|
user: process.env.MYSQL_USER,
|
|
password: process.env.MYSQL_PASSWORD,
|
|
database: process.env.MYSQL_DATABASE,
|
|
})
|
|
}
|
|
|
|
export async function POST(request) {
|
|
try {
|
|
const { eventId, ticketType, quantity, token } = await request.json()
|
|
|
|
if (!eventId || !ticketType || !quantity || !token) {
|
|
return Response.json({ error: 'Missing required fields' }, { status: 400 })
|
|
}
|
|
|
|
// Verify JWT token
|
|
let decoded
|
|
try {
|
|
decoded = jwt.verify(token, process.env.JWT_SECRET || 'dev-secret')
|
|
} catch (error) {
|
|
return Response.json({ error: 'Invalid or expired token' }, { status: 401 })
|
|
}
|
|
|
|
const connection = await getDbConnection()
|
|
if (!connection) {
|
|
return Response.json({ error: 'Database not configured' }, { status: 500 })
|
|
}
|
|
|
|
// Check if token is still active in database
|
|
const [activeRows] = await connection.execute(
|
|
'SELECT * FROM active_sessions WHERE event_id = ? AND socket_id = ? AND expires_at > NOW()',
|
|
[eventId, decoded.sid]
|
|
)
|
|
|
|
if (activeRows.length === 0) {
|
|
await connection.end()
|
|
return Response.json({ error: 'Session expired or not authorized' }, { status: 401 })
|
|
}
|
|
|
|
// Get ticket information
|
|
const [ticketRows] = await connection.execute(
|
|
'SELECT * FROM tickets WHERE event_id = ? AND type = ?',
|
|
[eventId, ticketType]
|
|
)
|
|
|
|
if (ticketRows.length === 0) {
|
|
await connection.end()
|
|
return Response.json({ error: 'Ticket type not found' }, { status: 404 })
|
|
}
|
|
|
|
const ticket = ticketRows[0]
|
|
const availableQuantity = ticket.total_quantity - ticket.sold_quantity
|
|
|
|
if (quantity > availableQuantity) {
|
|
await connection.end()
|
|
return Response.json({
|
|
error: 'Not enough tickets available',
|
|
available: availableQuantity
|
|
}, { status: 400 })
|
|
}
|
|
|
|
const totalPrice = ticket.price * quantity
|
|
|
|
// Start transaction
|
|
await connection.beginTransaction()
|
|
|
|
try {
|
|
// Create order
|
|
const [orderResult] = await connection.execute(
|
|
'INSERT INTO orders (event_id, socket_id, ticket_type, quantity, total_price, status) VALUES (?, ?, ?, ?, ?, ?)',
|
|
[eventId, decoded.sid, ticketType, quantity, totalPrice, 'completed']
|
|
)
|
|
|
|
// Update sold quantity
|
|
await connection.execute(
|
|
'UPDATE tickets SET sold_quantity = sold_quantity + ? WHERE event_id = ? AND type = ?',
|
|
[quantity, eventId, ticketType]
|
|
)
|
|
|
|
await connection.commit()
|
|
await connection.end()
|
|
|
|
return Response.json({
|
|
success: true,
|
|
orderId: orderResult.insertId,
|
|
totalPrice,
|
|
message: `Successfully purchased ${quantity} ${ticketType} ticket(s)`
|
|
})
|
|
|
|
} catch (error) {
|
|
await connection.rollback()
|
|
await connection.end()
|
|
throw error
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Purchase API error:', error)
|
|
return Response.json({ error: 'Purchase failed' }, { status: 500 })
|
|
}
|
|
}
|