0

I need some shiny wisdom, please. Below code works well in shiny server part; it sends an e-mail when user clicks actionButton("mailButton", "e-mail!") in ui part with a PDF report attached via gmailr. The only problem I have is that there is no feedback to the user whether e-mail has been sent. What I would ideally like to have is a message box mid-screen (maybe with overlay). When e-mail is sent it would tell so to the user who pressed the input$mailButton (and maybe the box would disappear with timeout of 15 seconds). This event approximately should correspond to the point of print("message sent") in the below code (this does get printed to the terminal). What would be a good way to do display user a confirmation that e-mail has indeed been sent and block inputs while sending is going on (which usually takes 4 seconds)?

    # email sender ------------------------------------------------------------
     observeEvent(input$mailButton,{
        isolate( {
            
            library(gmailr)
            
            params <- list(startDate = min(dashData()$mdate), 
                           endDate = max(dashData()$mdate), 
                           dfSurvey = dashData(), 
                           onePerson = input$checkOnePt, 
                           onePersonNumber = input$patientNumber, 
                           showAvg = input$checkAvgLine, 
                           alphaAvg = alphaAvg)            
            
            toAddress <- input$emailAddr
            
            if (input$checkOnePt) {
                mailSubject <- paste("Feedback graph for ", input$patientNumber)
                mailText <- paste("Hello, please see the attached report from us for ",input$patientNumber)
            } else {
                mailSubject <- paste("Feedback graph")
                mailText <- paste("Hello, please see the attached report from us.")
            }
            
                
            library(rmarkdown)
            out <- render('hwu-weekly.Rmd',
                              params = params,
                              pdf_document(),
                              envir = new.env(parent = globalenv())
                )

            
            gm_auth_configure(path  = "credentials.json")
            gm_auth(email = TRUE, cache = ".secret")
            
            email <- gm_mime() %>%
                gm_to(toAddress) %>%
                gm_from("user.us@gmail.com") %>%
                gm_subject(mailSubject) %>%
                gm_text_body( mailText ) %>% 
                gm_attach_file(filename = "hwu-weekly.pdf")
            
            gm_send_message(email)

            print("message sent")
        })
    
    })

r0berts
  • 842
  • 1
  • 13
  • 27

1 Answers1

1

This seems like a good use case of withProgress() and showNotification():

library(shiny)

ui <- fluidPage(
  actionButton('go', 'go')
)

server <- function(input, output, session) {
  observeEvent(input$go, {
    withProgress(message = "Please Wait", {
      Sys.sleep(1)
      setProgress(0.25, detail = "1 Sec")
      Sys.sleep(1)
      setProgress(0.5, detail = "2 Sec")
      Sys.sleep(1)
      setProgress(0.75, detail = "3 Sec")
      Sys.sleep(1)
      setProgress(1, detail = "4 Sec")
   })
    showNotification("Your message here", type = "message", duration = 15)
  })
}

shinyApp(ui, server)

Links to shiny documents for notifications and progress indicators.

You could also use a modal for something more obvious that the user would have to close before moving on:

library(shiny)

ui <- fluidPage(
  actionButton('go', 'go')
)

server <- function(input, output, session) {
  observeEvent(input$go, {
    withProgress(message = "Please Wait", {
      Sys.sleep(1)
      setProgress(0.25, detail = "1 Sec")
      Sys.sleep(1)
      setProgress(0.5, detail = "2 Sec")
      Sys.sleep(1)
      setProgress(0.75, detail = "3 Sec")
      Sys.sleep(1)
      setProgress(1, detail = "4 Sec")
   })
    showModal(modalDialog(title = 'Message', h2("Content Here")))
  })
}

shinyApp(ui, server)
bs93
  • 1,236
  • 6
  • 10
  • Thank you that is looking very good. Just a simple one - in this context where would my routine `isolate({my mail sending commands})` need to go? I am not really experienced with Shiny. – r0berts Nov 22 '20 at 10:14
  • They should go inside of withProgress({}). And you can manually use setProgress (or incProgress()) to move the progress indicator along. Here, I used Sys.sleep() as a placeholder function for the demonstration to simulate doing some calculation/function that would take some time. – bs93 Nov 22 '20 at 11:52
  • Thanks, that works beautifully once I got my head around to the simple idea that I enclose everything inside my `observeEvent{}` action `withProgress{}` and then simply pepper the code with appropriate `setProgress` messages. Works great. User attention on the finish is better grasped with a subsequent `showModal` with `easyClose=TRUE`. – r0berts Nov 25 '20 at 18:58