add homekeeper stack
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
screen_apiaries_ui <- function(id) {
|
||||
ns <- NS(id)
|
||||
shiny::tagList(
|
||||
shiny::div(class = "mb-3", style = "border-radius:8px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,.15)",
|
||||
leaflet::leafletOutput(ns("overview_map"), height = "200px", width = "100%")
|
||||
),
|
||||
shiny::uiOutput(ns("cards")),
|
||||
shiny::br(),
|
||||
shiny::actionButton(ns("add_btn"), shiny::tagList(shiny::icon("plus"), " Neuer Stand"),
|
||||
class = "add-dashed btn", style = "width:100%;min-height:80px"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
screen_apiaries_server <- function(id, db, nav) {
|
||||
moduleServer(id, function(input, output, session) {
|
||||
ns <- session$ns
|
||||
reload <- reactiveVal(0)
|
||||
edit_id <- reactiveVal(NULL)
|
||||
add_coords <- reactiveValues(lat = NA_real_, lng = NA_real_)
|
||||
edit_coords <- reactiveValues(lat = NA_real_, lng = NA_real_)
|
||||
|
||||
apiaries <- reactive({ reload(); db_apiaries_list(db) })
|
||||
|
||||
output$cards <- renderUI({
|
||||
ap <- apiaries()
|
||||
if (nrow(ap) == 0) return(shiny::p(class = "text-muted", "Noch keine Bienenstände angelegt."))
|
||||
lapply(seq_len(nrow(ap)), function(i) {
|
||||
row <- ap[i, ]
|
||||
shiny::div(
|
||||
class = "card tap-card mb-3",
|
||||
onclick = sprintf("Shiny.setInputValue('%s', %d, {priority:'event'})",
|
||||
ns("select"), row$id),
|
||||
bslib::card_body(
|
||||
class = "d-flex justify-content-between align-items-start",
|
||||
shiny::div(
|
||||
shiny::tags$strong(class = "fs-5", row$name),
|
||||
shiny::tags$p(class = "text-muted mb-0 small",
|
||||
if (!is.na(row$location_text) && nchar(row$location_text) > 0) row$location_text
|
||||
)
|
||||
),
|
||||
shiny::div(
|
||||
class = "d-flex flex-column align-items-end gap-1",
|
||||
shiny::tags$span(class = "badge bg-secondary",
|
||||
paste(row$colony_count, "Völker")),
|
||||
shiny::div(
|
||||
shiny::actionButton(ns(paste0("edit_", row$id)), shiny::icon("pencil"),
|
||||
class = "btn btn-sm btn-link p-0 text-muted",
|
||||
onclick = "event.stopPropagation()"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
observeEvent(input$select, {
|
||||
nav$apiary_id <- input$select
|
||||
nav$screen <- "colonies"
|
||||
})
|
||||
|
||||
# ---- Overview map -------------------------------------------------------
|
||||
output$overview_map <- leaflet::renderLeaflet({
|
||||
ap <- apiaries()
|
||||
m <- leaflet::leaflet(options = leaflet::leafletOptions(zoomControl = FALSE, attributionControl = FALSE)) |>
|
||||
leaflet::addTiles(group = "Karte") |>
|
||||
leaflet::addProviderTiles("Esri.WorldImagery", group = "Satellit") |>
|
||||
leaflet::addLayersControl(baseGroups = c("Karte", "Satellit"),
|
||||
options = leaflet::layersControlOptions(collapsed = TRUE))
|
||||
with_coords <- ap[!is.na(ap$lat) & !is.na(ap$lng), ]
|
||||
if (nrow(with_coords) > 0) {
|
||||
m <- leaflet::addMarkers(m,
|
||||
lng = with_coords$lng, lat = with_coords$lat,
|
||||
label = with_coords$name, layerId = as.character(with_coords$id),
|
||||
clusterOptions = leaflet::markerClusterOptions()
|
||||
)
|
||||
} else {
|
||||
m <- leaflet::setView(m, lng = 10.45, lat = 51.17, zoom = 6)
|
||||
}
|
||||
m
|
||||
})
|
||||
observeEvent(input$overview_map_marker_click, {
|
||||
click <- input$overview_map_marker_click
|
||||
if (!is.null(click$id)) {
|
||||
nav$apiary_id <- as.integer(click$id)
|
||||
nav$screen <- "colonies"
|
||||
}
|
||||
})
|
||||
|
||||
# ---- Add modal -----------------------------------------------------------
|
||||
output$add_map <- leaflet::renderLeaflet({
|
||||
leaflet::leaflet() |>
|
||||
leaflet::addTiles(group = "Karte") |>
|
||||
leaflet::addProviderTiles("Esri.WorldImagery", group = "Satellit") |>
|
||||
leaflet::addLayersControl(baseGroups = c("Karte", "Satellit"),
|
||||
options = leaflet::layersControlOptions(collapsed = TRUE)) |>
|
||||
leaflet::setView(lng = 10.45, lat = 51.17, zoom = 6)
|
||||
})
|
||||
observeEvent(input$add_map_click, {
|
||||
cl <- input$add_map_click
|
||||
add_coords$lat <- cl$lat; add_coords$lng <- cl$lng
|
||||
p <- leaflet::leafletProxy("add_map", session)
|
||||
leaflet::clearMarkers(p)
|
||||
leaflet::addMarkers(p, lng = cl$lng, lat = cl$lat)
|
||||
})
|
||||
|
||||
observeEvent(input$add_btn, {
|
||||
add_coords$lat <- NA_real_; add_coords$lng <- NA_real_
|
||||
shiny::showModal(shiny::modalDialog(
|
||||
title = "Neuer Bienenstand", size = "l",
|
||||
footer = shiny::tagList(
|
||||
shiny::modalButton("Abbrechen"),
|
||||
shiny::actionButton(ns("confirm_add"), "Anlegen", class = "btn-primary")
|
||||
),
|
||||
shiny::textInput(ns("new_name"), "Name *"),
|
||||
shiny::textInput(ns("new_loc"), "Standortbeschreibung"),
|
||||
shiny::tags$p(class = "text-muted small mt-3 mb-1",
|
||||
shiny::tags$em("Standort auf Karte setzen (optional):")),
|
||||
leaflet::leafletOutput(ns("add_map"), height = "280px"),
|
||||
shiny::uiOutput(ns("add_coords_lbl")),
|
||||
shiny::textAreaInput(ns("new_notes"), "Notizen", rows = 2)
|
||||
))
|
||||
})
|
||||
output$add_coords_lbl <- renderUI({
|
||||
req(!is.na(add_coords$lat))
|
||||
shiny::tags$p(class = "text-muted small mt-1",
|
||||
sprintf("%.5f, %.5f", add_coords$lat, add_coords$lng))
|
||||
})
|
||||
observeEvent(input$confirm_add, {
|
||||
req(nchar(trimws(input$new_name)) > 0)
|
||||
db_apiaries_insert(db,
|
||||
name = trimws(input$new_name), location_text = input$new_loc,
|
||||
lat = add_coords$lat, lng = add_coords$lng, notes = input$new_notes
|
||||
)
|
||||
shiny::removeModal(); reload(reload() + 1L)
|
||||
})
|
||||
|
||||
# ---- Edit modal ----------------------------------------------------------
|
||||
output$edit_map <- leaflet::renderLeaflet({
|
||||
lat <- if (!is.na(edit_coords$lat)) edit_coords$lat else 51.17
|
||||
lng <- if (!is.na(edit_coords$lng)) edit_coords$lng else 10.45
|
||||
zoom <- if (!is.na(edit_coords$lat)) 13L else 6L
|
||||
m <- leaflet::leaflet() |>
|
||||
leaflet::addTiles(group = "Karte") |>
|
||||
leaflet::addProviderTiles("Esri.WorldImagery", group = "Satellit") |>
|
||||
leaflet::addLayersControl(baseGroups = c("Karte", "Satellit"),
|
||||
options = leaflet::layersControlOptions(collapsed = TRUE)) |>
|
||||
leaflet::setView(lng = lng, lat = lat, zoom = zoom)
|
||||
if (!is.na(edit_coords$lat)) m <- leaflet::addMarkers(m, lng = lng, lat = lat)
|
||||
m
|
||||
})
|
||||
observeEvent(input$edit_map_click, {
|
||||
cl <- input$edit_map_click
|
||||
edit_coords$lat <- cl$lat; edit_coords$lng <- cl$lng
|
||||
p <- leaflet::leafletProxy("edit_map", session)
|
||||
leaflet::clearMarkers(p)
|
||||
leaflet::addMarkers(p, lng = cl$lng, lat = cl$lat)
|
||||
})
|
||||
|
||||
observe({
|
||||
ap <- apiaries()
|
||||
lapply(ap$id, function(aid) {
|
||||
local({
|
||||
lid <- aid
|
||||
observeEvent(input[[paste0("edit_", lid)]], {
|
||||
row <- db_apiaries_get(db, lid)
|
||||
edit_id(lid)
|
||||
edit_coords$lat <- row$lat %||% NA_real_
|
||||
edit_coords$lng <- row$lng %||% NA_real_
|
||||
shiny::showModal(shiny::modalDialog(
|
||||
title = "Stand bearbeiten", size = "l",
|
||||
footer = shiny::tagList(
|
||||
shiny::modalButton("Abbrechen"),
|
||||
shiny::actionButton(ns("confirm_edit"), "Speichern", class = "btn-primary"),
|
||||
shiny::actionButton(ns("confirm_delete"), "Löschen", class = "btn-danger ms-auto")
|
||||
),
|
||||
shiny::textInput(ns("edit_name"), "Name *", value = row$name),
|
||||
shiny::textInput(ns("edit_loc"), "Standortbeschreibung", value = row$location_text %||% ""),
|
||||
shiny::tags$p(class = "text-muted small mt-3 mb-1",
|
||||
shiny::tags$em("Standort auf Karte setzen:")),
|
||||
leaflet::leafletOutput(ns("edit_map"), height = "280px"),
|
||||
shiny::uiOutput(ns("edit_coords_lbl")),
|
||||
shiny::textAreaInput(ns("edit_notes"), "Notizen", rows = 2, value = row$notes %||% "")
|
||||
))
|
||||
}, ignoreInit = TRUE)
|
||||
})
|
||||
})
|
||||
})
|
||||
output$edit_coords_lbl <- renderUI({
|
||||
req(!is.na(edit_coords$lat))
|
||||
shiny::tags$p(class = "text-muted small mt-1",
|
||||
sprintf("%.5f, %.5f", edit_coords$lat, edit_coords$lng))
|
||||
})
|
||||
observeEvent(input$confirm_edit, {
|
||||
req(edit_id())
|
||||
db_apiaries_update(db, id = edit_id(),
|
||||
name = trimws(input$edit_name), location_text = input$edit_loc,
|
||||
lat = edit_coords$lat, lng = edit_coords$lng, notes = input$edit_notes
|
||||
)
|
||||
shiny::removeModal(); reload(reload() + 1L)
|
||||
})
|
||||
observeEvent(input$confirm_delete, {
|
||||
req(edit_id())
|
||||
db_apiaries_delete(db, edit_id())
|
||||
shiny::removeModal(); reload(reload() + 1L)
|
||||
})
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user