diff --git a/src/locales/en.json b/src/locales/en.json index f9f88b4..1b61b52 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1218,6 +1218,7 @@ "cannotDeleteHasSubscriptions": "Cannot delete: has active subscriptions", "confirmDelete": "Delete tariff?", "confirmDeleteText": "This action cannot be undone. The tariff will be permanently deleted.", + "deleteSuccess": "Tariff deleted successfully", "days": "days", "days_one": "{{count}} day", "days_other": "{{count}} days", diff --git a/src/locales/fa.json b/src/locales/fa.json index 5c89b73..6a0c26a 100644 --- a/src/locales/fa.json +++ b/src/locales/fa.json @@ -992,6 +992,7 @@ "cannotDeleteHasSubscriptions": "حذف ممکن نیست: اشتراک‌های فعال وجود دارد", "confirmDelete": "تعرفه حذف شود؟", "confirmDeleteText": "این عمل قابل بازگشت نیست. تعرفه برای همیشه حذف می‌شود.", + "deleteSuccess": "تعرفه با موفقیت حذف شد", "days": "روز", "days_other": "{{count}} روز", "tabs": { diff --git a/src/locales/ru.json b/src/locales/ru.json index 87eb108..181cca0 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1728,6 +1728,7 @@ "cannotDeleteHasSubscriptions": "Нельзя удалить: есть активные подписки", "confirmDelete": "Удалить тариф?", "confirmDeleteText": "Это действие нельзя отменить. Тариф будет удален навсегда.", + "deleteSuccess": "Тариф успешно удален", "days": "дней", "days_one": "{{count}} день", "days_few": "{{count}} дня", diff --git a/src/locales/zh.json b/src/locales/zh.json index e81ac0e..061f456 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -1030,6 +1030,7 @@ "cannotDeleteHasSubscriptions": "无法删除:有活跃订阅", "confirmDelete": "删除套餐?", "confirmDeleteText": "此操作不可撤销。套餐将被永久删除。", + "deleteSuccess": "套餐删除成功", "days": "天", "days_other": "{{count}} 天", "tabs": { diff --git a/src/pages/AdminEmailTemplates.tsx b/src/pages/AdminEmailTemplates.tsx index 8c81147..d78a611 100644 --- a/src/pages/AdminEmailTemplates.tsx +++ b/src/pages/AdminEmailTemplates.tsx @@ -9,7 +9,8 @@ import { EmailTemplateLanguageData, } from '../api/adminEmailTemplates'; import { AdminBackButton, BackIcon } from '../components/admin'; -import { useIsTelegram, usePlatform } from '../platform/hooks/usePlatform'; +import { useIsTelegram } from '../platform/hooks/usePlatform'; +import { useNotify } from '@/platform'; // Hook to check if on mobile function useIsMobile() { @@ -159,7 +160,7 @@ function TemplateEditor({ const { t } = useTranslation(); const navigate = useNavigate(); const queryClient = useQueryClient(); - const { dialog } = usePlatform(); + const notify = useNotify(); const isTelegram = useIsTelegram(); const isMobile = useIsMobile(); const isPreviewDisabled = isTelegram || isMobile; @@ -401,7 +402,7 @@ function TemplateEditor({ @@ -225,36 +233,6 @@ export default function AdminTariffs() { ))} )} - - {/* Delete Confirmation */} - {deleteConfirm !== null && ( -
-
setDeleteConfirm(null)} - /> -
-

- {t('admin.tariffs.confirmDelete')} -

-

{t('admin.tariffs.confirmDeleteText')}

-
- - -
-
-
- )}
); } diff --git a/src/platform/hooks/useNotify.ts b/src/platform/hooks/useNotify.ts new file mode 100644 index 0000000..46cd323 --- /dev/null +++ b/src/platform/hooks/useNotify.ts @@ -0,0 +1,92 @@ +import { useCallback } from 'react'; +import { usePlatform } from '@/platform/hooks/usePlatform'; +import { useToast } from '@/components/Toast'; + +type NotifyType = 'success' | 'error' | 'warning' | 'info'; + +interface NotifyOptions { + type?: NotifyType; + title?: string; + message: string; + duration?: number; +} + +/** + * Universal notification hook. + * - In Telegram Mini App: uses native showPopup + * - In browser: uses Toast component + * + * @example + * ```tsx + * const notify = useNotify(); + * + * // Warning notification + * notify.warning('Cannot delete: has active subscriptions'); + * + * // Success notification + * notify.success('Tariff created successfully'); + * + * // With title + * notify({ type: 'error', title: 'Error', message: 'Something went wrong' }); + * ``` + */ +export function useNotify() { + const { dialog, capabilities } = usePlatform(); + const { showToast } = useToast(); + + const notify = useCallback( + (options: NotifyOptions | string) => { + const opts: NotifyOptions = typeof options === 'string' ? { message: options } : options; + + const { type = 'info', title, message, duration } = opts; + + // In Telegram - use native popup for important messages + if (capabilities.hasNativeDialogs) { + dialog.popup({ + title: title, + message: message, + buttons: [{ id: 'ok', type: 'ok', text: 'OK' }], + }); + return; + } + + // In browser - use Toast + showToast({ + type, + title, + message, + duration: duration ?? (type === 'error' ? 7000 : 5000), + }); + }, + [capabilities.hasNativeDialogs, dialog, showToast], + ); + + // Shorthand methods + const success = useCallback( + (message: string, title?: string) => notify({ type: 'success', message, title }), + [notify], + ); + + const error = useCallback( + (message: string, title?: string) => notify({ type: 'error', message, title }), + [notify], + ); + + const warning = useCallback( + (message: string, title?: string) => notify({ type: 'warning', message, title }), + [notify], + ); + + const info = useCallback( + (message: string, title?: string) => notify({ type: 'info', message, title }), + [notify], + ); + + return { + notify, + success, + error, + warning, + info, + }; +} diff --git a/src/platform/index.ts b/src/platform/index.ts index 2001002..ff5d869 100644 --- a/src/platform/index.ts +++ b/src/platform/index.ts @@ -31,3 +31,4 @@ export { useBackButton, useConditionalBackButton } from './hooks/useBackButton'; export { useMainButton, useSimpleMainButton } from './hooks/useMainButton'; export { useHaptic, useHapticClick, useHapticFeedback } from './hooks/useHaptic'; export { useNativeDialog, useDestructiveConfirm, PopupButtons } from './hooks/useNativeDialog'; +export { useNotify } from './hooks/useNotify';