Files
homekeeper/beekeeper/R/screen_checklists.R
T
2026-07-06 19:25:38 +02:00

181 lines
6.6 KiB
R
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
screen_checklists_ui <- function(id) {
ns <- NS(id)
bslib::navset_card_tab(
bslib::nav_panel("Ausführen",
shiny::div(class = "p-2",
shiny::uiOutput(ns("checklist_sel")),
shiny::uiOutput(ns("run_items"))
)
),
bslib::nav_panel("Verwalten",
shiny::div(class = "p-2",
shiny::div(class = "d-flex gap-2 mb-3",
shiny::textInput(ns("new_name"), NULL, placeholder = "Neue Checkliste..."),
shiny::selectInput(ns("new_scope"), NULL,
choices = c("Volk" = "colony", "Stand" = "apiary"), width = "120px"),
shiny::actionButton(ns("add_list"), shiny::icon("plus"), class = "btn btn-primary")
),
shiny::uiOutput(ns("manage_list"))
)
)
)
}
screen_checklists_server <- function(id, db, nav) {
moduleServer(id, function(input, output, session) {
ns <- session$ns
reload <- reactiveVal(0)
sel_list <- reactiveVal(NULL)
checklists <- reactive({ reload(); db_checklists_list(db) })
output$checklist_sel <- renderUI({
cls <- checklists()
if (nrow(cls) == 0)
return(shiny::p(class = "text-muted", "Noch keine Checklisten. Im Tab 'Verwalten' anlegen."))
shiny::selectInput(ns("run_list"), "Checkliste",
choices = c("Bitte wählen" = "", setNames(cls$id,
paste0("[", cls$scope, "] ", cls$name)))
)
})
output$run_items <- renderUI({
req(input$run_list, input$run_list != "", nav$colony_id)
lid <- as.integer(input$run_list)
scope_id <- nav$colony_id
date <- as.character(Sys.Date())
items <- db_checklist_items_list(db, lid)
if (nrow(items) == 0) return(shiny::p(class = "text-muted", "Keine Einträge."))
done <- db_checklist_completions_list(db, lid, scope_id, date)
shiny::div(class = "list-group",
lapply(seq_len(nrow(items)), function(i) {
item <- items[i, ]
completed <- item$id %in% done$item_id
shiny::div(
class = paste("list-group-item d-flex align-items-center gap-3 py-3",
if (completed) "list-group-item-success" else ""),
shiny::tags$input(
class = "form-check-input flex-shrink-0",
type = "checkbox",
checked = if (completed) NA else NULL,
style = "width:1.3em;height:1.3em;cursor:pointer",
onclick = sprintf(
"Shiny.setInputValue('%s',{id:%d}, {priority:'event'})",
ns("toggle"), item$id
)
),
shiny::span(item$text,
style = if (completed) "text-decoration:line-through;opacity:.6" else "")
)
})
)
})
observeEvent(input$toggle, {
req(input$run_list, nav$colony_id)
db_checklist_completions_toggle(db,
checklist_id = as.integer(input$run_list),
item_id = as.integer(input$toggle$id),
scope_id = nav$colony_id,
date = as.character(Sys.Date())
)
})
# ---- Manage tab ---------------------------------------------------------
output$manage_list <- renderUI({
cls <- checklists()
if (nrow(cls) == 0) return(shiny::p(class = "text-muted", "Keine Checklisten."))
lapply(seq_len(nrow(cls)), function(i) {
row <- cls[i, ]
shiny::div(class = "card mb-2",
bslib::card_body(
class = "py-2",
shiny::div(class = "d-flex justify-content-between align-items-center",
shiny::div(
shiny::tags$strong(row$name),
shiny::tags$small(class = "text-muted ms-2", paste0("[", row$scope, "]"))
),
shiny::div(
shiny::actionButton(ns(paste0("sel_", row$id)), "Einträge",
class = "btn btn-sm btn-outline-secondary me-1"),
shiny::actionButton(ns(paste0("del_list_", row$id)), shiny::icon("trash"),
class = "btn btn-sm btn-outline-danger")
)
),
shiny::uiOutput(ns(paste0("items_", row$id)))
)
)
})
})
observe({
cls <- checklists()
lapply(cls$id, function(lid) {
local({
llid <- lid
observeEvent(input[[paste0("sel_", llid)]], sel_list(llid), ignoreInit = TRUE)
observeEvent(input[[paste0("del_list_", llid)]], {
db_checklists_delete(db, llid)
if (identical(sel_list(), llid)) sel_list(NULL)
reload(reload() + 1L)
}, ignoreInit = TRUE)
})
})
})
observe({
lid <- sel_list()
req(lid)
items <- db_checklist_items_list(db, lid)
output[[paste0("items_", lid)]] <- renderUI({
shiny::div(class = "mt-2",
if (nrow(items) > 0)
shiny::tags$ul(class = "list-unstyled mb-2",
lapply(seq_len(nrow(items)), function(i) {
it <- items[i, ]
shiny::tags$li(class = "d-flex justify-content-between align-items-center small py-1 border-bottom",
it$text,
shiny::actionButton(ns(paste0("del_item_", it$id)), "×",
class = "btn btn-sm btn-link text-danger p-0",
onclick = "event.stopPropagation()"
)
)
})
),
shiny::div(class = "d-flex gap-2",
shiny::textInput(ns(paste0("item_txt_", lid)), NULL, placeholder = "Neuer Eintrag..."),
shiny::actionButton(ns(paste0("add_item_", lid)), shiny::icon("plus"),
class = "btn btn-outline-primary")
)
)
})
lapply(items$id, function(iid) {
local({
liid <- iid
observeEvent(input[[paste0("del_item_", liid)]], {
db_checklist_items_delete(db, liid)
reload(reload() + 1L)
}, ignoreInit = TRUE)
})
})
observeEvent(input[[paste0("add_item_", lid)]], {
txt <- input[[paste0("item_txt_", lid)]]
req(nchar(trimws(txt)) > 0)
its <- db_checklist_items_list(db, lid)
pos <- if (nrow(its) > 0) max(its$position) + 1L else 1L
db_checklist_items_insert(db, lid, trimws(txt), pos)
shiny::updateTextInput(session, paste0("item_txt_", lid), value = "")
reload(reload() + 1L)
}, ignoreInit = TRUE)
})
observeEvent(input$add_list, {
req(nchar(trimws(input$new_name)) > 0)
db_checklists_insert(db, trimws(input$new_name), input$new_scope)
shiny::updateTextInput(session, "new_name", value = "")
reload(reload() + 1L)
})
})
}