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) => unknown, boolean] { const queryClient = useQueryClient(); const { mutate, isLoading } = useMutation(refreshRuleProviderByName, { onSuccess: () => { queryClient.invalidateQueries('/providers/rules'); }, }); const onClickRefreshButton = (ev: React.MouseEvent) => { ev.preventDefault(); mutate({ name, apiConfig }); }; return [onClickRefreshButton, isLoading]; } export function useUpdateAllRuleProviderItems( apiConfig: ClashAPIConfig ): [(ev: React.MouseEvent) => 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) => { 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, }; }