import initMutinyWallet, { MutinyWallet } from "@mutinywallet/mutiny-wasm"; import { createFileUploader } from "@solid-primitives/upload"; import { createSignal, Show } from "solid-js"; import { Button, ConfirmDialog, InfoBox, InnerCard, NiceP, showToast, SimpleDialog, TextField, VStack } from "~/components"; import { useI18n } from "~/i18n/context"; import { useMegaStore } from "~/state/megaStore"; import { downloadTextFile, eify } from "~/utils"; export function ImportExport(props: { emergency?: boolean }) { const i18n = useI18n(); const [state, _] = useMegaStore(); const [error, setError] = createSignal(); const [exportDecrypt, setExportDecrypt] = createSignal(false); const [password, setPassword] = createSignal(""); async function handleSave() { try { setError(undefined); const json = await MutinyWallet.export_json(); await downloadTextFile(json || "", "mutiny-state.json"); } catch (e) { console.error(e); const err = eify(e); if (err.message === "Incorrect password entered.") { setExportDecrypt(true); } else { setError(err); } } } async function savePassword(e: Event) { e.preventDefault(); try { setError(undefined); if (!password()) { throw new Error( i18n.t( "settings.emergency_kit.import_export.error_password" ) ); } const json = await MutinyWallet.export_json(password()); await downloadTextFile(json || "", "mutiny-state.json"); } catch (e) { console.error(e); setError(eify(e)); } finally { setExportDecrypt(false); setPassword(""); } } function noop() { // noop } const { files, selectFiles } = createFileUploader(); async function importJson() { setConfirmLoading(true); const fileReader = new FileReader(); try { setError(undefined); const file: File = files()[0].file; const text = await new Promise((resolve, reject) => { fileReader.onload = (e) => { const result = e.target?.result?.toString(); if (result) { resolve(result); } else { reject( new Error( i18n.t( "settings.emergency_kit.import_export.error_no_text" ) ) ); } }; fileReader.onerror = (_e) => reject( new Error( i18n.t( "settings.emergency_kit.import_export.error_read_file" ) ) ); fileReader.readAsText(file, "UTF-8"); }); if (state.mutiny_wallet && !props.emergency) { console.log("Mutiny wallet loaded, stopping"); try { await state.mutiny_wallet.stop(); } catch (e) { console.error(e); setError(eify(e)); } } else { // If there's no mutiny wallet loaded we need to initialize WASM console.log("Initializing WASM"); await initMutinyWallet(); } // This should throw if there's a parse error, so we won't end up clearing if (text) { JSON.parse(text); await MutinyWallet.import_json(text); } setTimeout(() => { window.location.href = "/"; }, 1000); } catch (e) { showToast(eify(e)); } finally { setConfirmOpen(false); setConfirmLoading(false); } } async function uploadFile() { selectFiles(async (files) => { if (files.length) { setConfirmOpen(true); return; } }); } const [confirmOpen, setConfirmOpen] = createSignal(false); const [confirmLoading, setConfirmLoading] = createSignal(false); return ( <> {i18n.t("settings.emergency_kit.import_export.tip")} {i18n.t( "settings.emergency_kit.import_export.caveat_header" )} {" "} {i18n.t("settings.emergency_kit.import_export.caveat")}
{error()?.message} setConfirmOpen(false)} > {i18n.t("settings.emergency_kit.import_export.confirm_replace")}{" "} {files()[0].name}? {/* TODO: this is pretty redundant with the DecryptDialog, could make a shared component */}
setPassword(e.currentTarget.value)} error={""} onBlur={noop} onChange={noop} /> {error()?.message}
); }