From b1f056809f4dee83d103fbab461137172fd300fc Mon Sep 17 00:00:00 2001 From: Shemy Gan Date: Mon, 9 Dec 2024 11:33:30 -0500 Subject: [PATCH] - Created Card type - Implemented drag and drop for the server list section --- .../TabPanels/Status/Card/ItemTypes.js | 4 + .../Status/{ => Card}/Server/index.jsx | 4 +- .../TabPanels/Status/Card/index.jsx | 90 +++++++++++++++++++ .../TabPanels/Status/ContentPanel.jsx | 65 +++++++++----- 4 files changed, 137 insertions(+), 26 deletions(-) create mode 100644 Client/src/Components/TabPanels/Status/Card/ItemTypes.js rename Client/src/Components/TabPanels/Status/{ => Card}/Server/index.jsx (80%) create mode 100644 Client/src/Components/TabPanels/Status/Card/index.jsx 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) => ( - ( + ))}