const LayoutEditor = ({ layoutId }) => {
	
	// Constants defining grid dimensions
	const rowHeight = 120;
	const gridCols = 6;
	const gridRows = 10;
	
	// Blocks Layout
	const [layout, setLayout] = useState([]);

	// Blocks
	const [blocks, setBlocks] = useState([]);// Current blocks on the grid
	const [blockContent, setBlockContent] = useState([]);// Content(Title) of current block
	const [editingBlock, setEditingBlock] = useState(null);// Currently edited block
	const [newBlockCount, setNewBlockCount] = useState(0);// Counter for new blocks added
	
	// Modals
	const [isModalOpen, setModalOpen] = useState(false);
	const [currentModalType, setCurrentModalType] = useState('');
	
	useEffect(() => {

		const fetchLayout = async () => {
		
			try {
				const layoutData = await fetchLayoutData(layoutId);
				const parsedLayoutData = typeof layoutData === 'string' ? JSON.parse(layoutData) : layoutData;
				const blocks = parsedLayoutData.reduce((acc, layout) => acc.concat(layout.blocks), []);
				
				setLayout(parsedLayoutData);
				setBlocks(blocks);// Set blocks to be used for rendering
			}
			catch (error) {
				
				logger.error('Failed to load layout:', error);
			}
		};
		
		fetchLayout();// Load layout when the component mounts
	}, [layoutId]);
	
	const calculateMaxBlocks = (blockList, newBlockWidth, newBlockHeight) => {
		
		// Create a grid to track occupied spaces
		const occupiedGrid = Array.from({ length: gridRows }, () => Array(gridCols).fill(false));
		
		// Fill the grid with existing blocks
		blockList.forEach(block => {
			
			for (let dy = 0; dy < block.h; dy++) {
				for (let dx = 0; dx < block.w; dx++) {
					
					const gridY = block.y + dy;
					const gridX = block.x + dx;
					
					// Ensure we don't go out of bounds of the grid
					if (gridY < gridRows && gridX < gridCols) {
						
						occupiedGrid[gridY][gridX] = true;
					}
				}
			}
		});
		
		// Count possible placements for the dimensions of the new block
		let maxPossible = 0;
		for (let y = 0; y <= gridRows - newBlockHeight; y++) {
			for (let x = 0; x <= gridCols - newBlockWidth; x++) {
				
				let canPlace = true;
				for (let dy = 0; dy < newBlockHeight; dy++) {
					for (let dx = 0; dx < newBlockWidth; dx++) {
						
						if (occupiedGrid[y + dy][x + dx]) {
							
							canPlace = false;
							break;
						}
					}
					if (!canPlace) {
						
						break;
					}
				}
				if (canPlace) {
					
					maxPossible++;
				}
			}
		}
		
		return maxPossible;
	};
	
	const handleBlockAdd = (width, height, content, id, type) => {
		
		// Calculate the maximum number of blocks that can be added
		const MAX_BLOCKS = calculateMaxBlocks(blocks, width, height);
		
		// If the current number of blocks meets the maximum allowed
		if (blocks.length >= MAX_BLOCKS) {
			
			alert("Maximum number of blocks reached!");
			return;
		}
		
		const newId = `block-${id}-${newBlockCount}`;
		let availablePosition = null;
		
		// Only proceed to find a position if there are available slots left
		if (blocks.length < MAX_BLOCKS) {
			
			// Iterate through each potential starting point in the grid
			for (let y = 0; y <= gridRows - height; y++) {
				for (let x = 0; x <= gridCols - width; x++) {
					
					// Check if new block fits within grid boundaries
					if (x + width <= gridCols && y + height <= gridRows) {
						
						let canPlace = true;
						
						// Check all cells within the dimensions of the new block to ensure they're free
						for (let dy = 0; dy < height; dy++) {
							for (let dx = 0; dx < width; dx++) {
								
								const checkX = x + dx;
								const checkY = y + dy;
								if (checkX < gridCols && checkY < gridRows) {
									
									if (blocks.some(block => 
										(block.x === checkX && block.y === checkY) ||// Exact overlap check
										(block.x < (checkX + width) && block.x + block.w > x &&// Block overlaps horizontally
										block.y < (checkY + height) && block.y + block.h > y)))// Block overlaps vertically
									{
										canPlace = false;
										break;
									}
								}
							}
							// Edit if there's overlap
							if (!canPlace) {
								
								break;
							}
						}
						// If Block can be placed, then set available position
						if (canPlace) {
							
							availablePosition = { x, y, w: width, h: height };
							break;
						}
					}
				}
				// Break the outer loop if a valid position has been found
				if (availablePosition) {
					
					break;
				}
			}
		}
		// If a position is available, add new block to state
		if (availablePosition) {
			
			setBlocks(prevBlocks => [
				...prevBlocks,
				{ i: newId, x: availablePosition.x, y: availablePosition.y, w: width, h: height, content, type }
			]);
			
			// Increment the count of new blocks added
			setNewBlockCount(prevCount => prevCount + 1);
			
			// Update layout with the new block's dimensions and position
			setLayout(prevLayout => [...prevLayout, { i: newId, ...availablePosition, type }]);
		}
		else {
			alert("No available space to add a new block.");
		}
	};
	
	const handleBlockData = (block) => {
		
		setEditingBlock(block);// Set the block that is currently being edited
		setBlockContent(block.content);// Pre-populate with current block content
		setCurrentModalType(block.type);// Set the type based on the block type being edited
		openModal();
	};
	
	const handleBlockRemove = (id) => {
		
		// Update blocks and layout state to remove the block specified by ID
		setBlocks(prevBlocks => prevBlocks.filter(block => block.i !== id));
		setLayout(prevLayout => prevLayout.filter(item => item.i !== id));
	};
	
	const handleBlockDataSave = async (data) => {
	
		logger.log('Data received from Modal:', data);// Log the incoming data
		logger.log('Blocks State:', blocks);// Log current blocks in state
		
		const existingBlock = blocks.find(block => block.i === data.id);
		if (!existingBlock) {
			
			logger.error(`No block found with id: ${data.id}`);
			return;
		}
		
		// Create updated block data based on user input
		const currentTimestamp = new Date().toISOString();// Returns a string in ISO format
		const updatedBlockData = {
			i: existingBlock.i,
			x: existingBlock.x,
			y: existingBlock.y,
			w: existingBlock.w,
			h: existingBlock.h,
			content: data.userInput || existingBlock.content,// Update content based on user input
			type: existingBlock.type,
			createdAt: existingBlock.createdAt || currentTimestamp,
			updatedAt: currentTimestamp
		};
		
		// Update blocks state
		const updatedBlocks = blocks.map(block => (block.i === data.id ? updatedBlockData : block));
		try {
			const dataToSave = {
				id: layoutId,
				blocks: updatedBlocks,
			};
			await saveLayoutData(dataToSave.id, dataToSave);
			
			logger.log('Block data saved.');
		}
		catch (error) {
			
			logger.error('Error saving block data:', error);
		}
		
		// Close the modal after saving
		closeModal();
	};
	
	const handleGridLayoutSave = (newLayout) => {
		
		// Update the layout ensuring the y position does not exceed grid boundaries
		const updatedLayout = newLayout.map(item => ({
			...item,
			y: Math.min(item.y, gridRows - 1),// Ensure y position does not exceed gridRows
		}));
		
		// Update layout state
		setLayout(updatedLayout);
		
		// Validate if the newly set layout items fit within the grid
		const isValidLayout = updatedLayout.every(item => {
			const block = blocks.find(b => b.i === item.i);
			
			return block && item.x + block.w <= gridCols && item.y + block.h <= gridRows;
		});
		if (!isValidLayout) {
			
			logger.warn('New layout exceeds grid boundaries. Changes will not be applied.');
			return;
		}
		
		// Update block states to reflect the new layout
		const updatedBlocks = blocks.map(block => {
			const layoutItem = updatedLayout.find(item => item.i === block.i);
			const currentTimestamp = new Date().toISOString();// Returns a string in ISO format
			
			return layoutItem
				? {
					...block,
					x: layoutItem.x,
					y: layoutItem.y,
					w: layoutItem.w,
					h: layoutItem.h,
					createdAt: block.createdAt,
					updatedAt: currentTimestamp
				}
			: block;// Keep the block unchanged			
		});
		
		// Update the blocks state
		setBlocks(updatedBlocks);
	};
	
	const openModal = () => {
	
		setModalOpen(true);
	};
	
	const closeModal = () => {
		
		setModalOpen(false);
		setEditingBlock(null);// Set block being edited as none
		setBlockContent('');// Reset block content
		setCurrentModalType('');// Reset modal type
	};
	
	logger.log('isModalOpen:', isModalOpen);
	logger.log('editingBlock:', editingBlock);
	logger.log('currentModalType:', currentModalType);
	logger.log('Current blocks:', blocks);
	
	return (
	
		<div className="container-md">

			{/* Create buttons for adding each block size defined in BlocksMap */}
			{BlocksMap.map((size, index) => (
				<button 
					key={index} 
					className="btn btn-primary mb-3 me-2"
					onClick={() => handleBlockAdd(size.width, size.height, size.content, size.id, size.type)}
				>
					Add {size.content}
				</button>
			))}
			
			{/* Pass the constants as props to BlocksGrid */}
			<BlocksGrid 
				layout={layout}
				layoutChange={handleGridLayoutSave}
				blocks={blocks}
				onEdit={handleBlockData}
				onRemove={handleBlockRemove}
				rowHeight={rowHeight}
				//gridHeight={gridHeight}
				gridCols={gridCols}
				gridRows={gridRows}
			/>
			
			{/* Bootstrap Modal for Editing Block Content */}
			{isModalOpen && currentModalType === 'text' && (
				<ModalText
					isOpen={isModalOpen}
					onRequestClose={closeModal}
					blockData={editingBlock}
					onSave={handleBlockDataSave}
				/>
			)}
			
		</div>
	);
};

