Skip to content

Commit

Permalink
Merge pull request #61 from ArthurLobopro/total-backup
Browse files Browse the repository at this point in the history
Total backup
  • Loading branch information
ArthurLobopro authored Oct 2, 2023
2 parents 4cd79d7 + 89862af commit f2bcc0c
Show file tree
Hide file tree
Showing 20 changed files with 818 additions and 385 deletions.
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dicionario",
"version": "2.6.4",
"version": "2.7.0",
"description": "Dicionário simples onde você pode cadastrar as palavras que você aprendeu recentemente, fácil e prático.",
"main": "./dist/main/main.js",
"scripts": {
Expand All @@ -21,16 +21,16 @@
"license": "MIT",
"devDependencies": {
"@arthur-lobo/eslint-config": "^1.0.0",
"@electron-forge/cli": "^6.4.1",
"@electron-forge/maker-deb": "^6.4.1",
"@electron-forge/maker-rpm": "^6.4.1",
"@electron-forge/maker-squirrel": "^6.4.1",
"@electron-forge/maker-zip": "^6.4.1",
"@electron-forge/publisher-github": "^6.4.1",
"@electron-forge/cli": "^6.4.2",
"@electron-forge/maker-deb": "^6.4.2",
"@electron-forge/maker-rpm": "^6.4.2",
"@electron-forge/maker-squirrel": "^6.4.2",
"@electron-forge/maker-zip": "^6.4.2",
"@electron-forge/publisher-github": "^6.4.2",
"@types/deep-equal": "^1.0.1",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"electron": "^26.1.0",
"electron": "^26.2.4",
"eslint": "^8.44.0",
"sass-compiler": "^1.3.3",
"svg-react-icon": "^1.0.3",
Expand All @@ -40,16 +40,16 @@
"@arthur-lobo/react-onclickout": "^1.1.1",
"@electron-fonts/nunito": "^1.1.0",
"@electron-fonts/open-sans": "^1.1.0",
"@hookform/resolvers": "^3.2.0",
"@hookform/resolvers": "^3.3.1",
"deep-equal": "^2.2.2",
"electron-frame": "^1.4.5",
"electron-squirrel-startup": "^1.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.4",
"react-router-dom": "^6.15.0",
"react-hook-form": "^7.46.2",
"react-router-dom": "^6.16.0",
"update-electron-app": "^2.0.1",
"zod": "^3.20.6",
"zod-electron-store": "^1.0.2"
"zod": "^3.22.2",
"zod-electron-store": "^1.0.3"
}
}
4 changes: 2 additions & 2 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import UpdateListener from "update-electron-app"
import Store from "zod-electron-store"
import { createJumpList } from "./windowsJumpList"

import { options } from "../store/Store/options"
import { optionsStore } from "../store/Store/options"

