I want to be able to drag and drop the draggable box to any other date and it should remove that previous one.
For example if I move drag box from 5th march to 6th march it should remove from 5th march and update to 6th march
my problem is when I drag and drop this box it shows a stop sign and I cannot move it. Is there any way to fix it or any other way so I can move my boxes to another date along with its data (has some data name and subrub when you hover over drag box?
my code for runsheetpreview.js
import React, { useState, useRef } from "react";
import { startOfMonth, endOfMonth, startOfWeek, endOfWeek, format, addDays, addMonths, subMonths, isSameMonth } from "date-fns";
import "../assets/css/RunSheetPDF.css";
const DraggableBox = ({ day, onDrop, name: initialName, suburb: initialSuburb }) => {
const [editable, setEditable] = useState(false);
const [name, setName] = useState(initialName);
const [suburb, setSuburb] = useState(initialSuburb);
const [showTooltip, setShowTooltip] = useState(false);
const boxRef = useRef(null);
const handleDoubleClick = () => {
setEditable(true);
};
const handleChangeName = (e) => {
setName(e.target.value);
};
const handleChangeSuburb = (e) => {
setSuburb(e.target.value);
};
const handleBlur = () => {
setEditable(false);
};
const handleDragStart = () => {
setShowTooltip(false);
boxRef.current.classList.add('dragging');
};
const handleDragEnd = () => {
boxRef.current.classList.remove('dragging');
};
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (e) => {
e.preventDefault();
const draggedDay = parseInt(e.dataTransfer.getData("text/plain"));
onDrop(draggedDay, day);
};
return (
<div
className="drag-box"
ref={boxRef}
draggable
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
onDoubleClick={handleDoubleClick}
onDragOver={handleDragOver}
onDrop={handleDrop}
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
style={{
width: "70px",
height: "80px",
textAlign: "center",
backgroundColor: "#F5F5F5",
color: "#333333",
marginTop: "5px",
position: "relative",
cursor: "move" // Set cursor to move when hovering over the box
}}
>
<p style={{ margin: 0, lineHeight: "80px" }}>{day}</p>
{showTooltip && (
<div className="tooltip">
<p>Name: {name}</p>
<p>Suburb: {suburb}</p>
</div>
)}
</div>
);
};
const RunSheetPreview = () => {
const [selectedDate, setSelectedDate] = useState(new Date());
const [calendarData, setCalendarData] = useState([
{ day: 5, name: "John", suburb: "Suburb 1" },
{ day: 15, name: "Alice", suburb: "Suburb 2" },
{ day: 25, name: "Bob", suburb: "Suburb 3" },
{ day: 27, name: "Eva", suburb: "Suburb 4" }
]);
const handleDrop = (draggedDay, dropDay) => {
const newData = [...calendarData];
const draggedItem = newData.find(item => item.day === draggedDay);
draggedItem.day = dropDay;
setCalendarData(newData);
};
const generateCalendar = () => {
const monthStart = startOfMonth(selectedDate);
const monthEnd = endOfMonth(selectedDate);
const startDate = startOfWeek(monthStart, { weekStartsOn: 0 });
const endDate = endOfWeek(monthEnd, { weekStartsOn: 0 });
const rows = [];
let days = [];
let day = startDate;
while (day <= endDate) {
for (let i = 0; i < 7; i++) {
const dayOfMonth = format(day, "d");
const isCurrentMonth = isSameMonth(day, monthStart);
const draggableData = calendarData.find(item => item.day === parseInt(dayOfMonth));
const draggableBoxExists = draggableData !== undefined;
days.push(
<td key={day} style={{ width: "70px", height: "80px" }}>
{isCurrentMonth && (
<div>
{draggableBoxExists ? (
<DraggableBox
day={draggableData.day}
name={draggableData.name}
suburb={draggableData.suburb}
onDrop={handleDrop}
/>
) : (
<p>{dayOfMonth}</p>
)}
</div>
)}
</td>
);
day = addDays(day, 1);
}
rows.push(<tr key={day}>{days}</tr>);
days = [];
}
return rows;
};
const handleNextMonth = () => {
setSelectedDate(addMonths(selectedDate, 1));
};
const handlePreviousMonth = () => {
setSelectedDate(subMonths(selectedDate, 1));
};
return (
<div style={{ width: "100%", display: "flex", flexDirection: "column", alignItems: "center", marginTop: "20px" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", marginBottom: "0px" }}>
<button onClick={handlePreviousMonth} style={{ backgroundColor: "#F5F5F5", color: "#333333", border: "1px solid #CCCCCC", borderRadius: "5px", padding: "5px 10px", marginRight: "10px" }}>Previous Month</button>
<h2 style={{ color: "#333333", margin: 0 }}>{format(selectedDate, "MMMM yyyy")}</h2>
<button onClick={handleNextMonth} style={{ backgroundColor: "#F5F5F5", color: "#333333", border: "1px solid #CCCCCC", borderRadius: "5px", padding: "5px 10px", marginLeft: "10px" }}>Next Month</button>
</div>
<div className="calendar-container">
<table className="calendar-table">
<thead>
<tr>
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
</tr>
</thead>
<tbody>
{generateCalendar()}
</tbody>
</table>
</div>
</div>
);
};
export default RunSheetPreview;
my code for RunSheetPDF.css
.centered-text {
text-align: center;
font-weight: 700;
}
.title {
text-align: left;
font-weight: bold;
font-size: 30px;
text-transform: uppercase;
font-style: bold;
}
.table-container {
width: 1000px;
background: white;
font-family: "Times New Roman";
}
.table {
width: 90%;
border-collapse: collapse;
}
.top-header th {
text-align: left;
border: none;
}
.table-body td {
text-align: left;
border: none;
}
.paper {
padding: 20px;
display: flex;
justify-content: space-between;
}
.left-content {
flex: 1;
text-align: left;
}
.right-content {
flex: 1;
text-align: left;
}
.flex-content {
display: flex;
justify-content: space-between;
}
.empty-box {
text-align: left;
}
.border-box {
width: 100px;
height: 20px;
border: 1px solid #000;
}
.bold-text {
font-weight: bold;
}
.normal-text {
font-weight: normal;
}
.text-left {
text-align: left;
font-family: "Times New Roman", Times, serif;
}
.no-border {
border: none;
}
.page-content {
height: 38rem;
overflow: auto;
border: solid 1px black;
margin: 0 80mm 30mm 45mm;
width: 35rem;
page-break-after: always;
}
/* Use media query to apply styles only when printing */
@media print {
.page-content {
page-break-before: always; /* This will force a page break before each .page-content element */
}
}
/* Add this to your CSS file or CSS module */
.print-button-wrapper {
position: fixed;
bottom: 130px; /* Adjust this value to change the vertical position */
right: 150px; /* Adjust this value to change the horizontal position */
}
.calendar-container {
margin: 20px auto;
max-width: 800px;
background-color: #f2f2f2;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.calendar-table {
width: 100%;
border-collapse: collapse;
}
.calendar-table th, .calendar-table td {
padding: 10px;
text-align: center;
border: 2px solid #fff; /* White border to separate cells */
}
.calendar-table th {
background-color: #3f51b5; /* Dark blue background for days */
color: #fff;
font-weight: bold;
font-size: 18px;
}
.calendar-table td {
background-color: #ffffff; /* White background for date cells */
}
.calendar-table td:first-child {
background-color: #f5f5f5; /* Light gray background for first column */
}
.drag-box {
padding: 10px;
border: 1px solid #ccc;
background-color: #fff;
cursor: pointer;
}
.drag-box p {
margin: 5px 0;
}
.drag-box input {
width: 100%;
padding: 5px;
margin-bottom: 5px;
}
.drag-box.draggable {
background-color: #ffd700; /* Gold background for draggable box */
border-color: #ffd700;
color: #000;
}
.drag-box.draggable p {
color: #000;
}
.drag-box {
background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 5px;
padding: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
width: 100px; /* Adjust the width as needed */
height: 60px; /* Adjust the height as needed */
transition: opacity 0.3s ease; /* Add transition for smooth hide/show effect */
}
.drag-box.hidden {
opacity: 0; /* Hide the box during drag */
}
.calendar-table {
border-collapse: collapse;
width: 100%; /* Make the table fill its container */
background-color: #f0e8ff; /* Light purple background color */
}
.calendar-table th,
.calendar-table td {
border: 1px solid #cccccc;
padding: 8px;
text-align: center;
width: 100px; /* Adjust the width of table cells */
}
.drag-box {
cursor: pointer;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
margin: 2px;
}
.calendar-table {
width: 100%;
}
.calendar-table td {
border: 1px solid #ccc;
padding: 5px;
text-align: center;
}
.calendar-table p {
margin: 0;
}
.drag-box {
cursor: pointer;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
margin: 2px;
position: relative; /* Add relative positioning */
}
.tooltip {
position: absolute;
top: 100%; /* Position below the draggable box */
left: 50%; /* Center horizontally */
transform: translateX(-50%); /* Center horizontally */
background-color: #fff;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
z-index: 1; /* Ensure tooltip appears above other elements */
white-space: nowrap; /* Prevent line breaks */
visibility: hidden; /* Initially hidden */
}
.drag-box:hover .tooltip {
visibility: visible; /* Show tooltip on hover */
}
After trying what was suggested in the answer it works fine however I updated a bit to get the actual data from database and now when i drag the box from 5th to 6th it duplicates the box instead rather removing the first one so its not removing the very first box however if i move from 5th to 6th there is a box at 6th date (which is what i want however can still see box at 5th too) and when I move 6th box to 7th it works fine so not only working for very first box for removing it and not working very well after my new changes to get actual data from database if any help? And also when I move box from date 1st of march to 4th of march it also moves the boxes in all other months but it should only move in that certain month
import React, { useState, useRef, useEffect } from "react";
import { startOfMonth, endOfMonth, startOfWeek, endOfWeek, format, addDays, addMonths, subMonths, isSameMonth } from "date-fns";
import "../assets/css/RunSheetPDF.css";
import { CircularProgress } from "@mui/material";
const DraggableBox = ({ day, calendarData, setCalendarData,
changeName, setChangeName, changeSuburb, setChangeSuburb, setChangeDay, changeDay, companyData }) => {
//eslint-disable-next-line
const [editable, setEditable] = useState(false);
const [showTooltip, setShowTooltip] = useState(false);
const boxRef = useRef(null);
const handleDoubleClick = () => {
setEditable(true);
};
//eslint-disable-next-line
const handleChangeName = (e) => {
setChangeName(e.target.value);
};
//eslint-disable-next-line
const handleChangeSuburb = (e) => {
setChangeSuburb(e.target.value);
};
//eslint-disable-next-line
const handleBlur = () => {
setEditable(false);
};
const handleDragStart = () => {
setShowTooltip(false);
setChangeName(companyData.Name);
setChangeSuburb(companyData.ABN)
setChangeDay(day)
boxRef.current.classList.add('dragging');
};
const handleDragEnd = () => {
boxRef.current.classList.remove('dragging');
};
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
if(Number(changeDay) !== Number(e.target.innerText)){
const newData = {
day: Number(e.target.innerText),
name: changeName,
suburb: changeSuburb,
}
const newCalData = [...calendarData];
const calData = newCalData.filter((f) => Number(f.day) !== Number(e.target.innerText) && Number(f.day) !== Number(changeDay) );
calData.push(newData);
calData.sort((a,b) => Number(a.day) - Number(b.day))
setCalendarData(calData)
setChangeDay(null);
setChangeName(null);
setChangeSuburb(null);
}
};
return (
<div
className="drag-box"
ref={boxRef}
draggable
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
onDoubleClick={handleDoubleClick}
onDragOver={handleDragOver}
onDrop={handleDrop}
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
style={{
width: "70px",
height: "80px",
textAlign: "center",
backgroundColor: "#F5F5F5",
color: "#333333",
marginTop: "5px",
position: "relative",
cursor: "move" // Set cursor to move when hovering over the box
}}
>
<p style={{ margin: 0, lineHeight: "80px" }}>{day}</p>
{showTooltip && (
<div className="tooltip">
<p>Name: {companyData.Name}</p>
<p>Suburb: {companyData.ABN}</p>
</div>
)}
</div>
);
};
const RunSheetPreview = ({
companyData,
}) => {
const [selectedDate, setSelectedDate] = useState(new Date());
const [calendarData, setCalendarData] = useState([]);
const boxRef = useRef(null);
const [changeName, setChangeName] = useState("");
const [changeDay, setChangeDay] = useState(null);
const [changeSuburb, setChangeSuburb] = useState(null);
const [showTooltip, setShowTooltip] = useState(false); // Define showTooltip here
const [day, setDay] = useState(null); // Define day here
useEffect(() => {
// Create calendar data based on company data
const initialData = [
...calendarData, // Include existing calendar data
{
day: 1, // Example day
name: companyData.Name,
suburb: companyData.StreetAddress,
},
// Add more data if needed
];
// Set calendar data
setCalendarData(initialData);
}, [companyData, calendarData, setCalendarData]);
const handleDragStart = () => {
setShowTooltip(false);
setChangeName(companyData.Name);
setChangeSuburb(companyData.ABN);
setChangeDay(day)
boxRef.current.classList.add('dragging');
};
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
if(Number(changeDay) !== Number(e.target.innerText)){
const newData = {
day: Number(e.target.innerText),
name: changeName,
suburb: changeSuburb,
}
const newCalData = [...calendarData];
const calData = newCalData.filter((f) => Number(f.day) !== Number(e.target.innerText) && Number(f.day) !== Number(changeDay) );
calData.push(newData);
calData.sort((a,b) => Number(a.day) - Number(b.day))
setCalendarData(calData)
setChangeDay(null);
setChangeName(null);
setChangeSuburb(null);
}
};
const generateCalendar = () => {
const monthStart = startOfMonth(selectedDate);
const monthEnd = endOfMonth(selectedDate);
const startDate = startOfWeek(monthStart, { weekStartsOn: 0 });
const endDate = endOfWeek(monthEnd, { weekStartsOn: 0 });
const rows = [];
let days = [];
let day = startDate;
while (day <= endDate) {
for (let i = 0; i < 7; i++) {
const dayOfMonth = format(day, "d");
const isCurrentMonth = isSameMonth(day, monthStart);
const draggableData = calendarData.find(item => item.day === parseInt(dayOfMonth));
const draggableBoxExists = draggableData;
days.push(
<td key={day} style={{ width: "70px", height: "80px" }}>
{isCurrentMonth && (
<div
>
{draggableBoxExists ? (
<DraggableBox
day={draggableData.day}
name={draggableData.name}
suburb={draggableData.suburb}
setCalendarData={setCalendarData}
calendarData={calendarData}
changeName={changeName}
setChangeName={setChangeName}
changeDay={changeDay}
setChangeDay={setChangeDay}
changeSuburb={changeSuburb}
setChangeSuburb={setChangeSuburb}
companyData={companyData}
/>
) : (
<p
style={{
height: "100px",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
ref={boxRef}
onDragStart={handleDragStart}
onDragOver={handleDragOver}
onDrop={handleDrop}
>
{dayOfMonth}
</p>
)}
</div>
)}
</td>
);
day = addDays(day, 1);
}
rows.push(<tr key={day}>{days}</tr>);
days = [];
}
return rows;
};
const handleNextMonth = () => {
setSelectedDate(addMonths(selectedDate, 1));
};
const handlePreviousMonth = () => {
setSelectedDate(subMonths(selectedDate, 1));
};
return (
<div style={{ width: "100%", display: "flex", flexDirection: "column", alignItems: "center", marginTop: "20px" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", marginBottom: "0px" }}>
<button onClick={handlePreviousMonth} style={{ backgroundColor: "#F5F5F5", color: "#333333", border: "1px solid #CCCCCC", borderRadius: "5px", padding: "5px 10px", marginRight: "10px" }}>Previous Month</button>
<h2 style={{ color: "#333333", margin: 0 }}>{format(selectedDate, "MMMM yyyy")}</h2>
<button onClick={handleNextMonth} style={{ backgroundColor: "#F5F5F5", color: "#333333", border: "1px solid #CCCCCC", borderRadius: "5px", padding: "5px 10px", marginLeft: "10px" }}>Next Month</button>
</div>
<div className="calendar-container">
<table className="calendar-table">
<thead>
<tr>
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
</tr>
</thead>
<tbody>
{generateCalendar()}
</tbody>
</table>
</div>
</div>
);
};
export default RunSheetPreview;
Also I want to also add a functionality to show the drag box only for the dates where data is available for the name and ABN instead of hardcoded it to 1st of date if every month like I did. Any help is appreciated
2
Answers
So, I have made some changes in your code. So want I understood is that, first if I drag one draggable box over other (say 5th one over 15th, then whatever data is in 15th box will be replaced by 5th box data and after that 5th box data will also be removed) so for that I have passed some additional states as props to Draggable box component ( calenddarData, changeName, changeDay, changeSuburb states ).
Then in Draggablebox component you have declared handleDragStart and handleDrop functions both are also updated. In handleDragStart whenever a drag is started I am saving the dragged element data in changeName, changeDay, changeSuburb states.
And then in handleDrop first I am checking whether the Dragged element is dropped on same date or not if not then I just update calendarData.First problem solved.
Now for the second problem, that is dropping draggable box on a date that didnt had its own draggable box (say drag 5th box on 6th date) same logic is used just I have passed handleDragStart handleDrop handleDragOver to the p tag. And you should define these functions in RunSheetPreview Compoenent. As these components are reused you could just pass these as props to the Draggable box component.
As the previous answer is accepted, I didnt know if I update that itself you will get notified about the changes or not as I am new, so I created this new answer.
So, first of all I to distinguish data between month we need to declare another variable month in calendar data ( there is no other way ) and then make changes by checking exact day and month so that changes are only done in a particular month ( Change the useEffect dependencies according to your need, I only executed it for when the page loads, as I dont have the companyData info and other dependencies you used in your question code).
And I have also change the code for filtering the data by creating custom filter so that when you change drag box the change is done only in that particular month.
And I couldnt create the same problem that first box data is not getting filtered.
If you could share the structure of companyData like how data is stored in companyData database ( just 2 months data will be enough ) it will help in recreating the error.
And one more thing, to comment on question you need min 50 rep and I dont have that, so can you contact on this email [email protected] so that I wil be able to message you if I dont understand part of your question.