Commit Graph

295 Commits

Author SHA1 Message Date
cf552d4b40 feat: chat — role on hover, role in direct header, @mention dropdown
- MessageBubble: role hidden by default, appears on hover of sender name (group/name CSS)
- Direct chat header: shows other user's role (from otherUserRole field added to backend)
- @mention: typing @ triggers filtered user dropdown, click inserts @Name into message
- Hint text updated: '@ — упомянуть'
- Backend: other_user_role added to rooms query

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 16:42:32 +03:00
e7ad9862ba feat: chat pagination — infinite scroll / load older messages
- Backend: cursor-based pagination via ?before=<ISO timestamp>
- Frontend: auto-load when scrolling to top (<60px), spinner + manual 'Загрузить ещё' button
- Poll merge: preserves older history when new messages arrive from polling
- hasMoreMsgs flag: shown only when exactly 50 msgs returned (more may exist)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 16:35:38 +03:00
ef1fd4246e feat: chat — smart scroll, sender role, close on outside click, per-room mute
- Scroll: only auto-scroll on poll when near bottom; openRoom uses double-RAF for instant jump
- Sender role: show position (Менеджер / Горничная etc) under name in message bubbles
- Close on outside click: mousedown listener when panel is open
- Per-room mute: ⋮ menu → Отключить/Включить уведомления, BellOff badge on muted rooms, saved to localStorage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 16:25:24 +03:00
1c3045f083 feat: chat messages — instant scroll, in-room search, room search reset on back
- openRoom: set instantScrollRef before setMessages → scrollTop=scrollHeight synchronously, no visible jump
- In-room search: 🔍 button in messages header, filter messages client-side, empty state
- Room search state reset when opening/closing room

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 16:13:25 +03:00
58ad4060c1 feat: chat — background badge polling, toast notifications, notification settings
- Room poll now runs always (10s when closed, 5s when open) — badge + sound work when minimized
- Toast pop-up (top-right) on new messages when chat is minimized or room not active
- Auto-dismiss toasts after 4.5s, click to open room
- Settings: popup enable/disable + show/hide message text in notification

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 13:39:23 +03:00
a3db2e9d5a fix: chat settings toggle — dot no longer overflows button bounds
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 13:29:31 +03:00
abf1920e6f feat: chat — ⋮ room menu, typing indicator, online presence, read receipts
- RoomRow: ⋮ button (hover) for pin/unpin context menu
- MessageBubble: right-click context menu with emoji reactions + edit/delete
- Typing indicator: debounced setTyping, animated TypingDots, polling getTyping every 2s
- Online presence: heartbeat setPresence every 30s, green dot on avatars/header
- Read receipts: ✓/✓✓ for own messages in direct rooms via otherUserLastRead
- Migration 075: chat_presence + chat_typing tables
- Context menus clamped to viewport bounds

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 13:16:35 +03:00
4de9cfa88e fix/feat: chat UX — context menu, sound, pin rooms, settings fix
- Replace hover toolbar with right-click context menu (no overflow issues)
  Messages: emoji reactions row + Edit + Delete (own only)
  Rooms: Pin / Unpin — pinned rooms always appear at top with 📌 icon
- Context menu clamped to viewport bounds, closes on any outside click
- Sound notifications: Web Audio API beep (880Hz, 0.25s) on new messages
  and on new unreads when widget is closed; respects soundEnabled setting
- Settings: added px-4 to sections so toggle is never clipped
  Added hint text about right-click shortcuts
- Pin state stored in localStorage (hotelsync-chat-pins)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 13:00:30 +03:00
a29f58282f feat: chat — edit/delete messages + emoji reactions
- Migration 074: edited_at, deleted_at columns + chat_reactions table
- Backend: PATCH edit (own only), DELETE soft-delete (own/admin), POST toggle reaction
  fetchMessage helper returns full message with aggregated reactions in one query
- API types: ChatReaction interface, editedAt/deletedAt/reactions in ChatMessage
- ChatWidget: hover toolbar (😊 react · ✏️ edit · 🗑️ delete), inline edit with
  save/cancel (Enter/Esc), reaction emoji picker (8 emojis), reaction pills below
  messages (click to toggle), '· изм.' label on edited messages, soft-deleted
  messages show 'Сообщение удалено' placeholder

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 12:31:17 +03:00
7ccf752429 feat: chat — photo attachments
- Migration 073: attachment_url column in chat_messages
- upload.ts: add 'chat' folder to ALLOWED_FOLDERS
- chat.ts: accept attachment_url in send message, return it in GET messages
- api.ts: attachmentUrl in ChatMessage type, uploadImage() with raw FormData fetch
- ChatWidget: paperclip button, file preview thumbnail with remove, image display
  inline in message bubbles (clickable, opens original), send enabled with image only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 12:13:07 +03:00