import "electron-frame/main"
import "./events"
Expand Down Expand Up @@ -55,7 +55,7 @@ function createWindow() {
height: 600,
minWidth: 800,
minHeight: 600,
frame: isLinux && options.store.linux.useSystemTitleBar,
frame: isLinux && optionsStore.store.linux.useSystemTitleBar,
autoHideMenuBar: true,
show: false,
icon: path.join(appPath, "assets", "icon.png"),
Expand Down
92 changes: 92 additions & 0 deletions src/renderer/components/modals/ExportData.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { zodResolver } from "@hookform/resolvers/zod"
import { ipcRenderer } from "electron"
import { useForm } from "react-hook-form"
import { z } from "zod"
import { SuccessModal } from "."
import { api } from "../../../store/Api"
import { defaultErrorHandler, hookformOnErrorFactory } from "../../ErrorHandler"
import { useModal } from "../../hooks/useModal"
import { FormModal } from "./FormModal"

interface ExportDataModalProps {
onClose: () => void
}

const dataSchema = z.object({
path: z.string().refine((value) => value !== "", {
message: "Escolha um local para exportar o dicionário",
}),
compress: z.boolean().default(true),
})

type data = z.infer<typeof dataSchema>

function getDefaulPath(): string {
return ipcRenderer.sendSync("get-path", "documents")
}

export function ExportDataModal(props: ExportDataModalProps) {
const { setValue, watch, handleSubmit, register } = useForm({
resolver: zodResolver(dataSchema),
defaultValues: {
path: getDefaulPath(),
compress: true,
},
})

const path = watch("path")
const modal = useModal()

function handleExport(data: data) {
try {
api.exporter.exportData(data.path, data.compress)

modal.open(
<SuccessModal
onClose={props.onClose}
message="Dados exportados com sucesso!"
/>,
)
} catch (error) {
defaultErrorHandler(error, modal)
}
}

const handleExportError = hookformOnErrorFactory(modal)

function handlePickFolder() {
const folder = ipcRenderer.sendSync("get-folder")
if (folder === "canceled") return
setValue("path", folder)
}

return (
<FormModal
disableSubmit={path === ""}
title="Exportar dicionário"
onSubmit={handleSubmit(handleExport, handleExportError)}
onClose={props.onClose}
submitText="Exportar"
>
{modal.content}
<div className="flex-column gap-10">
<div className="grid-column-fill-center align-center gap-10">
<span>Salvar em: </span>
<input
type="text"
className="simple"
readOnly
value={path}
title={path}
/>
<button className="simple" type="button" onClick={handlePickFolder}>
Escolher pasta
</button>

<span>Comprimir arquivo</span>
<input type="checkbox" {...register("compress")} />
</div>
</div>
</FormModal>
)
}
170 changes: 170 additions & 0 deletions src/renderer/components/modals/ImportData.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import { ipcRenderer } from "electron/renderer"
import fs from "node:fs"
import { FormEvent, useState } from "react"
import { ErrorModal, SuccessModal, WarningModal } from "."
import { api } from "../../../store/Api"
import {
backupData,
backupDataSchema,
} from "../../../store/ZodSchemas/exportdata"
import { defaultErrorHandler } from "../../ErrorHandler"
import { useModal } from "../../hooks/useModal"
import { If } from "../base"
import { WarningIcon } from "../icons"
import { FormModal } from "./FormModal"

function CheckFileContent(filePath: string) {
const fileContent = fs.readFileSync(filePath, "utf-8")
const json = JSON.parse(fileContent)
const isValid = backupDataSchema.safeParse(json)

if (isValid.success) {
return { isValid: true, data: isValid.data }
}

return { isValid: false }
}

interface ImportDataModalProps {
onClose: () => void
}

export function ImportDataModal(props: ImportDataModalProps) {
const [selectedFile, setSelectedFile] = useState({
path: "",
content: {} as backupData,
})

const [action, setAction] = useState<"merge" | "replace">("merge")

const modal = useModal()

function HandlePickFile() {
setSelectedFile({
path: "",
content: {} as backupData,
})

const file = ipcRenderer.sendSync("get-file")

if (file === "canceled") {
return
}

const check = CheckFileContent(file)

if (!check.isValid) {
return modal.open(
<ErrorModal onClose={modal.close} message="Arquivo inválido" />,
)
}

setSelectedFile({
path: file,
content: check.data as backupData,
})

setAction("merge")
}

const readyToImport = !!selectedFile.path

function HandleSubmit(event: FormEvent) {
event.preventDefault()
event.stopPropagation()

if (!readyToImport) {
return
}

try {
if (action === "merge") {
api.importer.importData(selectedFile.content, action)

modal.open(
<SuccessModal
message="Dados mesclados com sucesso"
onClose={props.onClose}
/>,
)
}

if (action === "replace") {
modal.open(
<WarningModal
title="Você tem certeza?"
children="Você irá perder todos os dados atuais ao realizar essa ação"
onClose={(res) => {
modal.close()

if (res) {
api.importer.importData(selectedFile.content, action)

modal.open(
<SuccessModal
message="Dados substituídos com sucesso"
onClose={props.onClose}
/>,
)
}
}}
/>,
)
}
} catch (error) {
defaultErrorHandler(error, modal)
}
}

return (
<>
{modal.content}
<FormModal
onClose={props.onClose}
title="Importar Dados"
submitText="Importar"
disableSubmit={!readyToImport}
onSubmit={HandleSubmit}
>
<div className="flex-column gap-10">
<span>Arquivo:</span>
<div className="flex gap-10">
<input
type="text"
className="simple"
readOnly
value={selectedFile.path}
/>

<button className="simple" onClick={HandlePickFile} type="button">
Selecionar
</button>
</div>

<If condition={readyToImport}>
<div className="lines">
<span>Tipo de importação:</span>
<select
onChange={(event) => {
setAction(event.target.value as "merge" | "replace")
}}
value={action}
>
<option value="merge">Mesclar</option>
<option value="replace">Substituir</option>
</select>
</div>

<If condition={action === "replace"}>
<span className="warning flex gap-10 align-center">
<WarningIcon />
Ao substituir os dados, todos seus dados anteriores serão
apagados.
</span>
</If>
</If>
</div>
</FormModal>
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function ExportDictionaryModal(props: ExportDictionaryModalProps) {

function handleExport(data: data) {
try {
api.dictionaries.exportDictionary(dictionary.name, data.path)
api.exporter.exportDictionary(dictionary.name, data.path)

modal.open(
<SuccessModal
Expand Down
10 changes: 5 additions & 5 deletions src/renderer/components/modals/dictionary/ImportDictionary.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ipcRenderer } from "electron"
import fs from "node:fs"
import { useRef, useState } from "react"
import { DictionariesController } from "../../../../store/Controllers/Dictionaries"
import { api } from "../../../../store/Api"
import {
dictionary,
dictionarySchema,
Expand Down Expand Up @@ -60,7 +60,7 @@ export function ImportDictionaryModal(props: ImportDictionaryModalProps) {

const alreadyExists =
readyToImport &&
DictionariesController.dictionariesNames.includes(selectedFile.content.name)
api.dictionaries.dictionariesNames.includes(selectedFile.content.name)

const [action, setAction] = useState<"merge" | "rename">("rename")
const [newName, setNewName] = useState("")
Expand Down Expand Up @@ -99,7 +99,7 @@ export function ImportDictionaryModal(props: ImportDictionaryModalProps) {
try {
if (alreadyExists) {
if (action === "merge") {
DictionariesController.mergeDictionary(selectedFile.content)
api.importer.mergeDictionary(selectedFile.content)

return modal.open(
<SuccessModal
Expand All @@ -109,7 +109,7 @@ export function ImportDictionaryModal(props: ImportDictionaryModalProps) {
)
}

DictionariesController.importDictionary({
api.importer.importDictionary({
...selectedFile.content,
name: newName,
})
Expand All @@ -121,7 +121,7 @@ export function ImportDictionaryModal(props: ImportDictionaryModalProps) {
/>,
)
} else {
DictionariesController.importDictionary(selectedFile.content)
api.importer.importDictionary(selectedFile.content)

modal.open(
<SuccessModal
Expand Down
Loading

0 comments on commit f2bcc0c

Please sign in to comment.