import cx from 'clsx'; import { formatDistance } from 'date-fns'; import * as React from 'react'; import { ChevronDown, RotateCw, Zap } from '~/components/shared/FeatherIcons'; import Button from '~/components/Button'; import Collapsible from '~/components/Collapsible'; import CollapsibleSectionHeader from '~/components/CollapsibleSectionHeader'; import s0 from '~/components/proxies/ProxyGroup.module.scss'; import { useStoreActions } from '~/components/StateProvider'; import { LazyMotion, domAnimation, m } from 'framer-motion'; import { useFilteredAndSorted, useUpdateProviderItem } from '~/modules/proxies/hooks'; import { healthcheckProviderByName } from '~/store/proxies'; import { DelayMapping, DispatchFn, ProxiesMapping, SubscriptionInfo } from '~/store/types'; import { ClashAPIConfig } from '~/types'; import { ProxyList, ProxyListSummaryView } from './ProxyList'; import s from './ProxyProvider.module.scss'; const { memo, useState, useCallback } = React; type Props = { name: string; proxies: Array; delay: DelayMapping; hideUnavailableProxies: boolean; proxySortBy: string; type: 'Proxy' | 'Rule'; vehicleType: 'HTTP' | 'File' | 'Compatible'; updatedAt?: string; subscriptionInfo?: SubscriptionInfo; proxyMapping: ProxiesMapping; latencyTestUrl: string; dispatch: DispatchFn; isOpen: boolean; apiConfig: ClashAPIConfig; }; export const ProxyProvider = memo(function ProxyProvider({ name, proxies: all, delay, hideUnavailableProxies, proxySortBy, vehicleType, updatedAt, subscriptionInfo, proxyMapping, latencyTestUrl, isOpen, dispatch, apiConfig, }: Props) { const proxies = useFilteredAndSorted(all, delay, hideUnavailableProxies, proxySortBy); const [isHealthcheckLoading, setIsHealthcheckLoading] = useState(false); const updateProvider = useUpdateProviderItem({ dispatch, apiConfig, name }); const healthcheckProvider = useCallback(async () => { setIsHealthcheckLoading(true); await dispatch(healthcheckProviderByName(apiConfig, name)); setIsHealthcheckLoading(false); }, [apiConfig, dispatch, name, setIsHealthcheckLoading]); const { app: { updateCollapsibleIsOpen }, } = useStoreActions(); const toggle = useCallback(() => { updateCollapsibleIsOpen('proxyProvider', name, !isOpen); }, [isOpen, updateCollapsibleIsOpen, name]); const timeAgo = formatDistance(new Date(updatedAt), new Date()); const total = subscriptionInfo ? formatBytes(subscriptionInfo.Total) : 0; const used = subscriptionInfo ? formatBytes(subscriptionInfo.Download + subscriptionInfo.Upload) : 0; const percentage = subscriptionInfo ? ( ((subscriptionInfo.Download + subscriptionInfo.Upload) / subscriptionInfo.Total) * 100 ).toFixed(2) : 0; const expireStr = () => { if (subscriptionInfo.Expire === 0) { return 'Null'; } const expire = new Date(subscriptionInfo.Expire * 1000); const getYear = expire.getFullYear() + '-'; const getMonth = (expire.getMonth() + 1 < 10 ? '0' + (expire.getMonth() + 1) : expire.getMonth() + 1) + '-'; const getDate = (expire.getDate() < 10 ? '0' + expire.getDate() : expire.getDate()) + ' '; return getYear + getMonth + getDate; }; return (
{subscriptionInfo && ( {used} / {total} ( {percentage}% )    Expire: {expireStr()}{' '} )}
Updated {timeAgo} ago
); }); const button = { rest: { scale: 1 }, pressed: { scale: 0.95 }, }; const arrow = { rest: { rotate: 0 }, hover: { rotate: 360, transition: { duration: 0.3 } }, }; function formatBytes(bytes, decimals = 2) { if (!+bytes) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`; } function Refresh() { return ( ); }