So I am using canvas in react and as i drag and drop my board icon, when i click it, it brings me to a new canvas. On the first canvas(canvas id: 1), I drag and drop my board or with a text that i created. Clicking to that board, i am navigated to a new canvas again (canvas id: 2) and i drag and drop my board icon with some text/label i created. Now, when i turn back to my previous canvas (canvas id: 1), the text/label disappears or prompts me to write the label/text again. Clicking on the board that takes me to canvas id: 2, the text/label disappears as well. It’s like everytime i leave this canvas and return, the saved label/text disappears.
import Navbar from "../components/Navbar"
import { PlusCircleIcon, ArrowUturnLeftIcon, WindowIcon, TrashIcon} from
'@heroicons/react/24/solid';
import StickyNote2Icon from '@mui/icons-material/StickyNote2';
import {Link, useLocation} from "react-router-dom";
import InfiniteCanvas from "../components/InfiniteCanvas";
import { useState, useEffect, useMemo} from "react";
type IconData = {
id: string;
type: string;
x: number;
y: number;
text: string;
showInput: boolean;
isLabel?: boolean;
showIcon: boolean;
dropped?: boolean;
};
type Entry = {
id: string;
description: string[]
}
export default function TruthJournal(){
const [icons, setIcons] = useState<IconData[]>([
{ id: "note", type: "note", x: 50, y: 12, text: "", showInput: false, showIcon:
true },
{ id: "delicious", type: "delicious", x: 110, y: 10, text: "", showInput: false,
showIcon: true},
]);
const [showCanvas, setShowCanvas] = useState(true);
const [canvasId, setCanvasId] = useState(1);
const [previousCanvasIds, setPreviousCanvasIds] = useState<number[]>([]);
const location = useLocation();
const entries: Entry[] = useMemo(() => {
return location.state?.entries || [];
}, [location.state?.entries]);
const loadIcons = (id: number) => {
const savedIcons = localStorage.getItem(`icons-${id}`);
if (savedIcons) {
setIcons(JSON.parse(savedIcons));
} else {
setIcons([]);
}
};
useEffect(() => {
const savedCanvasIds = localStorage.getItem("canvas-ids");
if (savedCanvasIds) {
const parsedIds = JSON.parse(savedCanvasIds);
setPreviousCanvasIds(parsedIds);
setCanvasId(parsedIds[parsedIds.length - 1] || 1);
}
}, []);
useEffect(() => {
if (canvasId) {
loadIcons(canvasId);
}
}, [canvasId]);
const handleCreateNewCanvas = () => {
setCanvasId((prevId) => {
const newCanvasId = prevId + 1;
setPreviousCanvasIds((prev) => {
const updatedIds = [...prev, newCanvasId];
localStorage.setItem("canvas-ids", JSON.stringify(updatedIds));
return updatedIds;
});
setIcons([]);
return newCanvasId;
});
setShowCanvas(true);
};
const handleBackClick = () => {
if (previousCanvasIds.length > 1) {
const prevIndex = previousCanvasIds.indexOf(canvasId) - 1;
if (prevIndex >= 0) {
setCanvasId(previousCanvasIds[prevIndex]);
}
}
}
const handleMouseDown = (e: React.MouseEvent) => {
console.log("Mouse down", e);
};
const handleMouseMove = (e: React.MouseEvent) => {
console.log("Mouse move", e);
};
const handleMouseUp = () => {
console.log("Mouse up");
};
const handleWheel = (e: React.WheelEvent) => {
console.log("Mouse wheel", e);
};
const handleDragOver = (e: React.DragEvent<HTMLCanvasElement>) => {
e.preventDefault();
};
const handleDrop = (e: React.DragEvent<HTMLCanvasElement>) => {
e.preventDefault();
const imageType = e.dataTransfer.getData("image-type");
const canvasBounds = e.currentTarget.getBoundingClientRect();
const mouseX = e.clientX - canvasBounds.left;
const mouseY = e.clientY - canvasBounds.top;
if (imageType) {
const newIcon = {
id: `${imageType}-${Date.now()}`,
type: imageType,
x: mouseX,
y: mouseY,
text: "",
showInput: imageType === "note",
isLabel: imageType === "delicious" ,
showIcon: imageType !== "note",
dropped: true
};
const updatedIcons = [...icons, newIcon];
setIcons(updatedIcons);
localStorage.setItem(`icons-${canvasId}`, JSON.stringify(updatedIcons));
}
}
const handleDragStart = (e: React.DragEvent<HTMLDivElement>, imageType: string) => {
e.dataTransfer.setData("image-type", imageType);
console.log(`Drag started with type: ${imageType}`);
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>, id: string) => {
setIcons((prevIcons) =>
prevIcons.map((icon) =>
icon.id === id ? { ...icon, text: e.target.value } : icon
)
);
};
console.log(showCanvas);
useEffect(() => {
const savedIcons = localStorage.getItem("icons");
if (savedIcons) {
setIcons(JSON.parse(savedIcons));
}
}, []);
useEffect(() => {
if (entries.length > 0) {
setIcons((prevIcons) => {
const updatedIcons = entries.map((entry, index) => {
const generateRandomPosition = () => {
const canvasWidth = window.innerWidth;
const canvasHeight = window.innerHeight;
return {
x: Math.floor(Math.random() * (canvasWidth - 100)),
y: Math.floor(Math.random() * (canvasHeight - 100)),
};
};
const isOverlapping = (x: number, y: number, icons: IconData[]) => {
const margin = 20;
return icons.some(
(icon) =>
Math.abs(icon.x - x) < margin && Math.abs(icon.y - y) < margin
);
};
let position = generateRandomPosition();
while (isOverlapping(position.x, position.y, prevIcons)) {
position = generateRandomPosition();
}
return {
id: `entry-${entry.id || index}`,
type: "note",
x: position.x,
y: position.y,
text: entry.description.join(", "),
showInput: true,
showIcon: false,
isLabel: false,
dropped: true,
};
});
return [...prevIcons, ...updatedIcons];
});
}
}, [entries]);
return (
<>
<div className="bg-customYellow h-[100vh] ref={divRef} overflow-hidden">
<Navbar
Journal='Journal'
Community = 'Community'
About = 'About'
/>
<div className="bg-customYellow relative top-[3rem] w-full" >
{showCanvas &&
(
<InfiniteCanvas
width={window.innerWidth}
height={window.innerHeight}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onWheel={handleWheel}
onDragOver={handleDragOver}
onDrop={handleDrop}
/>
)}
<div className="w-full h-[3em] flex items-center justify-between pt-5 relative bottom-[40em]">
{icons.map((icon) => (
<div key={icon.id} className="w-[15%] flex items-center justify-center gap-2 object-contain ">
{icon.showInput ? (
<input
type="text"
value={icon.text}
onChange={(e) => handleInputChange(e, icon.id)}
autoFocus
style={{ left: `${icon.x}px`, top: `${icon.y}px` }}
className="absolute font-annie pl-3 placeholder-white text-[12px] text-white border-none bg-customBrown w-[18rem] h-[3rem]"
placeholder="Enter text"
/>
) : icon.isLabel && (
<div
className="absolute bottom-0 left-0 text-sm"
style={{ top: `${icon.y + 30}px`, left: `${icon.x}px` }}
>
<input
type="text"
value={icon.text}
onChange={(e) => handleInputChange(e, icon.id)}
autoFocus
className="font-annie placeholder-customBrown text-[12px] text-center border-none text-customBrown bg-transparent w-[5rem] relative top-3 right-[1.50rem] focus:border-none focus:outline-none"
placeholder="Enter text"
/>
</div>
)}
{icon.showIcon && (
<div
onClick={handleCreateNewCanvas}
draggable="true"
onDragStart={(e) => handleDragStart(e, icon.type)}
className="w-[2.5rem] h-[2.5rem] object-contain border-box absolute"
style={{
left: `${icon.x}px`,
top: `${icon.y}px`,
width: "2rem",
height: "3rem",
}}
>
{icon.type === "note" ? (
<StickyNote2Icon sx={{ width: "2rem", height: "3rem" }} className="w-[2rem] h-[3rem]"/>
) : icon.type === "delicious" ? (
<WindowIcon className="w-[2rem] h-[3rem]" />
) : null}
</div>
)}
</div>
))}
<TrashIcon className="absolute w-[2rem] h-[3rem] right-[83.5%]"/>
<div className="mr-3 flex gap-3">
<ArrowUturnLeftIcon onClick={handleBackClick} className="w-8 h-8 fill-customBrown"/>
<Link to="/journalentrythree">
<PlusCircleIcon className="w-9 h-9 fill-customBrown"/>
</Link>
</div>
</div>
</div>
</div>
</div>
</>
)
}
I tried using local storage to save the data but still it resets every time i return to a specific canvas page.