mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
fix(payment-methods): admin display_name/description override locale on balance
White-label (per-method display_name + description in admin) was defeated on balance/top-up pages: render used `translatedName || method.name` and `translatedDesc || method.description`, so the bundled locale always won and the admin override was ignored. - Flip priority: admin-configured value first, locale as fallback (TopUpMethodSelect, Balance) - Add missing Description field to payment-method edit page (mirrors Display name: description / reset_description) - Add description to admin PaymentMethodConfig type - Add description/descriptionHint i18n keys (ru, en)
This commit is contained in:
@@ -1627,6 +1627,8 @@
|
|||||||
"openUrlDirectHint": "ON — the payment link opens immediately, without the intermediate button panel. OFF — an \"Open payment\" button is shown. Inside Telegram the link opens in the external browser either way (otherwise paying via a bank app/SBP fails); after payment the user returns to the result page. Stars/CryptoBot (t.me/ links) always open natively and ignore this flag.",
|
"openUrlDirectHint": "ON — the payment link opens immediately, without the intermediate button panel. OFF — an \"Open payment\" button is shown. Inside Telegram the link opens in the external browser either way (otherwise paying via a bank app/SBP fails); after payment the user returns to the result page. Stars/CryptoBot (t.me/ links) always open natively and ignore this flag.",
|
||||||
"displayName": "Display name",
|
"displayName": "Display name",
|
||||||
"displayNameHint": "Leave empty for default name",
|
"displayNameHint": "Leave empty for default name",
|
||||||
|
"description": "Description",
|
||||||
|
"descriptionHint": "Shown under the method name. Empty for default text",
|
||||||
"subOptions": "Payment options",
|
"subOptions": "Payment options",
|
||||||
"minAmount": "Min amount (kopeks)",
|
"minAmount": "Min amount (kopeks)",
|
||||||
"maxAmount": "Max amount (kopeks)",
|
"maxAmount": "Max amount (kopeks)",
|
||||||
|
|||||||
@@ -1649,6 +1649,8 @@
|
|||||||
"openUrlDirectHint": "ВКЛ — ссылка оплаты открывается сразу, без промежуточной панели с кнопкой. ВЫКЛ — показывается кнопка «Открыть оплату». В Telegram ссылка в обоих случаях открывается во внешнем браузере (иначе оплата через банковское приложение/СБП не срабатывает), после оплаты — возврат на страницу результата. Stars/CryptoBot (t.me/-ссылки) всегда открываются нативно, флаг к ним не применяется.",
|
"openUrlDirectHint": "ВКЛ — ссылка оплаты открывается сразу, без промежуточной панели с кнопкой. ВЫКЛ — показывается кнопка «Открыть оплату». В Telegram ссылка в обоих случаях открывается во внешнем браузере (иначе оплата через банковское приложение/СБП не срабатывает), после оплаты — возврат на страницу результата. Stars/CryptoBot (t.me/-ссылки) всегда открываются нативно, флаг к ним не применяется.",
|
||||||
"displayName": "Отображаемое имя",
|
"displayName": "Отображаемое имя",
|
||||||
"displayNameHint": "Оставьте пустым для имени по умолчанию",
|
"displayNameHint": "Оставьте пустым для имени по умолчанию",
|
||||||
|
"description": "Описание",
|
||||||
|
"descriptionHint": "Показывается под названием метода. Пусто — текст по умолчанию",
|
||||||
"subOptions": "Варианты оплаты",
|
"subOptions": "Варианты оплаты",
|
||||||
"minAmount": "Мин. сумма (коп.)",
|
"minAmount": "Мин. сумма (коп.)",
|
||||||
"maxAmount": "Макс. сумма (коп.)",
|
"maxAmount": "Макс. сумма (коп.)",
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ export default function AdminPaymentMethodEdit() {
|
|||||||
// Local state for editing
|
// Local state for editing
|
||||||
const [isEnabled, setIsEnabled] = useState(false);
|
const [isEnabled, setIsEnabled] = useState(false);
|
||||||
const [customName, setCustomName] = useState('');
|
const [customName, setCustomName] = useState('');
|
||||||
|
const [customDesc, setCustomDesc] = useState('');
|
||||||
const [subOptions, setSubOptions] = useState<Record<string, boolean>>({});
|
const [subOptions, setSubOptions] = useState<Record<string, boolean>>({});
|
||||||
const [minAmount, setMinAmount] = useState<number | ''>('');
|
const [minAmount, setMinAmount] = useState<number | ''>('');
|
||||||
const [maxAmount, setMaxAmount] = useState<number | ''>('');
|
const [maxAmount, setMaxAmount] = useState<number | ''>('');
|
||||||
@@ -249,6 +250,7 @@ export default function AdminPaymentMethodEdit() {
|
|||||||
if (config) {
|
if (config) {
|
||||||
setIsEnabled(config.is_enabled);
|
setIsEnabled(config.is_enabled);
|
||||||
setCustomName(config.display_name || '');
|
setCustomName(config.display_name || '');
|
||||||
|
setCustomDesc(config.description || '');
|
||||||
setSubOptions(config.sub_options || {});
|
setSubOptions(config.sub_options || {});
|
||||||
setMinAmount(config.min_amount_kopeks ?? '');
|
setMinAmount(config.min_amount_kopeks ?? '');
|
||||||
setMaxAmount(config.max_amount_kopeks ?? '');
|
setMaxAmount(config.max_amount_kopeks ?? '');
|
||||||
@@ -290,6 +292,13 @@ export default function AdminPaymentMethodEdit() {
|
|||||||
data.reset_display_name = true;
|
data.reset_display_name = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Description
|
||||||
|
if (customDesc.trim()) {
|
||||||
|
data.description = customDesc.trim();
|
||||||
|
} else {
|
||||||
|
data.reset_description = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Sub-options
|
// Sub-options
|
||||||
if (config.available_sub_options) {
|
if (config.available_sub_options) {
|
||||||
data.sub_options = subOptions;
|
data.sub_options = subOptions;
|
||||||
@@ -478,6 +487,22 @@ export default function AdminPaymentMethodEdit() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Description */}
|
||||||
|
<div>
|
||||||
|
<label className="mb-2 block text-sm font-medium text-dark-300">
|
||||||
|
{t('admin.paymentMethods.description')}
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
value={customDesc}
|
||||||
|
onChange={(e) => setCustomDesc(e.target.value)}
|
||||||
|
rows={2}
|
||||||
|
className="input"
|
||||||
|
/>
|
||||||
|
<p className="mt-1 text-xs text-dark-500">
|
||||||
|
{t('admin.paymentMethods.descriptionHint')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Sub-options */}
|
{/* Sub-options */}
|
||||||
{config.available_sub_options && config.available_sub_options.length > 0 && (
|
{config.available_sub_options && config.available_sub_options.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -335,11 +335,11 @@ export default function Balance() {
|
|||||||
onClick={() => method.is_available && navigate(`/balance/top-up/${method.id}`)}
|
onClick={() => method.is_available && navigate(`/balance/top-up/${method.id}`)}
|
||||||
>
|
>
|
||||||
<div className="font-semibold text-dark-100">
|
<div className="font-semibold text-dark-100">
|
||||||
{translatedName || method.name}
|
{method.name || translatedName}
|
||||||
</div>
|
</div>
|
||||||
{(translatedDesc || method.description) && (
|
{(method.description || translatedDesc) && (
|
||||||
<div className="mt-1 text-sm text-dark-500">
|
<div className="mt-1 text-sm text-dark-500">
|
||||||
{translatedDesc || method.description}
|
{method.description || translatedDesc}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="mt-3 text-xs text-dark-400">
|
<div className="mt-3 text-xs text-dark-400">
|
||||||
|
|||||||
@@ -74,12 +74,12 @@ export default function TopUpMethodSelect() {
|
|||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<PaymentMethodIcon method={methodKey} className="h-8 w-8 flex-shrink-0" />
|
<PaymentMethodIcon method={methodKey} className="h-8 w-8 flex-shrink-0" />
|
||||||
<div className="font-semibold text-dark-100">
|
<div className="font-semibold text-dark-100">
|
||||||
{translatedName || method.name}
|
{method.name || translatedName}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{(translatedDesc || method.description) && (
|
{(method.description || translatedDesc) && (
|
||||||
<div className="mt-1 text-sm text-dark-500">
|
<div className="mt-1 text-sm text-dark-500">
|
||||||
{translatedDesc || method.description}
|
{method.description || translatedDesc}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="mt-3 text-xs text-dark-400">
|
<div className="mt-3 text-xs text-dark-400">
|
||||||
|
|||||||
@@ -689,6 +689,7 @@ export interface PaymentMethodConfig {
|
|||||||
is_enabled: boolean;
|
is_enabled: boolean;
|
||||||
display_name: string | null;
|
display_name: string | null;
|
||||||
default_display_name: string;
|
default_display_name: string;
|
||||||
|
description: string | null;
|
||||||
sub_options: Record<string, boolean> | null;
|
sub_options: Record<string, boolean> | null;
|
||||||
available_sub_options: PaymentMethodSubOptionInfo[] | null;
|
available_sub_options: PaymentMethodSubOptionInfo[] | null;
|
||||||
quick_amounts: number[] | null;
|
quick_amounts: number[] | null;
|
||||||
|
|||||||
Reference in New Issue
Block a user