mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-27 16:26:16 +08:00
5fd3ec0d6a
* Add Traditional Chinese localization * fix: address zh-TW formatting and token units - Format `zh-TW.json` with Prettier. - Use Traditional Chinese `萬` and `億` units for zh-TW token summaries. - Add usage formatting coverage for Traditional Chinese locale aliases. --------- Co-authored-by: Jason <farion1231@gmail.com>
120 lines
3.3 KiB
TypeScript
120 lines
3.3 KiB
TypeScript
import { useCallback, useMemo } from "react";
|
||
import {
|
||
KeyboardSensor,
|
||
PointerSensor,
|
||
useSensor,
|
||
useSensors,
|
||
type DragEndEvent,
|
||
} from "@dnd-kit/core";
|
||
import { arrayMove, sortableKeyboardCoordinates } from "@dnd-kit/sortable";
|
||
import { useQueryClient } from "@tanstack/react-query";
|
||
import { toast } from "sonner";
|
||
import { useTranslation } from "react-i18next";
|
||
import type { Provider } from "@/types";
|
||
import { providersApi, type AppId } from "@/lib/api";
|
||
|
||
export function useDragSort(providers: Record<string, Provider>, appId: AppId) {
|
||
const queryClient = useQueryClient();
|
||
const { t, i18n } = useTranslation();
|
||
|
||
const sortedProviders = useMemo(() => {
|
||
const locale =
|
||
i18n.language === "zh"
|
||
? "zh-CN"
|
||
: i18n.language === "zh-TW"
|
||
? "zh-TW"
|
||
: "en-US";
|
||
return Object.values(providers).sort((a, b) => {
|
||
if (a.sortIndex !== undefined && b.sortIndex !== undefined) {
|
||
return a.sortIndex - b.sortIndex;
|
||
}
|
||
if (a.sortIndex !== undefined) return -1;
|
||
if (b.sortIndex !== undefined) return 1;
|
||
|
||
const timeA = a.createdAt ?? 0;
|
||
const timeB = b.createdAt ?? 0;
|
||
if (timeA && timeB && timeA !== timeB) {
|
||
return timeA - timeB;
|
||
}
|
||
|
||
return a.name.localeCompare(b.name, locale);
|
||
});
|
||
}, [providers, i18n.language]);
|
||
|
||
const sensors = useSensors(
|
||
useSensor(PointerSensor, {
|
||
activationConstraint: { distance: 8 },
|
||
}),
|
||
useSensor(KeyboardSensor, {
|
||
coordinateGetter: sortableKeyboardCoordinates,
|
||
}),
|
||
);
|
||
|
||
const handleDragEnd = useCallback(
|
||
async (event: DragEndEvent) => {
|
||
const { active, over } = event;
|
||
if (!over || active.id === over.id) {
|
||
return;
|
||
}
|
||
|
||
const oldIndex = sortedProviders.findIndex(
|
||
(provider) => provider.id === active.id,
|
||
);
|
||
const newIndex = sortedProviders.findIndex(
|
||
(provider) => provider.id === over.id,
|
||
);
|
||
|
||
if (oldIndex === -1 || newIndex === -1) {
|
||
return;
|
||
}
|
||
|
||
const reordered = arrayMove(sortedProviders, oldIndex, newIndex);
|
||
const updates = reordered.map((provider, index) => ({
|
||
id: provider.id,
|
||
sortIndex: index,
|
||
}));
|
||
|
||
try {
|
||
await providersApi.updateSortOrder(updates, appId);
|
||
await queryClient.invalidateQueries({
|
||
queryKey: ["providers", appId],
|
||
});
|
||
|
||
// 刷新故障转移队列(因为队列顺序依赖 sort_index)
|
||
await queryClient.invalidateQueries({
|
||
queryKey: ["failoverQueue", appId],
|
||
});
|
||
|
||
// 更新托盘菜单以反映新的排序(失败不影响主操作)
|
||
try {
|
||
await providersApi.updateTrayMenu();
|
||
} catch (trayError) {
|
||
console.error("Failed to update tray menu after sort", trayError);
|
||
// 托盘菜单更新失败不影响排序成功
|
||
}
|
||
|
||
toast.success(
|
||
t("provider.sortUpdated", {
|
||
defaultValue: "排序已更新",
|
||
}),
|
||
{ closeButton: true },
|
||
);
|
||
} catch (error) {
|
||
console.error("Failed to update provider sort order", error);
|
||
toast.error(
|
||
t("provider.sortUpdateFailed", {
|
||
defaultValue: "排序更新失败",
|
||
}),
|
||
);
|
||
}
|
||
},
|
||
[sortedProviders, appId, queryClient, t],
|
||
);
|
||
|
||
return {
|
||
sortedProviders,
|
||
sensors,
|
||
handleDragEnd,
|
||
};
|
||
}
|