summaryrefslogtreecommitdiff
path: root/src/components/Proxies.js
blob: 23b1bd8dd7dfadb7d29d88c6296001dbb1577b2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import React from 'react';

import { connect } from './StateProvider';

import Button from './Button';
import ContentHeader from './ContentHeader';
import ProxyGroup from './ProxyGroup';
import BaseModal from './shared/BaseModal';
import Settings from './proxies/Settings';
import Equalizer from './svg/Equalizer';
import { Zap } from 'react-feather';

import ProxyProviderList from './ProxyProviderList';
import { Fab, position as fabPosition } from './shared/Fab';

import s0 from './Proxies.module.css';

import {
  getDelay,
  getProxyGroupNames,
  getProxyProviders,
  fetchProxies,
  requestDelayAll,
} from '../store/proxies';
import { getClashAPIConfig } from '../store/app';

const { useState, useEffect, useCallback, useRef } = React;

function Proxies({ dispatch, groupNames, delay, proxyProviders, apiConfig }) {
  const refFetchedTimestamp = useRef({});
  const requestDelayAllFn = useCallback(
    () => dispatch(requestDelayAll(apiConfig)),
    [apiConfig, dispatch]
  );

  const fetchProxiesHooked = useCallback(() => {
    refFetchedTimestamp.current.startAt = new Date();
    dispatch(fetchProxies(apiConfig)).then(() => {
      refFetchedTimestamp.current.completeAt = new Date();
    });
  }, [apiConfig, dispatch]);
  useEffect(() => {
    // fetch it now
    fetchProxiesHooked();

    // arm a window on focus listener to refresh it
    const fn = () => {
      if (
        refFetchedTimestamp.current.startAt &&
        new Date() - refFetchedTimestamp.current.startAt > 3e4 // 30s
      ) {
        fetchProxiesHooked();
      }
    };
    window.addEventListener('focus', fn, false);
    return () => window.removeEventListener('focus', fn, false);
  }, [fetchProxiesHooked]);

  const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
  const closeSettingsModal = useCallback(() => {
    setIsSettingsModalOpen(false);
  }, []);

  return (
    <>
      <div className={s0.topBar}>
        <Button kind="minimal" onClick={() => setIsSettingsModalOpen(true)}>
          <Equalizer size={16} />
        </Button>
      </div>
      <BaseModal
        isOpen={isSettingsModalOpen}
        onRequestClose={closeSettingsModal}
      >
        <Settings />
      </BaseModal>
      <ContentHeader title="Proxies" />
      <div>
        {groupNames.map((groupName) => {
          return (
            <div className={s0.group} key={groupName}>
              <ProxyGroup
                name={groupName}
                delay={delay}
                apiConfig={apiConfig}
                dispatch={dispatch}
              />
            </div>
          );
        })}
      </div>
      <ProxyProviderList items={proxyProviders} />
      <div style={{ height: 60 }} />
      <Fab
        icon={<Zap width={16} />}
        onClick={requestDelayAllFn}
        text="Test Latency"
        position={fabPosition}
      />
    </>
  );
}

const mapState = (s) => ({
  apiConfig: getClashAPIConfig(s),
  groupNames: getProxyGroupNames(s),
  proxyProviders: getProxyProviders(s),
  delay: getDelay(s),
});

export default connect(mapState)(Proxies);