BookingModal: move extra beds+tags to right col, payment to full-width bottom; Calendar: fix today booking left edge fill
This commit is contained in:
@@ -533,41 +533,10 @@ export function BookingModal({ open, draft, rooms, bookings = [], onClose, onSav
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* TV Message — только для существующих броней с активным модулем */}
|
||||
{tvEnabled && existing && existing.roomId && (
|
||||
<div className="rounded-xl border border-violet-200 dark:border-violet-800/60 bg-violet-50 dark:bg-violet-900/20 p-3 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Tv2 size={14} className="text-violet-600 dark:text-violet-400 shrink-0" />
|
||||
<span className="text-sm font-medium text-violet-700 dark:text-violet-300">
|
||||
Сообщение гостю на TV
|
||||
</span>
|
||||
</div>
|
||||
<textarea
|
||||
rows={2}
|
||||
value={tvMsg}
|
||||
onChange={e => setTvMsg(e.target.value)}
|
||||
placeholder="Введите сообщение для гостя..."
|
||||
className="w-full rounded-lg border border-violet-200 dark:border-violet-700 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-slate-900 dark:text-slate-100 placeholder-slate-400 resize-none focus:outline-none focus:ring-2 focus:ring-violet-400"
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSendTv}
|
||||
disabled={tvSending || !tvMsg.trim()}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-violet-600 hover:bg-violet-700 disabled:opacity-50 text-white text-xs font-medium transition-colors"
|
||||
>
|
||||
{tvSending ? <Loader2 size={12} className="animate-spin" /> : <Send size={12} />}
|
||||
Отправить на TV
|
||||
</button>
|
||||
{tvSent && (
|
||||
<span className="flex items-center gap-1 text-xs text-emerald-600 dark:text-emerald-400">
|
||||
<CheckCircle2 size={12} /> Отправлено
|
||||
</span>
|
||||
)}
|
||||
{tvError && <span className="text-xs text-red-500">{tvError}</span>}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* ── RIGHT COLUMN ── */}
|
||||
<div className="w-56 shrink-0 space-y-4">
|
||||
|
||||
{/* Доп. места */}
|
||||
<div className="flex items-center justify-between px-3 py-2.5 rounded-xl bg-slate-50 dark:bg-slate-700/40 border border-slate-200 dark:border-slate-600">
|
||||
@@ -575,20 +544,20 @@ export function BookingModal({ open, draft, rooms, bookings = [], onClose, onSav
|
||||
<BedDouble size={15} className="text-slate-400 shrink-0" />
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-700 dark:text-slate-300 leading-tight">Доп. места</p>
|
||||
<p className="text-[10px] text-slate-400">{EXTRA_BED_PRICE.toLocaleString('ru-RU')} ₽/место{!isHourly && nights > 0 ? '/ночь' : ''}</p>
|
||||
<p className="text-[10px] text-slate-400">{EXTRA_BED_PRICE.toLocaleString('ru-RU')} ₽{!isHourly && nights > 0 ? '/ночь' : ''}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-1.5">
|
||||
{extraBeds > 0 && (
|
||||
<span className="text-xs font-medium text-amber-600 dark:text-amber-400 mr-1">
|
||||
+{extraBedsTotal.toLocaleString('ru-RU')} ₽
|
||||
<span className="text-[10px] font-medium text-amber-600 dark:text-amber-400">
|
||||
+{extraBedsTotal.toLocaleString('ru-RU')}₽
|
||||
</span>
|
||||
)}
|
||||
<button type="button" onClick={() => setExtraBeds(e => Math.max(0, e - 1))}
|
||||
className="w-6 h-6 rounded-md bg-slate-200 dark:bg-slate-600 flex items-center justify-center hover:bg-slate-300 dark:hover:bg-slate-500 transition-colors disabled:opacity-40"
|
||||
disabled={extraBeds === 0}
|
||||
><Minus size={11} /></button>
|
||||
<span className="w-5 text-center text-sm font-semibold text-slate-900 dark:text-slate-100">{extraBeds}</span>
|
||||
<span className="w-4 text-center text-sm font-semibold text-slate-900 dark:text-slate-100">{extraBeds}</span>
|
||||
<button type="button" onClick={() => setExtraBeds(e => Math.min(4, e + 1))}
|
||||
className="w-6 h-6 rounded-md bg-slate-200 dark:bg-slate-600 flex items-center justify-center hover:bg-slate-300 dark:hover:bg-slate-500 transition-colors disabled:opacity-40"
|
||||
disabled={extraBeds >= 4}
|
||||
@@ -611,7 +580,7 @@ export function BookingModal({ open, draft, rooms, bookings = [], onClose, onSav
|
||||
type="button"
|
||||
onClick={() => toggleTag(tag)}
|
||||
className={cn(
|
||||
'flex items-center gap-1 px-2.5 py-1 rounded-lg text-xs font-medium border transition-colors',
|
||||
'flex items-center gap-1 px-2 py-1 rounded-lg text-xs font-medium border transition-colors',
|
||||
selected
|
||||
? isVip
|
||||
? 'bg-amber-500 border-amber-500 text-white'
|
||||
@@ -626,133 +595,48 @@ export function BookingModal({ open, draft, rooms, bookings = [], onClose, onSav
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── RIGHT COLUMN ── */}
|
||||
<div className="flex-1 space-y-3 min-w-0">
|
||||
{/* Payment */}
|
||||
{total > 0 && (
|
||||
<div className="rounded-xl border border-slate-200 dark:border-slate-600 overflow-hidden">
|
||||
<div className="px-4 py-3 bg-slate-50 dark:bg-slate-700/40 border-b border-slate-200 dark:border-slate-600">
|
||||
<p className="text-sm font-semibold text-slate-700 dark:text-slate-300">Оплата</p>
|
||||
{/* TV Message */}
|
||||
{tvEnabled && existing && existing.roomId && (
|
||||
<div className="rounded-xl border border-violet-200 dark:border-violet-800/60 bg-violet-50 dark:bg-violet-900/20 p-3 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Tv2 size={14} className="text-violet-600 dark:text-violet-400 shrink-0" />
|
||||
<span className="text-sm font-medium text-violet-700 dark:text-violet-300">TV-сообщение</span>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1.5">Способ оплаты</label>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setPaymentMethod(p => p === 'cash' ? null : 'cash')}
|
||||
className={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium border transition-colors',
|
||||
paymentMethod === 'cash'
|
||||
? 'bg-emerald-600 text-white border-emerald-600'
|
||||
: 'bg-white dark:bg-slate-700 text-slate-700 dark:text-slate-300 border-slate-200 dark:border-slate-600 hover:border-emerald-400',
|
||||
)}
|
||||
>
|
||||
<Banknote size={14} />
|
||||
Наличные
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setPaymentMethod(p => p === 'terminal' ? null : 'terminal')}
|
||||
className={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium border transition-colors',
|
||||
paymentMethod === 'terminal'
|
||||
? 'bg-blue-600 text-white border-blue-600'
|
||||
: 'bg-white dark:bg-slate-700 text-slate-700 dark:text-slate-300 border-slate-200 dark:border-slate-600 hover:border-blue-400',
|
||||
)}
|
||||
>
|
||||
<CreditCard size={14} />
|
||||
Терминал
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/* Discount */}
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1.5 flex items-center gap-1">
|
||||
<Tag size={11} /> Скидка
|
||||
</label>
|
||||
<select
|
||||
className="input text-sm"
|
||||
value={selectedDiscountId}
|
||||
onChange={e => setSelectedDiscountId(e.target.value)}
|
||||
>
|
||||
<option value="">— Без скидки —</option>
|
||||
{activeDiscounts.map(d => (
|
||||
<option key={d.id} value={d.id}>
|
||||
{d.name} ({d.value === 100 ? 'Бесплатно' : `−${d.value}${d.valueType === 'percent' ? '%' : ' ₽'}`})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{selectedDiscount && (
|
||||
<p className="text-xs text-emerald-600 dark:text-emerald-400 mt-1">
|
||||
−{discountAmount.toLocaleString('ru-RU')} ₽
|
||||
{selectedDiscount.note ? ` · ${selectedDiscount.note}` : ''}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Additional services */}
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1.5">Дополнительные услуги</label>
|
||||
<div className="flex gap-2 mb-2">
|
||||
<select
|
||||
className="input flex-1 text-sm"
|
||||
value={selectedServiceId}
|
||||
onChange={e => setSelectedServiceId(e.target.value)}
|
||||
>
|
||||
{ADDITIONAL_SERVICES.map(s => (
|
||||
<option key={s.id} value={s.id}>{s.label} — {s.price.toLocaleString('ru-RU')} ₽</option>
|
||||
))}
|
||||
</select>
|
||||
<button type="button" onClick={addService} className="btn-secondary px-2">
|
||||
<Plus size={14} />
|
||||
</button>
|
||||
</div>
|
||||
{addedServices.length > 0 && (
|
||||
<div className="space-y-1">
|
||||
{addedServices.map(s => (
|
||||
<div key={s.id} className="flex items-center justify-between text-xs px-2 py-1 rounded bg-slate-100 dark:bg-slate-700">
|
||||
<span className="text-slate-700 dark:text-slate-300">{s.label} × {s.qty}</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-slate-900 dark:text-slate-100">{(s.price * s.qty).toLocaleString('ru-RU')} ₽</span>
|
||||
<button type="button" onClick={() => removeService(s.id)} className="text-slate-400 hover:text-red-500">
|
||||
<Trash2 size={11} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1.5">
|
||||
Оплачено (₽)
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min={0}
|
||||
max={total}
|
||||
className="input w-40"
|
||||
value={paidAmount}
|
||||
onChange={e => setPaidAmount(Math.min(total, Math.max(0, parseInt(e.target.value) || 0)))}
|
||||
/>
|
||||
</div>
|
||||
<textarea
|
||||
rows={2}
|
||||
value={tvMsg}
|
||||
onChange={e => setTvMsg(e.target.value)}
|
||||
placeholder="Сообщение гостю..."
|
||||
className="w-full rounded-lg border border-violet-200 dark:border-violet-700 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-slate-900 dark:text-slate-100 placeholder-slate-400 resize-none focus:outline-none focus:ring-2 focus:ring-violet-400"
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSendTv}
|
||||
disabled={tvSending || !tvMsg.trim()}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-violet-600 hover:bg-violet-700 disabled:opacity-50 text-white text-xs font-medium transition-colors"
|
||||
>
|
||||
{tvSending ? <Loader2 size={12} className="animate-spin" /> : <Send size={12} />}
|
||||
Отправить
|
||||
</button>
|
||||
{tvSent && (
|
||||
<span className="flex items-center gap-1 text-xs text-emerald-600 dark:text-emerald-400">
|
||||
<CheckCircle2 size={12} /> Отправлено
|
||||
</span>
|
||||
)}
|
||||
{tvError && <span className="text-xs text-red-500">{tvError}</span>}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── BOTTOM ROW: Notes + Summary ── */}
|
||||
<div className="flex gap-6">
|
||||
<div className="flex-1">
|
||||
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">
|
||||
Примечания
|
||||
</label>
|
||||
{/* ── BOTTOM: Примечания + Оплата (полная ширина) ── */}
|
||||
<div className="border-t border-slate-200 dark:border-slate-700 pt-4 space-y-3">
|
||||
{/* Примечания */}
|
||||
<div>
|
||||
<label className="block text-xs text-slate-500 dark:text-slate-400 mb-1">Примечания</label>
|
||||
<textarea
|
||||
className="input resize-none"
|
||||
rows={2}
|
||||
@@ -761,69 +645,133 @@ export function BookingModal({ open, draft, rooms, bookings = [], onClose, onSav
|
||||
onChange={e => set('notes', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
{(total > 0 || discountAmount > 0) && room && (
|
||||
<div className="flex-1 rounded-xl bg-slate-50 dark:bg-slate-700/50 px-4 py-3 space-y-1.5 self-end">
|
||||
{isHourly && room.allowHourly ? (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-300">
|
||||
{hourlyHours} {hourlyHours === 1 ? 'час' : hourlyHours < 5 ? 'часа' : 'часов'} × {(room.hourlyRate ?? 0).toLocaleString('ru-RU')} ₽
|
||||
</span>
|
||||
<span className={cn('font-semibold', discountAmount > 0 ? 'line-through text-slate-400' : 'text-slate-900 dark:text-slate-100')}>
|
||||
{roomBaseTotal.toLocaleString('ru-RU')} ₽
|
||||
</span>
|
||||
|
||||
{/* Оплата — горизонтальная полоса */}
|
||||
<div className="rounded-xl border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-700/40 px-4 py-3">
|
||||
<div className="flex flex-wrap items-end gap-4">
|
||||
{/* Способ оплаты */}
|
||||
<div className="shrink-0">
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 mb-1.5">Способ оплаты</p>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setPaymentMethod(p => p === 'cash' ? null : 'cash')}
|
||||
className={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium border transition-colors',
|
||||
paymentMethod === 'cash'
|
||||
? 'bg-emerald-600 text-white border-emerald-600'
|
||||
: 'bg-white dark:bg-slate-700 text-slate-700 dark:text-slate-300 border-slate-200 dark:border-slate-600 hover:border-emerald-400',
|
||||
)}
|
||||
>
|
||||
<Banknote size={14} /> Наличные
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setPaymentMethod(p => p === 'terminal' ? null : 'terminal')}
|
||||
className={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium border transition-colors',
|
||||
paymentMethod === 'terminal'
|
||||
? 'bg-blue-600 text-white border-blue-600'
|
||||
: 'bg-white dark:bg-slate-700 text-slate-700 dark:text-slate-300 border-slate-200 dark:border-slate-600 hover:border-blue-400',
|
||||
)}
|
||||
>
|
||||
<CreditCard size={14} /> Терминал
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-300">
|
||||
{nights} {nights === 1 ? 'ночь' : nights < 5 ? 'ночи' : 'ночей'} × {room.baseRate.toLocaleString('ru-RU')} ₽
|
||||
</span>
|
||||
<span className={cn('font-semibold', discountAmount > 0 ? 'line-through text-slate-400' : 'text-slate-900 dark:text-slate-100')}>
|
||||
{roomBaseTotal.toLocaleString('ru-RU')} ₽
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Скидка */}
|
||||
<div className="shrink-0 min-w-[160px]">
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 mb-1.5 flex items-center gap-1"><Tag size={11} /> Скидка</p>
|
||||
<select
|
||||
className="input text-sm"
|
||||
value={selectedDiscountId}
|
||||
onChange={e => setSelectedDiscountId(e.target.value)}
|
||||
>
|
||||
<option value="">— Без скидки —</option>
|
||||
{activeDiscounts.map(d => (
|
||||
<option key={d.id} value={d.id}>
|
||||
{d.name} ({d.value === 100 ? 'Бесплатно' : `−${d.value}${d.valueType === 'percent' ? '%' : ' ₽'}`})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Доп. услуги */}
|
||||
<div className="shrink-0 min-w-[180px]">
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 mb-1.5">Доп. услуги</p>
|
||||
<div className="flex gap-2">
|
||||
<select
|
||||
className="input flex-1 text-sm"
|
||||
value={selectedServiceId}
|
||||
onChange={e => setSelectedServiceId(e.target.value)}
|
||||
>
|
||||
{ADDITIONAL_SERVICES.map(s => (
|
||||
<option key={s.id} value={s.id}>{s.label} — {s.price.toLocaleString('ru-RU')} ₽</option>
|
||||
))}
|
||||
</select>
|
||||
<button type="button" onClick={addService} className="btn-secondary px-2 shrink-0">
|
||||
<Plus size={14} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{discountAmount > 0 && selectedDiscount && (
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-emerald-600 dark:text-emerald-400">
|
||||
{selectedDiscount.value === 100 ? 'Бесплатное проживание' : selectedDiscount.name}
|
||||
</span>
|
||||
<span className="font-semibold text-emerald-600 dark:text-emerald-400">
|
||||
−{discountAmount.toLocaleString('ru-RU')} ₽
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{servicesTotal > 0 && (
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-slate-600 dark:text-slate-300">Доп. услуги</span>
|
||||
<span className="font-semibold text-slate-900 dark:text-slate-100">{servicesTotal.toLocaleString('ru-RU')} ₽</span>
|
||||
</div>
|
||||
)}
|
||||
{(servicesTotal > 0 || discountAmount > 0) && (
|
||||
<div className="flex items-center justify-between border-t border-slate-200 dark:border-slate-600 pt-1.5">
|
||||
<span className="text-sm font-medium text-slate-700 dark:text-slate-200">Итого</span>
|
||||
<span className="text-xl font-bold text-slate-900 dark:text-slate-100">{total.toLocaleString('ru-RU')} ₽</span>
|
||||
</div>
|
||||
)}
|
||||
{servicesTotal === 0 && discountAmount === 0 && (
|
||||
<div className="text-xl font-bold text-slate-900 dark:text-slate-100 text-right">{total.toLocaleString('ru-RU')} ₽</div>
|
||||
)}
|
||||
{paidAmount > 0 && (
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-emerald-600 dark:text-emerald-400">Оплачено</span>
|
||||
<span className="font-semibold text-emerald-600 dark:text-emerald-400">
|
||||
{paidAmount.toLocaleString('ru-RU')} ₽
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{debt > 0 && (
|
||||
<div className="flex items-center gap-1.5 text-sm text-red-600 dark:text-red-400">
|
||||
<AlertCircle size={13} />
|
||||
<span className="flex-1">{isFutureBooking ? 'Задолженность' : 'Долг при заселении'}</span>
|
||||
<span className="font-semibold">{debt.toLocaleString('ru-RU')} ₽</span>
|
||||
{addedServices.length > 0 && (
|
||||
<div className="mt-1.5 space-y-1">
|
||||
{addedServices.map(s => (
|
||||
<div key={s.id} className="flex items-center justify-between text-xs px-2 py-0.5 rounded bg-white dark:bg-slate-700">
|
||||
<span className="text-slate-600 dark:text-slate-300">{s.label} × {s.qty}</span>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="font-medium">{(s.price * s.qty).toLocaleString('ru-RU')} ₽</span>
|
||||
<button type="button" onClick={() => removeService(s.id)} className="text-slate-400 hover:text-red-500">
|
||||
<Trash2 size={10} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Оплачено */}
|
||||
<div className="shrink-0">
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 mb-1.5">Оплачено (₽)</p>
|
||||
<input
|
||||
type="number" min={0} max={total}
|
||||
className="input w-32"
|
||||
value={paidAmount}
|
||||
onChange={e => setPaidAmount(Math.min(total, Math.max(0, parseInt(e.target.value) || 0)))}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Итого */}
|
||||
{room && total > 0 && (
|
||||
<div className="ml-auto text-right shrink-0">
|
||||
{room && (
|
||||
<p className="text-xs text-slate-400 mb-0.5">
|
||||
{isHourly && room.allowHourly
|
||||
? `${hourlyHours} ч × ${(room.hourlyRate ?? 0).toLocaleString('ru-RU')} ₽`
|
||||
: `${nights} ${nights === 1 ? 'ночь' : nights < 5 ? 'ночи' : 'ночей'} × ${room.baseRate.toLocaleString('ru-RU')} ₽`
|
||||
}
|
||||
{discountAmount > 0 && ` − ${discountAmount.toLocaleString('ru-RU')} ₽`}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-2xl font-bold text-slate-900 dark:text-slate-100">
|
||||
{total.toLocaleString('ru-RU')} ₽
|
||||
</p>
|
||||
{paidAmount > 0 && (
|
||||
<p className="text-xs text-emerald-600 dark:text-emerald-400">
|
||||
Оплачено {paidAmount.toLocaleString('ru-RU')} ₽
|
||||
</p>
|
||||
)}
|
||||
{debt > 0 && (
|
||||
<p className="text-xs text-red-500 flex items-center gap-1 justify-end">
|
||||
<AlertCircle size={11} />
|
||||
{isFutureBooking ? 'Задолженность' : 'Долг'} {debt.toLocaleString('ru-RU')} ₽
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBook
|
||||
if (rawColStart >= visibleDays || rawColEnd <= 0) return null
|
||||
|
||||
const INSET = Math.round(CELL_WIDTH / 3)
|
||||
const isClippedLeft = rawColStart < 0
|
||||
const isClippedLeft = rawColStart <= 0
|
||||
const isClippedRight = rawColEnd > visibleDays
|
||||
|
||||
const colStart = Math.max(0, rawColStart)
|
||||
|
||||
Reference in New Issue
Block a user