Files
CC-Switch/src/hooks/useDragSort.ts
T
滅ü 5fd3ec0d6a feat(i18n): add Traditional Chinese localization (#3093)
* 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>
2026-05-27 00:05:03 +08:00

120 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
};
}