mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
fix: normalize all API responses, add error handling and reset confirmation
- Extract normalizeConfig() for consistent response normalization - Add onError handlers to mutations with useNotify - Add window.confirm before destructive reset action - Add resetConfirm translation key to all locales
This commit is contained in:
@@ -33,6 +33,7 @@ export const BUTTON_SECTIONS = [
|
|||||||
|
|
||||||
export type ButtonSection = (typeof BUTTON_SECTIONS)[number];
|
export type ButtonSection = (typeof BUTTON_SECTIONS)[number];
|
||||||
|
|
||||||
|
// Bot-side locales (includes 'ua' for Ukrainian, mapped from ISO 'uk' internally).
|
||||||
export const BOT_LOCALES = ['ru', 'en', 'ua', 'zh', 'fa'] as const;
|
export const BOT_LOCALES = ['ru', 'en', 'ua', 'zh', 'fa'] as const;
|
||||||
|
|
||||||
export type BotLocale = (typeof BOT_LOCALES)[number];
|
export type BotLocale = (typeof BOT_LOCALES)[number];
|
||||||
@@ -54,19 +55,23 @@ export const DEFAULT_BUTTON_STYLES: ButtonStylesConfig = {
|
|||||||
admin: { ...DEFAULT_SECTION, style: 'danger' },
|
admin: { ...DEFAULT_SECTION, style: 'danger' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function normalizeConfig(data: ButtonStylesConfig): ButtonStylesConfig {
|
||||||
|
const result = {} as ButtonStylesConfig;
|
||||||
|
for (const section of BUTTON_SECTIONS) {
|
||||||
|
result[section] = {
|
||||||
|
...DEFAULT_SECTION,
|
||||||
|
...data[section],
|
||||||
|
labels: { ...(data[section]?.labels || {}) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
export const buttonStylesApi = {
|
export const buttonStylesApi = {
|
||||||
getStyles: async (): Promise<ButtonStylesConfig> => {
|
getStyles: async (): Promise<ButtonStylesConfig> => {
|
||||||
try {
|
try {
|
||||||
const response = await apiClient.get<ButtonStylesConfig>('/cabinet/admin/button-styles');
|
const response = await apiClient.get<ButtonStylesConfig>('/cabinet/admin/button-styles');
|
||||||
const data = response.data;
|
return normalizeConfig(response.data);
|
||||||
for (const section of BUTTON_SECTIONS) {
|
|
||||||
data[section] = {
|
|
||||||
...DEFAULT_SECTION,
|
|
||||||
...data[section],
|
|
||||||
labels: { ...(data[section]?.labels || {}) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
} catch {
|
} catch {
|
||||||
return DEFAULT_BUTTON_STYLES;
|
return DEFAULT_BUTTON_STYLES;
|
||||||
}
|
}
|
||||||
@@ -77,11 +82,11 @@ export const buttonStylesApi = {
|
|||||||
'/cabinet/admin/button-styles',
|
'/cabinet/admin/button-styles',
|
||||||
update,
|
update,
|
||||||
);
|
);
|
||||||
return response.data;
|
return normalizeConfig(response.data);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetStyles: async (): Promise<ButtonStylesConfig> => {
|
resetStyles: async (): Promise<ButtonStylesConfig> => {
|
||||||
const response = await apiClient.post<ButtonStylesConfig>('/cabinet/admin/button-styles/reset');
|
const response = await apiClient.post<ButtonStylesConfig>('/cabinet/admin/button-styles/reset');
|
||||||
return response.data;
|
return normalizeConfig(response.data);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
BOT_LOCALES,
|
BOT_LOCALES,
|
||||||
} from '../../api/buttonStyles';
|
} from '../../api/buttonStyles';
|
||||||
import { Toggle } from './Toggle';
|
import { Toggle } from './Toggle';
|
||||||
|
import { useNotify } from '../../platform/hooks/useNotify';
|
||||||
|
|
||||||
type StyleValue = 'primary' | 'success' | 'danger' | 'default';
|
type StyleValue = 'primary' | 'success' | 'danger' | 'default';
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ function stylesEqual(a: ButtonStylesConfig, b: ButtonStylesConfig): boolean {
|
|||||||
export function ButtonsTab() {
|
export function ButtonsTab() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
const notify = useNotify();
|
||||||
|
|
||||||
const { data: serverStyles } = useQuery({
|
const { data: serverStyles } = useQuery({
|
||||||
queryKey: ['button-styles'],
|
queryKey: ['button-styles'],
|
||||||
@@ -73,6 +75,9 @@ export function ButtonsTab() {
|
|||||||
setDraftStyles(data);
|
setDraftStyles(data);
|
||||||
queryClient.setQueryData(['button-styles'], data);
|
queryClient.setQueryData(['button-styles'], data);
|
||||||
},
|
},
|
||||||
|
onError: () => {
|
||||||
|
notify.error(t('common.error'));
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const resetMutation = useMutation({
|
const resetMutation = useMutation({
|
||||||
@@ -82,6 +87,9 @@ export function ButtonsTab() {
|
|||||||
setDraftStyles(data);
|
setDraftStyles(data);
|
||||||
queryClient.setQueryData(['button-styles'], data);
|
queryClient.setQueryData(['button-styles'], data);
|
||||||
},
|
},
|
||||||
|
onError: () => {
|
||||||
|
notify.error(t('common.error'));
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateSection = useCallback(
|
const updateSection = useCallback(
|
||||||
@@ -333,7 +341,11 @@ export function ButtonsTab() {
|
|||||||
{/* Reset */}
|
{/* Reset */}
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<button
|
<button
|
||||||
onClick={() => resetMutation.mutate()}
|
onClick={() => {
|
||||||
|
if (window.confirm(t('admin.buttons.resetConfirm'))) {
|
||||||
|
resetMutation.mutate();
|
||||||
|
}
|
||||||
|
}}
|
||||||
disabled={resetMutation.isPending}
|
disabled={resetMutation.isPending}
|
||||||
className="rounded-xl bg-dark-700 px-4 py-2 text-sm text-dark-300 transition-colors hover:bg-dark-600 disabled:opacity-50"
|
className="rounded-xl bg-dark-700 px-4 py-2 text-sm text-dark-300 transition-colors hover:bg-dark-600 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1292,6 +1292,7 @@
|
|||||||
"emojiId": "Custom Emoji ID",
|
"emojiId": "Custom Emoji ID",
|
||||||
"emojiPlaceholder": "Custom emoji ID (optional)",
|
"emojiPlaceholder": "Custom emoji ID (optional)",
|
||||||
"resetAll": "Reset all styles",
|
"resetAll": "Reset all styles",
|
||||||
|
"resetConfirm": "Reset all button styles to defaults?",
|
||||||
"hidden": "Hidden",
|
"hidden": "Hidden",
|
||||||
"customLabels": "Button labels",
|
"customLabels": "Button labels",
|
||||||
"labelPlaceholder": "Custom button text",
|
"labelPlaceholder": "Custom button text",
|
||||||
|
|||||||
@@ -1001,6 +1001,7 @@
|
|||||||
"emojiId": "شناسه ایموجی سفارشی",
|
"emojiId": "شناسه ایموجی سفارشی",
|
||||||
"emojiPlaceholder": "شناسه ایموجی سفارشی (اختیاری)",
|
"emojiPlaceholder": "شناسه ایموجی سفارشی (اختیاری)",
|
||||||
"resetAll": "بازنشانی همه سبکها",
|
"resetAll": "بازنشانی همه سبکها",
|
||||||
|
"resetConfirm": "همه سبکهای دکمه به حالت پیشفرض بازنشانی شوند؟",
|
||||||
"hidden": "پنهان",
|
"hidden": "پنهان",
|
||||||
"customLabels": "نامهای دکمه",
|
"customLabels": "نامهای دکمه",
|
||||||
"labelPlaceholder": "متن سفارشی دکمه",
|
"labelPlaceholder": "متن سفارشی دکمه",
|
||||||
|
|||||||
@@ -1807,6 +1807,7 @@
|
|||||||
"emojiId": "Custom Emoji ID",
|
"emojiId": "Custom Emoji ID",
|
||||||
"emojiPlaceholder": "ID кастомного эмодзи (необязательно)",
|
"emojiPlaceholder": "ID кастомного эмодзи (необязательно)",
|
||||||
"resetAll": "Сбросить все стили",
|
"resetAll": "Сбросить все стили",
|
||||||
|
"resetConfirm": "Сбросить все стили кнопок к значениям по умолчанию?",
|
||||||
"hidden": "Скрыта",
|
"hidden": "Скрыта",
|
||||||
"customLabels": "Названия кнопки",
|
"customLabels": "Названия кнопки",
|
||||||
"labelPlaceholder": "Свой текст кнопки",
|
"labelPlaceholder": "Свой текст кнопки",
|
||||||
|
|||||||
@@ -1039,6 +1039,7 @@
|
|||||||
"emojiId": "自定义表情 ID",
|
"emojiId": "自定义表情 ID",
|
||||||
"emojiPlaceholder": "自定义表情 ID(可选)",
|
"emojiPlaceholder": "自定义表情 ID(可选)",
|
||||||
"resetAll": "重置所有样式",
|
"resetAll": "重置所有样式",
|
||||||
|
"resetConfirm": "将所有按钮样式重置为默认值?",
|
||||||
"hidden": "已隐藏",
|
"hidden": "已隐藏",
|
||||||
"customLabels": "按钮名称",
|
"customLabels": "按钮名称",
|
||||||
"labelPlaceholder": "自定义按钮文本",
|
"labelPlaceholder": "自定义按钮文本",
|
||||||
|
|||||||
Reference in New Issue
Block a user