feat: widget settings persistence + remove redundant payment card
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import {
|
||||
Code2, CreditCard, Globe, CalendarCheck2, Copy, CheckCheck,
|
||||
Code2, CreditCard, Globe, CalendarCheck2, Copy, CheckCheck, Save,
|
||||
ChevronLeft, ChevronRight, Star, Users, Dumbbell, Waves,
|
||||
Eye, Settings2, ArrowRight, Plus, Trash2, Check, X as XIcon,
|
||||
BedDouble, Baby, ToggleLeft, ToggleRight, ChevronDown, ChevronUp,
|
||||
@@ -1100,11 +1100,27 @@ export function BookingWidgetPage() {
|
||||
Promise.all([
|
||||
api.widget.getConfig(slug).catch(() => null),
|
||||
api.paymentGateways.list(slug).catch(() => [] as PaymentGateway[]),
|
||||
]).then(([config, gws]) => {
|
||||
api.hotelSettings.get(slug).catch(() => ({}) as Record<string, unknown>),
|
||||
]).then(([config, gws, hsRaw]) => {
|
||||
const hs = hsRaw as Record<string, unknown>
|
||||
if (config?.rooms) setRealRooms(config.rooms)
|
||||
if (config?.categories) setRealCategories(config.categories)
|
||||
const widgetGw = gws.find(g => g.isActive && g.modules?.includes('booking-widget'))
|
||||
setGateway(widgetGw ?? null)
|
||||
// Restore saved widget settings
|
||||
setSettings(prev => ({
|
||||
...prev,
|
||||
hotelName: String(hs.widget_hotel_name ?? config?.hotelName ?? prev.hotelName),
|
||||
primaryColor: String(hs.widget_color ?? prev.primaryColor),
|
||||
language: (String(hs.widget_lang ?? prev.language)) as 'ru' | 'en',
|
||||
showRooms: hs.widget_show_rooms !== undefined ? Boolean(hs.widget_show_rooms) : prev.showRooms,
|
||||
showRental: hs.widget_show_rental !== undefined ? Boolean(hs.widget_show_rental) : prev.showRental,
|
||||
roomDisplayMode: (String(hs.widget_room_mode ?? prev.roomDisplayMode)) as 'rooms' | 'categories',
|
||||
minNights: hs.widget_min_nights !== undefined ? Number(hs.widget_min_nights) : prev.minNights,
|
||||
showPromo: hs.widget_show_promo !== undefined ? Boolean(hs.widget_show_promo) : prev.showPromo,
|
||||
allowExtraBeds: hs.widget_extra_beds !== undefined ? Boolean(hs.widget_extra_beds) : prev.allowExtraBeds,
|
||||
allowChildren: hs.widget_children !== undefined ? Boolean(hs.widget_children) : prev.allowChildren,
|
||||
}))
|
||||
}).finally(() => setGatewayLoading(false))
|
||||
}, [slug])
|
||||
|
||||
@@ -1124,6 +1140,8 @@ export function BookingWidgetPage() {
|
||||
additionalServices: DEFAULT_SERVICES,
|
||||
})
|
||||
const [copied, setCopied] = useState(false)
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [saved, setSaved] = useState(false)
|
||||
const [pageTab, setPageTab] = useState<'constructor' | 'code' | 'stats'>('constructor')
|
||||
const [newFieldLabel, setNewFieldLabel] = useState('')
|
||||
const [showAddField, setShowAddField] = useState(false)
|
||||
@@ -1131,6 +1149,28 @@ export function BookingWidgetPage() {
|
||||
const set = <K extends keyof WidgetSettings>(k: K, v: WidgetSettings[K]) =>
|
||||
setSettings(prev => ({ ...prev, [k]: v }))
|
||||
|
||||
const handleSaveSettings = async () => {
|
||||
if (!slug) return
|
||||
setSaving(true)
|
||||
try {
|
||||
await api.hotelSettings.update(slug, {
|
||||
widget_hotel_name: settings.hotelName,
|
||||
widget_color: settings.primaryColor,
|
||||
widget_lang: settings.language,
|
||||
widget_show_rooms: settings.showRooms,
|
||||
widget_show_rental: settings.showRental,
|
||||
widget_room_mode: settings.roomDisplayMode,
|
||||
widget_min_nights: settings.minNights,
|
||||
widget_show_promo: settings.showPromo,
|
||||
widget_extra_beds: settings.allowExtraBeds,
|
||||
widget_children: settings.allowChildren,
|
||||
})
|
||||
setSaved(true)
|
||||
setTimeout(() => setSaved(false), 2000)
|
||||
} catch { /* ignore */ }
|
||||
finally { setSaving(false) }
|
||||
}
|
||||
|
||||
const toggleService = (id: string) =>
|
||||
setSettings(prev => ({
|
||||
...prev,
|
||||
@@ -1454,33 +1494,17 @@ export function BookingWidgetPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Payment */}
|
||||
<div className="card p-5 space-y-3">
|
||||
<h3 className="font-semibold text-slate-900 dark:text-slate-100 flex items-center gap-2">
|
||||
<CreditCard size={16} className="text-emerald-600" />
|
||||
Онлайн-оплата
|
||||
</h3>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{PAYMENT_PROVIDERS.map(p => (
|
||||
{/* Save button */}
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
key={p.value}
|
||||
onClick={() => set('paymentProvider', p.value as any)}
|
||||
className={cn(
|
||||
'px-3 py-2 rounded-xl text-sm font-medium border transition-colors text-left',
|
||||
settings.paymentProvider === p.value
|
||||
? 'bg-brand-600 text-white border-brand-600'
|
||||
: 'bg-white dark:bg-slate-700 border-slate-200 dark:border-slate-600 text-slate-700 dark:text-slate-300 hover:border-brand-400',
|
||||
)}
|
||||
onClick={handleSaveSettings}
|
||||
disabled={saving}
|
||||
className="btn-primary flex items-center gap-2"
|
||||
>
|
||||
{p.label}
|
||||
{saving ? <Loader2 size={15} className="animate-spin" /> : <Save size={15} />}
|
||||
{saved ? 'Сохранено!' : 'Сохранить настройки'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{settings.paymentProvider !== 'none' && (
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
Настройте ключи API в разделе Настройки → Оплата
|
||||
</p>
|
||||
)}
|
||||
{saved && <span className="text-sm text-emerald-600 dark:text-emerald-400">Настройки виджета сохранены</span>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user