import { useState } from 'react' import * as api from '../lib/api' import { useAuth } from '../auth/AuthContext' import { useClientLoyalty } from './useClientLoyalty' import { inputStyle } from '../orders/formStyles' const TYPE_LABELS = { accrual: 'Начисление', redemption: 'Списание', adjustment: 'Корректировка' } const TYPE_COLORS = { accrual: 'var(--accent-green)', redemption: 'var(--accent-red)', adjustment: 'var(--text-muted)' } function RedeemForm({ clientId, balance, onDone }) { const [points, setPoints] = useState('') const [note, setNote] = useState('') const [busy, setBusy] = useState(false) const [error, setError] = useState('') const submit = async () => { const n = Number(points) if (!n || n <= 0) { setError('Укажите количество баллов'); return } setBusy(true) setError('') try { await api.loyalty.redeem(clientId, { points: n, note }) setPoints('') setNote('') onDone() } catch (err) { setError(err.message) } finally { setBusy(false) } } return (
setPoints(e.target.value)} placeholder="Баллов" style={{ ...inputStyle, width: '90px', padding: '6px 8px' }} /> setNote(e.target.value)} placeholder="Заметка (необязательно)" style={{ ...inputStyle, flex: 1, minWidth: '140px', padding: '6px 8px' }} /> {error && {error}}
) } function AdjustForm({ clientId, onDone }) { const [points, setPoints] = useState('') const [note, setNote] = useState('') const [busy, setBusy] = useState(false) const [error, setError] = useState('') const submit = async () => { const n = Number(points) if (!n) { setError('Укажите количество баллов (можно отрицательное)'); return } if (!note.trim()) { setError('Заметка обязательна для корректировки'); return } setBusy(true) setError('') try { await api.loyalty.adjust(clientId, { points: n, note }) setPoints('') setNote('') onDone() } catch (err) { setError(err.message) } finally { setBusy(false) } } return (
setPoints(e.target.value)} placeholder="±Баллов" style={{ ...inputStyle, width: '90px', padding: '6px 8px' }} /> setNote(e.target.value)} placeholder="Причина (обязательно)" style={{ ...inputStyle, flex: 1, minWidth: '140px', padding: '6px 8px' }} /> {error && {error}}
) } // Embedded in ClientsPage's ClientDetail modal, right after // ClientNotificationsSection — balance, manual redeem/adjust (owner/manager // only, matching the backend's cashOnly gate), and the ledger history. const ClientLoyaltySection = ({ clientId }) => { const { staff } = useAuth() const canManage = staff.role === 'owner' || staff.role === 'manager' const { balance, history, loading, reload } = useClientLoyalty(clientId) return (

Бонусные баллы

{balance}
{canManage && ( <> )}

История

{loading ? (

Загрузка...

) : history.length === 0 ? (

Пока нет операций

) : ( history.map((t) => (
{TYPE_LABELS[t.type] || t.type}{t.note ? ` — ${t.note}` : ''} {t.points > 0 ? '+' : ''}{t.points}

{new Date(t.created_at).toLocaleString('ru-RU')} · {t.staff_name}

)) )}
) } export default ClientLoyaltySection