import { Hono } from 'hono' import { cors } from 'hono/cors' import { serveStatic } from 'hono/cloudflare-workers' type Bindings = { DB: D1Database } const app = new Hono<{ Bindings: Bindings }>() // Enable CORS for API routes app.use('/api/*', cors()) // Serve static files app.use('/static/*', serveStatic({ root: './public' })) // ====================== // API ROUTES // ====================== // Get all vehicles app.get('/api/vehicles', async (c) => { const { DB } = c.env try { const { results } = await DB.prepare(` SELECT * FROM vehicles WHERE active = 1 ORDER BY category, name `).all() return c.json({ success: true, data: results }) } catch (error) { console.error('Error fetching vehicles:', error) return c.json({ success: false, error: 'Failed to fetch vehicles' }, 500) } }) // Get vehicle by ID with all service prices app.get('/api/vehicles/:id', async (c) => { const { DB } = c.env const id = c.req.param('id') try { const vehicle = await DB.prepare(` SELECT * FROM vehicles WHERE id = ? AND active = 1 `).bind(id).first() if (!vehicle) { return c.json({ success: false, error: 'Vehicle not found' }, 404) } return c.json({ success: true, data: vehicle }) } catch (error) { console.error('Error fetching vehicle:', error) return c.json({ success: false, error: 'Failed to fetch vehicle' }, 500) } }) // Get all extra services app.get('/api/extras', async (c) => { const { DB } = c.env try { const { results } = await DB.prepare(` SELECT * FROM extra_services WHERE active = 1 ORDER BY category, name `).all() return c.json({ success: true, data: results }) } catch (error) { console.error('Error fetching extras:', error) return c.json({ success: false, error: 'Failed to fetch extras' }, 500) } }) // Create booking app.post('/api/bookings', async (c) => { const { DB } = c.env try { const body = await c.req.json() // Generate unique booking code const bookingCode = 'SOL' + Date.now().toString(36).toUpperCase() + Math.random().toString(36).substring(2, 6).toUpperCase() // Insert booking const result = await DB.prepare(` INSERT INTO bookings ( booking_code, customer_name, customer_email, customer_phone, customer_nif, vehicle_id, vehicle_plate, vehicle_km, selected_services, selected_extras, preferred_date_1, preferred_time_1, preferred_date_2, preferred_time_2, preferred_date_3, preferred_time_3, observations, subtotal, extras_total, total_amount, payment_type, payment_status, service_status ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `).bind( bookingCode, body.customer_name, body.customer_email, body.customer_phone, body.customer_nif || null, body.vehicle_id, body.vehicle_plate || null, body.vehicle_km || null, JSON.stringify(body.selected_services), JSON.stringify(body.selected_extras || []), body.preferred_date_1, body.preferred_time_1, body.preferred_date_2 || null, body.preferred_time_2 || null, body.preferred_date_3 || null, body.preferred_time_3 || null, body.observations || null, body.subtotal, body.extras_total || 0, body.total_amount, body.payment_type || 'full', 'pending', 'scheduled' ).run() // Add status history await DB.prepare(` INSERT INTO status_history (booking_id, new_status, changed_by, notes) VALUES (?, 'scheduled', 'system', 'Agendamento criado') `).bind(result.meta.last_row_id).run() return c.json({ success: true, data: { booking_code: bookingCode, booking_id: result.meta.last_row_id } }) } catch (error) { console.error('Error creating booking:', error) return c.json({ success: false, error: 'Failed to create booking' }, 500) } }) // Get booking by code (for tracking) app.get('/api/bookings/:code', async (c) => { const { DB } = c.env const code = c.req.param('code') try { const booking = await DB.prepare(` SELECT b.*, v.name as vehicle_name, v.model_year, v.engine_type FROM bookings b LEFT JOIN vehicles v ON b.vehicle_id = v.id WHERE b.booking_code = ? `).bind(code).first() if (!booking) { return c.json({ success: false, error: 'Booking not found' }, 404) } // Get status history const { results: history } = await DB.prepare(` SELECT * FROM status_history WHERE booking_id = ? ORDER BY created_at DESC `).bind(booking.id).all() return c.json({ success: true, data: { ...booking, selected_services: JSON.parse(booking.selected_services as string), selected_extras: JSON.parse(booking.selected_extras as string || '[]'), history } }) } catch (error) { console.error('Error fetching booking:', error) return c.json({ success: false, error: 'Failed to fetch booking' }, 500) } }) // Admin: Get all bookings app.get('/api/admin/bookings', async (c) => { const { DB } = c.env try { const { results } = await DB.prepare(` SELECT b.*, v.name as vehicle_name, v.model_year FROM bookings b LEFT JOIN vehicles v ON b.vehicle_id = v.id ORDER BY b.created_at DESC `).all() return c.json({ success: true, data: results }) } catch (error) { console.error('Error fetching bookings:', error) return c.json({ success: false, error: 'Failed to fetch bookings' }, 500) } }) // Admin: Update booking status app.patch('/api/admin/bookings/:id/status', async (c) => { const { DB } = c.env const id = c.req.param('id') const { status, notes } = await c.req.json() try { // Get current status const booking = await DB.prepare(` SELECT service_status FROM bookings WHERE id = ? `).bind(id).first() if (!booking) { return c.json({ success: false, error: 'Booking not found' }, 404) } // Update status await DB.prepare(` UPDATE bookings SET service_status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? `).bind(status, id).run() // Add to history await DB.prepare(` INSERT INTO status_history (booking_id, old_status, new_status, changed_by, notes) VALUES (?, ?, ?, 'admin', ?) `).bind(id, booking.service_status, status, notes || null).run() return c.json({ success: true, message: 'Status updated successfully' }) } catch (error) { console.error('Error updating status:', error) return c.json({ success: false, error: 'Failed to update status' }, 500) } }) // Admin: Update vehicle prices app.patch('/api/admin/vehicles/:id', async (c) => { const { DB } = c.env const id = c.req.param('id') const data = await c.req.json() try { await DB.prepare(` UPDATE vehicles SET interim_service_price = ?, major_service_price = ?, front_pads_price = ?, front_pads_discs_price = ?, rear_pads_price = ?, rear_pads_discs_price = ?, cambelt_price = ?, brake_fluid_price = ?, front_wipers_price = ? WHERE id = ? `).bind( data.interim_service_price, data.major_service_price, data.front_pads_price, data.front_pads_discs_price, data.rear_pads_price, data.rear_pads_discs_price, data.cambelt_price, data.brake_fluid_price, data.front_wipers_price, id ).run() return c.json({ success: true, message: 'Vehicle updated successfully' }) } catch (error) { console.error('Error updating vehicle:', error) return c.json({ success: false, error: 'Failed to update vehicle' }, 500) } }) // Admin: Add new extra service app.post('/api/admin/extras', async (c) => { const { DB } = c.env const data = await c.req.json() try { const result = await DB.prepare(` INSERT INTO extra_services (name, description, price, category) VALUES (?, ?, ?, ?) `).bind( data.name, data.description, data.price, data.category || 'maintenance' ).run() return c.json({ success: true, data: { id: result.meta.last_row_id } }) } catch (error) { console.error('Error adding extra service:', error) return c.json({ success: false, error: 'Failed to add extra service' }, 500) } }) // Admin: Update extra service app.patch('/api/admin/extras/:id', async (c) => { const { DB } = c.env const id = c.req.param('id') const data = await c.req.json() try { await DB.prepare(` UPDATE extra_services SET name = ?, description = ?, price = ?, category = ? WHERE id = ? `).bind( data.name, data.description, data.price, data.category, id ).run() return c.json({ success: true, message: 'Extra service updated successfully' }) } catch (error) { console.error('Error updating extra service:', error) return c.json({ success: false, error: 'Failed to update extra service' }, 500) } }) // Admin: Delete extra service app.delete('/api/admin/extras/:id', async (c) => { const { DB } = c.env const id = c.req.param('id') try { await DB.prepare(` UPDATE extra_services SET active = 0 WHERE id = ? `).bind(id).run() return c.json({ success: true, message: 'Extra service deleted successfully' }) } catch (error) { console.error('Error deleting extra service:', error) return c.json({ success: false, error: 'Failed to delete extra service' }, 500) } }) // ====================== // FRONTEND PAGES // ====================== // Main landing page app.get('/', (c) => { return c.html(`
Revisões e manutenções certificadas com padrão premium.
Especialistas em veículos Land Rover e Jaguar em Portugal.
Escolha o seu veículo e personalize os serviços que necessita.
Transparência total nos preços e processos.
A CARREGAR CONFIGURADOR...
Selecione o modelo e motorização do seu veículo
Personalize os serviços conforme as suas necessidades
Escolha a data e horário mais conveniente
Monitorize o serviço em tempo real
Serviço oficial Land Rover & Jaguar
100% peças genuínas de fábrica
Garantia em todos os serviços
Estamos prontos para oferecer suporte especializado para o seu Land Rover ou Jaguar
Atendimento rápido, eficiente e especializado. Conte com a Solihull.
Insira o seu código de agendamento
A carregar agendamentos...