UNPKG

slanted-gamedev-toolz

Version:

A slanted mix of tools for your brilliant ideas in game design.

218 lines (217 loc) 11.2 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useCallback, useLayoutEffect, useRef, useState, } from "react"; import { ToastContainer, toast } from "react-toastify"; import { btnSx, jsxCss } from "../../theme/jsxCssClassics"; import { colors } from "../../theme/palettes/colors"; import { saveStringToastConfig, standardToastConfig, } from "../../theme/toastConfig"; import { getLocalizedTextRaw } from "../LocalizationSelect/useLocalization"; import { HexBtn } from "../buttons/HexBtn/HexBtn"; import { CopySaveStringToast } from "./CopySaveStringToast"; import { LoadFileBtns } from "./LoadFileBtns"; import { LoadGameInstruction } from "./LoadGameInstruction"; import { TextAreaSaveString } from "./TextAreaSaveString"; import { importExportSaveLocalization } from "./constants/ImportExportLocalization"; import { saveKeys } from "./constants/SAVE_KEYS"; import { useImportExportLocalStorageActions } from "./stores/importExportLocalStorageStore"; import { compressObjectWithPako, decompressStringWithPako, } from "./utils/saveStringUtil"; export const ImportExportLocalStorage = ({ defaultData }) => { const hasShownToastOnSave = useRef(false); const [saveString, setSaveString] = useState(""); const { setIsLoading, handleResetGame } = useImportExportLocalStorageActions(); const fileInputRef = useRef(null); const [showResetConfirmation, setShowResetConfirmation] = useState(false); // notifications const showLoadError = useCallback((src) => { console.error("invalid Save file", src); setIsLoading(false); toast(_jsx("div", { style: { textAlign: "center", width: "100%" }, children: getLocalizedTextRaw(importExportSaveLocalization.invalidSave) }), standardToastConfig); }, [setIsLoading]); const showLoadSuccess = useCallback(() => { setTimeout(() => { window.location.reload(); }, 1000); toast(_jsx("div", { style: { textAlign: "center", width: "100%" }, children: getLocalizedTextRaw(importExportSaveLocalization.saveLoading) }), standardToastConfig); }, []); const importLocalStorageFromFile = (file) => { if (!file) { console.error("No file selected."); return; } const reader = new FileReader(); reader.onload = (event) => { try { const importedData = decompressStringWithPako(event.target?.result); if (!importedData) { showLoadError("File: !importedData"); return; } const hasdata = importedData.hasOwnProperty(saveKeys.data); const isValidSave = hasdata; if (!isValidSave) { showLoadError(`File: missing ${saveKeys.data}`); return; } for (const key in importedData) { if (importedData.hasOwnProperty(key)) { localStorage.setItem(key, importedData[key]); } } window.location.reload(); } catch (error) { showLoadError("File: error"); console.error("Error importing local storage data:", error); } }; reader.readAsText(file); }; const handleFileChange = (event) => { const file = event.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (loadEvent) => { try { const importedData = decompressStringWithPako(loadEvent.target?.result); // Check if the importedData is a valid JSON object if (importedData && typeof importedData === "object") { importLocalStorageFromFile(file); } else { showLoadError("handleFileChange: !importedData"); console.error("Invalid JSON format."); } } catch (error) { showLoadError("handleFileChange: error"); console.error("Error parsing JSON:", error); } }; reader.readAsText(file); } }; // WEB FILE SAVE const exportLocalStorageAsFile = useCallback(() => { const localStorageData = compressObjectWithPako(localStorage); const blob = new Blob([localStorageData], { type: "application/json" }); const a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = `turnBasedBoxingSave.txt`; a.click(); }, []); const loadGameFromFile = useCallback(() => { setIsLoading(true); fileInputRef.current?.click(); }, [setIsLoading]); // STRING SAVE const exportLocalStorageAsString = useCallback(() => { // Convert localStorage to a regular JSON object const localStorageData = {}; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); if (key !== null) { // Ensure the key is not null // @ts-ignore localStorageData[key] = localStorage.getItem(key); } } const localStorageString = compressObjectWithPako(localStorageData); setSaveString(localStorageString); // Set the save string first // Copy to clipboard return navigator.clipboard .writeText(localStorageString) .then(() => { if (!hasShownToastOnSave.current) { hasShownToastOnSave.current = true; toast(_jsx(CopySaveStringToast, {}), saveStringToastConfig); } return localStorageString; // Return the value to ensure then() resolves with something }) .catch((err) => { console.error("Unable to copy to clipboard", err); throw err; // Ensure the error is propagated in the Promise chain }); }, []); const loadGameFromString = useCallback(async () => { if (!saveString || typeof saveString !== "string") { showLoadError("String: !saveString"); return; } const importedData = decompressStringWithPako(saveString); if (importedData && typeof importedData === "object") { const hasdata = importedData.hasOwnProperty(saveKeys.data); const isValidSave = hasdata; if (!isValidSave) { showLoadError(`String: missing ${saveKeys.data}`); return; } setIsLoading(true); // Assuming localStorageData is an object for (const key in importedData) { const isdata = key === saveKeys.data; if (!isdata) { console.log("skip loading.. additional key detected", key); } // @ts-ignore localStorage.setItem(key, importedData[key]); } showLoadSuccess(); } else { showLoadError("String: error"); console.error("Invalid Load String."); } }, [setIsLoading, saveString, showLoadError, showLoadSuccess]); const handleChangeSaveString = (event) => { setSaveString(event.target.value); }; // RESET const resetGame = () => { if (!showResetConfirmation) { setShowResetConfirmation(true); return; } setShowResetConfirmation(false); handleResetGame(); }; useLayoutEffect(() => { // Initialize Data if (!localStorage.getItem(saveKeys.data)) { localStorage.setItem(saveKeys.data, compressObjectWithPako(defaultData)); } }, [defaultData]); const sx = { ...btnSx, marginBottom: "10px", color: showResetConfirmation ? "red" : "white", width: showResetConfirmation ? "150px" : "100px", }; return (_jsxs(_Fragment, { children: [_jsx(ToastContainer, { position: "top-center", toastStyle: { border: "4px solid grey", borderRadius: "12px", minHeight: "initial", backgroundColor: "rgb(1,1,1,0.9)", boxSizing: "border-box", }, autoClose: 5000, hideProgressBar: false, newestOnTop: false, closeOnClick: true, rtl: false, pauseOnFocusLoss: true, draggable: false, pauseOnHover: true, theme: "dark", limit: 1 }), _jsxs("div", { style: { ...jsxCss.centerSpill, width: "100%", margin: "10px auto", border: `4px solid ${colors.absoluteBlack}`, boxSizing: "border-box", borderRadius: "12px", color: colors.azureBlue, backgroundColor: colors.blackestBlack, padding: "0px 12px", }, children: [_jsx("input", { type: "file", ref: fileInputRef, onChange: handleFileChange, accept: ".txt", style: { display: "none" } }), _jsxs("div", { style: { ...jsxCss.centerStack, width: "100%", margin: "10px auto 40px auto", }, children: [showResetConfirmation ? (_jsx("p", { id: "warning", style: { marginTop: "220px" }, children: getLocalizedTextRaw(importExportSaveLocalization.warningClearSave) })) : null, _jsx("div", { children: showResetConfirmation ? null : (_jsxs(_Fragment, { children: [_jsx(LoadGameInstruction, {}), _jsx(TextAreaSaveString, { saveString: saveString, handleChangeSaveString: handleChangeSaveString }), _jsxs("div", { style: { display: "flex", justifyContent: "center", flexWrap: "wrap", background: "black", borderRadius: "0px 0px 10px 10px", }, children: [_jsx(HexBtn, { label: getLocalizedTextRaw(importExportSaveLocalization.copySave), onClick: exportLocalStorageAsString, highlight: colors.lime }), _jsx(HexBtn, { label: getLocalizedTextRaw(importExportSaveLocalization.loadSave), onClick: loadGameFromString, highlight: colors.lime }), _jsx(LoadFileBtns, { loadGameFromFile: loadGameFromFile, exportLocalStorageAsFile: exportLocalStorageAsFile })] })] })) }), _jsxs("div", { style: { padding: 10 }, children: [_jsx(HexBtn, { onClick: resetGame, label: showResetConfirmation ? getLocalizedTextRaw(importExportSaveLocalization.clearDataNewGame) : getLocalizedTextRaw(importExportSaveLocalization.newGame) }), showResetConfirmation ? (_jsx(HexBtn, { onClick: () => setShowResetConfirmation(false), label: getLocalizedTextRaw(importExportSaveLocalization._cancel) })) : null] })] })] })] })); };