Files
cc-switch/src/lib/query/mutations.ts

190 lines
5.2 KiB
TypeScript

import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import { providersApi, settingsApi, type AppId } from "@/lib/api";
import type { Provider, Settings } from "@/types";
import { extractErrorMessage } from "@/utils/errorUtils";
export const useAddProviderMutation = (appId: AppId) => {
const queryClient = useQueryClient();
const { t } = useTranslation();
return useMutation({
mutationFn: async (providerInput: Omit<Provider, "id">) => {
const newProvider: Provider = {
...providerInput,
id: crypto.randomUUID(),
createdAt: Date.now(),
};
await providersApi.add(newProvider, appId);
return newProvider;
},
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
// 更新托盘菜单(失败不影响主操作)
try {
await providersApi.updateTrayMenu();
} catch (trayError) {
console.error(
"Failed to update tray menu after adding provider",
trayError,
);
}
toast.success(
t("notifications.providerAdded", {
defaultValue: "供应商已添加",
}), {
closeButton: true
}
);
},
onError: (error: Error) => {
toast.error(
t("notifications.addFailed", {
defaultValue: "添加供应商失败: {{error}}",
error: error.message,
}),
);
},
});
};
export const useUpdateProviderMutation = (appId: AppId) => {
const queryClient = useQueryClient();
const { t } = useTranslation();
return useMutation({
mutationFn: async (provider: Provider) => {
await providersApi.update(provider, appId);
return provider;
},
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
toast.success(
t("notifications.updateSuccess", {
defaultValue: "供应商更新成功",
}), {
closeButton: true
}
);
},
onError: (error: Error) => {
toast.error(
t("notifications.updateFailed", {
defaultValue: "更新供应商失败: {{error}}",
error: error.message,
}),
);
},
});
};
export const useDeleteProviderMutation = (appId: AppId) => {
const queryClient = useQueryClient();
const { t } = useTranslation();
return useMutation({
mutationFn: async (providerId: string) => {
await providersApi.delete(providerId, appId);
},
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
// 更新托盘菜单(失败不影响主操作)
try {
await providersApi.updateTrayMenu();
} catch (trayError) {
console.error(
"Failed to update tray menu after deleting provider",
trayError,
);
}
toast.success(
t("notifications.deleteSuccess", {
defaultValue: "供应商已删除",
}), {
closeButton: true
}
);
},
onError: (error: Error) => {
toast.error(
t("notifications.deleteFailed", {
defaultValue: "删除供应商失败: {{error}}",
error: error.message,
}),
);
},
});
};
export const useSwitchProviderMutation = (appId: AppId) => {
const queryClient = useQueryClient();
const { t } = useTranslation();
return useMutation({
mutationFn: async (providerId: string) => {
return await providersApi.switch(providerId, appId);
},
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
// 更新托盘菜单(失败不影响主操作)
try {
await providersApi.updateTrayMenu();
} catch (trayError) {
console.error(
"Failed to update tray menu after switching provider",
trayError,
);
}
toast.success(
t("notifications.switchSuccess", {
defaultValue: "切换供应商成功",
appName: t(`apps.${appId}`, { defaultValue: appId }),
}), {
closeButton: true
}
);
},
onError: (error: Error) => {
const detail = extractErrorMessage(error) || t("common.unknown");
// 标题与详情分离,便于扫描 + 一键复制
toast.error(
t("notifications.switchFailedTitle", { defaultValue: "切换失败" }),
{
description: t("notifications.switchFailed", {
defaultValue: "切换失败:{{error}}",
error: detail,
}),
duration: 6000,
action: {
label: t("common.copy", { defaultValue: "复制" }),
onClick: () => {
navigator.clipboard?.writeText(detail).catch(() => undefined);
},
},
},
);
},
});
};
export const useSaveSettingsMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (settings: Settings) => {
await settingsApi.save(settings);
},
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ["settings"] });
},
});
};