diff options
| author | Larvan2 <[email protected]> | 2026-03-15 15:01:57 +0800 |
|---|---|---|
| committer | Larvan2 <[email protected]> | 2026-03-15 15:01:57 +0800 |
| commit | 0e420859f5f7011ba124c965d8319bf3bf4c5fe3 (patch) | |
| tree | 2fc344b757e119ebae6e0b6243121fddba61603c /src/modules/rules | |
| parent | 17c4d2855ffb6914fcbece27367bafdd27a4c182 (diff) | |
refactor: reorganize code
Diffstat (limited to 'src/modules/rules')
| -rw-r--r-- | src/modules/rules/hooks.ts | 108 | ||||
| -rw-r--r-- | src/modules/rules/utils.ts | 24 |
2 files changed, 132 insertions, 0 deletions
diff --git a/src/modules/rules/hooks.ts b/src/modules/rules/hooks.ts new file mode 100644 index 0000000..e99b978 --- /dev/null +++ b/src/modules/rules/hooks.ts @@ -0,0 +1,108 @@ +import * as React from 'react'; +import { useMutation, useQuery, useQueryClient } from 'react-query'; +import { useRecoilState } from 'recoil'; + +import { + fetchRuleProviders, + refreshRuleProviderByName, + updateRuleProviders, +} from '~/api/rule-provider'; +import { fetchRules } from '~/api/rules'; +import { ruleFilterText } from '~/store/rules'; +import type { ClashAPIConfig } from '~/types'; + +const { useCallback, useState } = React; + +export function useUpdateRuleProviderItem( + name: string, + apiConfig: ClashAPIConfig +): [(ev: React.MouseEvent<HTMLButtonElement>) => unknown, boolean] { + const queryClient = useQueryClient(); + const { mutate, isLoading } = useMutation(refreshRuleProviderByName, { + onSuccess: () => { + queryClient.invalidateQueries('/providers/rules'); + }, + }); + const onClickRefreshButton = (ev: React.MouseEvent<HTMLButtonElement>) => { + ev.preventDefault(); + mutate({ name, apiConfig }); + }; + return [onClickRefreshButton, isLoading]; +} + +export function useUpdateAllRuleProviderItems( + apiConfig: ClashAPIConfig +): [(ev: React.MouseEvent<HTMLButtonElement>) => unknown, boolean] { + const queryClient = useQueryClient(); + const { data: provider } = useRuleProviderQuery(apiConfig); + const { mutate, isLoading } = useMutation(updateRuleProviders, { + onSuccess: () => { + queryClient.invalidateQueries('/providers/rules'); + }, + }); + const onClickRefreshButton = (ev: React.MouseEvent<HTMLButtonElement>) => { + ev.preventDefault(); + mutate({ names: provider.names, apiConfig }); + }; + return [onClickRefreshButton, isLoading]; +} + +export function useInvalidateQueries() { + const queryClient = useQueryClient(); + return useCallback(() => { + queryClient.invalidateQueries('/rules'); + queryClient.invalidateQueries('/providers/rules'); + }, [queryClient]); +} + +export function useRuleProviderQuery(apiConfig: ClashAPIConfig) { + return useQuery(['/providers/rules', apiConfig], () => + fetchRuleProviders('/providers/rules', apiConfig) + ); +} + +export function useRuleAndProvider(apiConfig: ClashAPIConfig) { + const { data: rules, isFetching } = useQuery(['/rules', apiConfig], () => + fetchRules('/rules', apiConfig) + ); + const { data: provider } = useRuleProviderQuery(apiConfig); + + const [filterText] = useRecoilState(ruleFilterText); + if (filterText === '') { + return { rules, provider, isFetching }; + } + + const f = filterText.toLowerCase(); + return { + rules: rules.filter((r) => r.payload.toLowerCase().indexOf(f) >= 0), + isFetching, + provider: { + byName: provider.byName, + names: provider.names.filter((t) => t.toLowerCase().indexOf(f) >= 0), + }, + }; +} + +export function useRulesPage(apiConfig: ClashAPIConfig) { + const { rules, provider } = useRuleAndProvider(apiConfig); + const [activeTab, setActiveTab] = useState('rules'); + const isRulesTab = activeTab === 'rules'; + + const handleTabKeyDown = useCallback( + (tab: string) => (e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + setActiveTab(tab); + } + }, + [] + ); + + return { + rules, + provider, + activeTab, + setActiveTab, + isRulesTab, + handleTabKeyDown, + }; +}
\ No newline at end of file diff --git a/src/modules/rules/utils.ts b/src/modules/rules/utils.ts new file mode 100644 index 0000000..c1d1464 --- /dev/null +++ b/src/modules/rules/utils.ts @@ -0,0 +1,24 @@ +import { ClashAPIConfig } from '~/types'; + +export type RulesListItemData = { + rules: any[] | null; + provider: any; + apiConfig: ClashAPIConfig; +}; + +export function itemKey(index: number, { rules, provider }: RulesListItemData) { + if (!rules) { + return provider.names[index]; + } + return rules[index].id; +} + +export function getItemSizeFactory({ isRulesTab }: { isRulesTab: boolean }) { + return function getItemSize() { + return isRulesTab ? 70 : 100; + }; +} + +export function formatQty(qty: number) { + return qty < 100 ? String(qty) : '99+'; +} |
