import React, { useRef, useState, useEffect } from "react"; import { Box, Label, Text, Button, Flex } from "theme-ui"; import * as streamSaver from "streamsaver"; import * as streamPonyfill from "web-streams-polyfill/ponyfill"; import * as Comlink from "comlink"; // Polyfill blob to get use to Blob.stream() on unsupported browsers (Safari) import "blob-polyfill"; import Modal from "../components/Modal"; import LoadingOverlay from "../components/LoadingOverlay"; import LoadingBar from "../components/LoadingBar"; import { useDatabase } from "../contexts/DatabaseContext"; import DatabaseWorker from "worker-loader!../workers/DatabaseWorker"; // eslint-disable-line import/no-webpack-loader-syntax // Add writableStream ponyfill streamSaver.WritableStream = streamSaver.WritableStream || streamPonyfill.WritableStream; const worker = Comlink.wrap(new DatabaseWorker()); function ImportDatabaseModal({ isOpen, onRequestClose }) { const { database } = useDatabase(); const [isLoading, setIsLoading] = useState(false); const backgroundTaskRunningRef = useRef(false); const fileInputRef = useRef(); function openFileDialog() { if (fileInputRef.current) { fileInputRef.current.click(); } } const loadingProgressRef = useRef(0); function handleDBProgress({ completedRows, totalRows }) { loadingProgressRef.current = completedRows / totalRows; } async function handleImportDatabase(file) { setIsLoading(true); backgroundTaskRunningRef.current = true; await database.delete(); await worker.importData(file, Comlink.proxy(handleDBProgress)); setIsLoading(false); backgroundTaskRunningRef.current = false; window.location.reload(); } const fileStreamRef = useRef(); async function handleExportDatabase() { setIsLoading(true); backgroundTaskRunningRef.current = true; const blob = await worker.exportData(Comlink.proxy(handleDBProgress)); setIsLoading(false); const fileStream = streamSaver.createWriteStream( `${new Date().toISOString()}.owlbear`, { size: blob.size, } ); fileStreamRef.current = fileStream; const readableStream = blob.stream(); try { await readableStream.pipeTo(fileStream); } catch (error) { console.error(error); } backgroundTaskRunningRef.current = false; fileStreamRef.current = null; } function handleClose() { if (isLoading) { return; } onRequestClose(); } useEffect(() => { function handleBeforeUnload(event) { if (backgroundTaskRunningRef.current) { event.returnValue = "Database is still processing, are you sure you want to leave?"; } } function handleUnload() { if (fileStreamRef.current) { fileStreamRef.current.abort(); } } window.addEventListener("beforeunload", handleBeforeUnload); window.addEventListener("unload", handleUnload); return () => { window.removeEventListener("beforeunload", handleBeforeUnload); window.removeEventListener("unload", handleUnload); }; }, []); return ( Importing a database will overwrite your current data. handleImportDatabase(event.target.files[0])} type="file" accept=".owlbear" style={{ display: "none" }} ref={fileInputRef} /> {isLoading && ( )} ); } export default ImportDatabaseModal;