mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
fix: partner system bugs - commission field, withdrawal UX, admin amount
1. Add desired commission percent field to partner application form and admin review page (Bug 1) 2. Add prominent "Requested Amount" row in admin withdrawal detail (Bug 2) 3. Switch withdrawal input from kopecks to rubles with auto-conversion on submit (Bug 3) Includes i18n updates for all 4 locales (ru, en, zh, fa).
This commit is contained in:
@@ -10,6 +10,7 @@ export interface PartnerApplicationInfo {
|
|||||||
telegram_channel: string | null;
|
telegram_channel: string | null;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
expected_monthly_referrals: number | null;
|
expected_monthly_referrals: number | null;
|
||||||
|
desired_commission_percent: number | null;
|
||||||
admin_comment: string | null;
|
admin_comment: string | null;
|
||||||
approved_commission_percent: number | null;
|
approved_commission_percent: number | null;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
@@ -41,6 +42,7 @@ export interface PartnerApplicationRequest {
|
|||||||
telegram_channel?: string;
|
telegram_channel?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
expected_monthly_referrals?: number;
|
expected_monthly_referrals?: number;
|
||||||
|
desired_commission_percent?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== Admin-facing types ====================
|
// ==================== Admin-facing types ====================
|
||||||
@@ -56,6 +58,7 @@ export interface AdminPartnerApplicationItem {
|
|||||||
telegram_channel: string | null;
|
telegram_channel: string | null;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
expected_monthly_referrals: number | null;
|
expected_monthly_referrals: number | null;
|
||||||
|
desired_commission_percent: number | null;
|
||||||
status: string;
|
status: string;
|
||||||
admin_comment: string | null;
|
admin_comment: string | null;
|
||||||
approved_commission_percent: number | null;
|
approved_commission_percent: number | null;
|
||||||
|
|||||||
@@ -755,7 +755,9 @@
|
|||||||
"description": "Description",
|
"description": "Description",
|
||||||
"descriptionPlaceholder": "Tell us about your audience and how you plan to promote...",
|
"descriptionPlaceholder": "Tell us about your audience and how you plan to promote...",
|
||||||
"expectedReferrals": "Expected Monthly Referrals",
|
"expectedReferrals": "Expected Monthly Referrals",
|
||||||
"expectedReferralsPlaceholder": "Estimated number per month"
|
"expectedReferralsPlaceholder": "Estimated number per month",
|
||||||
|
"desiredCommission": "Desired Commission (%)",
|
||||||
|
"desiredCommissionPlaceholder": "From 1 to 100%"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"withdrawal": {
|
"withdrawal": {
|
||||||
@@ -776,9 +778,9 @@
|
|||||||
"submitRequest": "Submit Request",
|
"submitRequest": "Submit Request",
|
||||||
"requestError": "Failed to create withdrawal request. Please try again.",
|
"requestError": "Failed to create withdrawal request. Please try again.",
|
||||||
"fields": {
|
"fields": {
|
||||||
"amount": "Amount (kopeks)",
|
"amount": "Amount",
|
||||||
"amountPlaceholder": "Enter amount in kopeks",
|
"amountPlaceholder": "Enter amount in {{currency}}",
|
||||||
"amountHint": "Enter the amount in kopeks (100 kopeks = 1 {{currency}})",
|
"amountHint": "Minimum: {{min}} {{currency}}",
|
||||||
"paymentDetails": "Payment Details",
|
"paymentDetails": "Payment Details",
|
||||||
"paymentDetailsPlaceholder": "Card number, wallet address, or other payment info..."
|
"paymentDetailsPlaceholder": "Card number, wallet address, or other payment info..."
|
||||||
},
|
},
|
||||||
@@ -2046,6 +2048,7 @@
|
|||||||
"balance": "Balance",
|
"balance": "Balance",
|
||||||
"totalReferrals": "Total referrals",
|
"totalReferrals": "Total referrals",
|
||||||
"totalEarnings": "Total earnings",
|
"totalEarnings": "Total earnings",
|
||||||
|
"requestedAmount": "Requested Amount",
|
||||||
"createdAt": "Created",
|
"createdAt": "Created",
|
||||||
"paymentDetails": "Payment Details",
|
"paymentDetails": "Payment Details",
|
||||||
"noPaymentDetails": "No payment details provided",
|
"noPaymentDetails": "No payment details provided",
|
||||||
@@ -2101,7 +2104,8 @@
|
|||||||
"website": "Website",
|
"website": "Website",
|
||||||
"channel": "Channel",
|
"channel": "Channel",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
"expectedReferrals": "Expected referrals/mo"
|
"expectedReferrals": "Expected referrals/mo",
|
||||||
|
"desiredCommission": "Desired commission"
|
||||||
},
|
},
|
||||||
"approveDialog": {
|
"approveDialog": {
|
||||||
"title": "Approve Application",
|
"title": "Approve Application",
|
||||||
|
|||||||
@@ -594,7 +594,9 @@
|
|||||||
"description": "توضیحات",
|
"description": "توضیحات",
|
||||||
"descriptionPlaceholder": "درباره مخاطبان خود و نحوه تبلیغ بگویید...",
|
"descriptionPlaceholder": "درباره مخاطبان خود و نحوه تبلیغ بگویید...",
|
||||||
"expectedReferrals": "تعداد معرفی ماهانه مورد انتظار",
|
"expectedReferrals": "تعداد معرفی ماهانه مورد انتظار",
|
||||||
"expectedReferralsPlaceholder": "تعداد تخمینی در ماه"
|
"expectedReferralsPlaceholder": "تعداد تخمینی در ماه",
|
||||||
|
"desiredCommission": "درصد کمیسیون مورد نظر",
|
||||||
|
"desiredCommissionPlaceholder": "از ۱ تا ۱۰۰٪"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"withdrawal": {
|
"withdrawal": {
|
||||||
@@ -615,9 +617,9 @@
|
|||||||
"submitRequest": "ارسال درخواست",
|
"submitRequest": "ارسال درخواست",
|
||||||
"requestError": "ایجاد درخواست برداشت ناموفق بود. لطفاً دوباره تلاش کنید.",
|
"requestError": "ایجاد درخواست برداشت ناموفق بود. لطفاً دوباره تلاش کنید.",
|
||||||
"fields": {
|
"fields": {
|
||||||
"amount": "مبلغ (کوپک)",
|
"amount": "مبلغ",
|
||||||
"amountPlaceholder": "مبلغ را به کوپک وارد کنید",
|
"amountPlaceholder": "مبلغ را وارد کنید",
|
||||||
"amountHint": "مبلغ را به کوپک وارد کنید (۱۰۰ کوپک = ۱ {{currency}})",
|
"amountHint": "حداقل: {{min}} {{currency}}",
|
||||||
"paymentDetails": "اطلاعات پرداخت",
|
"paymentDetails": "اطلاعات پرداخت",
|
||||||
"paymentDetailsPlaceholder": "شماره کارت، آدرس کیف پول یا سایر اطلاعات پرداخت..."
|
"paymentDetailsPlaceholder": "شماره کارت، آدرس کیف پول یا سایر اطلاعات پرداخت..."
|
||||||
},
|
},
|
||||||
@@ -1729,6 +1731,7 @@
|
|||||||
"balance": "موجودی",
|
"balance": "موجودی",
|
||||||
"totalReferrals": "مجموع معرفیها",
|
"totalReferrals": "مجموع معرفیها",
|
||||||
"totalEarnings": "مجموع درآمد",
|
"totalEarnings": "مجموع درآمد",
|
||||||
|
"requestedAmount": "مبلغ درخواستی",
|
||||||
"createdAt": "تاریخ ایجاد",
|
"createdAt": "تاریخ ایجاد",
|
||||||
"paymentDetails": "اطلاعات پرداخت",
|
"paymentDetails": "اطلاعات پرداخت",
|
||||||
"noPaymentDetails": "اطلاعات پرداختی ارائه نشده",
|
"noPaymentDetails": "اطلاعات پرداختی ارائه نشده",
|
||||||
@@ -1784,7 +1787,8 @@
|
|||||||
"website": "وبسایت",
|
"website": "وبسایت",
|
||||||
"channel": "کانال",
|
"channel": "کانال",
|
||||||
"description": "توضیحات",
|
"description": "توضیحات",
|
||||||
"expectedReferrals": "معرفی مورد انتظار/ماه"
|
"expectedReferrals": "معرفی مورد انتظار/ماه",
|
||||||
|
"desiredCommission": "کمیسیون مورد نظر"
|
||||||
},
|
},
|
||||||
"approveDialog": {
|
"approveDialog": {
|
||||||
"title": "تأیید درخواست",
|
"title": "تأیید درخواست",
|
||||||
|
|||||||
@@ -783,7 +783,9 @@
|
|||||||
"description": "Описание",
|
"description": "Описание",
|
||||||
"descriptionPlaceholder": "Расскажите о вашей аудитории и планах продвижения...",
|
"descriptionPlaceholder": "Расскажите о вашей аудитории и планах продвижения...",
|
||||||
"expectedReferrals": "Ожидаемое количество рефералов в месяц",
|
"expectedReferrals": "Ожидаемое количество рефералов в месяц",
|
||||||
"expectedReferralsPlaceholder": "Примерное количество в месяц"
|
"expectedReferralsPlaceholder": "Примерное количество в месяц",
|
||||||
|
"desiredCommission": "Желаемый процент комиссии",
|
||||||
|
"desiredCommissionPlaceholder": "От 1 до 100%"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"withdrawal": {
|
"withdrawal": {
|
||||||
@@ -804,9 +806,9 @@
|
|||||||
"submitRequest": "Отправить запрос",
|
"submitRequest": "Отправить запрос",
|
||||||
"requestError": "Не удалось создать запрос на вывод. Попробуйте снова.",
|
"requestError": "Не удалось создать запрос на вывод. Попробуйте снова.",
|
||||||
"fields": {
|
"fields": {
|
||||||
"amount": "Сумма (копейки)",
|
"amount": "Сумма",
|
||||||
"amountPlaceholder": "Введите сумму в копейках",
|
"amountPlaceholder": "Введите сумму в {{currency}}",
|
||||||
"amountHint": "Введите сумму в копейках (100 копеек = 1 {{currency}})",
|
"amountHint": "Минимум: {{min}} {{currency}}",
|
||||||
"paymentDetails": "Реквизиты для оплаты",
|
"paymentDetails": "Реквизиты для оплаты",
|
||||||
"paymentDetailsPlaceholder": "Номер карты, адрес кошелька или другие реквизиты..."
|
"paymentDetailsPlaceholder": "Номер карты, адрес кошелька или другие реквизиты..."
|
||||||
},
|
},
|
||||||
@@ -2567,6 +2569,7 @@
|
|||||||
"balance": "Баланс",
|
"balance": "Баланс",
|
||||||
"totalReferrals": "Всего рефералов",
|
"totalReferrals": "Всего рефералов",
|
||||||
"totalEarnings": "Общий заработок",
|
"totalEarnings": "Общий заработок",
|
||||||
|
"requestedAmount": "Запрошенная сумма",
|
||||||
"createdAt": "Создано",
|
"createdAt": "Создано",
|
||||||
"paymentDetails": "Реквизиты для оплаты",
|
"paymentDetails": "Реквизиты для оплаты",
|
||||||
"noPaymentDetails": "Реквизиты не указаны",
|
"noPaymentDetails": "Реквизиты не указаны",
|
||||||
@@ -2622,7 +2625,8 @@
|
|||||||
"website": "Сайт",
|
"website": "Сайт",
|
||||||
"channel": "Канал",
|
"channel": "Канал",
|
||||||
"description": "Описание",
|
"description": "Описание",
|
||||||
"expectedReferrals": "Ожидаемых рефералов/мес"
|
"expectedReferrals": "Ожидаемых рефералов/мес",
|
||||||
|
"desiredCommission": "Желаемая комиссия"
|
||||||
},
|
},
|
||||||
"approveDialog": {
|
"approveDialog": {
|
||||||
"title": "Одобрить заявку",
|
"title": "Одобрить заявку",
|
||||||
|
|||||||
@@ -594,7 +594,9 @@
|
|||||||
"description": "描述",
|
"description": "描述",
|
||||||
"descriptionPlaceholder": "请介绍您的受众以及推广计划...",
|
"descriptionPlaceholder": "请介绍您的受众以及推广计划...",
|
||||||
"expectedReferrals": "预计每月推荐数",
|
"expectedReferrals": "预计每月推荐数",
|
||||||
"expectedReferralsPlaceholder": "每月预估数量"
|
"expectedReferralsPlaceholder": "每月预估数量",
|
||||||
|
"desiredCommission": "期望佣金比例 (%)",
|
||||||
|
"desiredCommissionPlaceholder": "1 到 100%"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"withdrawal": {
|
"withdrawal": {
|
||||||
@@ -615,9 +617,9 @@
|
|||||||
"submitRequest": "提交请求",
|
"submitRequest": "提交请求",
|
||||||
"requestError": "创建提现请求失败,请重试。",
|
"requestError": "创建提现请求失败,请重试。",
|
||||||
"fields": {
|
"fields": {
|
||||||
"amount": "金额(戈比)",
|
"amount": "金额",
|
||||||
"amountPlaceholder": "输入金额(戈比)",
|
"amountPlaceholder": "输入金额({{currency}})",
|
||||||
"amountHint": "请输入戈比金额(100戈比 = 1 {{currency}})",
|
"amountHint": "最低:{{min}} {{currency}}",
|
||||||
"paymentDetails": "付款信息",
|
"paymentDetails": "付款信息",
|
||||||
"paymentDetailsPlaceholder": "银行卡号、钱包地址或其他付款信息..."
|
"paymentDetailsPlaceholder": "银行卡号、钱包地址或其他付款信息..."
|
||||||
},
|
},
|
||||||
@@ -1728,6 +1730,7 @@
|
|||||||
"balance": "余额",
|
"balance": "余额",
|
||||||
"totalReferrals": "总推荐数",
|
"totalReferrals": "总推荐数",
|
||||||
"totalEarnings": "总收益",
|
"totalEarnings": "总收益",
|
||||||
|
"requestedAmount": "请求金额",
|
||||||
"createdAt": "创建时间",
|
"createdAt": "创建时间",
|
||||||
"paymentDetails": "付款信息",
|
"paymentDetails": "付款信息",
|
||||||
"noPaymentDetails": "未提供付款信息",
|
"noPaymentDetails": "未提供付款信息",
|
||||||
@@ -1783,7 +1786,8 @@
|
|||||||
"website": "网站",
|
"website": "网站",
|
||||||
"channel": "频道",
|
"channel": "频道",
|
||||||
"description": "描述",
|
"description": "描述",
|
||||||
"expectedReferrals": "预计每月推荐数"
|
"expectedReferrals": "预计每月推荐数",
|
||||||
|
"desiredCommission": "期望佣金"
|
||||||
},
|
},
|
||||||
"approveDialog": {
|
"approveDialog": {
|
||||||
"title": "批准申请",
|
"title": "批准申请",
|
||||||
|
|||||||
@@ -136,6 +136,14 @@ export default function AdminApplicationReview() {
|
|||||||
<span className="text-dark-200">{app.expected_monthly_referrals}</span>
|
<span className="text-dark-200">{app.expected_monthly_referrals}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{app.desired_commission_percent != null && (
|
||||||
|
<div className="rounded-lg bg-dark-700/50 p-3">
|
||||||
|
<span className="text-dark-500">
|
||||||
|
{t('admin.partners.applicationFields.desiredCommission')}:
|
||||||
|
</span>{' '}
|
||||||
|
<span className="text-dark-200">{app.desired_commission_percent}%</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -126,6 +126,14 @@ export default function AdminWithdrawalDetail() {
|
|||||||
<h3 className="mb-4 font-medium text-dark-200">
|
<h3 className="mb-4 font-medium text-dark-200">
|
||||||
{t('admin.withdrawals.detail.userInfo')}
|
{t('admin.withdrawals.detail.userInfo')}
|
||||||
</h3>
|
</h3>
|
||||||
|
<div className="mb-3 rounded-lg border border-accent-500/30 bg-accent-500/10 p-3">
|
||||||
|
<div className="mb-1 text-sm text-dark-400">
|
||||||
|
{t('admin.withdrawals.detail.requestedAmount')}
|
||||||
|
</div>
|
||||||
|
<div className="text-lg font-bold text-accent-400">
|
||||||
|
{formatWithCurrency(detail.amount_kopeks / 100, 0)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3">
|
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3">
|
||||||
<div className="rounded-lg bg-dark-700/50 p-3">
|
<div className="rounded-lg bg-dark-700/50 p-3">
|
||||||
<div className="mb-1 text-sm text-dark-400">
|
<div className="mb-1 text-sm text-dark-400">
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export default function ReferralPartnerApply() {
|
|||||||
telegram_channel: '',
|
telegram_channel: '',
|
||||||
description: '',
|
description: '',
|
||||||
expected_monthly_referrals: undefined,
|
expected_monthly_referrals: undefined,
|
||||||
|
desired_commission_percent: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Guard: redirect if already approved or pending
|
// Guard: redirect if already approved or pending
|
||||||
@@ -50,6 +51,9 @@ export default function ReferralPartnerApply() {
|
|||||||
if (form.expected_monthly_referrals) {
|
if (form.expected_monthly_referrals) {
|
||||||
payload.expected_monthly_referrals = form.expected_monthly_referrals;
|
payload.expected_monthly_referrals = form.expected_monthly_referrals;
|
||||||
}
|
}
|
||||||
|
if (form.desired_commission_percent) {
|
||||||
|
payload.desired_commission_percent = form.desired_commission_percent;
|
||||||
|
}
|
||||||
applyMutation.mutate(payload);
|
applyMutation.mutate(payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -126,6 +130,25 @@ export default function ReferralPartnerApply() {
|
|||||||
placeholder={t('referral.partner.fields.expectedReferralsPlaceholder')}
|
placeholder={t('referral.partner.fields.expectedReferralsPlaceholder')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="mb-1 block text-sm font-medium text-dark-300">
|
||||||
|
{t('referral.partner.fields.desiredCommission')}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min={1}
|
||||||
|
max={100}
|
||||||
|
className="input w-full"
|
||||||
|
value={form.desired_commission_percent ?? ''}
|
||||||
|
onChange={(e) =>
|
||||||
|
setForm({
|
||||||
|
...form,
|
||||||
|
desired_commission_percent: e.target.value ? Number(e.target.value) : undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
placeholder={t('referral.partner.fields.desiredCommissionPlaceholder')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{applyMutation.isError && (
|
{applyMutation.isError && (
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default function ReferralWithdrawalRequest() {
|
|||||||
const { formatWithCurrency, currencySymbol } = useCurrency();
|
const { formatWithCurrency, currencySymbol } = useCurrency();
|
||||||
|
|
||||||
const [form, setForm] = useState({
|
const [form, setForm] = useState({
|
||||||
amount_kopeks: 0,
|
amount_rubles: 0,
|
||||||
payment_details: '',
|
payment_details: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -40,9 +40,9 @@ export default function ReferralWithdrawalRequest() {
|
|||||||
const handleSubmit = (e: FormEvent) => {
|
const handleSubmit = (e: FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (form.payment_details.length < 5) return;
|
if (form.payment_details.length < 5) return;
|
||||||
if (form.amount_kopeks <= 0) return;
|
if (form.amount_rubles <= 0) return;
|
||||||
withdrawMutation.mutate({
|
withdrawMutation.mutate({
|
||||||
amount_kopeks: form.amount_kopeks,
|
amount_kopeks: form.amount_rubles * 100,
|
||||||
payment_details: form.payment_details,
|
payment_details: form.payment_details,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -64,21 +64,25 @@ export default function ReferralWithdrawalRequest() {
|
|||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
min={balance?.min_amount_kopeks ?? 0}
|
min={balance ? Math.ceil(balance.min_amount_kopeks / 100) : 0}
|
||||||
max={balance?.available_total ?? 0}
|
max={balance ? Math.floor(balance.available_total / 100) : 0}
|
||||||
step={100}
|
|
||||||
className="input w-full"
|
className="input w-full"
|
||||||
value={form.amount_kopeks || ''}
|
value={form.amount_rubles || ''}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setForm({
|
setForm({
|
||||||
...form,
|
...form,
|
||||||
amount_kopeks: e.target.value ? Number(e.target.value) : 0,
|
amount_rubles: e.target.value ? Number(e.target.value) : 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
placeholder={t('referral.withdrawal.fields.amountPlaceholder')}
|
placeholder={t('referral.withdrawal.fields.amountPlaceholder', {
|
||||||
|
currency: currencySymbol,
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
<p className="mt-1 text-xs text-dark-500">
|
<p className="mt-1 text-xs text-dark-500">
|
||||||
{t('referral.withdrawal.fields.amountHint', { currency: currencySymbol })}
|
{t('referral.withdrawal.fields.amountHint', {
|
||||||
|
min: balance ? Math.ceil(balance.min_amount_kopeks / 100) : 0,
|
||||||
|
currency: currencySymbol,
|
||||||
|
})}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -115,12 +119,12 @@ export default function ReferralWithdrawalRequest() {
|
|||||||
disabled={
|
disabled={
|
||||||
withdrawMutation.isPending ||
|
withdrawMutation.isPending ||
|
||||||
form.payment_details.length < 5 ||
|
form.payment_details.length < 5 ||
|
||||||
form.amount_kopeks <= 0
|
form.amount_rubles <= 0
|
||||||
}
|
}
|
||||||
className={`btn-primary flex-1 px-5 ${
|
className={`btn-primary flex-1 px-5 ${
|
||||||
withdrawMutation.isPending ||
|
withdrawMutation.isPending ||
|
||||||
form.payment_details.length < 5 ||
|
form.payment_details.length < 5 ||
|
||||||
form.amount_kopeks <= 0
|
form.amount_rubles <= 0
|
||||||
? 'opacity-50'
|
? 'opacity-50'
|
||||||
: ''
|
: ''
|
||||||
}`}
|
}`}
|
||||||
|
|||||||
Reference in New Issue
Block a user