Explorar el Código

feat: Confirm before deletion

#703
MystiPanda hace 1 año
padre
commit
b1c458359d

+ 46 - 0
src/components/profile/confirm-viewer.tsx

@@ -0,0 +1,46 @@
+import { useEffect, useRef } from "react";
+import { useTranslation } from "react-i18next";
+import {
+  Button,
+  Dialog,
+  DialogActions,
+  DialogContent,
+  DialogTitle,
+} from "@mui/material";
+
+interface Props {
+  open: boolean;
+  title: string;
+  message: string;
+  onClose: () => void;
+  onConfirm: () => void;
+}
+
+export const ConfirmViewer = (props: Props) => {
+  const { open, title, message, onClose, onConfirm } = props;
+
+  const { t } = useTranslation();
+
+  useEffect(() => {
+    if (!open) return;
+  }, [open]);
+
+  return (
+    <Dialog open={open} onClose={onClose} maxWidth="xs" fullWidth>
+      <DialogTitle>{t(title)}</DialogTitle>
+
+      <DialogContent sx={{ width: "95%", pb: 1, userSelect: "text" }}>
+        {t(message)}
+      </DialogContent>
+
+      <DialogActions>
+        <Button onClick={onClose} variant="outlined">
+          {t("Cancel")}
+        </Button>
+        <Button onClick={onConfirm} variant="contained">
+          {t("Confirm")}
+        </Button>
+      </DialogActions>
+    </Dialog>
+  );
+};

+ 37 - 3
src/components/profile/profile-item.tsx

@@ -23,6 +23,7 @@ import { Notice } from "@/components/base";
 import { EditorViewer } from "./editor-viewer";
 import { ProfileBox } from "./profile-box";
 import parseTraffic from "@/utils/parse-traffic";
+import { ConfirmViewer } from "./confirm-viewer";
 
 const round = keyframes`
   from { transform: rotate(0deg); }
@@ -92,6 +93,7 @@ export const ProfileItem = (props: Props) => {
   }, [hasUrl, updated]);
 
   const [fileOpen, setFileOpen] = useState(false);
+  const [confirmOpen, setConfirmOpen] = useState(false);
 
   const onEditInfo = () => {
     setAnchorEl(null);
@@ -171,14 +173,24 @@ export const ProfileItem = (props: Props) => {
     { label: "Open File", handler: onOpenFile },
     { label: "Update", handler: () => onUpdate(0) },
     { label: "Update(Proxy)", handler: () => onUpdate(2) },
-    { label: "Delete", handler: onDelete },
+    {
+      label: "Delete",
+      handler: () => {
+        setConfirmOpen(true);
+      },
+    },
   ];
   const fileModeMenu = [
     { label: "Select", handler: onForceSelect },
     { label: "Edit Info", handler: onEditInfo },
     { label: "Edit File", handler: onEditFile },
     { label: "Open File", handler: onOpenFile },
-    { label: "Delete", handler: onDelete },
+    {
+      label: "Delete",
+      handler: () => {
+        setConfirmOpen(true);
+      },
+    },
   ];
 
   const boxStyle = {
@@ -341,7 +353,19 @@ export const ProfileItem = (props: Props) => {
           <MenuItem
             key={item.label}
             onClick={item.handler}
-            sx={{ minWidth: 120 }}
+            sx={[
+              {
+                minWidth: 120,
+              },
+              (theme) => {
+                return {
+                  color:
+                    item.label === "Delete"
+                      ? theme.palette.error.main
+                      : undefined,
+                };
+              },
+            ]}
             dense
           >
             {t(item.label)}
@@ -355,6 +379,16 @@ export const ProfileItem = (props: Props) => {
         mode="yaml"
         onClose={() => setFileOpen(false)}
       />
+      <ConfirmViewer
+        title="Confirm deletion"
+        message="This operation is not reversible"
+        open={confirmOpen}
+        onClose={() => setConfirmOpen(false)}
+        onConfirm={() => {
+          onDelete();
+          setConfirmOpen(false);
+        }}
+      />
     </Box>
   );
 };

+ 35 - 4
src/components/profile/profile-more.tsx

@@ -17,6 +17,7 @@ import { Notice } from "@/components/base";
 import { EditorViewer } from "./editor-viewer";
 import { ProfileBox } from "./profile-box";
 import { LogViewer } from "./log-viewer";
+import { ConfirmViewer } from "./confirm-viewer";
 
 interface Props {
   selected: boolean;
@@ -51,6 +52,7 @@ export const ProfileMore = (props: Props) => {
   const [anchorEl, setAnchorEl] = useState<any>(null);
   const [position, setPosition] = useState({ left: 0, top: 0 });
   const [fileOpen, setFileOpen] = useState(false);
+  const [confirmOpen, setConfirmOpen] = useState(false);
   const [logOpen, setLogOpen] = useState(false);
 
   const onEditInfo = () => {
@@ -87,7 +89,12 @@ export const ProfileMore = (props: Props) => {
     { label: "Open File", handler: onOpenFile },
     { label: "To Top", show: showMove, handler: fnWrapper(onMoveTop) },
     { label: "To End", show: showMove, handler: fnWrapper(onMoveEnd) },
-    { label: "Delete", handler: fnWrapper(onDelete) },
+    {
+      label: "Delete",
+      handler: () => {
+        setConfirmOpen(true);
+      },
+    },
   ];
 
   const disableMenu = [
@@ -95,7 +102,12 @@ export const ProfileMore = (props: Props) => {
     { label: "Edit Info", handler: onEditInfo },
     { label: "Edit File", handler: onEditFile },
     { label: "Open File", handler: onOpenFile },
-    { label: "Delete", handler: fnWrapper(onDelete) },
+    {
+      label: "Delete",
+      handler: () => {
+        setConfirmOpen(true);
+      },
+    },
   ];
 
   const boxStyle = {
@@ -200,7 +212,17 @@ export const ProfileMore = (props: Props) => {
             <MenuItem
               key={item.label}
               onClick={item.handler}
-              sx={{ minWidth: 120 }}
+              sx={[
+                { minWidth: 120 },
+                (theme) => {
+                  return {
+                    color:
+                      item.label === "Delete"
+                        ? theme.palette.error.main
+                        : undefined,
+                  };
+                },
+              ]}
               dense
             >
               {t(item.label)}
@@ -214,7 +236,16 @@ export const ProfileMore = (props: Props) => {
         mode={type === "merge" ? "yaml" : "javascript"}
         onClose={() => setFileOpen(false)}
       />
-
+      <ConfirmViewer
+        title="Confirm deletion"
+        message="This operation is not reversible"
+        open={confirmOpen}
+        onClose={() => setConfirmOpen(false)}
+        onConfirm={() => {
+          onDelete();
+          setConfirmOpen(false);
+        }}
+      />
       {selected && (
         <LogViewer
           open={logOpen}

+ 3 - 0
src/locales/zh.json

@@ -45,6 +45,8 @@
   "Update All Profiles": "更新所有订阅",
   "View Runtime Config": "查看运行时订阅",
   "Reactivate Profiles": "重新激活订阅",
+  "Confirm deletion": "确认删除",
+  "This operation is not reversible": "此操作不可逆",
 
   "Location": "当前节点",
   "Delay check": "延迟测试",
@@ -138,6 +140,7 @@
   "Save": "保存",
   "Cancel": "取消",
   "Exit": "退出",
+  "Confirm": "确认",
 
   "Default": "默认",
   "Download Speed": "下载速度",