d0dbf33701 fix: chat — VARCHAR(10) overflow for notifications type, skeleton loading
- Migration 072: widen type column to VARCHAR(20), add partial unique index for general rooms
- Backend: replace brittle ON CONFLICT with explicit SELECT-then-INSERT ensureRoom helper
- Frontend: show room skeletons (Общий чат + Уведомления) during load instead of spinner,
  hide '0 чатов' subtitle when list is empty

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 12:03:35 +03:00
3c4c40da44 feat: chat — search, notifications room, settings
- Migration 071: nullable sender_id, is_system flag, notifications room type
- Backend: notifications room auto-created per hotel, search messages endpoint,
  notify endpoint (manager/admin posts system messages), read-only enforcement
- API: ChatSearchResult type, chat.search(), chat.notify(), updated ChatMessage type
- Frontend ChatWidget: search view (people + messages tabs), settings panel
  (notifications visibility toggle, sound toggle), notifications room (bell icon,
  read-only banner, amber styling for system messages), new-chat button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:25:40 +03:00
291d45622b fix: widget embed — hide scrollbar in iframe mode 2026-04-12 02:00:31 +03:00
c144793ae5 fix: widget embed mode — remove shadow/border/rounded when embed=true
WidgetPreview now accepts embed prop; when set, outer container loses
rounded-2xl shadow-2xl border-slate-200 so modal dialog styles apply cleanly.
All step screens (main, form, payment, success) patched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 01:34:15 +03:00
85ccd32574 fix: widget modal — clean embed mode, better close button, backdrop blur
- ?embed=true renders widget without page wrapper (white bg, no padding)
- widget-loader.js appends &embed=true to modal URL automatically
- Close button is now inside dialog (not overlapping iframe), light style
- Backdrop blur effect, Escape key closes modal
- FAB: subtle translateY on hover instead of scale

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 01:28:23 +03:00
e614905ca1 fix: widget embed — full-width support + one-liner script tags via hosted loader
- Standalone page: ?width=full removes max-w-lg container constraint
- iframeSnippet: passes &width=full to URL when 100% width selected
- public/widget-loader.js: hosted script, reads data-* attrs, no inline code needed
  - data-mode="floating" → styled FAB button bottom-right
  - data-mode="trigger"  → listens for .hotelsync-book class clicks
  - Proper modal with close button and backdrop click
- Code tab snippets for floating/trigger are now single <script src> lines

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 01:15:36 +03:00
60346f3580 feat: widget code tab — 3 install modes + width customization + better expand button
1. Expand button now shows "X фото / Детали ▾" and "Скрыть ▴" instead of bare chevron
2. Code tab: 3 install modes
   - Встроенный (iframe) — width presets 400/500/700px/full-width + custom input
   - Плавающая кнопка — floating button script with custom text, color from settings
   - По классу — script that opens modal on click of .hotelsync-book (or custom class)
