diff --git a/Client/src/Components/TabPanels/Status/Card/ItemTypes.js b/Client/src/Components/TabPanels/Status/Card/ItemTypes.js
new file mode 100644
index 000000000..a7cde4907
--- /dev/null
+++ b/Client/src/Components/TabPanels/Status/Card/ItemTypes.js
@@ -0,0 +1,4 @@
+export default {
+ CARD: 'card',
+ }
+
\ No newline at end of file
diff --git a/Client/src/Components/TabPanels/Status/Server/index.jsx b/Client/src/Components/TabPanels/Status/Card/Server/index.jsx
similarity index 80%
rename from Client/src/Components/TabPanels/Status/Server/index.jsx
rename to Client/src/Components/TabPanels/Status/Card/Server/index.jsx
index 4bc5155b5..ee2934d7f 100644
--- a/Client/src/Components/TabPanels/Status/Server/index.jsx
+++ b/Client/src/Components/TabPanels/Status/Card/Server/index.jsx
@@ -1,5 +1,5 @@
-import TextInput from "../../../Inputs/TextInput";
-import { ServerStartAdornment, ServerEndAdornment } from "../../../Inputs/TextInput/Adornments";
+import TextInput from "../../../../Inputs/TextInput";
+import { ServerStartAdornment, ServerEndAdornment } from "../../../../Inputs/TextInput/Adornments";
const Server = ({ id, removeItem, value }) => {
diff --git a/Client/src/Components/TabPanels/Status/Card/index.jsx b/Client/src/Components/TabPanels/Status/Card/index.jsx
new file mode 100644
index 000000000..6a89618ff
--- /dev/null
+++ b/Client/src/Components/TabPanels/Status/Card/index.jsx
@@ -0,0 +1,90 @@
+import React, { useRef } from "react";
+import { useDrag, useDrop } from "react-dnd";
+import ItemTypes from "./ItemTypes";
+import Card from "@mui/material/Card";
+import CardActionArea from "@mui/material/CardActionArea";
+import CardContent from "@mui/material/CardContent";
+import Server from "./Server"
+
+const CustomCard = React.forwardRef((props, ref) => (
+
+
+
+
+
+
+
+));
+
+const MyCard = ({ id, index, moveCard, removeCard, value }) => {
+ const ref = useRef(null);
+ const [, drop] = useDrop({
+ accept: ItemTypes.CARD,
+ hover(item, monitor) {
+ if (!ref.current) {
+ return;
+ }
+ const dragIndex = item.index;
+ const hoverIndex = index;
+
+ // Don't replace items with themselves
+ if (dragIndex === hoverIndex) {
+ return;
+ }
+
+ // Determine rectangle on screen
+ const hoverBoundingRect = ref.current.getBoundingClientRect();
+ // Get vertical middle
+ const hoverMiddleY =
+ (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
+ // Determine mouse position
+ const clientOffset = monitor.getClientOffset();
+ // Get pixels to the top
+ const hoverClientY = clientOffset.y - hoverBoundingRect.top;
+ // Only perform the move when the mouse has crossed half of the items height
+ // When dragging downwards, only move when the cursor is below 50%
+ // When dragging upwards, only move when the cursor is above 50%
+ // Dragging downwards
+
+ if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
+ return;
+ }
+ // Dragging upwards
+ if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
+ return;
+ }
+
+ // Time to actually perform the action
+ moveCard(dragIndex, hoverIndex);
+ // Note: we're mutating the monitor item here!
+ // Generally it's better to avoid mutations,
+ // but it's good here for the sake of performance
+ // to avoid expensive index searches.
+ item.index = hoverIndex;
+ }
+ });
+ const [ {isDragging}, drag] = useDrag({
+ type: ItemTypes.CARD,
+ item: {id: id, index:index},
+ collect: monitor => ({
+ isDragging: monitor.isDragging()
+ })
+ });
+ drag(drop(ref));
+ return (
+
+ );
+};
+
+export default MyCard;
+
+
diff --git a/Client/src/Components/TabPanels/Status/ContentPanel.jsx b/Client/src/Components/TabPanels/Status/ContentPanel.jsx
index b0bc80610..98005e22e 100644
--- a/Client/src/Components/TabPanels/Status/ContentPanel.jsx
+++ b/Client/src/Components/TabPanels/Status/ContentPanel.jsx
@@ -1,21 +1,24 @@
-import { useState } from "react";
+import { useState, useCallback } from "react";
import { Button, Box, Stack, Typography } from "@mui/material";
import { ConfigBox } from "../../../Pages/Settings/styled";
import { useTheme } from "@emotion/react";
import TabPanel from "@mui/lab/TabPanel";
-import {
- publicPageGeneralSettingsValidation,
-} from "../../../Validation/validation";
+import { publicPageGeneralSettingsValidation } from "../../../Validation/validation";
import { buildErrors } from "../../../Validation/error";
import { hasValidationErrors } from "../../../Validation/error";
-import Server from "./Server"
+import Card from "./Card";
+import update from "immutability-helper";
+
const ContentPanel = () => {
const theme = useTheme();
const [errors, setErrors] = useState({});
// Local state for form data, errors, and file handling
const [localData, setLocalData] = useState({
- monitors: []
+ monitors: [],
});
+
+ const [cards, setCards] = useState(localData.monitors);
+
// Clears specific error from errors state
const clearError = (err) => {
setErrors((prev) => {
@@ -25,6 +28,21 @@ const ContentPanel = () => {
});
};
+ const moveCard = useCallback(
+ (dragIndex, hoverIndex) => {
+ const dragCard = cards[dragIndex];
+ setCards(
+ update(cards, {
+ $splice: [
+ [dragIndex, 1],
+ [hoverIndex, 0, dragCard],
+ ],
+ })
+ );
+ },
+ [cards]
+ );
+
const handleChange = (event) => {
event.preventDefault();
const { value, id } = event.target;
@@ -41,16 +59,11 @@ const ContentPanel = () => {
};
const handleAddNew = () => {
- let arr = localData.monitors;
- arr.push({ id: "" + Math.random() });
- setLocalData({ ...localData, monitors: arr });
- }
-
- const removeItem = (id) =>{
- const currentMonitors = localData.monitors.filter(m => m.id !=id)
- setLocalData({...localData, monitors: currentMonitors})
- }
-
+ setCards([...cards, { id: "" + Math.random() }]);
+ };
+ const removeCard = (id) => {
+ setCards(cards.filter((c) => c?.id != id));
+ };
const handleBlur = (event) => {
event.preventDefault();
const { value, id } = event.target;
@@ -122,22 +135,26 @@ const ContentPanel = () => {
- {localData.monitors.length > 0 && (
+ {cards.length > 0 && (
- {localData.monitors.map((m, idx) => (
- (
+
))}