From dd15837d4d34a324227eee8042e10de5221b7cce Mon Sep 17 00:00:00 2001 From: Ricardo Campos Date: Wed, 22 Jul 2026 14:53:51 +0000 Subject: [PATCH] feat: add closing and saving button to modal. Closes #15 (#16) # What - Closes #15 # Why - Make users life easier.Reviewed-on: https://lightroasted.vps-kinghost.net/rmcampos/tasknote/pulls/16 --- CHANGELOG.md | 10 ++ client/package-lock.json | 18 ---- client/src/components/ModalMarkdown/index.tsx | 23 ++++- client/src/components/ModalMarkdown/style.css | 5 + client/src/views/NoteAdd/index.tsx | 96 +++++++++---------- 5 files changed, 85 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0f7506..8bce83c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## 2026-07-22 + +### Added +- Button to save notes from the preview modal. Closes [#15](https://lightroasted.vps-kinghost.net/rmcampos/tasknote/issues/15) + ### Changed - Removed deployments to staging in PR pipelines. PR only runs CI now. Closes [#14](https://lightroasted.vps-kinghost.net/rmcampos/tasknote/issues/14) ### Removed - Old files from project and moved scripts to `tools` folder. +```bash +# Docker images +docker pull rmcampos/tasknote-app:app-v2026.07.22.? +``` + ## 2026-07-20 ### Changed diff --git a/client/package-lock.json b/client/package-lock.json index d8ba4b4..b6a76d0 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1404,9 +1404,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1423,9 +1420,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1442,9 +1436,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1461,9 +1452,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1480,9 +1468,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1499,9 +1484,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ diff --git a/client/src/components/ModalMarkdown/index.tsx b/client/src/components/ModalMarkdown/index.tsx index 9260e25..aaf6779 100644 --- a/client/src/components/ModalMarkdown/index.tsx +++ b/client/src/components/ModalMarkdown/index.tsx @@ -10,6 +10,8 @@ type Props = { title: string; markdownText: string; onHide: () => void; + onSave?: () => Promise; + saveButtonLabel?: string; }; /** @@ -73,13 +75,18 @@ const ModalMarkdown: React.FC = (props: Props): React.ReactNode => { )} - @@ -87,9 +94,23 @@ const ModalMarkdown: React.FC = (props: Props): React.ReactNode => { variant="outline-primary" onClick={handleCopy} data-testid="modal-copy-button" + className="modal-action-btn" > {copied ? 'Copied!' : 'Copy'} + {props.onSave && ( + + )} ) diff --git a/client/src/components/ModalMarkdown/style.css b/client/src/components/ModalMarkdown/style.css index 690e3b1..036e7ba 100644 --- a/client/src/components/ModalMarkdown/style.css +++ b/client/src/components/ModalMarkdown/style.css @@ -168,6 +168,11 @@ max-height: 60vh; } +.modal-action-btn { + border-radius: 3px; + height: 48px; +} + @media (max-width: 576px) { .markdown-source { font-size: 12px; diff --git a/client/src/views/NoteAdd/index.tsx b/client/src/views/NoteAdd/index.tsx index 2e6f7c2..9231cc6 100644 --- a/client/src/views/NoteAdd/index.tsx +++ b/client/src/views/NoteAdd/index.tsx @@ -201,6 +201,51 @@ function NoteAdd(): React.ReactNode { saveDraft(noteTitle, noteContent, noteUrl, newTags); }; + /** + * Saves the note, either adding a new one or editing an existing one. + * + * @returns {Promise} True if the note was saved successfully, false otherwise. + */ + const saveNote = async (): Promise => { + setValidated(true); + + if (!noteTitle.trim() || !noteContent.trim()) { + setErrorMessage(translateServerResponse('Please fill in all the fields', i18n.language)); + return false; + } + + const finalTags = [...selectedTags]; + if (currentTag.trim()) { + const normalized = currentTag.trim().toLowerCase(); + if (!finalTags.includes(normalized)) { + finalTags.push(normalized); + } + } + + const payload: NoteResponse = { + id: action === 'edit' ? noteId : 0, + title: noteTitle, + description: noteContent, + url: noteUrl, + tags: finalTags, + lastUpdate: '', + shared: false, + shareToken: null + }; + + const saved = action === 'add' + ? await addNote(payload) + : await submitEditNote(payload); + + if (saved) { + clearDraft(); + resetInputs(); + navigate('/home'); + } + + return saved; + }; + /** * Handles the form submission. * @@ -217,54 +262,7 @@ function NoteAdd(): React.ReactNode { return; } - const finalTags = [...selectedTags]; - if (currentTag.trim()) { - const normalized = currentTag.trim().toLowerCase(); - if (!finalTags.includes(normalized)) { - finalTags.push(normalized); - } - } - - if (action === 'add') { - const payload: NoteResponse = { - id: 0, - title: noteTitle, - description: noteContent, - url: noteUrl, - tags: finalTags, - lastUpdate: '', - shared: false, - shareToken: null - }; - - const added: boolean = await addNote(payload); - if (added) { - clearDraft(); - form.reset(); - resetInputs(); - navigate('/home'); - } - } - else if (action === 'edit') { - const payload: NoteResponse = { - id: noteId, - title: noteTitle, - description: noteContent, - url: noteUrl, - tags: finalTags, - lastUpdate: '', - shared: false, - shareToken: null - }; - - const edited: boolean = await submitEditNote(payload); - if (edited) { - clearDraft(); - form.reset(); - resetInputs(); - navigate('/home'); - } - } + await saveNote(); }; /** @@ -569,6 +567,8 @@ function NoteAdd(): React.ReactNode { onHide={handleCloseModal} title={noteTitle} markdownText={noteContent} + onSave={saveNote} + saveButtonLabel={t('note_form_submit')} /> );