3. Floating/trigger modes share modal logic, generate ready-to-paste <script> tag

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 00:39:27 +03:00
66cab853f1 fix: widget rooms mode — show real photos, hide mock-only meta fields
- displayRooms now maps r.photos (URL strings) to photoUrls[]
- Collapsed thumbnail: shows <img> if real photo URL exists, falls back to emoji
- Expanded gallery: full-width <img> for real photos, gradient for mock
- Thumbnail strip: renders real photo thumbnails when available
- Photo nav buttons use totalPhotos (real or mock count)
- beds/area/rating hidden when value is 0 (real rooms have no beds/area/rating data)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 00:26:06 +03:00
c153e12543 feat: widget additional services — sourced from rental objects module
- Additional services in widget are now derived from rental_objects (not a separate list)
- Settings page shows rental objects with enable/disable toggle; link to rental module
- Saves only {id, enabled}[] to widget_services — rental objects manage name/price/icon
- Standalone widget also derives additionalServices from config.rentalObjects
- Widget config API includes services[] in widgetSettings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 12:13:13 +03:00
c8ff5ad0ed feat: widget category cards — full-width photo gallery with carousel
- Cards now show wide photo (h-44) at top instead of small thumbnail
- Gallery navigation: left/right arrows on hover, dot indicators, counter
- Gradient overlay with available badge (top-left) and photo count
- Select button at bottom of each card
- Graceful fallback to 🛏️ placeholder when no photos

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:56:59 +03:00
bbea04ce2e feat: widget — editable additional services with add/edit/delete + DB persistence
- Services can now be added, edited inline (icon/name/price/unit), and deleted
- List persisted to DB as widget_services key in hotel_settings (auto-save)
- Services loaded from DB on settings page init; fall back to DEFAULT_SERVICES
- Toggle enable/disable retained; edit/delete buttons appear on row hover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 11:24:11 +03:00
f5878c0447 fix: widget — show category photos, load rental objects in settings preview
- Category cards now show photos[0] as <img> when available, fallback to 🛏️ emoji
- Settings page preview loads rentalObjects from API and passes to WidgetPreview
- MockCategory type and MOCK_CATEGORIES get photos: [] to match updated type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:50:56 +03:00
59307ba6b4 feat: widget rental tab — real objects, time slots, actual rental_bookings
- Add rental_objects to /api/widget/:slug/config response
- Add POST /api/widget/:slug/rental-bookings endpoint with availability check
- Widget rental tab now shows real rental objects (not additionalServices)
- Date picker, hourly or full-day toggle, start/end hour selectors
- Booking submit creates actual rental_booking record in DB
- Success screen shows rental object, date and time slot
- WidgetRentalObject + WidgetRentalBookingPayload types added to api.ts
- BookingWidgetStandalonePage passes rentalObjects to WidgetPreview

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 11:32:10 +03:00
60c49d97d1 fix: unify YooKassa webhook to single URL + add webhook instruction in UI
- Consolidate online booking payment handling into existing /api/webhooks/yookassa
  (was previously split — deposit.ts had partial handling, new route had full)
- deposit.ts webhook now fully handles online_bookings: reserved→confirmed,
  payment_status=paid, paid_amount, WS broadcast, and confirmation email
- Remove POST /api/yookassa/webhook (keep only GET /api/online-bookings/:id)
- PaymentSettingsPage: add webhook URL instruction panel with copy button
  showing https://api.hotelsync.ru/api/webhooks/yookassa and required events

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 03:08:02 +03:00
c8d2d87db4 fix: BookingConfirmPage date format + guest confirmation email on payment
- Fix date display: slice ISO timestamp to first 10 chars before splitting
- Add sendBookingConfirmedEmail() to email.ts — sends green styled HTML email
  with booking details (dates, amount) on payment.succeeded webhook
- Webhook now sends confirmation email to guest email if present

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 03:02:18 +03:00
fb7d907b40 feat: YooKassa webhook, payment timeout, reserved status, BookingConfirmPage
- Add YooKassa webhook handler (POST /api/yookassa/webhook) that updates
  booking to confirmed+paid on payment.succeeded, cancelled on payment.canceled
- Add public status endpoint GET /api/online-bookings/:id for return URL polling
- Add 'reserved' booking status (violet) shown in calendar while awaiting payment
- Add 'website' to BookingSource type
- Payment timeout job (every 2 min) auto-cancels expired unpaid bookings
- Widget setting: "Время ожидания оплаты" (5–60 min, default 15)
- BookingConfirmPage at /booking-confirm/:id — polls status, countdown timer,
  shows success/pending/cancelled state
- Widget bookings now use status='reserved' instead of 'inquiry' when YooKassa
  is configured; set to 'confirmed' by webhook on payment.succeeded
- Migration 070: add 'reserved' to bookings status constraint + payment_expires_at

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 02:55:24 +03:00
b0bbb11c87 fix: dates timezone, guest lookup fallback to bookings, regex fix
- localDate() uses local timezone instead of UTC (prevents showing yesterday
  after midnight in UTC+3)
- Guest lookup: fallback to bookings table by guest_email/guest_phone when
  no guest profile found in CRM (guests table)
