2021-02-05 21:32:38 -05:00
|
|
|
import React, { useState, useEffect, useContext } from "react";
|
2021-04-22 21:46:52 -04:00
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
import Dexie from "dexie";
|
2021-03-19 00:32:17 -04:00
|
|
|
import * as Comlink from "comlink";
|
2020-11-25 23:24:33 -05:00
|
|
|
|
2021-03-17 23:02:13 -04:00
|
|
|
import ErrorBanner from "../components/banner/ErrorBanner";
|
2020-05-03 05:52:01 -04:00
|
|
|
|
|
|
|
import { getDatabase } from "../database";
|
2020-05-03 04:22:09 -04:00
|
|
|
|
2021-03-19 00:32:17 -04:00
|
|
|
import DatabaseWorker from "worker-loader!../workers/DatabaseWorker"; // eslint-disable-line import/no-webpack-loader-syntax
|
|
|
|
|
2021-04-22 21:46:52 -04:00
|
|
|
/**
|
|
|
|
* @typedef DatabaseContext
|
|
|
|
* @property {Dexie|undefined} database
|
|
|
|
* @property {any} worker
|
|
|
|
* @property {string} databaseStatus
|
|
|
|
* @property {Error|undefined} databaseError
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @type {React.Context<undefined|DatabaseContext>}
|
|
|
|
*/
|
2020-05-03 04:22:09 -04:00
|
|
|
const DatabaseContext = React.createContext();
|
|
|
|
|
2021-03-19 00:32:17 -04:00
|
|
|
const worker = Comlink.wrap(new DatabaseWorker());
|
|
|
|
|
2020-05-03 04:22:09 -04:00
|
|
|
export function DatabaseProvider({ children }) {
|
|
|
|
const [database, setDatabase] = useState();
|
2021-06-24 02:14:20 -04:00
|
|
|
// "loading" | "disabled" | "upgrading" | "loaded"
|
2020-05-03 04:22:09 -04:00
|
|
|
const [databaseStatus, setDatabaseStatus] = useState("loading");
|
2020-11-25 23:24:33 -05:00
|
|
|
const [databaseError, setDatabaseError] = useState();
|
2020-05-03 04:22:09 -04:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
// Create a test database and open it to see if indexedDB is enabled
|
|
|
|
let testDBRequest = window.indexedDB.open("__test");
|
2020-10-23 07:16:18 -04:00
|
|
|
testDBRequest.onsuccess = async function () {
|
2020-05-03 04:22:09 -04:00
|
|
|
testDBRequest.result.close();
|
2021-06-24 02:14:20 -04:00
|
|
|
let db = getDatabase(
|
|
|
|
{ autoOpen: false },
|
|
|
|
undefined,
|
|
|
|
undefined,
|
|
|
|
true,
|
2021-06-25 03:43:43 -04:00
|
|
|
() => {
|
2021-06-24 02:14:20 -04:00
|
|
|
setDatabaseStatus("upgrading");
|
|
|
|
}
|
|
|
|
);
|
2020-05-03 04:22:09 -04:00
|
|
|
setDatabase(db);
|
2020-10-23 07:16:18 -04:00
|
|
|
db.on("ready", () => {
|
|
|
|
setDatabaseStatus("loaded");
|
|
|
|
});
|
2021-06-23 23:06:00 -04:00
|
|
|
db.on("versionchange", () => {
|
|
|
|
// When another tab loads a new version of the database refresh the page
|
|
|
|
window.location.reload();
|
|
|
|
});
|
2020-10-23 07:16:18 -04:00
|
|
|
await db.open();
|
2020-05-03 04:22:09 -04:00
|
|
|
window.indexedDB.deleteDatabase("__test");
|
|
|
|
};
|
|
|
|
// If indexedb disabled create an in memory database
|
|
|
|
testDBRequest.onerror = async function () {
|
|
|
|
console.warn("Database is disabled, no state will be saved");
|
|
|
|
const indexedDB = await import("fake-indexeddb");
|
|
|
|
const IDBKeyRange = await import("fake-indexeddb/lib/FDBKeyRange");
|
2020-10-23 07:16:18 -04:00
|
|
|
let db = getDatabase({ indexedDB, IDBKeyRange, autoOpen: false });
|
2020-05-03 04:22:09 -04:00
|
|
|
setDatabase(db);
|
2020-10-23 07:16:18 -04:00
|
|
|
db.on("ready", () => {
|
|
|
|
setDatabaseStatus("disabled");
|
|
|
|
});
|
|
|
|
await db.open();
|
2020-05-03 04:22:09 -04:00
|
|
|
window.indexedDB.deleteDatabase("__test");
|
|
|
|
};
|
2020-11-25 23:24:33 -05:00
|
|
|
|
|
|
|
function handleDatabaseError(event) {
|
2021-03-31 20:48:10 -04:00
|
|
|
event.preventDefault();
|
2021-06-06 05:27:23 -04:00
|
|
|
if (event?.reason?.message?.startsWith("QuotaExceededError")) {
|
2020-11-25 23:24:33 -05:00
|
|
|
setDatabaseError({
|
2021-06-06 05:27:23 -04:00
|
|
|
name: event?.reason?.name,
|
2020-11-25 23:24:33 -05:00
|
|
|
message: "Storage Quota Exceeded Please Clear Space and Try Again.",
|
|
|
|
});
|
2021-03-31 20:48:10 -04:00
|
|
|
} else {
|
|
|
|
setDatabaseError({
|
2021-06-06 05:27:23 -04:00
|
|
|
name: event?.reason?.name,
|
2021-03-31 20:48:10 -04:00
|
|
|
message: "Something went wrong, please refresh your browser.",
|
|
|
|
});
|
2020-11-25 23:24:33 -05:00
|
|
|
}
|
2021-06-06 05:27:23 -04:00
|
|
|
console.error(event?.reason);
|
2020-11-25 23:24:33 -05:00
|
|
|
}
|
|
|
|
window.addEventListener("unhandledrejection", handleDatabaseError);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
window.removeEventListener("unhandledrejection", handleDatabaseError);
|
|
|
|
};
|
2020-05-03 04:22:09 -04:00
|
|
|
}, []);
|
|
|
|
|
|
|
|
const value = {
|
|
|
|
database,
|
|
|
|
databaseStatus,
|
2020-11-25 23:24:33 -05:00
|
|
|
databaseError,
|
2021-03-19 00:32:17 -04:00
|
|
|
worker,
|
2020-05-03 04:22:09 -04:00
|
|
|
};
|
|
|
|
return (
|
|
|
|
<DatabaseContext.Provider value={value}>
|
2020-11-25 23:24:33 -05:00
|
|
|
<>
|
|
|
|
{children}
|
2021-03-17 23:02:13 -04:00
|
|
|
<ErrorBanner
|
|
|
|
error={databaseError}
|
2020-11-25 23:24:33 -05:00
|
|
|
onRequestClose={() => setDatabaseError()}
|
2021-03-17 23:02:13 -04:00
|
|
|
/>
|
2020-11-25 23:24:33 -05:00
|
|
|
</>
|
2020-05-03 04:22:09 -04:00
|
|
|
</DatabaseContext.Provider>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-02-05 21:32:38 -05:00
|
|
|
export function useDatabase() {
|
|
|
|
const context = useContext(DatabaseContext);
|
|
|
|
if (context === undefined) {
|
|
|
|
throw new Error("useDatabase must be used within a DatabaseProvider");
|
|
|
|
}
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
2020-05-03 04:22:09 -04:00
|
|
|
export default DatabaseContext;
|