feat: edit profile item

This commit is contained in:
GyDi 2022-03-02 01:58:16 +08:00
parent 8dc2c1a38f
commit 17f1c487a8
No known key found for this signature in database
GPG Key ID: 1C95E0D3467B3084
3 changed files with 123 additions and 10 deletions

View File

@ -0,0 +1,93 @@
import { useEffect, useState } from "react";
import { useLockFn } from "ahooks";
import { mutate } from "swr";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
TextField,
} from "@mui/material";
import { CmdType } from "../../services/types";
import { patchProfile } from "../../services/cmds";
import Notice from "../base/base-notice";
interface Props {
open: boolean;
itemData: CmdType.ProfileItem;
onClose: () => void;
}
// edit the profile item
const ProfileEdit = (props: Props) => {
const { open, itemData, onClose } = props;
// todo: more type
const [name, setName] = useState(itemData.name);
const [desc, setDesc] = useState(itemData.desc);
const [url, setUrl] = useState(itemData.url);
useEffect(() => {
if (itemData) {
setName(itemData.name);
setDesc(itemData.desc);
setUrl(itemData.url);
}
}, [itemData]);
const onUpdate = useLockFn(async () => {
try {
const { uid } = itemData;
await patchProfile(uid, { uid, name, desc, url });
mutate("getProfiles");
onClose();
} catch (err: any) {
Notice.error(err?.message || err?.toString());
}
});
return (
<Dialog open={open} onClose={onClose}>
<DialogTitle>Edit Profile</DialogTitle>
<DialogContent sx={{ width: 360, pb: 0.5 }}>
<TextField
autoFocus
fullWidth
label="Name"
margin="dense"
variant="outlined"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<TextField
fullWidth
label="Descriptions"
margin="normal"
variant="outlined"
value={desc}
onChange={(e) => setDesc(e.target.value)}
/>
<TextField
fullWidth
label="Remote URL"
margin="normal"
variant="outlined"
value={url}
onChange={(e) => setUrl(e.target.value)}
/>
</DialogContent>
<DialogActions sx={{ px: 2, pb: 2 }}>
<Button onClick={onClose}>Cancel</Button>
<Button onClick={onUpdate} variant="contained">
Update
</Button>
</DialogActions>
</Dialog>
);
};
export default ProfileEdit;

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { import {
alpha, alpha,
@ -16,9 +16,10 @@ import { useSWRConfig } from "swr";
import { RefreshRounded } from "@mui/icons-material"; import { RefreshRounded } from "@mui/icons-material";
import { CmdType } from "../../services/types"; import { CmdType } from "../../services/types";
import { updateProfile, deleteProfile, viewProfile } from "../../services/cmds"; import { updateProfile, deleteProfile, viewProfile } from "../../services/cmds";
import Notice from "../base/base-notice";
import parseTraffic from "../../utils/parse-traffic";
import relativeTime from "dayjs/plugin/relativeTime"; import relativeTime from "dayjs/plugin/relativeTime";
import parseTraffic from "../../utils/parse-traffic";
import ProfileEdit from "./profile-edit";
import Notice from "../base/base-notice";
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
@ -38,8 +39,10 @@ const round = keyframes`
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
`; `;
// save the state of each item loading
const loadingCache: Record<string, boolean> = {};
interface Props { interface Props {
// index: number;
selected: boolean; selected: boolean;
itemData: CmdType.ProfileItem; itemData: CmdType.ProfileItem;
onSelect: (force: boolean) => void; onSelect: (force: boolean) => void;
@ -49,7 +52,7 @@ const ProfileItem: React.FC<Props> = (props) => {
const { selected, itemData, onSelect } = props; const { selected, itemData, onSelect } = props;
const { mutate } = useSWRConfig(); const { mutate } = useSWRConfig();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(loadingCache[itemData.uid] ?? false);
const [anchorEl, setAnchorEl] = useState<any>(null); const [anchorEl, setAnchorEl] = useState<any>(null);
const [position, setPosition] = useState({ left: 0, top: 0 }); const [position, setPosition] = useState({ left: 0, top: 0 });
@ -66,6 +69,16 @@ const ProfileItem: React.FC<Props> = (props) => {
const hasUrl = !!itemData.url; const hasUrl = !!itemData.url;
const hasExtra = !!extra; // only subscription url has extra info const hasExtra = !!extra; // only subscription url has extra info
useEffect(() => {
loadingCache[itemData.uid] = loading;
}, [itemData, loading]);
const [editOpen, setEditOpen] = useState(false);
const onEdit = () => {
setAnchorEl(null);
setEditOpen(true);
};
const onView = async () => { const onView = async () => {
setAnchorEl(null); setAnchorEl(null);
try { try {
@ -86,11 +99,11 @@ const ProfileItem: React.FC<Props> = (props) => {
setLoading(true); setLoading(true);
try { try {
await updateProfile(itemData.uid, withProxy); await updateProfile(itemData.uid, withProxy);
setLoading(false);
mutate("getProfiles"); mutate("getProfiles");
} catch (err: any) { } catch (err: any) {
Notice.error(err.toString());
} finally {
setLoading(false); setLoading(false);
Notice.error(err?.message || err.toString());
} }
}; };
@ -101,7 +114,7 @@ const ProfileItem: React.FC<Props> = (props) => {
await deleteProfile(itemData.uid); await deleteProfile(itemData.uid);
mutate("getProfiles"); mutate("getProfiles");
} catch (err: any) { } catch (err: any) {
Notice.error(err.toString()); Notice.error(err?.message || err.toString());
} }
}); });
@ -123,6 +136,7 @@ const ProfileItem: React.FC<Props> = (props) => {
const urlModeMenu = [ const urlModeMenu = [
{ label: "Select", handler: onForceSelect }, { label: "Select", handler: onForceSelect },
{ label: "Edit", handler: onEdit },
{ label: "View", handler: onView }, { label: "View", handler: onView },
{ label: "Update", handler: onUpdateWrapper(false) }, { label: "Update", handler: onUpdateWrapper(false) },
{ label: "Update(Proxy)", handler: onUpdateWrapper(true) }, { label: "Update(Proxy)", handler: onUpdateWrapper(true) },
@ -130,7 +144,8 @@ const ProfileItem: React.FC<Props> = (props) => {
]; ];
const fileModeMenu = [ const fileModeMenu = [
{ label: "Select", handler: onForceSelect }, { label: "Select", handler: onForceSelect },
{ label: "Edit", handler: onView }, { label: "Edit", handler: onEdit },
{ label: "View", handler: onView },
{ label: "Delete", handler: onDelete }, { label: "Delete", handler: onDelete },
]; ];
@ -261,6 +276,12 @@ const ProfileItem: React.FC<Props> = (props) => {
</MenuItem> </MenuItem>
))} ))}
</Menu> </Menu>
<ProfileEdit
open={editOpen}
itemData={itemData}
onClose={() => setEditOpen(false)}
/>
</> </>
); );
}; };

View File

@ -91,7 +91,6 @@ export namespace CmdType {
name?: string; name?: string;
desc?: string; desc?: string;
file?: string; file?: string;
mode?: string;
url?: string; url?: string;
updated?: number; updated?: number;
selected?: { selected?: {