feat: guest email field on QR review form for reply
Some checks failed
Deploy to Production / deploy (push) Has been cancelled
Some checks failed
Deploy to Production / deploy (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
4
backend/migrations/091_reviews_guest_email.sql
Normal file
4
backend/migrations/091_reviews_guest_email.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
-- Migration 091 — Add guest_email to reviews (for QR anonymous reviews)
|
||||
|
||||
ALTER TABLE reviews
|
||||
ADD COLUMN IF NOT EXISTS guest_email VARCHAR(255);
|
||||
@@ -38,7 +38,7 @@ const reviewsRoutes: FastifyPluginAsync = async (fastify) => {
|
||||
if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' })
|
||||
|
||||
const { rows } = await db.query(
|
||||
`SELECT r.id, r.booking_id, r.guest_id, r.guest_name, r.source,
|
||||
`SELECT r.id, r.booking_id, r.guest_id, r.guest_name, r.guest_email, r.source,
|
||||
r.rating, r.text, r.reply, r.replied_at, r.is_public, r.rejected_at,
|
||||
r.created_at, r.updated_at,
|
||||
b.room_id,
|
||||
@@ -94,8 +94,8 @@ const reviewsRoutes: FastifyPluginAsync = async (fastify) => {
|
||||
|
||||
// Send email to guest when manager adds a reply
|
||||
if (replyText) {
|
||||
// Determine email: from booking (direct reviews) or manually entered (QR reviews)
|
||||
let emailTo: string | null = guestEmail?.trim() || null
|
||||
// Determine email: manager override → review's own guest_email (QR) → booking email
|
||||
let emailTo: string | null = guestEmail?.trim() || (rows[0].guest_email as string | null) || null
|
||||
let guestFirstName = ''
|
||||
|
||||
if (!emailTo && rows[0].booking_id) {
|
||||
@@ -329,11 +329,11 @@ const reviewsRoutes: FastifyPluginAsync = async (fastify) => {
|
||||
)
|
||||
|
||||
// ── POST /api/public/review-qr/:slug/:room ────────────────────────────────
|
||||
fastify.post<SlugRoomParam & { Body: { rating: number; text?: string } }>(
|
||||
fastify.post<SlugRoomParam & { Body: { rating: number; text?: string; email?: string } }>(
|
||||
'/api/public/review-qr/:slug/:room',
|
||||
async (request, reply) => {
|
||||
const { slug, room } = request.params
|
||||
const { rating, text } = request.body
|
||||
const { rating, text, email } = request.body
|
||||
|
||||
if (!rating || rating < 1 || rating > 5) {
|
||||
return reply.code(400).send({ error: 'Rating must be 1–5' })
|
||||
@@ -354,11 +354,12 @@ const reviewsRoutes: FastifyPluginAsync = async (fastify) => {
|
||||
|
||||
await db.query(
|
||||
`INSERT INTO reviews
|
||||
(hotel_id, booking_id, guest_id, guest_name, source, rating, text, is_public)
|
||||
VALUES ($1, NULL, NULL, $2, 'qr', $3, $4, $5)`,
|
||||
(hotel_id, booking_id, guest_id, guest_name, guest_email, source, rating, text, is_public)
|
||||
VALUES ($1, NULL, NULL, $2, $3, 'qr', $4, $5, $6)`,
|
||||
[
|
||||
hotel.id,
|
||||
roomRows[0] ? `Номер ${room}` : `QR (номер ${room})`,
|
||||
email?.trim() || null,
|
||||
rating,
|
||||
text ?? null,
|
||||
rating >= 4,
|
||||
|
||||
Reference in New Issue
Block a user