mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 10:27:49 +00:00
feat: add Stars payment confirmation and admin validation
- Show confirmation dialog before redirecting to Telegram for Stars payment (native popup in Mini App, confirm in browser) - Warn admin when saving wheel config with Stars enabled but Telegram Stars payment method is disabled globally - Add translation keys: confirmStarsTitle, confirmStarsPayment, starsNotEnabledGlobally (ru, en, zh, fa)
This commit is contained in:
@@ -714,6 +714,8 @@
|
|||||||
"starsPaymentFailed": "Payment failed. Please try again.",
|
"starsPaymentFailed": "Payment failed. Please try again.",
|
||||||
"starsPaymentRedirected": "Telegram will open for payment. Refresh the page after payment.",
|
"starsPaymentRedirected": "Telegram will open for payment. Refresh the page after payment.",
|
||||||
"starsNotAvailable": "Star payments are currently unavailable. Contact support.",
|
"starsNotAvailable": "Star payments are currently unavailable. Contact support.",
|
||||||
|
"confirmStarsTitle": "Star payment",
|
||||||
|
"confirmStarsPayment": "You will be redirected to Telegram to pay for one wheel spin. Continue?",
|
||||||
"youWon": "You won",
|
"youWon": "You won",
|
||||||
"noPrize": "No luck this time...",
|
"noPrize": "No luck this time...",
|
||||||
"noHistory": "No spin history yet",
|
"noHistory": "No spin history yet",
|
||||||
@@ -978,6 +980,7 @@
|
|||||||
"promocodes": "Promocodes",
|
"promocodes": "Promocodes",
|
||||||
"promoPrefix": "Promo code prefix"
|
"promoPrefix": "Promo code prefix"
|
||||||
},
|
},
|
||||||
|
"starsNotEnabledGlobally": "Star payments are not enabled in Payment Methods. Enable \"Telegram Stars\" in the Payment Methods section.",
|
||||||
"prizes": {
|
"prizes": {
|
||||||
"addPrize": "Add Prize",
|
"addPrize": "Add Prize",
|
||||||
"editPrize": "Edit Prize",
|
"editPrize": "Edit Prize",
|
||||||
|
|||||||
@@ -600,6 +600,8 @@
|
|||||||
"starsPaymentFailed": "پرداخت ناموفق. دوباره تلاش کنید.",
|
"starsPaymentFailed": "پرداخت ناموفق. دوباره تلاش کنید.",
|
||||||
"starsPaymentRedirected": "تلگرام برای پرداخت باز میشود. پس از پرداخت صفحه را بازخوانی کنید.",
|
"starsPaymentRedirected": "تلگرام برای پرداخت باز میشود. پس از پرداخت صفحه را بازخوانی کنید.",
|
||||||
"starsNotAvailable": "پرداخت با ستاره در حال حاضر در دسترس نیست. با پشتیبانی تماس بگیرید.",
|
"starsNotAvailable": "پرداخت با ستاره در حال حاضر در دسترس نیست. با پشتیبانی تماس بگیرید.",
|
||||||
|
"confirmStarsTitle": "پرداخت با ستاره",
|
||||||
|
"confirmStarsPayment": "شما به تلگرام برای پرداخت یک چرخش منتقل خواهید شد. ادامه میدهید؟",
|
||||||
"noHistory": "هنوز تاریخچهای نیست",
|
"noHistory": "هنوز تاریخچهای نیست",
|
||||||
"banner": {
|
"banner": {
|
||||||
"title": "شانس خود را امتحان کنید!",
|
"title": "شانس خود را امتحان کنید!",
|
||||||
@@ -700,6 +702,7 @@
|
|||||||
"limitsAndRtp": "محدودیتها و RTP",
|
"limitsAndRtp": "محدودیتها و RTP",
|
||||||
"promocodes": "کدهای تخفیف"
|
"promocodes": "کدهای تخفیف"
|
||||||
},
|
},
|
||||||
|
"starsNotEnabledGlobally": "پرداخت با ستاره در روشهای پرداخت فعال نیست. «Telegram Stars» را در بخش «روشهای پرداخت» فعال کنید.",
|
||||||
"prizes": {
|
"prizes": {
|
||||||
"addPrize": "افزودن جایزه",
|
"addPrize": "افزودن جایزه",
|
||||||
"editPrize": "ویرایش جایزه",
|
"editPrize": "ویرایش جایزه",
|
||||||
|
|||||||
@@ -742,6 +742,8 @@
|
|||||||
"starsPaymentFailed": "Ошибка оплаты. Попробуйте еще раз.",
|
"starsPaymentFailed": "Ошибка оплаты. Попробуйте еще раз.",
|
||||||
"starsPaymentRedirected": "Откроется Telegram для оплаты. После оплаты обновите страницу.",
|
"starsPaymentRedirected": "Откроется Telegram для оплаты. После оплаты обновите страницу.",
|
||||||
"starsNotAvailable": "Оплата звёздами сейчас недоступна. Обратитесь в поддержку.",
|
"starsNotAvailable": "Оплата звёздами сейчас недоступна. Обратитесь в поддержку.",
|
||||||
|
"confirmStarsTitle": "Оплата звёздами",
|
||||||
|
"confirmStarsPayment": "Вы будете перенаправлены в Telegram для оплаты одного вращения колеса. Продолжить?",
|
||||||
"youWon": "Вы выиграли",
|
"youWon": "Вы выиграли",
|
||||||
"noPrize": "В этот раз не повезло...",
|
"noPrize": "В этот раз не повезло...",
|
||||||
"noHistory": "История вращений пуста",
|
"noHistory": "История вращений пуста",
|
||||||
@@ -1002,6 +1004,7 @@
|
|||||||
"promocodes": "Промокоды",
|
"promocodes": "Промокоды",
|
||||||
"promoPrefix": "Префикс промокодов"
|
"promoPrefix": "Префикс промокодов"
|
||||||
},
|
},
|
||||||
|
"starsNotEnabledGlobally": "Оплата звёздами не включена в платёжных методах. Включите метод «Telegram Stars» в разделе «Платёжные методы».",
|
||||||
"prizes": {
|
"prizes": {
|
||||||
"addPrize": "Добавить приз",
|
"addPrize": "Добавить приз",
|
||||||
"editPrize": "Редактировать приз",
|
"editPrize": "Редактировать приз",
|
||||||
|
|||||||
@@ -604,6 +604,8 @@
|
|||||||
"starsPaymentFailed": "支付失败。请重试。",
|
"starsPaymentFailed": "支付失败。请重试。",
|
||||||
"starsPaymentRedirected": "将打开Telegram进行支付。支付后请刷新页面。",
|
"starsPaymentRedirected": "将打开Telegram进行支付。支付后请刷新页面。",
|
||||||
"starsNotAvailable": "星星支付暂不可用。请联系客服。",
|
"starsNotAvailable": "星星支付暂不可用。请联系客服。",
|
||||||
|
"confirmStarsTitle": "星星支付",
|
||||||
|
"confirmStarsPayment": "您将被重定向到Telegram进行一次转盘支付。继续吗?",
|
||||||
"noHistory": "暂无抽奖记录",
|
"noHistory": "暂无抽奖记录",
|
||||||
"banner": {
|
"banner": {
|
||||||
"title": "试试运气!",
|
"title": "试试运气!",
|
||||||
@@ -752,6 +754,7 @@
|
|||||||
"limitsAndRtp": "限制和RTP",
|
"limitsAndRtp": "限制和RTP",
|
||||||
"promocodes": "促销码"
|
"promocodes": "促销码"
|
||||||
},
|
},
|
||||||
|
"starsNotEnabledGlobally": "星星支付未在支付方式中启用。请在「支付方式」中启用「Telegram Stars」。",
|
||||||
"prizes": {
|
"prizes": {
|
||||||
"addPrize": "添加奖品",
|
"addPrize": "添加奖品",
|
||||||
"editPrize": "编辑奖品",
|
"editPrize": "编辑奖品",
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ import {
|
|||||||
} from '@dnd-kit/sortable';
|
} from '@dnd-kit/sortable';
|
||||||
import { CSS } from '@dnd-kit/utilities';
|
import { CSS } from '@dnd-kit/utilities';
|
||||||
import { adminWheelApi, type WheelPrizeAdmin, type CreateWheelPrizeData } from '../api/wheel';
|
import { adminWheelApi, type WheelPrizeAdmin, type CreateWheelPrizeData } from '../api/wheel';
|
||||||
|
import { adminPaymentMethodsApi } from '../api/adminPaymentMethods';
|
||||||
import { useDestructiveConfirm } from '@/platform';
|
import { useDestructiveConfirm } from '@/platform';
|
||||||
|
import { useNotify } from '@/platform/hooks/useNotify';
|
||||||
import FortuneWheel from '../components/wheel/FortuneWheel';
|
import FortuneWheel from '../components/wheel/FortuneWheel';
|
||||||
import { ColorPicker } from '@/components/ColorPicker';
|
import { ColorPicker } from '@/components/ColorPicker';
|
||||||
import { useBackButton } from '../platform/hooks/useBackButton';
|
import { useBackButton } from '../platform/hooks/useBackButton';
|
||||||
@@ -291,6 +293,7 @@ export default function AdminWheel() {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const confirmDelete = useDestructiveConfirm();
|
const confirmDelete = useDestructiveConfirm();
|
||||||
const { capabilities } = usePlatform();
|
const { capabilities } = usePlatform();
|
||||||
|
const notify = useNotify();
|
||||||
|
|
||||||
// Use native Telegram back button in Mini App
|
// Use native Telegram back button in Mini App
|
||||||
useBackButton(() => navigate('/admin'));
|
useBackButton(() => navigate('/admin'));
|
||||||
@@ -794,10 +797,21 @@ export default function AdminWheel() {
|
|||||||
{hasSettingsChanges && (
|
{hasSettingsChanges && (
|
||||||
<div className="flex justify-end border-t border-dark-700 pt-6">
|
<div className="flex justify-end border-t border-dark-700 pt-6">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
if (settingsForm) {
|
if (!settingsForm) return;
|
||||||
updateConfigMutation.mutate(settingsForm);
|
if (settingsForm.spin_cost_stars_enabled) {
|
||||||
|
try {
|
||||||
|
const methods = await adminPaymentMethodsApi.getAll();
|
||||||
|
const starsMethod = methods.find((m) => m.method_id === 'telegram_stars');
|
||||||
|
if (!starsMethod?.is_enabled) {
|
||||||
|
notify.warning(t('admin.wheel.starsNotEnabledGlobally'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// If we can't check, allow saving
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
updateConfigMutation.mutate(settingsForm);
|
||||||
}}
|
}}
|
||||||
disabled={updateConfigMutation.isPending}
|
disabled={updateConfigMutation.isPending}
|
||||||
className="btn-primary flex items-center gap-2"
|
className="btn-primary flex items-center gap-2"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import WheelLegend from '../components/wheel/WheelLegend';
|
|||||||
import InsufficientBalancePrompt from '../components/InsufficientBalancePrompt';
|
import InsufficientBalancePrompt from '../components/InsufficientBalancePrompt';
|
||||||
import { usePlatform, useHaptic } from '@/platform';
|
import { usePlatform, useHaptic } from '@/platform';
|
||||||
import { useNotify } from '@/platform/hooks/useNotify';
|
import { useNotify } from '@/platform/hooks/useNotify';
|
||||||
|
import { useNativeDialog } from '@/platform/hooks/useNativeDialog';
|
||||||
import { Card } from '@/components/data-display/Card/Card';
|
import { Card } from '@/components/data-display/Card/Card';
|
||||||
import { Button } from '@/components/primitives/Button/Button';
|
import { Button } from '@/components/primitives/Button/Button';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
@@ -63,6 +64,7 @@ export default function Wheel() {
|
|||||||
const { openInvoice, capabilities } = usePlatform();
|
const { openInvoice, capabilities } = usePlatform();
|
||||||
const haptic = useHaptic();
|
const haptic = useHaptic();
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
|
const dialog = useNativeDialog();
|
||||||
|
|
||||||
const [isSpinning, setIsSpinning] = useState(false);
|
const [isSpinning, setIsSpinning] = useState(false);
|
||||||
const [targetRotation, setTargetRotation] = useState<number | null>(null);
|
const [targetRotation, setTargetRotation] = useState<number | null>(null);
|
||||||
@@ -306,7 +308,12 @@ export default function Wheel() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleDirectStarsPay = () => {
|
const handleDirectStarsPay = async () => {
|
||||||
|
const confirmed = await dialog.confirm(
|
||||||
|
t('wheel.confirmStarsPayment'),
|
||||||
|
t('wheel.confirmStarsTitle'),
|
||||||
|
);
|
||||||
|
if (!confirmed) return;
|
||||||
setIsPayingStars(true);
|
setIsPayingStars(true);
|
||||||
starsInvoiceMutation.mutate();
|
starsInvoiceMutation.mutate();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user