From 81e23e88629c89e78d871e00a03de3b4b36b60d3 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 11 Aug 2022 23:49:40 +0530 Subject: [PATCH] feat: Webform Success Page and some customization options (backport #17790) (#17809) Co-authored-by: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> --- cypress/integration/web_form.js | 6 +- frappe/public/js/frappe/utils/utils.js | 14 + frappe/public/js/frappe/web_form/web_form.js | 72 ++--- frappe/public/scss/website/web_form.scss | 292 +++++++++++------- .../doctype/web_form/templates/web_form.html | 104 +++++-- .../web_form/templates/web_form_skeleton.html | 38 +++ frappe/website/doctype/web_form/web_form.json | 63 ++-- frappe/website/doctype/web_form/web_form.py | 2 +- 8 files changed, 386 insertions(+), 205 deletions(-) create mode 100644 frappe/website/doctype/web_form/templates/web_form_skeleton.html diff --git a/cypress/integration/web_form.js b/cypress/integration/web_form.js index 66975ce19b..4c99451146 100644 --- a/cypress/integration/web_form.js +++ b/cypress/integration/web_form.js @@ -142,10 +142,9 @@ context("Web Form", () => { it("Custom Breadcrumbs", () => { cy.visit("/app/web-form/note"); - cy.findByRole("tab", { name: "Form Settings" }).click(); - cy.get(".form-section .section-head").contains("Customization").click(); + cy.findByRole("tab", { name: "Customization" }).click(); cy.fill_field("breadcrumbs", '[{"label": _("Notes"), "route":"note"}]', "Code"); - cy.get(".form-section .section-head").contains("Customization").click(); + cy.get(".form-tabs .nav-item .nav-link").contains("Customization").click(); cy.save(); cy.visit("/note/Note 1"); @@ -188,6 +187,7 @@ context("Web Form", () => { cy.fill_field("title", " Edited"); cy.get(".web-form-actions button").contains("Save").click(); + cy.get(".success-page .edit-button").click(); cy.get_field("title").should("have.value", "Note 1 Edited"); }); diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index 928484a5f4..ee13d31d9f 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -982,6 +982,20 @@ Object.assign(frappe.utils, { } }); }, + setup_timer(start, end, $element) { + const increment = end > start; + let counter = start; + + let interval = setInterval(() => { + increment ? counter++ : counter--; + if (increment ? counter > end : counter < end) { + clearInterval(interval); + return; + } + $element.text(counter); + }, 1000); + }, + deep_equal(a, b) { return deep_equal(a, b); }, diff --git a/frappe/public/js/frappe/web_form/web_form.js b/frappe/public/js/frappe/web_form/web_form.js index cb622ea704..ccd88f0ba3 100644 --- a/frappe/public/js/frappe/web_form/web_form.js +++ b/frappe/public/js/frappe/web_form/web_form.js @@ -20,6 +20,7 @@ export default class WebForm extends frappe.ui.FieldGroup { } make() { + this.parent.empty(); super.make(); this.set_page_breaks(); this.set_field_values(); @@ -29,7 +30,6 @@ export default class WebForm extends frappe.ui.FieldGroup { this.setup_primary_action(); } - this.setup_footer_actions(); this.setup_previous_next_button(); this.toggle_section(); @@ -73,14 +73,6 @@ export default class WebForm extends frappe.ui.FieldGroup { this.is_multi_step_form = true; } - setup_footer_actions() { - if (this.is_multi_step_form) return; - - if ($(".web-form-container").height() > 600) { - $(".web-form-footer").removeClass("hide"); - } - } - setup_previous_next_button() { let me = this; @@ -380,45 +372,45 @@ export default class WebForm extends frappe.ui.FieldGroup { return false; } - edit() { - window.location.href = window.location.pathname + "/edit"; - } - - cancel() { - let path = window.location.pathname; - if (this.is_new) { - path = path.replace("/new", ""); - } else { - path = path.replace("/edit", ""); - } - window.location.href = path; - } - handle_success(data) { // TODO: remove this (used for payments app) if (this.accept_payment && !this.doc.paid) { window.location.href = data; } - const success_message = this.success_message || __("Submitted"); + if (!this.is_new) { + $(".success-title").text(__("Updated")); + $(".success-message").text(__("Your form has been successfully updated")); + } - frappe.toast({ message: success_message, indicator: "green" }); + $(".web-form-container").hide(); + $(".success-page").removeClass("hide"); - // redirect - setTimeout(() => { - let path = window.location.pathname; + if (this.success_url) { + frappe.utils.setup_timer(5, 0, $(".time")); + setTimeout(() => { + window.location.href = this.success_url; + }, 5000); + } else { + this.render_success_page(data); + } + } - if (this.success_url) { - path = this.success_url; - } else if (this.login_required) { - if (this.is_new && data.name) { - path = path.replace("/new", ""); - path = path + "/" + data.name; - } else if (this.is_form_editable) { - path = path.replace("/edit", ""); - } - } - window.location.href = path; - }, 3000); + render_success_page(data) { + if (this.allow_edit && data.name) { + $(".success-page").append(` + + ${__("Edit your response", null, "Button in web form")} + + `); + } + + if (this.login_required && !this.allow_multiple && !this.show_list && data.name) { + $(".success-page").append(` + + ${__("View your response", null, "Button in web form")} + + `); + } } } diff --git a/frappe/public/scss/website/web_form.scss b/frappe/public/scss/website/web_form.scss index 17aa4fba9c..0a4350e0bf 100644 --- a/frappe/public/scss/website/web_form.scss +++ b/frappe/public/scss/website/web_form.scss @@ -6,36 +6,69 @@ margin: auto; h1 { - font-size: 1.9rem; + font-size: 2.25rem; margin-top: 0; margin-bottom: 0; } - .web-form-container { + .web-form-banner-image { + margin: -4rem -14rem 5rem; + padding-top: 3rem; + position: relative; + + img { + position: absolute; + object-fit: cover; + width: 100%; + height: 250px; + z-index: -1; + } + } + + .web-form-header { border: 1px solid var(--dark-border-color); - border-radius: var(--border-radius-md); - padding: 2rem; + border-bottom: none; + border-top-left-radius: var(--border-radius-md); + border-top-right-radius: var(--border-radius-md); + background-color: var(--fg-color); + padding: 2rem 2rem 0; - .web-form-header { - display: flex; - justify-content: space-between; - margin: 0 -2rem 1rem; - padding: 0 2rem 1rem; - border-bottom: 1px solid var(--border-color); + .breadcrumb-container { + padding: 0px; + margin: 0 0 2rem; - .web-form-actions { - align-self: center; + ol.breadcrumb { + padding: 0px; } } - .web-form-introduction { - color: var(--text-muted); - margin-bottom: 2rem; + .web-form-head { + border-bottom: 1px solid var(--dark-border-color); + padding-bottom: 1.25rem; - p { + .title { + display: flex; + justify-content: space-between; + } + + .web-form-introduction { color: var(--text-muted); + margin-top: 1.25rem; + + p { + color: var(--text-muted); + } } } + } + + .web-form { + background-color: var(--fg-color); + padding: 1.25rem 2rem 2rem; + border: 1px solid var(--dark-border-color); + border-top: none; + border-bottom-left-radius: var(--border-radius); + border-bottom-right-radius: var(--border-radius); .web-form-wrapper { .form-control { @@ -52,7 +85,7 @@ } .form-column { - padding: 0 var(--padding-md); + padding: 0 var(--padding-sm); &:first-child { padding-left: 0; @@ -66,6 +99,34 @@ padding: 0; } } + + .web-form-skeleton { + .box-group { + display: flex; + gap: 20px; + margin-bottom: 15px; + + .box-container { + width: 100%; + + .box { + background-color: var(--control-bg); + border-radius: var(--border-radius); + } + + .box-label { + height: 20px; + width: 100px; + margin-bottom: 0.5rem; + } + + .box-area { + height: 34px; + width: 100%; + } + } + } + } } .web-form-footer { @@ -83,33 +144,115 @@ padding: 0.5rem; display: flex; align-items: center; + + .slides-progress { + display: flex; + margin-right: .5rem; + + .slide-step { + @include flex(flex, center, center, null); + + height: 18px; + width: 18px; + border-radius: var(--border-radius-full); + border: 1px solid var(--gray-300); + margin: 0 var(--margin-xs); + background-color: var(--card-bg); + + .slide-step-indicator { + height: 6px; + width: 6px; + background-color: var(--gray-300); + border-radius: var(--border-radius-full); + } + + .slide-step-complete { + display: none; + + .icon-xs { + height: 10px; + width: 10px; + } + } + + &.active { + border: 1px solid var(--primary); + + .slide-step-indicator { + display: block; + background-color: var(--primary); + } + } + + &.step-success:not(.active) { + background-color: var(--primary); + border: 1px solid var(--primary); + + .slide-step-indicator { + display: none; + } + + .slide-step-complete { + display: flex; + + .icon use { + stroke-width: 2; + stroke: var(--white); + } + } + } + } + } } } } + } - .attachments { - margin: 1rem -2rem 0; - padding: 1rem 2rem 0; - border-top: 1px solid var(--border-color); + .attachments { + margin-top: 2rem; + padding: 2rem; + border-radius: var(--border-radius); + border: 1px solid var(--dark-border-color); - .attachment { - display: flex; - justify-content: space-between; - gap: 6px; - max-width: 300px; - color: var(--text-muted); - font-size: var(--text-md); + .attachment { + display: flex; + justify-content: space-between; + gap: 6px; + color: var(--text-muted); + font-size: var(--text-md); - &:hover { - text-decoration: none; - .file-name span { - text-decoration: underline; - } + &:hover { + text-decoration: none; + .file-name span { + text-decoration: underline; } } } } + .success-page { + background-color: var(--fg-color); + padding: 2rem; + border: 1px solid var(--dark-border-color); + border-radius: var(--border-radius); + text-align: center; + + svg.icon { + width: 5rem; + height: 5rem; + margin: 1rem; + } + + h2 { + margin-top: 0; + margin-bottom: 0; + } + + .success-message { + margin-bottom: 1.6rem; + } + } + .web-list-container { min-height: 470px; border: 1px solid var(--dark-border-color); @@ -119,6 +262,8 @@ .web-list-header { display: flex; justify-content: space-between; + border-bottom: 1px solid var(--dark-border-color); + padding-bottom: 1.25rem; .web-list-actions { align-self: center; @@ -128,9 +273,7 @@ .web-list-filters { display: flex; flex-wrap: wrap; - margin: 1rem -2rem 0; - padding: 1rem 2rem 0; - border-top: 1px solid var(--border-color); + margin: 1.25rem 0; gap: 10px; .form-group.frappe-control { @@ -158,7 +301,6 @@ .web-list-table { overflow: auto; - margin: 1rem -2rem 0; .table { border-bottom: 1px solid var(--border-color); @@ -171,14 +313,6 @@ font-weight: normal; color: var(--text-muted); - &:first-child { - padding-left: 1.5rem; - } - - &:last-child { - padding-right: 1.5rem; - } - input[type="checkbox"] { margin-bottom: -2px; } @@ -192,19 +326,10 @@ td { font-size: 13px; border-top: 1px solid var(--border-color); - - &:first-child { - padding-left: 1.5rem; - } - - &:last-child { - padding-right: 1.5rem; - } } } input[type="checkbox"] { - margin-left: 0.5rem; margin-top: 2px; } @@ -234,63 +359,4 @@ } } } - - .slides-progress { - display: flex; - margin-right: .5rem; - - .slide-step { - @include flex(flex, center, center, null); - - height: 18px; - width: 18px; - border-radius: var(--border-radius-full); - border: 1px solid var(--gray-300); - margin: 0 var(--margin-xs); - background-color: var(--card-bg); - - .slide-step-indicator { - height: 6px; - width: 6px; - background-color: var(--gray-300); - border-radius: var(--border-radius-full); - } - - .slide-step-complete { - display: none; - - .icon-xs { - height: 10px; - width: 10px; - } - } - - &.active { - border: 1px solid var(--primary); - - .slide-step-indicator { - display: block; - background-color: var(--primary); - } - } - - &.step-success:not(.active) { - background-color: var(--primary); - border: 1px solid var(--primary); - - .slide-step-indicator { - display: none; - } - - .slide-step-complete { - display: flex; - - .icon use { - stroke-width: 2; - stroke: var(--white); - } - } - } - } - } } diff --git a/frappe/website/doctype/web_form/templates/web_form.html b/frappe/website/doctype/web_form/templates/web_form.html index 05af654e47..fce6401457 100644 --- a/frappe/website/doctype/web_form/templates/web_form.html +++ b/frappe/website/doctype/web_form/templates/web_form.html @@ -20,7 +20,7 @@ {% macro action_buttons() %} {% if is_new or is_form_editable %}
- + {% if is_form_editable %} {{ _("Reset Form", null, "Button in web form") }} @@ -38,33 +38,53 @@ {% endmacro %} {% block page_content %} - - - {% if has_header and login_required and show_list %} - {% include "templates/includes/breadcrumbs.html" %} - {% else %} -
+ + {% if banner_image %} +
+ Banner Image +
{% endif %} - -
+ +
+ + {% if not banner_image and has_header and login_required and show_list %} + {% include "templates/includes/breadcrumbs.html" %} + {% else %} +
+ {% endif %} + +
-

{{ _(title) }}

-
- {{ header_buttons() }} + {% if banner_image and has_header and login_required and show_list %} + {% include "templates/includes/breadcrumbs.html" %} + {% endif %} +
+
+

{{ _(title) }}

+
+ {{ header_buttons() }} +
+
+ {% if is_new and introduction_text %} +
{{ introduction_text }}
+ {% endif %}
-
- {% if is_new and introduction_text %} -
{{ introduction_text }}
- {% endif %} -
+ + + +
+
+ {% include "website/doctype/web_form/templates/web_form_skeleton.html" %} +
+
-
+ {% if show_attachments and not is_new and attachments %} @@ -81,17 +101,45 @@ {% endfor %}
{% endif %} {# attachments #} - - - {% if allow_comments and not is_new and not is_list -%} -
-

{{ _("Comments") }}

- {% include 'templates/includes/comments/comments.html' %} -
- {%- else -%} -
- {%- endif %} {# comments #} + + {% if allow_comments and not is_new and not is_list -%} +
+

{{ _("Comments") }}

+ {% include 'templates/includes/comments/comments.html' %} +
+ {%- else -%} +
+ {%- endif %} {# comments #} +
+ + +
+ + + +

{{ _(success_title) or _("Submitted") }}

+

{{ _(success_message) or _("Thank you for spending your valuable time to fill this form") }}

+ + {% if success_url %} +
+

+ Click on this + {{_("URL")}} + if you are not redirected within + 5 + seconds. +

+
+ {% else %} + {% if show_list %} + {{ _("See previous responses", null, "Button in web form") }} + {% endif %} + {% if not login_required or allow_multiple %} + {{ _("Submit another response", null, "Button in web form") }} + {% endif %} + {% endif %} +
{% endblock page_content %} diff --git a/frappe/website/doctype/web_form/templates/web_form_skeleton.html b/frappe/website/doctype/web_form/templates/web_form_skeleton.html new file mode 100644 index 0000000000..82fb2bccac --- /dev/null +++ b/frappe/website/doctype/web_form/templates/web_form_skeleton.html @@ -0,0 +1,38 @@ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/frappe/website/doctype/web_form/web_form.json b/frappe/website/doctype/web_form/web_form.json index 64bf04f3e8..8faa263e5b 100644 --- a/frappe/website/doctype/web_form/web_form.json +++ b/frappe/website/doctype/web_form/web_form.json @@ -30,12 +30,6 @@ "form_fields", "web_form_fields", "max_attachment_size", - "actions", - "breadcrumbs", - "button_label", - "column_break_29", - "success_message", - "success_url", "list_settings_tab", "list_setting_message", "show_list", @@ -44,6 +38,16 @@ "sidebar_settings_tab", "show_sidebar", "website_sidebar", + "customization_tab", + "button_label", + "banner_image", + "column_break_37", + "breadcrumbs", + "section_break_43", + "success_title", + "success_url", + "column_break_41", + "success_message", "scripting_style_tab", "client_script", "custom_css" @@ -162,7 +166,7 @@ }, { "fieldname": "introduction_text", - "fieldtype": "Small Text", + "fieldtype": "Text Editor", "ignore_xss_filter": 1, "label": "Introduction" }, @@ -183,12 +187,6 @@ "fieldtype": "Code", "label": "Client Script" }, - { - "collapsible": 1, - "fieldname": "actions", - "fieldtype": "Section Break", - "label": "Customization" - }, { "default": "Save", "fieldname": "button_label", @@ -196,7 +194,7 @@ "label": "Submit Button Label" }, { - "description": "Message to be displayed on successful completion (only for Guest users)", + "description": "Message to be displayed on successful completion", "fieldname": "success_message", "fieldtype": "Text", "label": "Success Message" @@ -217,7 +215,8 @@ "description": "List as [{\"label\": _(\"Jobs\"), \"route\":\"jobs\"}]", "fieldname": "breadcrumbs", "fieldtype": "Code", - "label": "Breadcrumbs" + "label": "Breadcrumbs", + "max_height": "140px" }, { "fieldname": "custom_css", @@ -272,10 +271,6 @@ "label": "Website Sidebar", "options": "Website Sidebar" }, - { - "fieldname": "column_break_29", - "fieldtype": "Column Break" - }, { "fieldname": "list_setting_message", "fieldtype": "HTML", @@ -303,13 +298,41 @@ "fieldname": "scripting_style_tab", "fieldtype": "Tab Break", "label": "Scripting / Style" + }, + { + "fieldname": "customization_tab", + "fieldtype": "Tab Break", + "label": "Customization" + }, + { + "fieldname": "success_title", + "fieldtype": "Data", + "label": "Success Title" + }, + { + "fieldname": "banner_image", + "fieldtype": "Attach Image", + "label": "Banner Image" + }, + { + "fieldname": "column_break_41", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_43", + "fieldtype": "Section Break", + "label": "After Submission" + }, + { + "fieldname": "column_break_37", + "fieldtype": "Column Break" } ], "has_web_view": 1, "icon": "icon-edit", "is_published_field": "published", "links": [], - "modified": "2022-08-10 15:38:28.611328", + "modified": "2022-08-11 16:27:25.914627", "modified_by": "Administrator", "module": "Website", "name": "Web Form", diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py index eee7827500..718088212f 100644 --- a/frappe/website/doctype/web_form/web_form.py +++ b/frappe/website/doctype/web_form/web_form.py @@ -281,7 +281,7 @@ def get_context(context): context.title = strip_html( context.reference_doc.get(context.reference_doc.meta.get_title_field()) ) - if context.is_form_editable: + if context.is_form_editable and context.parents: context.parents.append( { "label": _(context.title),