fix: widget payment screen always shown, phone mask, today's date default
- Always show payment step when paymentEnabled=true even if YooKassa confirmationUrl is null (payment creation failed silently) - Add third payment screen variant: "manager will contact you" when no YooKassa URL and no bank details configured - Add Russian phone mask +7 (___) ___-__-__ on phone type fields - Default check-in/check-out dates to today/tomorrow instead of hardcoded past dates Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -196,8 +196,10 @@ export function WidgetPreview({ settings, slug, realRooms, realCategories, payme
|
||||
paymentEnabled?: boolean
|
||||
}) {
|
||||
const [previewTab, setPreviewTab] = useState<'rooms' | 'rental'>('rooms')
|
||||
const [checkIn, setCheckIn] = useState('2026-03-20')
|
||||
const [checkOut, setCheckOut] = useState('2026-03-22')
|
||||
const todayStr = new Date().toISOString().slice(0, 10)
|
||||
const tomorrowStr = new Date(Date.now() + 86400000).toISOString().slice(0, 10)
|
||||
const [checkIn, setCheckIn] = useState(todayStr)
|
||||
const [checkOut, setCheckOut] = useState(tomorrowStr)
|
||||
const [guests, setGuests] = useState(2)
|
||||
const [extraBeds, setExtraBeds] = useState(0)
|
||||
const [children, setChildren] = useState(0)
|
||||
@@ -289,7 +291,8 @@ export function WidgetPreview({ settings, slug, realRooms, realCategories, payme
|
||||
if (result.confirmationUrl) {
|
||||
setConfirmUrl(result.confirmationUrl)
|
||||
setStep('payment')
|
||||
} else if (settings.bankDetails) {
|
||||
} else if (settings.bankDetails || needsPayment) {
|
||||
// YooKassa failed or bank transfer configured — always show payment screen
|
||||
setStep('payment')
|
||||
} else {
|
||||
setStep('success')
|
||||
@@ -379,6 +382,7 @@ export function WidgetPreview({ settings, slug, realRooms, realCategories, payme
|
||||
// ── Payment screen ──
|
||||
if (step === 'payment') {
|
||||
const isYookassa = !!confirmUrl
|
||||
const hasBankDetails = !isYookassa && !!settings.bankDetails
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-2xl shadow-2xl overflow-hidden border border-slate-200" style={{ fontFamily: 'Inter, sans-serif' }}>
|
||||
@@ -410,14 +414,14 @@ export function WidgetPreview({ settings, slug, realRooms, realCategories, payme
|
||||
</p>
|
||||
<p className="text-xs text-slate-400">🔒 Защищённое соединение · ЮKassa</p>
|
||||
</div>
|
||||
) : (
|
||||
) : hasBankDetails ? (
|
||||
/* Bank transfer details */
|
||||
<div className="space-y-3">
|
||||
<p className="text-sm font-medium text-slate-700">
|
||||
{settings.language === 'ru' ? 'Реквизиты для оплаты' : 'Payment details'}
|
||||
</p>
|
||||
<div className="bg-slate-50 rounded-xl p-4 text-sm text-slate-700 whitespace-pre-wrap leading-relaxed">
|
||||
{settings.bankDetails || 'Реквизиты не указаны'}
|
||||
{settings.bankDetails}
|
||||
</div>
|
||||
<p className="text-xs text-slate-400">
|
||||
{settings.language === 'ru'
|
||||
@@ -425,6 +429,16 @@ export function WidgetPreview({ settings, slug, realRooms, realCategories, payme
|
||||
: 'After transfer, the hotel will confirm your booking. Include your name and dates in the payment reference.'}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
/* No payment configured — pending confirmation */
|
||||
<div className="text-center space-y-3 py-2">
|
||||
<div className="w-14 h-14 rounded-full flex items-center justify-center mx-auto bg-amber-50">
|
||||
<AlertCircle size={28} className="text-amber-500" />
|
||||
</div>
|
||||
<p className="text-sm text-slate-700 font-medium">
|
||||
{settings.language === 'ru' ? 'Бронирование принято. Менеджер отеля свяжется с вами для подтверждения оплаты.' : 'Booking received. Hotel manager will contact you to confirm payment.'}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -437,7 +451,7 @@ export function WidgetPreview({ settings, slug, realRooms, realCategories, payme
|
||||
>
|
||||
{settings.language === 'ru' ? `Перейти к оплате · ${grandTotal.toLocaleString('ru-RU')} ₽` : `Proceed to pay · ${grandTotal.toLocaleString('ru-RU')} ₽`}
|
||||
</button>
|
||||
) : (
|
||||
) : hasBankDetails ? (
|
||||
<button
|
||||
onClick={() => setStep('success')}
|
||||
className="w-full py-3 rounded-xl text-white font-semibold text-sm transition-opacity hover:opacity-90"
|
||||
@@ -445,6 +459,14 @@ export function WidgetPreview({ settings, slug, realRooms, realCategories, payme
|
||||
>
|
||||
{settings.language === 'ru' ? 'Я перевёл оплату' : 'I have paid'}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => setStep('success')}
|
||||
className="w-full py-3 rounded-xl text-white font-semibold text-sm transition-opacity hover:opacity-90"
|
||||
style={{ background: settings.primaryColor }}
|
||||
>
|
||||
{settings.language === 'ru' ? 'Понятно' : 'OK'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -603,13 +625,29 @@ export function WidgetPreview({ settings, slug, realRooms, realCategories, payme
|
||||
</select>
|
||||
) : (
|
||||
<input
|
||||
type={field.type}
|
||||
type={field.type === 'phone' ? 'tel' : field.type}
|
||||
inputMode={field.type === 'phone' ? 'tel' : undefined}
|
||||
placeholder={field.type === 'phone' ? '+7 (___) ___-__-__' : undefined}
|
||||
className="w-full text-sm border border-slate-200 rounded-lg px-3 py-2 focus:outline-none"
|
||||
value={formValues[field.id] ?? ''}
|
||||
onChange={e => {
|
||||
setFormValues(prev => ({ ...prev, [field.id]: e.target.value }))
|
||||
if (field.id === 'email') doGuestLookup(e.target.value, formValues['phone'])
|
||||
if (field.id === 'phone') doGuestLookup(formValues['email'], e.target.value)
|
||||
let val = e.target.value
|
||||
if (field.type === 'phone') {
|
||||
const digits = val.replace(/\D/g, '').slice(0, 11)
|
||||
if (digits.length === 0) { val = '' }
|
||||
else {
|
||||
const d = digits.startsWith('8') ? '7' + digits.slice(1) : digits
|
||||
const n = d.startsWith('7') ? d : '7' + d
|
||||
val = '+7'
|
||||
if (n.length > 1) val += ' (' + n.slice(1, 4)
|
||||
if (n.length > 4) val += ') ' + n.slice(4, 7)
|
||||
if (n.length > 7) val += '-' + n.slice(7, 9)
|
||||
if (n.length > 9) val += '-' + n.slice(9, 11)
|
||||
}
|
||||
}
|
||||
setFormValues(prev => ({ ...prev, [field.id]: val }))
|
||||
if (field.id === 'email') doGuestLookup(val, formValues['phone'])
|
||||
if (field.id === 'phone') doGuestLookup(formValues['email'], val)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user