From 53f69b7547b082d940fa4bf3a651a516c3d5aa89 Mon Sep 17 00:00:00 2001 From: CasVT Date: Sat, 28 Jan 2023 18:59:27 +0100 Subject: [PATCH] Fixes issue #28 --- backend/db.py | 18 +++++- backend/reminders.py | 41 +++++++----- backend/templates.py | 30 +++++---- frontend/api.py | 71 +++++++++++++++------ frontend/static/css/add_edit.css | 30 ++++++++- frontend/static/css/general.css | 4 +- frontend/static/css/reminders_templates.css | 3 +- frontend/static/js/add.js | 41 +++++++++++- frontend/static/js/edit.js | 17 ++++- frontend/static/js/reminders.js | 3 + frontend/static/js/templates.js | 42 ++++++++++-- frontend/templates/reminders.html | 16 ++++- 12 files changed, 255 insertions(+), 61 deletions(-) diff --git a/backend/db.py b/backend/db.py index 54a1667..6333578 100644 --- a/backend/db.py +++ b/backend/db.py @@ -8,7 +8,7 @@ from typing import Union from flask import g -__DATABASE_VERSION__ = 2 +__DATABASE_VERSION__ = 3 class Singleton(type): _instances = {} @@ -79,7 +79,17 @@ def migrate_db(current_db_version: int) -> None: for reminder in reminders: new_reminders_append([round((datetime.fromtimestamp(reminder[0]) - utc_offset).timestamp()), reminder[1]]) cursor.executemany("UPDATE reminders SET time = ? WHERE id = ?;", new_reminders) - __DATABASE_VERSION__ = 2 + current_db_version = 2 + + if current_db_version == 2: + # V2 -> V3 + cursor.executescript(""" + ALTER TABLE reminders + ADD color VARCHAR(7); + ALTER TABLE templates + ADD color VARCHAR(7); + """) + current_db_version = 3 return @@ -115,6 +125,8 @@ def setup_db() -> None: repeat_interval INTEGER, original_time INTEGER, + color VARCHAR(7), + FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (notification_service) REFERENCES notification_services(id) ); @@ -125,6 +137,8 @@ def setup_db() -> None: text TEXT, notification_service INTEGER NOT NULL, + color VARCHAR(7), + FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (notification_service) REFERENCES notification_services(id) ); diff --git a/backend/reminders.py b/backend/reminders.py index 97ced51..d07167a 100644 --- a/backend/reminders.py +++ b/backend/reminders.py @@ -156,7 +156,8 @@ class Reminder: r.notification_service, ns.title AS notification_service_title, r.repeat_quantity, - r.repeat_interval + r.repeat_interval, + r.color FROM reminders r INNER JOIN notification_services ns @@ -176,7 +177,8 @@ class Reminder: notification_service: int = None, text: str = None, repeat_quantity: Literal["year", "month", "week", "day", "hours", "minutes"] = None, - repeat_interval: int = None + repeat_interval: int = None, + color: str = None ) -> dict: """Edit the reminder @@ -185,6 +187,9 @@ class Reminder: time (int): The new UTC epoch timestamp the the reminder should be send. Defaults to None. notification_service (int): The new id of the notification service to use to send the reminder. Defaults to None. text (str, optional): The new body of the reminder. Defaults to None. + repeat_quantity (Literal["year", "month", "week", "day", "hours", "minutes"], optional): The new quantity of the repeat specified for the reminder. Defaults to None. + repeat_interval (int, optional): The new amount of repeat_quantity, like "5" (hours). Defaults to None. + color (str, optional): The new hex code of the color of the reminder, which is shown in the web-ui. Defaults to None. Returns: dict: The new reminder info @@ -212,10 +217,11 @@ class Reminder: 'notification_service': notification_service, 'text': text, 'repeat_quantity': repeat_quantity, - 'repeat_interval': repeat_interval + 'repeat_interval': repeat_interval, + 'color': color } for k, v in new_values.items(): - if k in ('repeat_quantity', 'repeat_interval') or v is not None: + if k in ('repeat_quantity', 'repeat_interval', 'color') or v is not None: data[k] = v # Update database @@ -224,7 +230,7 @@ class Reminder: next_time = data["time"] cursor.execute(""" UPDATE reminders - SET title=?, text=?, time=?, notification_service=?, repeat_quantity=?, repeat_interval=? + SET title=?, text=?, time=?, notification_service=?, repeat_quantity=?, repeat_interval=?, color=? WHERE id = ?; """, ( data["title"], @@ -233,13 +239,14 @@ class Reminder: data["notification_service"], data["repeat_quantity"], data["repeat_interval"], + data["color"], self.id )) else: next_time = _find_next_time(data["time"], data["repeat_quantity"], data["repeat_interval"]) cursor.execute(""" UPDATE reminders - SET title=?, text=?, time=?, notification_service=?, repeat_quantity=?, repeat_interval=?, original_time=? + SET title=?, text=?, time=?, notification_service=?, repeat_quantity=?, repeat_interval=?, original_time=?, color=? WHERE id = ?; """, ( data["title"], @@ -249,6 +256,7 @@ class Reminder: data["repeat_quantity"], data["repeat_interval"], data["time"], + data["color"], self.id )) except IntegrityError: @@ -284,7 +292,7 @@ class Reminders: sort_by (Literal["time", "time_reversed", "title", "title_reversed"], optional): How to sort the result. Defaults to "time". Returns: - List[dict]: The id, title, text, time, notification_service and notification_service_title of each reminder + List[dict]: The id, title, text, time, notification_service, notification_service_title and color of each reminder """ sort_function = self.sort_functions.get( sort_by, @@ -300,7 +308,8 @@ class Reminders: r.notification_service, ns.title AS notification_service_title, r.repeat_quantity, - r.repeat_interval + r.repeat_interval, + r.color FROM reminders r INNER JOIN notification_services ns @@ -350,7 +359,8 @@ class Reminders: notification_service: int, text: str = '', repeat_quantity: Literal["year", "month", "week", "day", "hours", "minutes"] = None, - repeat_interval: int = None + repeat_interval: int = None, + color: str = None ) -> Reminder: """Add a reminder @@ -361,6 +371,7 @@ class Reminders: text (str, optional): The body of the reminder. Defaults to ''. repeat_quantity (Literal["year", "month", "week", "day", "hours", "minutes"], optional): The quantity of the repeat specified for the reminder. Defaults to None. repeat_interval (int, optional): The amount of repeat_quantity, like "5" (hours). Defaults to None. + color (str, optional): The hex code of the color of the reminder, which is shown in the web-ui. Defaults to None. Returns: dict: The info about the reminder @@ -377,15 +388,15 @@ class Reminders: try: if repeat_quantity is None and repeat_interval is None: id = get_db().execute(""" - INSERT INTO reminders(user_id, title, text, time, notification_service) - VALUES (?,?,?,?,?); - """, (self.user_id, title, text, time, notification_service) + INSERT INTO reminders(user_id, title, text, time, notification_service, color) + VALUES (?,?,?,?,?, ?); + """, (self.user_id, title, text, time, notification_service, color) ).lastrowid else: id = get_db().execute(""" - INSERT INTO reminders(user_id, title, text, time, notification_service, repeat_quantity, repeat_interval, original_time) - VALUES (?, ?, ?, ?, ?, ?, ?, ?); - """, (self.user_id, title, text, time, notification_service, repeat_quantity, repeat_interval, time) + INSERT INTO reminders(user_id, title, text, time, notification_service, repeat_quantity, repeat_interval, original_time, color) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); + """, (self.user_id, title, text, time, notification_service, repeat_quantity, repeat_interval, time, color) ).lastrowid except IntegrityError: raise NotificationServiceNotFound diff --git a/backend/templates.py b/backend/templates.py index efe22ab..4f82364 100644 --- a/backend/templates.py +++ b/backend/templates.py @@ -27,7 +27,8 @@ class Template: SELECT id, title, text, - notification_service + notification_service, + color FROM templates WHERE id = ?; """, @@ -39,7 +40,8 @@ class Template: def update(self, title: str = None, notification_service: int = None, - text: str = None + text: str = None, + color: str = None ) -> dict: """Edit the template @@ -47,6 +49,7 @@ class Template: title (str): The new title of the entry. Defaults to None. notification_service (int): The new id of the notification service to use to send the reminder. Defaults to None. text (str, optional): The new body of the template. Defaults to None. + color (str, optional): The new hex code of the color of the template, which is shown in the web-ui. Defaults to None. Returns: dict: The new template info @@ -57,21 +60,23 @@ class Template: new_values = { 'title': title, 'notification_service': notification_service, - 'text': text + 'text': text, + 'color': color } for k, v in new_values.items(): - if v is not None: + if k in ('color',) or v is not None: data[k] = v try: cursor.execute(""" UPDATE templates - SET title=?, notification_service=?, text=? + SET title=?, notification_service=?, text=?, color=? WHERE id = ?; """, ( data['title'], data['notification_service'], data['text'], + data['color'], self.id )) except IntegrityError: @@ -95,13 +100,14 @@ class Templates: """Get all templates Returns: - List[dict]: The id, title, text and notification_service + List[dict]: The id, title, text, notification_service and color """ templates: list = list(map(dict, get_db(dict).execute(""" SELECT id, title, text, - notification_service + notification_service, + color FROM templates WHERE user_id = ? ORDER BY title, id; @@ -126,7 +132,8 @@ class Templates: self, title: str, notification_service: int, - text: str = '' + text: str = '', + color: str = None ) -> Template: """Add a template @@ -134,16 +141,17 @@ class Templates: title (str): The title of the entry notification_service (int): The id of the notification service to use to send the reminder. text (str, optional): The body of the reminder. Defaults to ''. + color (str, optional): The hex code of the color of the template, which is shown in the web-ui. Defaults to None. Returns: Template: The info about the template """ try: id = get_db().execute(""" - INSERT INTO templates(user_id, title, text, notification_service) - VALUES (?,?,?,?); + INSERT INTO templates(user_id, title, text, notification_service, color) + VALUES (?,?,?,?,?); """, - (self.user_id, title, text, notification_service) + (self.user_id, title, text, notification_service, color) ).lastrowid except IntegrityError: raise NotificationServiceNotFound diff --git a/frontend/api.py b/frontend/api.py index c6e9d13..ba977e3 100644 --- a/frontend/api.py +++ b/frontend/api.py @@ -3,6 +3,7 @@ from os import urandom from time import time as epoch_time from typing import Any, Tuple +from re import compile from flask import Blueprint, g, request @@ -20,6 +21,7 @@ from backend.users import User, register_user api = Blueprint('api', __name__) api_key_map = {} +color_regex = compile(r'#[0-9a-f]{6}') """ AUTHENTICATION: @@ -104,6 +106,10 @@ def extract_key(values: dict, key: str, check_existence: bool=True) -> Any: 'text', 'query'): if not isinstance(value, str): raise InvalidKeyValue(key, value) + + elif key == 'color': + if not color_regex.search(value): + raise InvalidKeyValue(key, value) else: if key == 'sort_by': @@ -127,7 +133,7 @@ def api_login(): Requires being logged in: No Methods: POST: - Parameters (body (content-type: application/json)): + Parameters (body): username (required): the username of the user account password (required): the password of the user account Returns: @@ -216,7 +222,7 @@ def api_add_user(): Requires being logged in: No Methods: POST: - Parameters (body (content-type: application/json)): + Parameters (body): username (required): the username of the new user account password (required): the password of the new user account Returns: @@ -248,7 +254,7 @@ def api_manage_user(): Methods: PUT: Description: Change the password of the user account - Parameters (body (content-type: application/json)): + Parameters (body): new_password (required): the new password of the user account Returns: 200: @@ -297,7 +303,7 @@ def api_notification_services_list(): The id, title and url of every notification service POST: Description: Add a notification service - Parameters (body (content-type: application/json)): + Parameters (body): title (required): the title of the notification service url (required): the apprise url of the notification service Returns: @@ -340,7 +346,7 @@ def api_notification_service(n_id: int): No notification service found with the given id PUT: Description: Edit the notification service - Parameters (body (content-type: application/json)): + Parameters (body): title: The new title of the entry. url: The new apprise url of the entry. Returns: @@ -396,16 +402,17 @@ def api_reminders_list(): sort_by: how to sort the result. Allowed values are 'title', 'title_reversed', 'time' and 'time_reversed' Returns: 200: - The id, title, text, time, notification_service, notification_service_title, repeat_quantity and repeat_interval of each reminder + The id, title, text, time, notification_service, notification_service_title, repeat_quantity, repeat_interval and color of each reminder POST: Description: Add a reminder - Parameters (body (content-type: application/json)): + Parameters (body): title (required): the title of the reminder time (required): the UTC epoch timestamp that the reminder should be sent at notification_service (required): the id of the notification service to use to send the notification text: the body of the reminder repeat_quantity ('year', 'month', 'week', 'day', 'hours', 'minutes'): The quantity of the repeat_interval repeat_interval: The number of the interval + color: The hex code of the color of the reminder, which is shown in the web-ui Returns: 200: The info about the new reminder entry @@ -427,13 +434,15 @@ def api_reminders_list(): text = extract_key(data, 'text', check_existence=False) repeat_quantity = extract_key(data, 'repeat_quantity', check_existence=False) repeat_interval = extract_key(data, 'repeat_interval', check_existence=False) + color = extract_key(data, 'color', check_existence=False) result = reminders.add(title=title, time=time, notification_service=notification_service, text=text, repeat_quantity=repeat_quantity, - repeat_interval=repeat_interval) + repeat_interval=repeat_interval, + color=color) return return_api(result.get(), code=201) @api.route('/reminders/search', methods=['GET']) @@ -463,6 +472,24 @@ def api_reminders_query(): @error_handler @auth def api_test_reminder(): + """ + Endpoint: /reminders/test + Description: Test send a reminder draft + Requires being logged in: Yes + Methods: + GET: + Parameters (body): + title (required): The title of the entry. + notification_service (required): The new id of the notification service to use to send the reminder. + text: The body of the reminder. + Returns: + 201: + The reminder is sent (doesn't mean it works, just that it was sent) + 400: + KeyNotFound: One of the required parameters was not given + 404: + NotificationServiceNotFound: The notification service given was not found + """ data = request.get_json() title = extract_key(data, 'title') notification_service = extract_key(data, 'notification_service') @@ -491,13 +518,14 @@ def api_get_reminder(r_id: int): No reminder found with the given id PUT: Description: Edit the reminder - Parameters (body (content-type: application/json)): + Parameters (body): title: The new title of the entry. time: The new UTC epoch timestamp the the reminder should be send. notification_service: The new id of the notification service to use to send the reminder. text: The new body of the reminder. - repeat_quantity ('year', 'month', 'week', 'day', 'hours', 'minutes'): The quantity of the repeat_interval - repeat_interval: The number of the interval + repeat_quantity ('year', 'month', 'week', 'day', 'hours', 'minutes'): The new quantity of the repeat_interval. + repeat_interval: The new number of the interval. + color: The new hex code of the color of the reminder, which is shown in the web-ui. Returns: 200: Reminder updated successfully @@ -524,14 +552,15 @@ def api_get_reminder(r_id: int): text = extract_key(data, 'text', check_existence=False) repeat_quantity = extract_key(data, 'repeat_quantity', check_existence=False) repeat_interval = extract_key(data, 'repeat_interval', check_existence=False) - + color = extract_key(data, 'color', check_existence=False) result = reminders.fetchone(r_id).update(title=title, time=time, notification_service=notification_service, text=text, repeat_quantity=repeat_quantity, - repeat_interval=repeat_interval) + repeat_interval=repeat_interval, + color=color) return return_api(result) elif request.method == 'DELETE': @@ -555,13 +584,14 @@ def api_get_templates(): Description: Get a list of all templates Returns: 200: - The id, title, notification_service and text of every template + The id, title, notification_service, text and color of every template POST: Description: Add a template - Parameters (body (content-type: application/json)): + Parameters (body): title (required): the title of the template notification_service (required): the id of the notification service to use to send the notification text: the body of the template + color: the hex code of the color of the template, which is shown in the web-ui Returns: 200: The info about the new template entry @@ -579,10 +609,12 @@ def api_get_templates(): title = extract_key(data, 'title') notification_service = extract_key(data, 'notification_service') text = extract_key(data, 'text', check_existence=False) + color = extract_key(data, 'color', check_existence=False) result = templates.add(title=title, notification_service=notification_service, - text=text) + text=text, + color=color) return return_api(result.get(), code=201) @api.route('/templates/', methods=['GET', 'PUT', 'DELETE']) @@ -605,10 +637,11 @@ def api_get_template(t_id: int): No template found with the given id PUT: Description: Edit the template - Parameters (body (content-type: application/json)): + Parameters (body): title: The new title of the entry. notification_service: The new id of the notification service to use to send the reminder. text: The new body of the template. + color: The new hex code of the color of the template. Returns: 200: Template updated successfully @@ -633,10 +666,12 @@ def api_get_template(t_id: int): title = extract_key(data, 'title', check_existence=False) notification_service = extract_key(data, 'notification_service', check_existence=False) text = extract_key(data, 'text', check_existence=False) + color = extract_key(data, 'color', check_existence=False) result = template.update(title=title, notification_service=notification_service, - text=text) + text=text, + color=color) return return_api(result) elif request.method == 'DELETE': diff --git a/frontend/static/css/add_edit.css b/frontend/static/css/add_edit.css index 2fca5a7..179971b 100644 --- a/frontend/static/css/add_edit.css +++ b/frontend/static/css/add_edit.css @@ -33,6 +33,7 @@ width: calc(50% - (var(--gap) / 2)); } +.form-container > form > button, .sub-inputs > button { display: flex; justify-content: center; @@ -54,6 +55,32 @@ opacity: 0; } +.color-list { + display: flex; + justify-content: center; + align-items: center; + gap: 1rem; + flex-wrap: wrap; + + padding: 1rem; + border: 2px solid var(--color-gray); + border-radius: 4px; + box-shadow: var(--default-shadow); +} + +.color-list > button { + height: 1.5rem; + width: 1.5rem; + + padding: 1rem; + border: 1px solid transparent; + background-color: var(--color); +} + +.color-list > button[data-selected='true'] { + border-color: var(--color-white); +} + .repeat-bar, .repeat-edit-bar { display: flex; @@ -134,7 +161,8 @@ div.options > button { @media (max-width: 460px) { .sub-inputs > input, - .sub-inputs > select { + .sub-inputs > select, + .sub-inputs > button { width: 100%; } } \ No newline at end of file diff --git a/frontend/static/css/general.css b/frontend/static/css/general.css index dabaaa5..71d45c6 100644 --- a/frontend/static/css/general.css +++ b/frontend/static/css/general.css @@ -11,8 +11,8 @@ --color-gray: #3c3c3c; --color-dark: #1b1b1b; - --color-error: rgb(219, 84, 97); - --color-success: rgb(84, 219, 104); + --color-error: #db5461; + --color-success: #54db68; --header-height: 4.5rem; --nav-width: 4rem; diff --git a/frontend/static/css/reminders_templates.css b/frontend/static/css/reminders_templates.css index 5ec7de9..f518152 100644 --- a/frontend/static/css/reminders_templates.css +++ b/frontend/static/css/reminders_templates.css @@ -84,6 +84,7 @@ } .entry { + --color: var(--color-gray); width: var(--entry-width); height: 6rem; position: relative; @@ -95,7 +96,7 @@ border-radius: 4px; padding: .75rem; - background-color: var(--color-gray); + background-color: var(--color); } button.entry.fit { diff --git a/frontend/static/js/add.js b/frontend/static/js/add.js index da48db9..6d1d668 100644 --- a/frontend/static/js/add.js +++ b/frontend/static/js/add.js @@ -1,8 +1,10 @@ +const colors = ["#3c3c3c", "#49191e", "#171a42", "#083b06", "#3b3506", "#300e40"]; const inputs = { 'title': document.getElementById('title-input'), 'time': document.getElementById('time-input'), 'notification_service': document.getElementById('notification-service-input'), - 'text': document.getElementById('text-input') + 'text': document.getElementById('text-input'), + 'color': document.querySelector('#add .color-list') }; const type_buttons = { @@ -22,7 +24,11 @@ function addReminder() { 'title': inputs.title.value, 'time': (new Date(inputs.time.value) / 1000) + (new Date(inputs.time.value).getTimezoneOffset() * 60), 'notification_service': inputs.notification_service.value, - 'text': inputs.text.value + 'text': inputs.text.value, + 'color': null + }; + if (!inputs.color.classList.contains('hidden')) { + data['color'] = inputs.color.querySelector('button[data-selected="true"]').dataset.color; }; if (type_buttons['repeat-button'].dataset.selected === 'true') { data['repeat_quantity'] = type_buttons['repeat-quantity'].value; @@ -69,6 +75,9 @@ function closeAdd() { hideWindow(); setTimeout(() => { document.getElementById('template-selection').value = document.querySelector('#template-selection option[selected]').value; + if (!inputs.color.classList.contains('hidden')) { + toggleColor(inputs.color); + }; inputs.title.value = ''; inputs.time.value = ''; inputs.notification_service.value = document.querySelector('#notification-service-input option[selected]').value; @@ -78,6 +87,31 @@ function closeAdd() { }, 500); }; +function loadColor() { + document.querySelectorAll('.color-list').forEach(list => { + colors.forEach(color => { + const entry = document.createElement('button'); + entry.dataset.color = color; + entry.title = color; + entry.type = 'button'; + entry.style.setProperty('--color', color); + entry.addEventListener('click', e => selectColor(list, color)) + list.appendChild(entry); + }); + }); +}; + +function selectColor(list, color_code) { + list.querySelector(`button[data-color="${color_code}"]`).dataset.selected = 'true'; + list.querySelectorAll(`button:not([data-color="${color_code}"])`).forEach(b => b.dataset.selected = 'false'); + return; +} + +function toggleColor(list) { + selectColor(list, colors[0]); + list.classList.toggle('hidden'); +} + function toggleNormal() { type_buttons['normal-button'].dataset.selected = 'true'; type_buttons['repeat-button'].dataset.selected = 'false'; @@ -133,7 +167,10 @@ function testReminder() { document.getElementById('add-form').setAttribute('action', 'javascript:addReminder();'); document.getElementById('template-selection').addEventListener('change', e => loadTemplate()); +document.getElementById('color-toggle').addEventListener('click', e => toggleColor(inputs.color)); document.getElementById('normal-button').addEventListener('click', e => toggleNormal()); document.getElementById('repeat-button').addEventListener('click', e => toggleRepeated()); document.getElementById('close-add').addEventListener('click', e => closeAdd()); document.getElementById('test-reminder').addEventListener('click', e => testReminder()); + +loadColor(); diff --git a/frontend/static/js/edit.js b/frontend/static/js/edit.js index a93f52f..9b0fb30 100644 --- a/frontend/static/js/edit.js +++ b/frontend/static/js/edit.js @@ -2,7 +2,8 @@ const edit_inputs = { 'title': document.getElementById('title-edit-input'), 'time': document.getElementById('time-edit-input'), 'notification_service': document.getElementById('notification-service-edit-input'), - 'text': document.getElementById('text-edit-input') + 'text': document.getElementById('text-edit-input'), + 'color': document.querySelector('#edit .color-list') }; const edit_type_buttons = { @@ -22,7 +23,11 @@ function editReminder() { 'notification_service': edit_inputs.notification_service.value, 'text': edit_inputs.text.value, 'repeat_quantity': null, - 'repeat_interval': null + 'repeat_interval': null, + 'color': null + }; + if (!edit_inputs.color.classList.contains('hidden')) { + data['color'] = edit_inputs.color.querySelector('button[data-selected="true"]').dataset.color; }; if (edit_type_buttons['repeat-edit-button'].dataset.selected === 'true') { data['repeat_quantity'] = edit_type_buttons['repeat-edit-quantity'].value; @@ -65,6 +70,13 @@ function showEdit(id) { return response.json(); }) .then(json => { + if (json.result['color'] !== null) { + if (edit_inputs.color.classList.contains('hidden')) { + toggleColor(edit_inputs.color); + }; + selectColor(edit_inputs.color, json.result['color']); + }; + edit_inputs.title.value = json.result.title; var trigger_date = new Date( @@ -142,6 +154,7 @@ function deleteReminder() { // code run on load document.getElementById('edit-form').setAttribute('action', 'javascript:editReminder();'); +document.getElementById('color-edit-toggle').addEventListener('click', e => toggleColor(edit_inputs.color)); document.getElementById('normal-edit-button').addEventListener('click', e => toggleEditNormal()); document.getElementById('repeat-edit-button').addEventListener('click', e => toggleEditRepeated()); document.getElementById('close-edit').addEventListener('click', e => hideWindow()); diff --git a/frontend/static/js/reminders.js b/frontend/static/js/reminders.js index 5f05675..9399fc0 100644 --- a/frontend/static/js/reminders.js +++ b/frontend/static/js/reminders.js @@ -7,6 +7,9 @@ function fillTable(result) { entry.classList.add('entry'); entry.dataset.id = reminder.id; entry.addEventListener('click', e => showEdit(reminder.id)); + if (reminder.color !== null) { + entry.style.setProperty('--color', reminder.color); + }; const title = document.createElement('h2'); title.innerText = reminder.title; diff --git a/frontend/static/js/templates.js b/frontend/static/js/templates.js index cb9672f..c5993d0 100644 --- a/frontend/static/js/templates.js +++ b/frontend/static/js/templates.js @@ -1,13 +1,15 @@ const template_inputs = { 'title': document.getElementById('title-template-input'), 'notification-service': document.getElementById('notification-service-template-input'), - 'text': document.getElementById('text-template-input') + 'text': document.getElementById('text-template-input'), + 'color': document.querySelector('#add-template .color-list') }; const edit_template_inputs = { 'title': document.getElementById('title-template-edit-input'), 'notification-service': document.getElementById('notification-service-template-edit-input'), - 'text': document.getElementById('text-template-edit-input') + 'text': document.getElementById('text-template-edit-input'), + 'color': document.querySelector('#edit-template .color-list') }; function loadTemplates(force=true) { @@ -68,6 +70,9 @@ function loadTemplate() { inputs.title.value = ''; inputs.notification_service.value = document.querySelector('#notification-service-input option[selected]').value; inputs.text.value = ''; + if (!inputs.color.classList.contains('hidden')) { + toggleColor(inputs.color); + }; } else { fetch(`/api/templates/${id}?api_key=${api_key}`) .then(response => { @@ -81,6 +86,16 @@ function loadTemplate() { inputs.title.value = json.result.title; inputs.notification_service.value = json.result.notification_service; inputs.text.value = json.result.text; + if (json.result.color !== null) { + if (inputs.color.classList.contains('hidden')) { + toggleColor(inputs.color); + }; + selectColor(inputs.color, json.result.color); + } else { + if (!inputs.color.classList.contains('hidden')) { + toggleColor(inputs.color); + }; + }; }) .catch(e => { if (e === 401) { @@ -96,7 +111,11 @@ function addTemplate() { const data = { 'title': template_inputs.title.value, 'notification_service': template_inputs["notification-service"].value, - 'text': template_inputs.text.value + 'text': template_inputs.text.value, + 'color': null + }; + if (!template_inputs.color.classList.contains('hidden')) { + data['color'] = template_inputs.color.querySelector('button[data-selected="true"]').dataset.color; }; fetch(`/api/templates?api_key=${api_key}`, { 'method': 'POST', @@ -128,6 +147,9 @@ function closeAddTemplate() { template_inputs.title.value = ''; template_inputs['notification-service'].value = document.querySelector('#notification-service-template-input option[selected]').value; template_inputs.text.value = ''; + if (!template_inputs.color.classList.contains('hidden')) { + toggleColor(inputs.color); + }; }, 500); }; @@ -145,6 +167,12 @@ function showEditTemplate(id) { edit_template_inputs.title.value = json.result.title; edit_template_inputs['notification-service'].value = json.result.notification_service; edit_template_inputs.text.value = json.result.text; + if (json.result.color !== null) { + if (edit_template_inputs.color.classList.contains('hidden')) { + toggleColor(edit_template_inputs.color); + }; + selectColor(edit_template_inputs.color, json.result.color); + }; showWindow('edit-template'); }) .catch(e => { @@ -161,7 +189,11 @@ function saveTemplate() { const data = { 'title': edit_template_inputs.title.value, 'notification_service': edit_template_inputs['notification-service'].value, - 'text': edit_template_inputs.text.value + 'text': edit_template_inputs.text.value, + 'color': null + }; + if (!edit_template_inputs.color.classList.contains('hidden')) { + data['color'] = edit_template_inputs.color.querySelector('button[data-selected="true"]').dataset.color; }; fetch(`/api/templates/${id}?api_key=${api_key}`, { 'method': 'PUT', @@ -211,7 +243,9 @@ function deleteTemplate() { // code run on load document.getElementById('template-form').setAttribute('action', 'javascript:addTemplate();'); +document.getElementById('color-template-toggle').addEventListener('click', e => toggleColor(template_inputs.color)); document.getElementById('close-template').addEventListener('click', e => closeAddTemplate()); document.getElementById('template-edit-form').setAttribute('action', 'javascript:saveTemplate()'); +document.getElementById('color-template-edit-toggle').addEventListener('click', e => toggleColor(edit_template_inputs.color)); document.getElementById('close-edit-template').addEventListener('click', e => hideWindow()); document.getElementById('delete-template').addEventListener('click', e => deleteTemplate()); diff --git a/frontend/templates/reminders.html b/frontend/templates/reminders.html index 518f378..018ecf1 100644 --- a/frontend/templates/reminders.html +++ b/frontend/templates/reminders.html @@ -137,9 +137,13 @@

Add a reminder

- +
+ + +
+
@@ -191,6 +195,8 @@

Edit a reminder

+ +
@@ -302,6 +308,8 @@

Add a template

+ + @@ -316,6 +324,8 @@

Edit a template

+ +