// dummyData.json
{
    "layouts": [
        {
            "id": "layout-1",
            "blocks": [
                { "i": "block-text-0", "x": 0, "y": 0, "w": 1, "h": 2, "content": "Text Block 0", "type": "text" },
                { "i": "block-text-1", "x": 1, "y": 0, "w": 2, "h": 3, "content": "Text Block 1", "type": "text" }
            ]
        },
        {
            "id": "layout-2",
            "blocks": [
                { "i": "block-text-2", "x": 2, "y": 1, "w": 3, "h": 2, "content": "Text Block 2", "type": "text" }
            ]
        }
        // Add more layouts as needed...
    ]
}


// src/services/LayoutService.js
import IndexedDB from '../utils/IndexedDB';
import { checkOnlineStatus } from '../utils/Connectivity';
import logger from '../utils/logger';

/**
* Data Structure
*
* 	const blocks = [
* 		{ i: "block-text-0", x: 0, y: 0, w: 1, h: 2, content: "Text Block 0", type: "text", timestamp: Date.now() },
* 		{ i: "block-text-1", x: 1, y: 0, w: 2, h: 3, content: "Text Block 1", type: "text", timestamp: Date.now() },
* 	];
*/
const layoutDB = new IndexedDB('ReactCard', 1);

// .ENV API URL
const API_URL = process.env.REACT_APP_API_URL;
const LOG_LEVEL = process.env.REACT_APP_LOG_LEVEL;

/**
* IndexedDB Broswer Database
* Ensure the database is opened and the store is created
*/
const openDatabase = async () => {
	
	try {
		await layoutDB.initialize();
	}
	catch (error) {
		
		logger.error("Failed to open IndexedDB:", error);
		
		throw error;
	}
};


export const fetchLayoutData = async (layoutId) => {
	
	await openDatabase();// Ensure the IndexedDB is opened
	let response;// Declare 'response' var for scope access
	
	if (LOG_LEVEL === 'deve') {
		
		// Grab dummyData.json from public dir and store in indexedDB, then return
	}
	
	try {
		// Online fetch from the API
		if (checkOnlineStatus()) {
		
			// TODO axios get, put, post, delete
			const response = await fetch(`${API_URL}/api/fetch/${layoutId}`);
			if (!response.ok) {
				
				throw new Error("Failed to fetch layout data from API");
			}
			
			const apiLayoutData = await response.json();
			// Save new layout data in IndexedDB
			await layoutDB.putData('LayoutData', { id: layoutId, blocks: apiLayoutData.blocks });
			return apiLayoutData.blocks;
		}
		// Offline fetch from IndexedDB
		else {
			logger.log("Fetching layout data from IndexedDB");
		
			const storedLayoutData = await layoutDB.getData('Layouts', layoutId);
			return storedLayoutData?.blocks ?? [];// Return blocks or empty array
		}
	}
	catch (error) {
		
		logger.error("Error fetching layout data:", error);
		
		throw error;
	}
	
	
};

export const saveLayoutData = async (layoutId, layoutData) => { };

export const deleteLayoutData = async (layoutId) => { };


//src/utils/IndexedDB.js
import logger from './logger';

class IndexedDB {
	
	constructor(dbName, version) {
		
		this.dbName = dbName;
		this.version = version;
		this.db = null;
	}
	
	/**
	* Initialize the DB connection
	*
	* Example on how to use initialize:
	*
	* 	(async function main() {
	* 		const db = new IndexedDB('myDatabase', 1);
	* 		try {
        * 			await db.initialize();
        * 			const user = { id: 1, name: 'John Doe' };
        * 			await db.putData('UserData', user);
        * 			const retrievedUser = await db.getData('UserData', 1);
        * 			logger.log('Retrieved User:', retrievedUser); 
        * 			db.close();
        * 		}
        * 		catch (error) {
        * 			console.error('An error occurred:', error); // Handling any possible errors
        * 		}
        * 	})();
	*/
	async initialize() {
	
		try {
			await this.open();
			
			logger.log('Database opened successfully.');
		}
		catch (error) {
			
			logger.error('Database failed to open:', error);
			
			throw error;
		}
	}
	
	/**
	* Open
	* Open the database
	*/
	async open() {
		
		if (this.db) {
			
			logger.log('Database is already initialized.');
			
			return this.db;
		}
		
		return new Promise((resolve, reject) => {
			
			const request = indexedDB.open(this.dbName, this.version);
			request.onsuccess = (event) => {
				
				this.db = event.target.result;
				resolve(this.db);
			};
			
			request.onerror = (event) => {
				
				reject(`Error opening DB: ${event.target.errorCode}`);
			};
			
			request.onupgradeneeded = (event) => {
				
				const db = event.target.result;
				/*if (!db.objectStoreNames.contains('UserData')) {
					
					db.createObjectStore('UserData', { keyPath: 'id' });
				}*/
				if (!db.objectStoreNames.contains('LayoutData')) {
					
					db.createObjectStore('LayoutData', { keyPath: 'id' });
				}
				
				// Add additional stores as needed
			};
		});
	}
	
	/**
	* Put
	* Put data into a specified object store
	*/
	async putData(storeName, data) {
		
		this.checkDB();// Ensure the database is initialized
		const transaction = this.db.transaction(storeName, 'readwrite');
		const store = transaction.objectStore(storeName);
		
		return new Promise((resolve, reject) => {
			
			const request = store.put(data);
			request.onsuccess = () => resolve();
			request.onerror = () => reject('Error putting data');
		});
	}
	
	/**
	* Get Data
	* Get data from a specified object store
	*/
	async getData(storeName, id) {
		
		this.checkDB();
		const transaction = this.db.transaction(storeName, 'readonly');
		const store = transaction.objectStore(storeName);
		
		return new Promise((resolve, reject) => {
		
			const request = store.get(id);// Ensure to create the request first
			request.onsuccess = (event) => resolve(event.target.result);
			request.onerror = () => reject('Error getting data');
		});
	}
	
	/**
	* Delete Data
	* Delete data from a specified object store
	*/
	async deleteData(storeName, id) {
		
		this.checkDB();
		const transaction = this.db.transaction(storeName, 'readwrite');
		const store = transaction.objectStore(storeName);
		
		return new Promise((resolve, reject) => {
			
			const request = store.delete(id);// Ensure to create the request first
			request.onsuccess = () => resolve();
			request.onerror = () => reject('Error deleting data');
		});
	}
	
	/**
	* Clear Data
	* Clear data from a specified object store
	*/
	async clearStore(storeName) {
		
		this.checkDB();
		const transaction = this.db.transaction(storeName, 'readwrite');
		const store = transaction.objectStore(storeName);
		
		return new Promise((resolve, reject) => {
			
			const request = store.clear();
			request.onsuccess = () => resolve();
			request.onerror = () => reject('Error clearing the store');
		});
	}
	
	/**
	* Check if Database is open
	*/
	checkDB() {
		
		if (!this.db) {
			
			throw new Error('Database not initialized. Please open it first.');
		}
	}
	
	/**
	* Close the database
	*/
	close() {
		
		if (this.db) {
			
			this.db.close();
			this.db = null;// Clear the db reference
		}
	}
}

export default IndexedDB;


The goal is:
I have a backend database being my api, creating a app that uses indexedDB to store the users app data(so the app can work offline/online).
During the development phase, using dummyData.json to grab and store data into the indexedDB(since the backend is not developed). With 
this design I rely on that the indexedDB is always the most up to date data and then backing it up when the user has a connect. This makes sense
right?