export default LayoutEditor;


// Wrapping Responsive in WidthProvider to handle width calculations for the grid layout
const ResponsiveGridLayout = WidthProvider(Responsive);

const BlocksGrid = ({ layout, layoutChange, blocks, onEdit, onRemove, rowHeight, gridCols, gridRows }) => {
	
	const renderBlock = (block) => {
		
		switch (block.type) {
		
			case 'text' :
				return <BlockText block={block} onEdit={onEdit} />;
				
			default :
				console.warn(`Unknown Block Type: ${block.type}`);
				return <div>Unknown Block Type: {block.type}</div>;
		}
	};
	
	return (
	
		<ResponsiveGridLayout
			className="layout"
			layouts={layout}
			style={{ minHeight: `${rowHeight * 5}px`, position: 'relative' }}// Minimum height for 5 rows
			breakpoints={{ lg: 1200 }}// Breakpoint to determine layout changes
			cols={{ lg: gridCols }}// Number of columns for the grid
			rowHeight={ rowHeight }// Height of each grid row
			onLayoutChange={ layoutChange }// Function to call on layout change
			isBounded={ false }// Prevent blocks from being dragged outside the grid
			preventCollision={ true }// Prevent collisions when dragging
			isResizable={ false }// Disable resizing of blocks
			draggableHandle=".block-option-drag"// Handle class for dragging
			verticalCompact={ true }
		>
			{blocks.map(block => (
				<div key={block.i} className="block" data-grid={{ i: block.i, x: block.x, y: block.y, w: block.w, h: block.h }}>
				
					<div className="block-header d-flex">
							<div className="block-option-drag flex-grow-1" style={{ cursor: 'move' }}>
								<i className="bi bi-arrows-move"></i>
							</div>
							<div className="block-option-edit">
								<button
									className="btn btn-sm"
									onClick={() => onEdit(block)}
									aria-label="Edit Block"
								>
									<i className="bi bi-pencil"></i>
								</button>
							</div>
							<div className="block-option-remove">
								<button
									className="btn btn-sm"
									onClick={() => onRemove(block.i)}
									aria-label="Remove Block"
								>
									<i className="bi bi-trash"></i>
								</button>
							</div>
						</div>
						
						<div className="block-content d-flex align-items-center justify-content-center">
							{renderBlock(block)}
						</div>
				</div>
			))}
		</ResponsiveGridLayout>
	);
};

