Files
clash-proxy/src/components/proxy/provider-button.tsx

200 lines
6.0 KiB
TypeScript
Raw Normal View History

2023-08-05 21:38:44 +08:00
import dayjs from "dayjs";
import useSWR, { mutate } from "swr";
import { useState } from "react";
import {
Button,
IconButton,
List,
ListItem,
ListItemText,
2024-01-18 01:01:47 +08:00
styled,
Box,
alpha,
Typography,
Divider,
LinearProgress,
2023-08-05 21:38:44 +08:00
} from "@mui/material";
import { RefreshRounded } from "@mui/icons-material";
import { useTranslation } from "react-i18next";
import { useLockFn } from "ahooks";
2024-01-18 01:01:47 +08:00
import { getProxyProviders, proxyProviderUpdate } from "@/services/api";
2023-08-05 21:38:44 +08:00
import { BaseDialog } from "../base";
import parseTraffic from "@/utils/parse-traffic";
2023-08-05 21:38:44 +08:00
export const ProviderButton = () => {
const { t } = useTranslation();
2024-01-18 01:01:47 +08:00
const { data } = useSWR("getProxyProviders", getProxyProviders);
2023-08-05 21:38:44 +08:00
const [open, setOpen] = useState(false);
const hasProvider = Object.keys(data || {}).length > 0;
const handleUpdate = useLockFn(async (key: string) => {
2024-01-18 01:01:47 +08:00
await proxyProviderUpdate(key);
2023-08-05 21:38:44 +08:00
await mutate("getProxies");
2024-01-18 01:01:47 +08:00
await mutate("getProxyProviders");
2023-08-05 21:38:44 +08:00
});
if (!hasProvider) return null;
return (
<>
<Button
size="small"
variant="outlined"
sx={{ textTransform: "capitalize" }}
onClick={() => setOpen(true)}
>
{t("Provider")}
</Button>
<BaseDialog
open={open}
2024-01-18 01:01:47 +08:00
title={
<Box display="flex" justifyContent="space-between" gap={1}>
<Typography variant="h6">{t("Proxy Provider")}</Typography>
<Button
variant="contained"
2024-02-22 00:19:45 +08:00
size="small"
2024-01-18 01:01:47 +08:00
onClick={async () => {
Object.entries(data || {}).forEach(async ([key, item]) => {
await proxyProviderUpdate(key);
await mutate("getProxies");
await mutate("getProxyProviders");
});
}}
>
{t("Update All")}
</Button>
</Box>
}
2023-08-05 21:38:44 +08:00
contentSx={{ width: 400 }}
disableOk
cancelBtn={t("Cancel")}
onClose={() => setOpen(false)}
onCancel={() => setOpen(false)}
>
<List sx={{ py: 0, minHeight: 250 }}>
{Object.entries(data || {}).map(([key, item]) => {
const time = dayjs(item.updatedAt);
const sub = item.subscriptionInfo;
const hasSubInfo = !!sub;
const upload = sub?.Upload || 0;
const download = sub?.Download || 0;
const total = sub?.Total || 0;
const expire = sub?.Expire || 0;
const progress = Math.round(
((download + upload) * 100) / (total + 0.1)
);
2023-08-05 21:38:44 +08:00
return (
2024-01-18 01:01:47 +08:00
<>
<ListItem
sx={(theme) => ({
p: 0,
borderRadius: "10px",
boxShadow: theme.shadows[2],
mb: 1,
})}
key={key}
>
2024-01-18 01:01:47 +08:00
<ListItemText
sx={{ px: 1 }}
2024-01-18 01:01:47 +08:00
primary={
<>
<Typography
variant="h6"
component="span"
noWrap
title={key}
>
{key}
</Typography>
2024-02-10 13:13:27 +08:00
<TypeBox component="span" sx={{ marginLeft: "8px" }}>
{item.proxies.length}
</TypeBox>
2024-01-18 01:01:47 +08:00
</>
}
secondary={
<>
<StyledTypeBox component="span">
{item.vehicleType}
</StyledTypeBox>
<StyledTypeBox component="span">
{t("Update At")} {time.fromNow()}
</StyledTypeBox>
{hasSubInfo && (
<>
<Box sx={{ ...boxStyle, fontSize: 14 }}>
<span title="Used / Total">
{parseTraffic(upload + download)} /{" "}
{parseTraffic(total)}
</span>
<span title="Expire Time">
{parseExpire(expire)}
</span>
</Box>
<LinearProgress
variant="determinate"
value={progress}
color="inherit"
/>
</>
)}
2024-01-18 01:01:47 +08:00
</>
}
/>
<Divider orientation="vertical" flexItem />
2024-01-18 01:01:47 +08:00
<IconButton
size="small"
color="inherit"
title="Update Provider"
onClick={() => handleUpdate(key)}
>
<RefreshRounded />
</IconButton>
</ListItem>
</>
2023-08-05 21:38:44 +08:00
);
})}
</List>
</BaseDialog>
</>
);
};
2024-02-10 13:13:27 +08:00
const TypeBox = styled(Box)(({ theme }) => ({
display: "inline-block",
border: "1px solid #ccc",
borderColor: alpha(theme.palette.secondary.main, 0.5),
color: alpha(theme.palette.secondary.main, 0.8),
borderRadius: 4,
fontSize: 10,
marginRight: "4px",
padding: "0 2px",
lineHeight: 1.25,
}));
2024-01-18 01:01:47 +08:00
const StyledTypeBox = styled(Box)(({ theme }) => ({
display: "inline-block",
border: "1px solid #ccc",
borderColor: alpha(theme.palette.primary.main, 0.5),
color: alpha(theme.palette.primary.main, 0.8),
borderRadius: 4,
fontSize: 10,
marginRight: "4px",
padding: "0 2px",
lineHeight: 1.25,
}));
const boxStyle = {
height: 26,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
};
function parseExpire(expire?: number) {
if (!expire) return "-";
return dayjs(expire * 1000).format("YYYY-MM-DD");
}