diff --git a/backend/dao/activitiesDao.js b/backend/dao/activitiesDao.js index c63cee1..76e2740 100644 --- a/backend/dao/activitiesDao.js +++ b/backend/dao/activitiesDao.js @@ -4,14 +4,13 @@ const daoHelper = require('./daoHelper.js'); class activitiesDao { + /** + * @param {import('better-sqlite3').Database} dbConnection - The database connection + */ constructor(dbConnection) { this._conn = dbConnection; } - getConnection() { - return this._conn; - } - loadById(id) { var sql = 'SELECT * FROM activities WHERE id=? ORDER BY date DESC'; var statement = this._conn.prepare(sql); diff --git a/backend/dao/plantsDao.js b/backend/dao/plantsDao.js index b3009eb..6e7692a 100644 --- a/backend/dao/plantsDao.js +++ b/backend/dao/plantsDao.js @@ -2,16 +2,19 @@ const helper = require('../helper.js'); const daoHelper = require('./daoHelper.js'); + +/** + * Data Access Object for plants + */ class plantsDao { + /** + * @param {import('better-sqlite3').Database} dbConnection - The database connection + */ constructor(dbConnection) { this._conn = dbConnection; } - getConnection() { - return this._conn; - } - loadById(plant_id) { var sql = 'SELECT * FROM plants WHERE plant_id=?'; var statement = this._conn.prepare(sql); @@ -24,8 +27,25 @@ class plantsDao { return result; } + /** + * Loads all plants from the DB + * Ignores plants that have been composted + * @returns {json[]} + */ loadAll() { - var sql = 'SELECT * from plants order by name'; + var sql = 'SELECT * FROM plants WHERE composted IS NULL ORDER BY name'; + var statement = this._conn.prepare(sql); + var result = statement.all(); + var arrayResult = daoHelper.guaranteeArray(result); + return arrayResult; + } + + /** + * Loads all composted plants from the DB + * @returns {json[]} + */ + loadAllComposted() { + var sql = 'SELECT * FROM plants WHERE composted IS NOT NULL ORDER BY name'; var statement = this._conn.prepare(sql); var result = statement.all(); var arrayResult = daoHelper.guaranteeArray(result); @@ -58,10 +78,10 @@ class plantsDao { return this.loadById(result.lastInsertRowid); } - update(plant_id, name, species_name, image, watering_interval, watering_interval_offset) { - var sql = 'UPDATE plants SET name=?, species_name=?, image=?, watering_interval=?, watering_interval_offset=? WHERE plant_id=?'; + update(plant_id, name, species_name, image, watering_interval, watering_interval_offset, composted) { + var sql = 'UPDATE plants SET name=?, species_name=?, image=?, watering_interval=?, watering_interval_offset=?, composted=? WHERE plant_id=?'; var statement = this._conn.prepare(sql); - var params = [name, species_name, image, watering_interval, watering_interval_offset, plant_id]; + var params = [name, species_name, image, watering_interval, watering_interval_offset, composted, plant_id]; var result = statement.run(params); if (result.changes != 1){ diff --git a/backend/dao/templateDao.js b/backend/dao/templateDao.js index 53ee64b..5024c8b 100644 --- a/backend/dao/templateDao.js +++ b/backend/dao/templateDao.js @@ -5,14 +5,13 @@ const helper = require('../helper.js'); class templateDao { + /** + * @param {import('better-sqlite3').Database} dbConnection - The database connection + */ constructor(dbConnection) { this._conn = dbConnection; } - getConnection() { - return this._conn; - } - loadById(id) { // Code goes here diff --git a/backend/dbMigrationTool.js b/backend/dbMigrationTool.js index 76b7995..defa4c0 100644 --- a/backend/dbMigrationTool.js +++ b/backend/dbMigrationTool.js @@ -1,17 +1,46 @@ /** * Checks if the DB is from an earlier version and needs to be upgraded - * @param {*} dbConnection the connection to the DB + * @param {import('better-sqlite3').Database} dbConnection the connection to the DB * @returns {boolean} false if the DB is fine and true if it needs to be migrated */ module.exports.dbNeedsMigration = function(dbConnection) { - // TODO implement this when necessary + // ============== Check requirement for v1.0.1 ============== + const columnExists = dbConnection.prepare(` + PRAGMA table_info(plants) + `).all().some(col => col.name === 'composted'); + + if(!columnExists) + { + return true; + } + + // ============== Check requirement for v.. ============== + // ... + + // All good return false; } /** * Migrates the DB to the current schema - * @param {*} dbConnection the connection to the DB + * @param {import('better-sqlite3').Database} dbConnection the connection to the DB */ module.exports.migrateDB = function(dbConnection) { - // TODO implement this when necessary + // ============== Upgrade from v1.0.0 to v1.1.0 ============== + // Add 'composted' column to 'plants' table if it does not exist + const columnExists = dbConnection.prepare(` + PRAGMA table_info(plants) + `).all().some(col => col.name === 'composted'); + + if (!columnExists) { + dbConnection.prepare(` + ALTER TABLE plants ADD COLUMN composted DATE DEFAULT NULL + `).run(); + console.log("Column 'composted' added to 'plants' table."); + } else { + console.log("Column 'composted' already exists in 'plants' table."); + } + + // ============== Upgrade from v1.0.0 to v.. ============== + // ... } \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 4525d30..1ca65c6 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "plant_manager", - "version": "0.1.0", + "version": "1.1.0", "description": "Backend for PlantManager with fileupload and sqlite", "main": "server.js", "scripts": { diff --git a/backend/server.js b/backend/server.js index a5f6333..df61ab9 100644 --- a/backend/server.js +++ b/backend/server.js @@ -73,7 +73,7 @@ try // ====== BINDING ENDPOINTS ====== const TOPLEVELPATH = '/api'; let serviceRouter; - console.log('Binding enpoints, top level Path at ' + TOPLEVELPATH); + console.log('Binding endpoints, top level Path at ' + TOPLEVELPATH); serviceRouter = require('./services/plants.js'); app.use(TOPLEVELPATH, serviceRouter); diff --git a/backend/services/plants.js b/backend/services/plants.js index 567e03c..5bf0686 100644 --- a/backend/services/plants.js +++ b/backend/services/plants.js @@ -104,6 +104,26 @@ serviceRouter.get('/plants/get/:id', function(request, response) { } }); +serviceRouter.get('/plants/composted', function(request, response) { + console.log('Service plants: Client requested all records'); + + const plantDaoInstance = new plantsDao(request.app.locals.dbConnection); + const activitiesDaoInstance = new activitiesDao(request.app.locals.dbConnection); + try { + var plantArr = plantDaoInstance.loadAllComposted(); + // foreach Schleife über alle plant JSON, diese werden dabei erweitert + plantArr.forEach(plant => { + extendPlantJSON(plant,activitiesDaoInstance); + }); + + console.log('Service plants: Records loaded, count= ' + plantArr.length); + response.status(200).json(plantArr); + } catch (ex) { + console.error('Service plants: Error loading all records. Exception occured: ' + ex.message); + response.status(400).json({ 'fehler': true, 'nachricht': ex.message }); + } +}); + serviceRouter.get('/plants/all', function(request, response) { console.log('Service plants: Client requested all records'); @@ -185,6 +205,7 @@ serviceRouter.post('/plants', function(request, response) { serviceRouter.put('/plants', function(request, response) { console.log('Service plants: Client requested update of existing plant'); + // TODO Replace this madness with a validation Framework like express validator const plantDaoInstance = new plantsDao(request.app.locals.dbConnection); var errorMsgs=[]; if (helper.isUndefined(request.body.plant_id)) { @@ -194,29 +215,35 @@ serviceRouter.put('/plants', function(request, response) { } else if (request.body.plant_id <= 0) { errorMsgs.push('plant_id has to be a bigger number than 0'); } + if (helper.isUndefined(request.body.name)) { errorMsgs.push('name missing'); - } + } + if (helper.isUndefined(request.body.species_name)) { errorMsgs.push('species_name missing'); } + if (helper.isUndefined(request.body.watering_interval)) { errorMsgs.push('watering_interval missing'); } else if (!helper.isNumeric(request.body.watering_interval)) { errorMsgs.push('watering_interval has to be a number'); } else if (request.body.watering_interval <= 0) { - errorMsgs.push('watering_interval has to be a bigger number than 0'); + errorMsgs.push('watering_interval has to be a number bigger than 0'); } + if (helper.isUndefined(request.body.watering_interval_offset)) { errorMsgs.push('watering_interval_offset missing'); } else if (!helper.isNumeric(request.body.watering_interval_offset)) { errorMsgs.push('watering_interval has to be a number'); } + if (errorMsgs.length > 0) { console.log('Service plants: Update not possible, data missing or invalid'); response.status(400).json({ 'fehler': true, 'nachricht': 'Function not possible. Missing or invalid data: ' + helper.concatArray(errorMsgs) }); return; } + try { // check if the plant even exists if(!plantDaoInstance.exists(request.body.plant_id)) @@ -230,7 +257,7 @@ serviceRouter.put('/plants', function(request, response) { let image = plantDaoInstance.loadById(request.body.plant_id).image; // update the plant - var obj = plantDaoInstance.update(request.body.plant_id,request.body.name, request.body.species_name,image,request.body.watering_interval,request.body.watering_interval_offset); + var obj = plantDaoInstance.update(request.body.plant_id,request.body.name, request.body.species_name,image,request.body.watering_interval,request.body.watering_interval_offset,request.body.composted); console.log('Service plants: Record updated, plant_id=' + request.body.plant_id); response.status(200).json(obj); } catch (ex) { diff --git a/docs/API.md b/docs/API.md index 3425f61..792abc5 100644 --- a/docs/API.md +++ b/docs/API.md @@ -79,6 +79,11 @@ Alle HTTP Aufrufe sind englisch und kleingeschrieben! - GET - `…/api/plants/all` - Liefert alle JSON Objekte vom Typ Plant + - Pflanzen die kompostiert wurden werden nicht berücksichtigt +- GET + - `…/api/plants/composted` + - Liefert alle JSON Objekte vom Typ Plant + - Nur Pflanzen die kompostiert wurden werden berücksichtigt - GET - `…/api/plants/exists/[id]` - Prüft nach, ob ein Objekt vom Typ Plant unter dieser [id] existiert @@ -110,7 +115,8 @@ Beispiel: "watering_interval_calculated": 11, "days_since_watering": 10, "days_until_watering": 1, - "repotted": "2023-03-14" + "repotted": "2023-03-14", + "composted": null } ``` ### Attribute @@ -178,6 +184,12 @@ Beispiel: - Durch Backend berechneter Wert - Datum des letzten Umtopfen - Wenn noch nie umgetopft Datum des hinzufügens +- composted + - Typ: Text(Datum) + - Pflichtfeld bei: nie + - Nullbar: ja + - Datum des soften-löschens + - Wenn die Pflanze noch nicht soft-gelöscht wurde null ## Activities - GET diff --git a/frontend/.dockerignore b/frontend/.dockerignore index 12e03c3..3ca437f 100644 --- a/frontend/.dockerignore +++ b/frontend/.dockerignore @@ -3,4 +3,5 @@ npm-debug.log Dockerfile .dockerignore jsconfig.json -eslint.config.mjs \ No newline at end of file +eslint.config.mjs +*/dev/* \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index f88f368..bf2cfb4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "plant_manager_frontend", - "version": "1.0.0", + "version": "1.1.0", "description": "Frontend for PlantManager", "main": "client.js", "scripts": { diff --git a/frontend/public/css/style.css b/frontend/public/css/style.css index 8774651..7f35275 100644 --- a/frontend/public/css/style.css +++ b/frontend/public/css/style.css @@ -91,6 +91,10 @@ main { background-color: white !important; } +.list-group-item { + background-color: white !important; +} + .text-water { color: var(--qd-color-water); } diff --git a/frontend/public/detailseite_pflanze.html b/frontend/public/detailseite_pflanze.html index c881906..87aef9d 100644 --- a/frontend/public/detailseite_pflanze.html +++ b/frontend/public/detailseite_pflanze.html @@ -42,6 +42,9 @@ + @@ -60,15 +63,15 @@
-
Loading...
- Lade Planze + Lade Pflanze

-

diff --git a/frontend/public/imageUploadTest.html b/frontend/public/dev/imageUploadTest.html similarity index 100% rename from frontend/public/imageUploadTest.html rename to frontend/public/dev/imageUploadTest.html diff --git a/frontend/public/dev/index.html b/frontend/public/dev/index.html new file mode 100644 index 0000000..d122a6b --- /dev/null +++ b/frontend/public/dev/index.html @@ -0,0 +1,69 @@ + + + + + + + + + Plant Manager + + + + + + + + + + + + + + + + + + + +
+ + + +

Dev Page

+

Page used to test various features of the frontend

+ + + +
+ + + + + + \ No newline at end of file diff --git a/frontend/public/dev/index.mjs b/frontend/public/dev/index.mjs new file mode 100644 index 0000000..9c93741 --- /dev/null +++ b/frontend/public/dev/index.mjs @@ -0,0 +1,56 @@ +import { backendUrl_plantImages } from "../mjs/config.mjs"; +import * as navigation from "../mjs/navigation.mjs"; +import * as alerts from "../mjs/alerts.mjs"; +import * as backend from "../mjs/backend_api.mjs"; +import * as error_handler from "../mjs/error_handler.mjs"; +import * as utils from "../mjs/utils.mjs"; + + + + +async function onButtonAlertClick() { + testAlert(); + testAlert2(); + testAlert3(); + testAlert4(); +} + + +function registerEventHandlers(plant){ + + $('#alert-button').on('click', function() { + onButtonAlertClick(plant); + }); +} + +function testAlert(){ + const mainText = "Pflanze wurde kompostiert"; + const secondaryText = "Die Pflanze wurde am 09.06.2025 kompostiert"; + alerts.displayAlert(mainText, "warning", secondaryText); +} + +function testAlert2(){ + const mainText = "Pflanze wurde kompostiert"; + alerts.displayAlert(mainText, "warning"); +} + +function testAlert3(){ + const mainText = "Pflanze wurde kompostiert"; + alerts.displayAlert(mainText, "warning", null, "bi-exclamation-triangle-fill"); +} + +function testAlert4(){ + const mainText = "Pflanze wurde kompostiert"; + const secondaryText = "Die Pflanze wurde am 09.06.2025 kompostiert"; + alerts.displayAlert(mainText, "warning", secondaryText, "bi-exclamation-triangle-fill"); +} + +async function init() { + alerts.initializeAlertDisplay(); + registerEventHandlers(); +} + +// Call the init function, when site is done loading +$(document).ready(function() { + init(); +}); \ No newline at end of file diff --git a/frontend/public/index.html b/frontend/public/index.html index 4c57687..6115839 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -42,6 +42,9 @@ +
diff --git a/frontend/public/js/detailseite_pflanze.mjs b/frontend/public/js/detailseite_pflanze.mjs index 47c5fb5..5aa8989 100644 --- a/frontend/public/js/detailseite_pflanze.mjs +++ b/frontend/public/js/detailseite_pflanze.mjs @@ -19,6 +19,10 @@ function showPlantDetails(plant) { document.getElementById('location').innerText = location; const wateringFrequency = plant.watering_interval; document.getElementById('watering-frequency').innerText = wateringFrequency; + + // disable compost button if it has been composted + let compostButton = document.getElementById('compost-button'); + compostButton.disabled = (plant.composted != null); const plantImage = plant.image; const imgElement = document.getElementById('plant-image'); @@ -101,7 +105,7 @@ function createActivityCard(type, date, days_since) { async function onButtonWaterPlantClick(plant) { // call Backend try{ - await backend.waterPlant(plant); + await backend.waterPlant(plant.plant_id); } catch(e) { @@ -115,7 +119,7 @@ async function onButtonWaterPlantClick(plant) { async function onButtonRepotPlantClick(plant) { // call Backend try{ - await backend.repotPlant(plant); + await backend.repotPlant(plant.plant_id); } catch(e) { @@ -127,9 +131,14 @@ async function onButtonRepotPlantClick(plant) { updatePlantDetails(plant.plant_id); } -async function onButtonDeletePlantClick(plant_id) { +async function onButtonDeletePlantClick(plant) { + if(!confirm("Willst du die Pflanze wirklich kompostieren?")) + { + return; + } + try { - await backend.deletePlant(plant_id); + await backend.compostPlant(plant.plant_id); } catch (error) { error_handler.handleError(error); return; @@ -153,11 +162,18 @@ function registerEventHandlers(plant){ onButtonRepotPlantClick(plant); }); - $('#delete-button').on('click', function() { - onButtonDeletePlantClick(plant.plant_id); + $('#compost-button').on('click', function() { + onButtonDeletePlantClick(plant); }); } +function showCompostInfo(date){ + const mainText = "Pflanze wurde kompostiert"; + const dateFormatted = utils.convertSqlDateToGermanFormat(date); + const secondaryText = "Die Pflanze wurde am " + dateFormatted + " kompostiert"; + alerts.displayAlert(mainText, "warning", secondaryText, "bi-recycle"); +} + async function init() { alerts.initializeAlertDisplay(); const plantId = utils.getArgumentFromURL("id"); @@ -166,6 +182,10 @@ async function init() { const plant = await backend.fetchPlant(plantId); registerEventHandlers(plant); showPlantDetails(plant); + if(plant.composted != null) + { + showCompostInfo(plant.composted); + } await reloadActivities(plantId); } catch (error) { document.getElementById('plant-name').textContent = "Fehler beim Laden"; diff --git a/frontend/public/js/index.mjs b/frontend/public/js/index.mjs index fc090d6..975cf0c 100644 --- a/frontend/public/js/index.mjs +++ b/frontend/public/js/index.mjs @@ -165,7 +165,7 @@ async function buttonWaterClick(plant) { // call Backend try{ - await backend.waterPlant(plant); + await backend.waterPlant(plant.plant_id); } catch(e) { diff --git a/frontend/public/js/kompostierte_pflanzen.mjs b/frontend/public/js/kompostierte_pflanzen.mjs new file mode 100644 index 0000000..029b64f --- /dev/null +++ b/frontend/public/js/kompostierte_pflanzen.mjs @@ -0,0 +1,172 @@ +import * as navigation from "../mjs/navigation.mjs"; +import * as alerts from "../mjs/alerts.mjs"; +import * as backend from "../mjs/backend_api.mjs"; +import * as error_handler from "../mjs/error_handler.mjs"; +import * as utils from "../mjs/utils.mjs"; + +async function init() { + alerts.initializeAlertDisplay(); + registerEventHandlers(); + + console.log('Document ready, loading data from Service'); + await reloadPlants(); +} + +function registerEventHandlers() +{ + let restoreButton = document.getElementById("restore-button"); + restoreButton.addEventListener("click", () => {onButtonClick(restoreButton)}) + let deleteButton = document.getElementById("delete-button"); + deleteButton.addEventListener("click", () => {onButtonClick(deleteButton)}) +} + +async function onButtonClick(button) { + // disable buttons and change appearance of the clicked + document.getElementById("restore-button").disabled = true; + document.getElementById("delete-button").disabled = true; + let originalHTML = button.innerHTML; + button.innerHTML = '
Einen Moment...'; + + // go through all checkboxes + var checkboxes = document.querySelectorAll("input[type='checkbox']"); + for (const checkbox of checkboxes) + { + if (checkbox.checked){ + let plant_id = checkbox.getAttribute("plant_id"); + + try { + if(button.id == "delete-button"){ + await backend.deletePlant(plant_id); + } else if (button.id == "restore-button") { + await backend.restorePlant(plant_id); + } + removeListItem(plant_id); + } catch (error) { + // enable buttons and change appearance back + document.getElementById("restore-button").disabled = false; + document.getElementById("delete-button").disabled = false; + button.innerHTML = originalHTML; + // deal with the error + error_handler.handleError(error); + } + } + } + + // If there are no more list items, create info + let plantsContainer = document.getElementById("plants"); + if (plantsContainer.innerHTML == "") + { + let infoListItem = createInformationalListItem("bi-check2","Es befinden sich keine Pflanzen mehr auf dem Kompost"); + $('#plants').append(infoListItem); + } + + // enable buttons and change appearance back + document.getElementById("restore-button").disabled = false; + document.getElementById("delete-button").disabled = false; + button.innerHTML = originalHTML; +} + +function removeListItem(plant_id) { + document.getElementById("li" + plant_id).remove(); +} + +async function reloadPlants() { + let plants = null; + try{ + plants = await backend.fetchPlants(true); + } + catch(e) + { + error_handler.handleError(e); + } + displayPlants(plants); +} + +function displayPlants(plants) { + // Clear the existing content + let plantsContainer = $('#plants'); + plantsContainer.empty(); + + if(plants == null) + { + let errorListItem = createInformationalListItem("bi-exclamation-triangle-fill","Pflanzen konnten nicht geladen werden"); + plantsContainer.append(errorListItem); + return; + } + if(plants.length == 0) + { + let errorListItem = createInformationalListItem("bi-check2","Es befinden sich noch keine Pflanzen auf dem Kompost..."); + plantsContainer.append(errorListItem); + return; + } + + // Loop through the plants and create cards for each + plants.forEach(function (plant) { + let listItem = createPlantListItem(plant); + plantsContainer.append(listItem); + }); +} + +function createPlantListItem(plant) { + let listItem = $('
  • '); + listItem.prop("id","li" + plant.plant_id); + + // Create base structure + let row = $('
    '); + listItem.append(row); + let startCol = $('
    '); + let middleCol = $('
    '); + let endCol = $('
    '); + row.append(startCol); + row.append(middleCol); + row.append(endCol); + + // Fill startCol + let checkbox = $(''); + checkbox.prop("id","checkbox" + plant.plant_id); + checkbox.attr("plant_id",plant.plant_id); + startCol.append(checkbox); + + // Fill middleCol + let label = $('
  • '); + + // Create base structure + let row = $('
    '); + listItem.append(row); + let startCol = $('
    '); + let mainCol = $('
    '); + row.append(startCol); + row.append(mainCol); + + // Fill startCol + let iconElement = $(''); + startCol.append(iconElement); + + // Fill mainCol + mainCol.text(text); + + return listItem; +} + +document.addEventListener('DOMContentLoaded', init); \ No newline at end of file diff --git a/frontend/public/js/meine_pflanzen.mjs b/frontend/public/js/meine_pflanzen.mjs index e976d34..464b77c 100644 --- a/frontend/public/js/meine_pflanzen.mjs +++ b/frontend/public/js/meine_pflanzen.mjs @@ -97,7 +97,7 @@ function createPlantCard(plant) {
    `); cardFooter.append(buttonWater); buttonWater.on("click", () => { - // needed to be wraped in this anonymus function + // needed to be wrapped in this anonymous function buttonWaterClick(plant); }); let buttonDetails = $(` + + +
    + + +
    + + + +
    + +
    + +
      + + + +
    • +
      +
      +
      + Loading... +
      +
      +
      + Lade Pflanzen... +
      +
      +
    • + +
    + +
    + +
    +
    +
    + +

    Kompost

    + +

    + Die hier aufgeführten Pflanzen wurden von dir auf den Kompost geworfen. + Du kannst Sie entweder endgültig löschen oder wiederherstellen. +

    + + + +
    +
    +
    + +
    + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/frontend/public/meine_pflanzen.html b/frontend/public/meine_pflanzen.html index 5ad1314..efb7e19 100644 --- a/frontend/public/meine_pflanzen.html +++ b/frontend/public/meine_pflanzen.html @@ -42,6 +42,9 @@
  • +
    diff --git a/frontend/public/mjs/alerts.mjs b/frontend/public/mjs/alerts.mjs index ce15213..76f2cfa 100644 --- a/frontend/public/mjs/alerts.mjs +++ b/frontend/public/mjs/alerts.mjs @@ -13,24 +13,45 @@ export function initializeAlertDisplay() * Displays a Bootstrap alert in the DOM. * Must be called after initializeAlertDisplay(). * - * @param {string} message a string that will be displayed to the user - * @param {string} type a string to change the apperance based on Bootsrap (e.g. danger) + * @param {string} mainMessage a string that will be displayed to the user + * @param {string} type a string to change the appearance based on Bootsrap (e.g. danger) * @param {string} secondaryMessage (optional) additional information that will be displayed to the user + * @param {string} icon (optional) a Bootstrap icon string (e.g. bi-exclamation-triangle-fill) */ -export function displayAlert(mainMessage, type, secondaryMessage) { +export function displayAlert(mainMessage, type, secondaryMessage, icon=null) { + + let alert = $('
    '); + alert.prop('class', 'alert alert-' + type + ' alert-dismissible'); + + // Create base structure + let row = $('
    '); + alert.append(row); + let startCol = $('
    '); + let mainCol = $('
    '); + row.append(startCol); + row.append(mainCol); + + // Create Icon + if (icon) + { + let iconElement = $(''); + startCol.append(iconElement); + } - let message = mainMessage; - // Append secondary message + // Create Content + let div = $('
    '); + mainCol.append(div); + let strong = $(''); + strong.text(mainMessage); + div.append(strong); if(secondaryMessage != null) { - message = "" + message + ""; - message += "
    " + secondaryMessage; + let secondDiv = $('
    '); + div.append(secondDiv); + secondDiv.text(secondaryMessage); } - let alert = $(' diff --git a/frontend_static/style.css b/frontend_static/css/style.css similarity index 97% rename from frontend_static/style.css rename to frontend_static/css/style.css index 8774651..7f35275 100644 --- a/frontend_static/style.css +++ b/frontend_static/css/style.css @@ -91,6 +91,10 @@ main { background-color: white !important; } +.list-group-item { + background-color: white !important; +} + .text-water { color: var(--qd-color-water); } diff --git a/frontend_static/detailseite_pflanze.html b/frontend_static/detailseite_pflanze.html index ed737d2..64eb05b 100644 --- a/frontend_static/detailseite_pflanze.html +++ b/frontend_static/detailseite_pflanze.html @@ -14,7 +14,7 @@ - + @@ -55,7 +55,7 @@
    Pflanziska
    diff --git a/frontend_static/index.html b/frontend_static/index.html index 2af1652..e052f31 100644 --- a/frontend_static/index.html +++ b/frontend_static/index.html @@ -14,7 +14,7 @@ - + diff --git a/frontend_static/kompostierte_pflanzen.html b/frontend_static/kompostierte_pflanzen.html new file mode 100644 index 0000000..48367c3 --- /dev/null +++ b/frontend_static/kompostierte_pflanzen.html @@ -0,0 +1,143 @@ + + + + + + + + + Plant Manager - Kompost + + + + + + + + + + + + + + + + + + + +
    + + + +
    + +
    + + +
      +
    • +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
    • +
    • +
      +
      + +
      +
      + +
      +
      + +
      +
      +
    • +
    • +
      +
      + +
      +
      + +
      +
      + +
      +
      +
    • +
    + +
    + +
    +
    +
    + +

    Kompost

    + +

    + Die hier aufgeführten Pflanzen wurden von dir auf den Kompost geworfen. + Du kannst Sie entweder endgültig löschen oder wiederherstellen. +

    + + + + +
    +
    +
    + +
    + +
    + + +
    + + + + + + \ No newline at end of file diff --git a/frontend_static/meine_pflanzen.html b/frontend_static/meine_pflanzen.html index 0eba5e3..94b83b3 100644 --- a/frontend_static/meine_pflanzen.html +++ b/frontend_static/meine_pflanzen.html @@ -14,7 +14,7 @@ - + diff --git a/frontend_static/pflanze_bearbeiten.html b/frontend_static/pflanze_bearbeiten.html index 459385c..a8cf56a 100644 --- a/frontend_static/pflanze_bearbeiten.html +++ b/frontend_static/pflanze_bearbeiten.html @@ -14,7 +14,7 @@ - + diff --git a/frontend_static/template.html b/frontend_static/template.html index 8e30bd4..b810418 100644 --- a/frontend_static/template.html +++ b/frontend_static/template.html @@ -8,13 +8,18 @@ Plant Manager + + + - + - - - + + + + +