diff --git a/src/pages/DepositHistoryPage.tsx b/src/pages/DepositHistoryPage.tsx
index 7489e88..47fe734 100644
--- a/src/pages/DepositHistoryPage.tsx
+++ b/src/pages/DepositHistoryPage.tsx
@@ -1,5 +1,6 @@
import { useState, useEffect } from 'react'
-import { Loader2, ShieldCheck, CreditCard, Banknote, RefreshCw } from 'lucide-react'
+import { Loader2, ShieldCheck, CreditCard, Banknote, RefreshCw, ArrowLeft } from 'lucide-react'
+import { Link } from 'react-router-dom'
import { api, type BookingDeposit } from '../lib/api'
import { useAuth } from '../contexts/AuthContext'
import { cn, formatCurrency } from '../lib/utils'
@@ -40,14 +41,17 @@ export function DepositHistoryPage() {
return (
-
-
- История депозитов
-
-
+
+
+
+ Назад
+
+
+
+ История депозитов
+
+
+
Обновить
diff --git a/src/pages/DepositSettingsPage.tsx b/src/pages/DepositSettingsPage.tsx
index f6ad359..b533269 100644
--- a/src/pages/DepositSettingsPage.tsx
+++ b/src/pages/DepositSettingsPage.tsx
@@ -1,10 +1,10 @@
import { useState, useEffect } from 'react'
-import { Save, Eye, EyeOff, Loader2, ShieldCheck, Printer, History, Info } from 'lucide-react'
+import { Save, Eye, EyeOff, Loader2, ShieldCheck, Printer, History, Info, Plus, Trash2, Check } from 'lucide-react'
import { QRCodeSVG } from 'qrcode.react'
import { Link } from 'react-router-dom'
-import { api, type DepositSettings } from '../lib/api'
+import { api, type DepositSettings, type DepositPreset } from '../lib/api'
import { useAuth } from '../contexts/AuthContext'
-import { cn } from '../lib/utils'
+import { cn, formatCurrency } from '../lib/utils'
function Toggle({ on, onChange }: { on: boolean; onChange: () => void }) {
return (
@@ -33,24 +33,33 @@ export function DepositSettingsPage() {
const [secretKey, setSecretKey] = useState('')
const [showSecret, setShowSecret] = useState(false)
+ // Deduction presets
+ const [presets, setPresets] = useState([])
+ const [newPresetName, setNewPresetName] = useState('')
+ const [newPresetAmount, setNewPresetAmount] = useState('')
+ const [addingPreset, setAddingPreset] = useState(false)
+ const [editingPreset, setEditingPreset] = useState(null)
+ const [editName, setEditName] = useState('')
+ const [editAmount, setEditAmount] = useState('')
+
useEffect(() => {
if (!slug) return
- api.deposits.getSettings(slug)
- .then(s => {
- setSettings(s)
- setIsEnabled(s.isEnabled)
- setAmount(String(s.amount))
- setShopId(s.yookassaShopId ?? '')
- setSecretKey(s.yookassaSecretKey ?? '')
- })
- .catch(() => {
- // No settings yet — defaults
- setIsEnabled(false)
- setAmount('5000')
- setShopId('')
- setSecretKey('')
- })
- .finally(() => setLoading(false))
+ Promise.all([
+ api.deposits.getSettings(slug),
+ api.deposits.getPresets(slug).catch(() => []),
+ ]).then(([s, p]) => {
+ setSettings(s)
+ setIsEnabled(s.isEnabled)
+ setAmount(String(s.amount))
+ setShopId(s.yookassaShopId ?? '')
+ setSecretKey(s.yookassaSecretKey ?? '')
+ setPresets(p)
+ }).catch(() => {
+ setIsEnabled(false)
+ setAmount('5000')
+ setShopId('')
+ setSecretKey('')
+ }).finally(() => setLoading(false))
}, [slug])
const handleSave = async () => {
@@ -75,6 +84,47 @@ export function DepositSettingsPage() {
}
}
+ const handleAddPreset = async () => {
+ const name = newPresetName.trim()
+ const amt = parseFloat(newPresetAmount)
+ if (!name || !amt || amt <= 0) return
+ setAddingPreset(true)
+ try {
+ const p = await api.deposits.createPreset(slug, name, amt)
+ setPresets(prev => [...prev, p])
+ setNewPresetName('')
+ setNewPresetAmount('')
+ } catch {
+ // ignore
+ } finally {
+ setAddingPreset(false)
+ }
+ }
+
+ const handleDeletePreset = async (id: string) => {
+ await api.deposits.deletePreset(slug, id).catch(() => {})
+ setPresets(prev => prev.filter(p => p.id !== id))
+ }
+
+ const startEdit = (p: DepositPreset) => {
+ setEditingPreset(p.id)
+ setEditName(p.name)
+ setEditAmount(String(p.amount))
+ }
+
+ const saveEdit = async (id: string) => {
+ const name = editName.trim()
+ const amt = parseFloat(editAmount)
+ if (!name || !amt) return
+ try {
+ const updated = await api.deposits.updatePreset(slug, id, { name, amount: amt })
+ setPresets(prev => prev.map(p => p.id === id ? updated : p))
+ } catch {
+ // ignore
+ }
+ setEditingPreset(null)
+ }
+
if (loading) {
return (
@@ -95,10 +145,7 @@ export function DepositSettingsPage() {
Настройте предоплату или залог при заселении гостей.
-
+
История платежей
@@ -110,8 +157,8 @@ export function DepositSettingsPage() {
)}
+ {/* Main settings card */}
- {/* Enable toggle */}
Включить депозит
@@ -125,66 +172,47 @@ export function DepositSettingsPage() {
{isEnabled && (
<>
- {/* Amount */}
Сумма депозита, руб.
setAmount(e.target.value)}
+ type="number" min="0" step="100"
+ value={amount} onChange={e => setAmount(e.target.value)}
+ onFocus={e => e.target.select()}
className="input w-48"
/>
- {/* YooKassa section */}
ЮКасса (опционально)
- Укажите реквизиты ЮКасса для создания холда (предавторизации) оплаты. Без этих данных доступен только наличный депозит.
+ Укажите реквизиты ЮКасса для создания холда (предавторизации) оплаты.
-
ID магазина (shopId)
- setShopId(e.target.value)}
- placeholder="123456"
- className="input w-full"
- />
+ setShopId(e.target.value)} placeholder="123456" className="input w-full" />
-
Секретный ключ
setSecretKey(e.target.value)}
+ value={secretKey} onChange={e => setSecretKey(e.target.value)}
placeholder={settings?.yookassaSecretKey ? '••••••••' : 'live_xxxx...'}
className="input w-full pr-10"
/>
- setShowSecret(s => !s)}
- className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600"
- >
+ setShowSecret(s => !s)} className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600">
{showSecret ? : }
{settings?.yookassaSecretKey && (
-
- Ключ уже сохранён. Оставьте поле пустым, чтобы не менять.
-
+
Ключ уже сохранён. Оставьте поле пустым, чтобы не менять.
)}
- {/* Webhook notice */}
{shopId && (
@@ -192,7 +220,7 @@ export function DepositSettingsPage() {
Настройте webhook в ЮКасса
- Чтобы статус депозита обновлялся автоматически после оплаты, добавьте URL уведомлений в личном кабинете ЮКасса (Настройки → HTTP-уведомления):
+ Чтобы статус депозита обновлялся автоматически, добавьте URL в личном кабинете ЮКасса (Настройки → HTTP-уведомления):
https://api.hotelsync.ru/api/webhooks/yookassa
@@ -204,29 +232,20 @@ export function DepositSettingsPage() {
)}
- {/* QR code section — only when shopId is configured */}
{shopId && (
QR-код для гостей
- Распечатайте и разместите на стойке ресепшена. Гость сканирует код и оплачивает депозит картой.
+ Распечатайте и разместите на стойке ресепшена.
-
+
https://app.hotelsync.ru/{slug}/pay
-
window.print()}
- className="btn-secondary flex items-center gap-2"
- >
+ window.print()} className="btn-secondary flex items-center gap-2">
Распечатать QR-код
@@ -234,16 +253,8 @@ export function DepositSettingsPage() {
@@ -254,18 +265,103 @@ export function DepositSettingsPage() {
-
+
{saving ? : }
{saved ? 'Сохранено!' : 'Сохранить'}
- {saved && (
- Настройки сохранены
- )}
+ {saved && Настройки сохранены }
+
+ {/* Deduction presets */}
+ {isEnabled && (
+
+
+
Позиции удержания
+
+ Стандартные причины для списания из депозита. При возврате депозита менеджер выбирает из этого списка.
+
+
+
+ {/* Existing presets */}
+ {presets.length > 0 && (
+
+ )}
+
+ {/* Add new preset */}
+
+
+ )}
)
}