feat: configurable source→platform map, custom location QR codes

- Settings tab: replace static source map rows with editable table
  (add/delete mappings, persisted as review_source_map in hotel_settings)
- QR tab: add custom location QR codes (Ресепшн, Ресторан, etc.)
  not tied to a room, stored as review_custom_locations
- Backend: GET /api/public/review/:token reads review_source_map from
  hotel_settings instead of hardcoded SOURCE_KEYWORD mapping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 10:44:07 +03:00
parent 47215c7d64
commit 0e2180e3bc
2 changed files with 168 additions and 77 deletions

View File

@@ -159,38 +159,36 @@ const reviewsRoutes: FastifyPluginAsync = async (fastify) => {
AND key IN (
'review_redirect_threshold','review_platforms',
'review_show_text_field','review_welcome_text',
'review_brand_color','review_redirect_source'
'review_brand_color','review_redirect_source',
'review_source_map'
)`,
[row.hotel_id],
)
const s: Record<string, unknown> = {}
for (const r of settings) s[r.key] = r.value
// Mapping booking source → keyword to match in platform name
const SOURCE_KEYWORD: Record<string, string> = {
booking_com: 'booking',
airbnb: 'airbnb',
expedia: 'expedia',
vrbo: 'vrbo',
yandex_travel: 'яндекс',
}
const allPlatforms = Array.isArray(s.review_platforms)
? (s.review_platforms as { name: string; url: string; enabled: boolean }[])
.filter(p => p.enabled)
: []
const sourceMap = Array.isArray(s.review_source_map)
? (s.review_source_map as { bookingSource: string; platformName: string }[])
: []
const useSourceRedirect = s.review_redirect_source !== false
const bookingSrc = row.booking_source ?? 'direct'
const keyword = SOURCE_KEYWORD[bookingSrc]
// If source redirect is on and we have a matching platform — show only that one
// If source redirect is on, find matching entry in sourceMap, then find the platform by name
let platforms = allPlatforms.map(p => ({ name: p.name, url: p.url }))
if (useSourceRedirect && keyword) {
const match = allPlatforms.find(p =>
p.name.toLowerCase().includes(keyword),
)
if (match) platforms = [{ name: match.name, url: match.url }]
if (useSourceRedirect && sourceMap.length > 0) {
const entry = sourceMap.find(e => e.bookingSource === bookingSrc)
if (entry) {
const match = allPlatforms.find(p =>
p.name.toLowerCase().includes(entry.platformName.toLowerCase()),
)
if (match) platforms = [{ name: match.name, url: match.url }]
}
}
return {