- Fix REGEXP_REPLACE pattern from '\D' (PCRE) to '[^0-9]' (PostgreSQL POSIX)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 02:41:38 +03:00
85b4ae4ee0 fix: booking widget payment flow and success message
- On API error: show error message instead of false success screen
- Success message: "Оплата прошла успешно" only when paidViaGateway=true (user actually clicked pay in YooKassa); otherwise "Бронирование принято. Менеджер свяжется с вами" or "Оплата на месте"
- Payment screen: simplified to YooKassa-only redirect (removed bank transfer variant)
- Removed bankDetails from WidgetSettings entirely (not needed per product decision)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 02:21:55 +03:00
bd27be72c1 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>
2026-04-08 02:10:02 +03:00
2b20fc18b3 feat: blacklist, guest lookup, bank transfer payment page
- Add is_blacklisted column to guests (migration 068)
- POST /widget/bookings: block blacklisted guests (403, generic message)
- GET /widget/:slug/guests/lookup: find existing guest by email/phone for auto-fill
- Widget form: debounce guest lookup on email/phone input, show "Заполнить" suggestion
- Widget payment screen: replace fake card form with proper YooKassa redirect screen or bank transfer details page
- Add bank transfer details field to widget settings (saved as widget_bank_details)
- GuestsPage: blacklist toggle button in edit modal + 🚫 ЧС badge in table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 01:31:10 +03:00
08d6629ae8 fix: standalone /book page applies saved widget settings from backend
BookingWidgetStandalonePage now fetches widgetSettings from the public
config API and applies them (color, language, mode, etc.) instead of
always falling back to URL param defaults. URL params still work as
overrides if present.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:36:44 +03:00
0eababe4e0 fix: load widget settings with camelCase keys (transformKeys converts response) 2026-04-07 22:31:25 +03:00
643774ce0a fix: widget settings auto-save with debounce 2026-04-07 22:25:00 +03:00
99274dfa04 feat: widget settings persistence + remove redundant payment card 2026-04-07 22:14:45 +03:00
a02cf342a2 feat: widget iframe embed — standalone /:slug/book page 2026-04-07 21:57:46 +03:00
328753fc1e feat: persist assignment_strategy + apply to widget category bookings 2026-04-07 21:45:12 +03:00
ab37430243 feat: widget — room display mode toggle (by room / by category) 2026-04-07 20:46:30 +03:00
57531f2022 feat: long-stay deposit charge + refunds + auto-confirm widget + white page fix
- Widget white page fix: fallback photo when real rooms have no photos array
- Long-stay deposits: if booking > threshold days and toggle on → full charge instead of hold (bypasses YooKassa 7-day limit)
- DepositSettingsPage: toggle + day threshold input for long-stay full payment
- Refund endpoint: POST /deposit/refund supports full and partial refunds via YooKassa refunds API
- DepositWidget: refund UI for yookassa_charge deposits (full/partial, shows remaining amount)
- partially_refunded status support with badge and "Вернуть ещё" button
- Auto-confirm: webhook now auto-confirms booking status on payment.succeeded for widget bookings
- PaymentSettingsPage: auto-confirm toggle per gateway (shown when booking-widget module active)
- Migration 067: long_stay columns on hotel_deposit_settings, auto_confirm_on_payment on gateways, refunded_amount on deposits

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 20:30:26 +03:00
bddfa355f2 feat: deposit release lock + billing fixes + centralized payment gateway
- Add releaseRequiresCheckout toggle in DepositSettingsPage (UI + payload)
- Migration 066: release_requires_checkout column on hotel_deposit_settings
- Migration 065: hotel_payment_gateways table for centralized YooKassa config
- Block deposit release buttons when releaseRequiresCheckout && not checked_out
- Fix billing calculation: use Number() to prevent PostgreSQL NUMERIC string concat
- Fix minibar billing: show current price (JOIN minibar_items.price) not recorded price
- Auto-poll deposit status every 5s while hold_created; clear QR message on confirmation
- Add billing/folio tab in BookingDetailPanel (room charges + minibar + payments + balance)
- PaymentSettingsPage: new "Онлайн-оплата (ЮКасса)" section with gateway CRUD
- DepositSettingsPage: replace YooKassa fields with link to centralized payment settings
- BookingWidgetPage: connect to real API, gateway status banner, async booking submission
- New backend routes: paymentGateways, publicWidget
- YooKassa service: add createCharge() for immediate payment (online bookings)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 20:47:52 +03:00
6859817bdf feat: centralized payment gateways + booking widget API
Backend:
- Migration 065: hotel_payment_gateways table (migrates YooKassa from deposit_settings)
- online_bookings table for widget submissions
- Routes: CRUD /api/hotels/:slug/payment-gateways
- Public widget API: /api/widget/:slug/{config,availability,bookings}
- yookassa.ts: add createCharge() for immediate capture

