diff --git a/public/electron.js b/public/electron.js index c216342..20e2965 100644 --- a/public/electron.js +++ b/public/electron.js @@ -3,8 +3,7 @@ const path = require("path"); const fs = require("fs"); const Store = require("electron-store"); var QRCode = require("qrcode"); - -const { app, BrowserWindow, ipcMain } = require("electron"); +const { app, BrowserWindow, ipcMain, dialog } = require("electron"); let mainWindow; const store = new Store(); @@ -30,7 +29,7 @@ function createWindow() { mainWindow.on("closed", () => (mainWindow = null)); } -const historyDirName = "QRsHistory"; +const historyDirName = `${app.getPath("appData")}/QRsHistory`; app.whenReady().then(() => { ipcMain.handle("storage", () => store.get("unicorn")); @@ -61,32 +60,48 @@ ipcMain.on("convertUrlsToQRs", (event, urlsArray) => { const extension = "svg"; - const qrData = urlsArray?.map((url) => { - const urlFilename = url?.replace(/^https?:\/\//, "")?.replaceAll("/", "_"); - const savedPath = `${storagePath}/${urlFilename}.${extension}`; + const qrData = urlsArray + ?.filter((url) => !!url) + ?.map((url) => { + const urlFilename = url + ?.replace(/^https?:\/\//, "") + ?.replaceAll("/", "_"); + const savedPath = `${storagePath}/${urlFilename}.${extension}`; - QRCode.toString(url, { type: extension }, function (err, urlData) { - fs.writeFile(savedPath, urlData, function (err) { - if (err) { - return console.log(err); - } + QRCode.toFile(savedPath, url, { type: extension }, function (err) { + if (err) throw err; }); - }); - - return { - id: url, - file: "file://" + path.resolve(savedPath), - fileName: urlFilename, - extension: extension, - }; - }); - // console.log(qrData); + return { + id: `${url}${Date.now()}`, + file: path.resolve(savedPath), + fileName: urlFilename, + extension: extension, + }; + }); mainWindow.webContents.send("qrData", qrData); - // fs.readFile("path/to/file", (error, data) => { - // // Do something with file contents +}); - // // Send result back to renderer process - // }); +ipcMain.on("saveQRfile", (event, fileData) => { + const options = { + title: "Save QR", + defaultPath: app.getPath("documents"), + filters: [ + { + name: fileData?.fileName, + extensions: [fileData?.extension], + }, + ], + }; + + dialog + .showSaveDialog(mainWindow, options) + .then(({ filePath }) => { + if (!filePath) return; + const origin = fs.createReadStream(fileData?.file, { flags: "r" }); + const destination = fs.createWriteStream(filePath, { flags: "w+" }); + origin.pipe(destination); + }) + .catch((err) => {}); }); diff --git a/public/preload.js b/public/preload.js index 1b48279..d5619e9 100644 --- a/public/preload.js +++ b/public/preload.js @@ -4,13 +4,13 @@ const { contextBridge, ipcRenderer } = require("electron"); contextBridge.exposeInMainWorld("api", { send: (channel, data) => { // whitelist channels - let validChannels = ["convertUrlsToQRs"]; + const validChannels = ["convertUrlsToQRs", "saveQRfile"]; if (validChannels.includes(channel)) { ipcRenderer.send(channel, data); } }, receive: (channel, func) => { - let validChannels = ["qrData"]; + const validChannels = ["qrData", "saveQRfile"]; if (validChannels.includes(channel)) { // Deliberately strip event as it includes `sender` ipcRenderer.on(channel, (event, ...args) => func(...args)); @@ -22,4 +22,3 @@ contextBridge.exposeInMainWorld("api", { return result; }), }); - diff --git a/src/components/DialogOverlay/DialogOverlay.module.scss b/src/components/DialogOverlay/DialogOverlay.module.scss index 8ff818c..06c4557 100644 --- a/src/components/DialogOverlay/DialogOverlay.module.scss +++ b/src/components/DialogOverlay/DialogOverlay.module.scss @@ -50,8 +50,6 @@ height: rem(32); position: absolute; - top: 50%; - transform: translateY(-50%); right: 0; } diff --git a/src/components/Table/QRContentTable.jsx b/src/components/Table/QRContentTable.jsx index 7c424db..4571233 100644 --- a/src/components/Table/QRContentTable.jsx +++ b/src/components/Table/QRContentTable.jsx @@ -16,7 +16,9 @@ import DialogOverlay from "components/DialogOverlay/DialogOverlay"; import useDialog from "hooks/useDialog"; import { StandardDropDown } from "components/DropDown/DropDowns"; -const QRContentTable = ({ rows, handleRows, tableStyles }) => { +import styles from "./QRContentTable.module.scss"; + +const QRContentTable = ({ rows, handleRows }) => { const qrViewDialog = useDialog(); const [qrView, setQrView] = useState(""); @@ -46,7 +48,8 @@ const QRContentTable = ({ rows, handleRows, tableStyles }) => { const newRows = rows.map((row) => { if (row.id === id) { - return { ...row, [name]: value, canBeReverted: true }; + const hasChanged = previous[row.id]?.[name] !== value; + return { ...row, [name]: value, canBeReverted: hasChanged }; } return row; }); @@ -57,14 +60,18 @@ const QRContentTable = ({ rows, handleRows, tableStyles }) => { const handleChangeCell = (row) => (e) => handleChangeRow(e, row); const handleQrPreview = (row) => (e) => { - console.log(row?.file); - setQrView(row?.file); + setQrView(`file://${row?.file}`); qrViewDialog.show(); }; + const handleSaveAs = (row) => (e) => { + console.log("save as"); + window.api.send("saveQRfile", row); + }; + return ( <> - + @@ -79,6 +86,7 @@ const QRContentTable = ({ rows, handleRows, tableStyles }) => { onRevert(row.id)} disabled={!row.canBeReverted} @@ -111,7 +119,10 @@ const QRContentTable = ({ rows, handleRows, tableStyles }) => { {/* add drop down at the above one */} {}}> - + { > Generate - +
+ + {}}> + Save as all + +
); }; diff --git a/src/views/QRGenerator.module.scss b/src/views/QRGenerator.module.scss index 94dec98..657bcf4 100644 --- a/src/views/QRGenerator.module.scss +++ b/src/views/QRGenerator.module.scss @@ -7,10 +7,21 @@ width: 100%; } -.tableContainer{ +.submitButton { + max-width: rem(256); + align-self: center; +} + +.container { flex: 1; + overflow: auto; + + display: flex; + flex-direction: column; + gap: rem(16); } -.submitButton{ - max-width: rem(256); -} \ No newline at end of file +.saveAsButton { + max-width: rem(212); + align-self: flex-end; +}