export default BlocksGrid;

Uncaught runtime errors:
ERROR
block is undefined
./src/components/main/blocks/BlocksGrid.js/BlocksGrid/

Ive been working on trying to fetchLayout from my indexedDB, fetching works, displaying the json does not. Here how the json array looks:

[
	{
		"id": "layout-1",
		"blocks": [
			{
				"i": "block-text-0",
				"x": 0,
				"y": 0,
				"w": 1,
				"h": 2,
				"content": "Text Block 0",
				"type": "text",
				"createdAt": "2023-10-15T12:34:56Z",
				"updatedAt": "2023-10-16T15:30:00Z"
			},
			{
				"i": "block-text-1",
				"x": 1,
				"y": 0,
				"w": 2,
				"h": 3,
				"content": "Text Block 1",
				"type": "text",
				"createdAt": "2023-10-15T12:34:56Z",
				"updatedAt": "2023-10-16T15:30:00Z"
			}
		]
	},{
		"id": "layout-2",
		"blocks": [
			{
				"i": "block-text-2",
				"x": 2,
				"y": 1,
				"w": 3,
				"h": 2,
				"content": "Text Block 2",
				"type": "text",
				"createdAt": "2023-10-15T12:34:56Z",
				"updatedAt": "2023-10-16T15:30:00Z"
			}
		]
	}
]

I'm calling a layout from id, it should load the layout and then display it.