From bb8b823b3778ac31538cb980c7323f7ca33d212a Mon Sep 17 00:00:00 2001 From: Boris Kovalskii <36034823+JustYay@users.noreply.github.com> Date: Wed, 10 Jun 2026 23:39:22 +1000 Subject: [PATCH] feat(admin): quick amounts editor in payment method settings --- src/locales/en.json | 6 +++ src/locales/ru.json | 6 +++ src/pages/AdminPaymentMethodEdit.tsx | 81 ++++++++++++++++++++++++++++ src/types/index.ts | 2 + 4 files changed, 95 insertions(+) diff --git a/src/locales/en.json b/src/locales/en.json index 63eeeb0..314fa52 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1607,6 +1607,12 @@ "subOptions": "Payment options", "minAmount": "Min amount (kopeks)", "maxAmount": "Max amount (kopeks)", + "quickAmounts": "Quick amounts (₽)", + "quickAmountsHint": "Quick top-up amount buttons. Empty — defaults are used: {{defaults}} ₽", + "quickAmountsPlaceholder": "Amount in rubles", + "quickAmountsAdd": "Add", + "quickAmountsInvalid": "Enter a positive amount in rubles", + "quickAmountsLimit": "No more than 10 amounts", "conditions": "Display conditions", "userTypeFilter": "User type", "userTypeAll": "All", diff --git a/src/locales/ru.json b/src/locales/ru.json index caec2c7..00a12f3 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1629,6 +1629,12 @@ "subOptions": "Варианты оплаты", "minAmount": "Мин. сумма (коп.)", "maxAmount": "Макс. сумма (коп.)", + "quickAmounts": "Быстрые суммы (₽)", + "quickAmountsHint": "Кнопки быстрого выбора суммы пополнения. Пусто — используются значения по умолчанию: {{defaults}} ₽", + "quickAmountsPlaceholder": "Сумма в рублях", + "quickAmountsAdd": "Добавить", + "quickAmountsInvalid": "Введите положительную сумму в рублях", + "quickAmountsLimit": "Не более 10 сумм", "conditions": "Условия отображения", "userTypeFilter": "Тип пользователя", "userTypeAll": "Все", diff --git a/src/pages/AdminPaymentMethodEdit.tsx b/src/pages/AdminPaymentMethodEdit.tsx index f5fa4b2..3e778fb 100644 --- a/src/pages/AdminPaymentMethodEdit.tsx +++ b/src/pages/AdminPaymentMethodEdit.tsx @@ -41,6 +41,9 @@ export default function AdminPaymentMethodEdit() { const [promoGroupFilterMode, setPromoGroupFilterMode] = useState<'all' | 'selected'>('all'); const [selectedPromoGroupIds, setSelectedPromoGroupIds] = useState([]); const [openUrlDirect, setOpenUrlDirect] = useState(false); + const [quickAmounts, setQuickAmounts] = useState([]); + const [quickAmountInput, setQuickAmountInput] = useState(''); + const [quickAmountsError, setQuickAmountsError] = useState(null); // Initialize state when config loads useEffect(() => { @@ -56,6 +59,7 @@ export default function AdminPaymentMethodEdit() { setSelectedPromoGroupIds(config.allowed_promo_group_ids); // ?? false — защита от stale-config (backend ещё не пришёл с миграцией) setOpenUrlDirect(config.open_url_direct ?? false); + setQuickAmounts((config.quick_amounts ?? []).map((kopeks) => kopeks / 100)); } }, [config]); @@ -104,6 +108,14 @@ export default function AdminPaymentMethodEdit() { data.reset_max_amount = true; } + if (quickAmounts.length > 0) { + data.quick_amounts = [...quickAmounts] + .sort((a, b) => a - b) + .map((rubles) => Math.round(rubles * 100)); + } else { + data.reset_quick_amounts = true; + } + updateMethodMutation.mutate(data); }; @@ -113,6 +125,29 @@ export default function AdminPaymentMethodEdit() { ); }; + const addQuickAmount = () => { + setQuickAmountsError(null); + const value = parseFloat(quickAmountInput.replace(',', '.')); + if (isNaN(value) || value <= 0) { + setQuickAmountsError(t('admin.paymentMethods.quickAmountsInvalid')); + return; + } + if (quickAmounts.includes(value)) { + setQuickAmountInput(''); + return; + } + if (quickAmounts.length >= 10) { + setQuickAmountsError(t('admin.paymentMethods.quickAmountsLimit')); + return; + } + setQuickAmounts((prev) => [...prev, value].sort((a, b) => a - b)); + setQuickAmountInput(''); + }; + + const removeQuickAmount = (value: number) => { + setQuickAmounts((prev) => prev.filter((amount) => amount !== value)); + }; + if (isLoading) { return (
@@ -305,6 +340,52 @@ export default function AdminPaymentMethodEdit() {
+
+ + {quickAmounts.length > 0 && ( +
+ {quickAmounts.map((value) => ( + + ))} +
+ )} +
+ setQuickAmountInput(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault(); + addQuickAmount(); + } + }} + placeholder={t('admin.paymentMethods.quickAmountsPlaceholder')} + className="input flex-1" + /> + +
+ {quickAmountsError &&

{quickAmountsError}

} +

+ {t('admin.paymentMethods.quickAmountsHint', { + defaults: config.default_quick_amounts.map((kopeks) => kopeks / 100).join(', '), + })} +

+
+ {/* Display conditions */}

diff --git a/src/types/index.ts b/src/types/index.ts index 20cbbb8..f4fd660 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -688,6 +688,8 @@ export interface PaymentMethodConfig { default_display_name: string; sub_options: Record | null; available_sub_options: PaymentMethodSubOptionInfo[] | null; + quick_amounts: number[] | null; + default_quick_amounts: number[]; min_amount_kopeks: number | null; max_amount_kopeks: number | null; default_min_amount_kopeks: number;