Frontend:
- PaymentSettingsPage: add 'Онлайн-оплата' section with gateway CRUD and module toggles
- DepositSettingsPage: replace YooKassa fields with link to centralized settings
- BookingWidgetPage: connect to real API, show gateway status, real booking submit
- api.ts: add PaymentGateway types, paymentGateways and widget API methods

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 20:37:06 +03:00
340b3ddec9 feat: deposit auto-poll + billing folio tab
- DepositWidget: auto-poll every 5s while hold_created, clear QR message on hold_confirmed
- Add 'Счёт' tab (billing folio): room charges + minibar lines + payments + deposit badge + balance
- Billing data loads lazily on tab open

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 20:24:03 +03:00
bb72a24757 feat: deposit auto-apply to room payment on checkout
- Add activeDeposit state to BookingDetailPanel via DepositWidget callback
- On checkout, if active deposit (hold_confirmed/paid_cash) exists and balance > 0:
  show checkbox 'Зачесть депозит в счёт оплаты' with editable amount
- On confirm: capture deposit via /deposit/release + add booking_payment record
- Default apply amount = min(deposit.amount, outstanding balance)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 16:21:20 +03:00
f94d4723d5 feat: настройки оплаты — способы оплаты + контроль при заселении
- Миграция 064: таблица hotel_payment_methods, поле require_payment_checkin
- Бэкенд: CRUD /api/hotels/:slug/payment-methods, /api/hotels/:slug/payment-settings
- PaymentSettingsPage (/settings/payments): управление способами оплаты
  (название, валюта, тип, активность, сортировка), контроль при заселении (нет/мягкий/жёсткий)
- BookingDetailPanel: динамические методы оплаты вместо захардкоженных
- Кнопка «Заселить»: hard — заблокирована при балансе > 0; soft — предупреждение с выбором

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 16:12:38 +03:00
45a8cf7c10 ui: боковая панель — ширина 560px, вкладка «Оплата» двухколоночная
- w-[400px] → w-[560px] для боковой панели бронирования
- Вкладка «Оплата»: расчёт + платежи слева, депозит справа (grid 2 cols)
- На мобиле — одна колонка как прежде

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 15:59:20 +03:00
83d797c55f fix: minibar deposit — использовать актуальную цену из справочника, а не историческую
Ранее в форме удержания депозита показывалась цена на момент уборки (price_per_unit).
Теперь используется текущая цена позиции (mi.price) — чтобы изменения цен сразу
отражались в счёте. Если цена менялась — показываем индикатор ↑ с tooltip.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 15:51:34 +03:00
54d0d2d817 feat: deposit release — детальный список позиций + HTML-чек на email гостю
- Форма удержания: позиции мини-бара расписаны по отдельности (товар × кол-во, цена/шт.)
  с кнопками «+ Добавить» для каждой и «+ Добавить всё»
- Email гостю: HTML-шаблон с таблицей-чеком (позиция / сумма), итоговые строки,
  остаток возврата, брендинг отеля; текстовый fallback сохранён

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 15:42:14 +03:00
1f4def0a34 feat: minibar — category dropdown, учёт остатков (приходы/списания/инвентаризация/отчёт)
- MinibarSettingsPage: поле категории → выпадающий список с существующими + «Новая...»
- Кнопка «Учёт и остатки» ведёт на /settings/minibar/stock
- MinibarStockPage: 5 вкладок — Остатки, Приходы, Списания, Инвентаризация, Отчёт
- api.ts: добавлены методы и типы для stock/receipts/writeoffs/inventory/report

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 15:36:40 +03:00
5b46175c91 fix: minibar consumptions not showing in deposit release form
Wrong column names in SQL query: price_at_time→price_per_unit,
created_at→recorded_at. Also fixed type mismatch priceAtTime→pricePerUnit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 15:28:38 +03:00
d686f5abe6 feat: deposit presets UI, back button in history, onFocus select on inputs
- DepositSettingsPage: deduction presets management (add/edit/delete inline)
- DepositHistoryPage: "← Назад" link back to settings
- Amount inputs: onFocus selects all text

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:03:20 +03:00
1ab24dfe27 feat: deposit deductions, booking payments persistence, minibar in release form
- Migrations 061 (booking_payments) + 062 (deposit_deduction_presets)
- Backend: booking payments CRUD (GET/POST/DELETE), auto-updates paid_amount on booking
- Backend: deposit deduction presets CRUD (GET/POST/PATCH/DELETE)
- Backend: GET /deposit/minibar endpoint returns minibar consumptions for booking
- Backend: release endpoint accepts items[] for itemized email to guest
- Frontend: payments loaded from API — persist across page reloads
- Frontend: deposit release form redesigned — preset buttons, minibar auto-fill, itemized list
- Frontend: onFocus select on all amount inputs (no more manual "0" removal)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 12:55:42 +03:00