Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions R/messages.R
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ get_messages_default <- function() {
"previous" = "Previous",
"next" = "Next",
"exit" = "Exit Survey",
"restart" = "Restart Survey",
"close-tab" = "Please close this tab manually to exit the survey.",
"choose-option" = "Choose an option...",
"click" = "Click here",
Expand All @@ -85,6 +86,7 @@ get_messages_default <- function() {
"previous" = "Zur\u00fcck",
"next" = "Weiter",
"exit" = "Umfrage beenden",
"restart" = "Umfrage neu starten",
"close-tab" = "Bitte schlie\u00dfen Sie diesen Tab manuell, um die Umfrage zu beenden.",
"choose-option" = "Option ausw\u00e4hlen...",
"click" = "Hier klicken",
Expand All @@ -108,6 +110,7 @@ get_messages_default <- function() {
"previous" = "Anterior",
"next" = "Siguiente",
"exit" = "Salir de la Encuesta",
"restart" = "Reiniciar Encuesta",
"close-tab" = "Por favor, cierre esta pesta\u00f1a manualmente para salir de la encuesta.",
"choose-option" = "Elija una opci\u00f3n...",
"click" = "Haga clic aqu\u00ed",
Expand All @@ -131,6 +134,7 @@ get_messages_default <- function() {
"previous" = "Pr\u00e9c\u00e9dent",
"next" = "Suivant",
"exit" = "Quitter le sondage",
"restart" = "Redémarrer le sondage",
"close-tab" = "Veuillez fermer cet onglet manuellement pour quitter le sondage.",
"choose-option" = "Choisissez une option...",
"click" = "Cliquez ici",
Expand All @@ -154,6 +158,7 @@ get_messages_default <- function() {
"previous" = "Indietro",
"next" = "Avanti",
"exit" = "Esci dal Sondaggio",
"restart" = "Riavvia Sondaggio",
"close-tab" = "Per favore, chiudi questa scheda manualmente per uscire dal sondaggio.",
"choose-option" = "Scegli un'opzione...",
"click" = "Clicca qui",
Expand All @@ -177,6 +182,7 @@ get_messages_default <- function() {
"previous" = "\u4e0a\u4e00\u9875", # \u4e0a\u4e00\u9875
"next" = "\u4e0b\u4e00\u9875", # \u4e0b\u4e00\u9875
"exit" = "\u9000\u51fa\u95ee\u5377", # \u9000\u51fa\u95ee\u5377
"restart" = "\u91cd\u65b0\u5f00\u59cb\u95ee\u5377", # \u91cd\u65b0\u5f00\u59cb\u95ee\u5377
"close-tab" = "\u8bf7\u624b\u52a8\u5173\u95ed\u672c\u9875\u9762\u3002", # \u8bf7\u624b\u52a8\u5173\u95ed\u672c\u9875\u9762\u3002
"choose-option" = "\u8bf7\u9009\u62e9\u4e00\u9879\u2026", # \u8bf7\u9009\u62e9\u4e00\u9879\u2026
"click" = "\u5355\u51fb\u6b64\u5904", # \u5355\u51fb\u6b64\u5904
Expand Down
29 changes: 29 additions & 0 deletions R/server.R
Original file line number Diff line number Diff line change
Expand Up @@ -2195,6 +2195,9 @@ sd_server <- function(

# Observer to handle the rating submission or exit confirmation
shiny::observeEvent(input$submit_rating, {
# Check if cookies should be cleared on exit
clear_cookies_on_exit <- input$clear_cookies_on_exit

# Save the rating
rating <- input$survey_rating
all_data[['exit_survey_rating']] <- rating
Expand All @@ -2203,21 +2206,47 @@ sd_server <- function(
shiny::isolate({
update_data(time_last = TRUE)
})

# Clear cookies if requested
if (!is.null(clear_cookies_on_exit) && clear_cookies_on_exit) {
session$sendCustomMessage("clearCookies", list())
}

# Close the modal and the window
shiny::removeModal()
session$sendCustomMessage("closeWindow", list())
})

shiny::observeEvent(input$confirm_exit, {
# Check if cookies should be cleared on exit
clear_cookies_on_exit <- input$clear_cookies_on_exit

# Update checkpoint 4 - when exiting survey
shiny::isolate({
update_data(time_last = TRUE)
})

# Clear cookies if requested
if (!is.null(clear_cookies_on_exit) && clear_cookies_on_exit) {
session$sendCustomMessage("clearCookies", list())
}

# Close the modal and the window
shiny::removeModal()
session$sendCustomMessage("closeWindow", list())
})

# Observer for restart survey functionality
shiny::observeEvent(input$restart_survey, {
# Update checkpoint 4 - when restarting survey
shiny::isolate({
update_data(time_last = TRUE)
})

# Send force restart message to clear cookies and reload page
session$sendCustomMessage("forceRestart", list())
})

# Update checkpoint 5 - when session ends
shiny::onSessionEnded(function() {
shiny::isolate({
Expand Down
78 changes: 68 additions & 10 deletions R/ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -1786,6 +1786,13 @@ sd_nav <- function(
#' @param show_previous Logical. Whether to show the Previous button alongside the Close button.
#' Set to `TRUE` to allow users to go back before closing. Defaults to `FALSE`. Note: Unlike
#' `sd_nav()`, this parameter does NOT read from the `show-previous` YAML setting.
#' @param show_restart Logical. Whether to show a 'Restart Survey' button alongside the
#' Close button. When `TRUE`, displays two side-by-side buttons. Defaults to `FALSE`.
#' @param label_restart Character string. The label for the 'Restart Survey' button.
#' Defaults to `NULL`, which uses "Restart Survey" (or the translated equivalent).
#' @param clear_cookies Logical. Whether to clear cookies on exit without showing a
#' restart button. Use for use cases where the restart button isn't needed but
#' cookies should be cleared for later resubmission. Defaults to `FALSE`.
#'
#' @return A 'shiny' tagList containing the 'Close' button UI element and
#' associated JavaScript for the exit process.
Expand Down Expand Up @@ -1837,7 +1844,10 @@ sd_nav <- function(
sd_close <- function(
label_close = NULL,
label_previous = NULL,
show_previous = NULL
show_previous = NULL,
show_restart = FALSE,
label_restart = NULL,
clear_cookies = FALSE
) {
# Get messages
messages <- get_messages()$messages
Expand All @@ -1858,14 +1868,21 @@ sd_close <- function(
label_previous <- paste0("\u2190 ", messages[['previous']]) # ← Previous
}

# Default label for restart button
if (is.null(label_restart)) {
label_restart <- messages[['restart']]
}

button_id <- "close-survey-button"
restart_button_id <- "restart-survey-button"

shiny::tagList(
shiny::div(
style = "margin-top: 0.5rem; margin-bottom: 0.5rem; position: relative; min-height: 40px;",
class = "sd-nav-container",

# Previous button (only if show_previous is TRUE)
# Use absolute positioning so it doesn't affect the close button's centering
# Use absolute positioning so it doesn't affect the main buttons' centering
if (show_previous) {
shiny::actionButton(
inputId = "page_id_prev",
Expand All @@ -1876,16 +1893,42 @@ sd_close <- function(
)
},

# Close button (always perfectly centered, unaffected by previous button)
# Main buttons container (centered, unaffected by previous button)
shiny::div(
style = "width: 100%; text-align: center;",
shiny::actionButton(
inputId = button_id,
label = label_close,
class = "sd-enter-button sd-nav-button",
style = "display: inline-block;",
onclick = "Shiny.setInputValue('show_exit_modal', true, {priority: 'event'});"
)

# If restart is enabled, show two side-by-side buttons
if (show_restart) {
shiny::tagList(
shiny::actionButton(
inputId = button_id,
label = label_close,
class = "sd-enter-button sd-nav-button",
style = "display: inline-block; margin-right: 10px;",
onclick = paste0("Shiny.setInputValue('show_exit_modal', true, {priority: 'event'}); ",
"Shiny.setInputValue('clear_cookies_on_exit', ",
tolower(as.character(clear_cookies)), ", {priority: 'event'});")
),
shiny::actionButton(
inputId = restart_button_id,
label = label_restart,
class = "sd-enter-button sd-nav-button",
style = "display: inline-block; margin-left: 10px;",
onclick = "Shiny.setInputValue('restart_survey', true, {priority: 'event'});"
)
)
} else {
# Single close button
shiny::actionButton(
inputId = button_id,
label = label_close,
class = "sd-enter-button sd-nav-button",
style = "display: inline-block;",
onclick = paste0("Shiny.setInputValue('show_exit_modal', true, {priority: 'event'}); ",
"Shiny.setInputValue('clear_cookies_on_exit', ",
tolower(as.character(clear_cookies)), ", {priority: 'event'});")
)
}
)
),
shiny::tags$script(htmltools::HTML(
Expand All @@ -1896,6 +1939,21 @@ sd_close <- function(
alert('Please close this tab manually to exit the survey.');
}
});

Shiny.addCustomMessageHandler('clearCookies', function(message) {
if (typeof surveydownCookies !== 'undefined' && surveydownCookies.clear) {
surveydownCookies.clear();
}
});

Shiny.addCustomMessageHandler('forceRestart', function(message) {
if (typeof surveydownCookies !== 'undefined' && surveydownCookies.forceRestart) {
surveydownCookies.forceRestart();
} else if (typeof surveydownCookies !== 'undefined' && surveydownCookies.clear) {
surveydownCookies.clear();
}
window.location.reload();
});
"
))
)
Expand Down
28 changes: 28 additions & 0 deletions inst/js/cookies.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,34 @@ const surveydownCookies = {
console.error("Error getting answer data:", e);
return null;
}
},

clear: function() {
try {
// Clear survey session cookie
document.cookie = "surveydown_session=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Strict";

// Clear survey answers cookie
document.cookie = "surveydown_answers=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Strict";

console.log("Survey cookies cleared");
} catch (e) {
console.error("Error clearing survey cookies:", e);
}
},

forceRestart: function() {
try {
// Clear all survey cookies
this.clear();

// Log restart action
console.log("Survey restart initiated");

// Note: Page reload will be handled by the calling function
} catch (e) {
console.error("Error during force restart:", e);
}
}
};

Expand Down
19 changes: 18 additions & 1 deletion man/sd_close.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.