feat: widget iframe embed — standalone /:slug/book page
This commit is contained in:
@@ -14,7 +14,7 @@ import { api, type WidgetRoom, type WidgetCategory, type PaymentGateway } from '
|
||||
|
||||
// ── Widget settings type ───────────────────────────────────────────────────────
|
||||
|
||||
interface FormField {
|
||||
export interface FormField {
|
||||
id: string
|
||||
label: string
|
||||
type: 'text' | 'email' | 'phone' | 'textarea' | 'select'
|
||||
@@ -23,7 +23,7 @@ interface FormField {
|
||||
isCustom?: boolean
|
||||
}
|
||||
|
||||
interface AdditionalService {
|
||||
export interface AdditionalService {
|
||||
id: string
|
||||
name: string
|
||||
icon: string
|
||||
@@ -32,7 +32,7 @@ interface AdditionalService {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
interface WidgetSettings {
|
||||
export interface WidgetSettings {
|
||||
hotelName: string
|
||||
primaryColor: string
|
||||
language: 'ru' | 'en'
|
||||
@@ -170,7 +170,7 @@ const AMENITY_ICONS: Record<string, React.ElementType> = {
|
||||
|
||||
const EXTRA_BED_PRICE = 1500
|
||||
|
||||
const DEFAULT_FORM_FIELDS: FormField[] = [
|
||||
export const DEFAULT_FORM_FIELDS: FormField[] = [
|
||||
{ id: 'name', label: 'Имя и фамилия', type: 'text', required: true, enabled: true },
|
||||
{ id: 'email', label: 'Email', type: 'email', required: true, enabled: true },
|
||||
{ id: 'phone', label: 'Телефон', type: 'phone', required: true, enabled: true },
|
||||
@@ -178,7 +178,7 @@ const DEFAULT_FORM_FIELDS: FormField[] = [
|
||||
{ id: 'arrival', label: 'Время заезда', type: 'select', required: false, enabled: false },
|
||||
]
|
||||
|
||||
const DEFAULT_SERVICES: AdditionalService[] = [
|
||||
export const DEFAULT_SERVICES: AdditionalService[] = [
|
||||
{ id: 's1', name: 'Теннисный корт', icon: '🎾', price: 1200, unit: 'ч', enabled: true },
|
||||
{ id: 's2', name: 'Сауна', icon: '🧖', price: 2500, unit: 'ч', enabled: true },
|
||||
{ id: 's3', name: 'Банкетный зал', icon: '🎪', price: 15000, unit: 'день',enabled: false },
|
||||
@@ -187,7 +187,7 @@ const DEFAULT_SERVICES: AdditionalService[] = [
|
||||
|
||||
// ── Widget Preview Component ───────────────────────────────────────────────────
|
||||
|
||||
function WidgetPreview({ settings, slug, realRooms, realCategories, paymentEnabled }: {
|
||||
export function WidgetPreview({ settings, slug, realRooms, realCategories, paymentEnabled }: {
|
||||
settings: WidgetSettings
|
||||
slug?: string
|
||||
realRooms?: WidgetRoom[]
|
||||
@@ -1170,14 +1170,17 @@ export function BookingWidgetPage() {
|
||||
formFields: prev.formFields.filter(f => f.id !== id),
|
||||
}))
|
||||
|
||||
const snippet = `<script src="https://widget.hotelsync.ru/v1/embed.js"
|
||||
data-hotel="grand-palace"
|
||||
data-color="${settings.primaryColor}"
|
||||
data-lang="${settings.language}"
|
||||
data-rental="${settings.showRental}"
|
||||
data-min-nights="${settings.minNights}"
|
||||
data-payment="${settings.paymentProvider}">
|
||||
</script>`
|
||||
const widgetUrl = `https://app.hotelsync.ru/${slug || 'grand-palace'}/book?color=${encodeURIComponent(settings.primaryColor)}&lang=${settings.language}&mode=${settings.roomDisplayMode}&min-nights=${settings.minNights}&rental=${settings.showRental}&promo=${settings.showPromo}&extra-beds=${settings.allowExtraBeds}&children=${settings.allowChildren}`
|
||||
|
||||
const snippet = `<iframe
|
||||
src="${widgetUrl}"
|
||||
width="100%"
|
||||
height="680"
|
||||
frameborder="0"
|
||||
style="border-radius:16px;border:none;box-shadow:0 4px 24px rgba(0,0,0,0.10);"
|
||||
allow="payment"
|
||||
loading="lazy"
|
||||
></iframe>`
|
||||
|
||||
const copyCode = () => {
|
||||
navigator.clipboard.writeText(snippet).catch(() => {})
|
||||
|
||||
Reference in New Issue
Block a user