From 2c315dd9b1ed737172d052c13383a217bc19f7da Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 10:11:21 -0400 Subject: [PATCH] feat: add consent banner requirement for signers (B6) (#16) * feat: add consent banner requirement for signers (B6) - Add REQUIRE_CONSENT_KEY to AccountConfig for per-account toggle - Add consent_given event type to SubmissionEvent for audit trail - Add consent checkbox UI on last step of signing form (form.vue) - Add isLastStep computed property and onConsentChange method - Create API endpoint (submitter_consents#create) to record consent - Add requireConsent prop passing from server via data attribute - Add settings toggle in Account preferences page - Add i18n translations for all 14 languages (JS + Rails) - Submit button disabled until consent checkbox is checked * fix: add REQUIRE_CONSENT_KEY to AccountConfigsController ALLOWED_KEYS * fix: keep consent checkbox visible after checking (don't remove from DOM) * fix: bind checkbox checked state to consentAccepted for step navigation sync --------- Co-authored-by: mario.pander --- app/controllers/account_configs_controller.rb | 3 +- .../api/submitter_consents_controller.rb | 16 +++++++ app/javascript/form.js | 1 + app/javascript/submission_form/form.vue | 45 ++++++++++++++++++- app/javascript/submission_form/i18n.js | 42 +++++++++++------ app/models/account_config.rb | 1 + app/models/submission_event.rb | 3 +- app/views/accounts/show.html.erb | 17 +++++++ .../submit_form/_submission_form.html.erb | 2 +- config/locales/i18n.yml | 28 ++++++++++++ config/routes.rb | 1 + lib/submitters/form_configs.rb | 5 ++- 12 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 app/controllers/api/submitter_consents_controller.rb diff --git a/app/controllers/account_configs_controller.rb b/app/controllers/account_configs_controller.rb index fb749895..8881697e 100644 --- a/app/controllers/account_configs_controller.rb +++ b/app/controllers/account_configs_controller.rb @@ -26,7 +26,8 @@ class AccountConfigsController < ApplicationController AccountConfig::REQUIRE_SIGNING_REASON_KEY, AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY, AccountConfig::ENABLE_MCP_KEY, - AccountConfig::IP_ALLOWLIST_KEY + AccountConfig::IP_ALLOWLIST_KEY, + AccountConfig::REQUIRE_CONSENT_KEY ].freeze InvalidKey = Class.new(StandardError) diff --git a/app/controllers/api/submitter_consents_controller.rb b/app/controllers/api/submitter_consents_controller.rb new file mode 100644 index 00000000..447d9fce --- /dev/null +++ b/app/controllers/api/submitter_consents_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Api + class SubmitterConsentsController < ApiBaseController + skip_before_action :authenticate_user! + skip_authorization_check + + def create + @submitter = Submitter.find_by!(slug: params[:submitter_slug]) + + SubmissionEvents.create_with_tracking_data(@submitter, 'consent_given', request) + + render json: {} + end + end +end diff --git a/app/javascript/form.js b/app/javascript/form.js index c8d5790e..26b1aa50 100644 --- a/app/javascript/form.js +++ b/app/javascript/form.js @@ -42,6 +42,7 @@ safeRegisterElement('submission-form', class extends HTMLElement { withConfetti: this.dataset.withConfetti === 'true', withFieldLabels: this.dataset.withFieldLabels !== 'false', withDisclosure: this.dataset.withDisclosure === 'true', + requireConsent: this.dataset.requireConsent === 'true', reuseSignature: this.dataset.reuseSignature !== 'false', withTypedSignature: this.dataset.withTypedSignature !== 'false', authenticityToken: document.querySelector('meta[name="csrf-token"]')?.content, diff --git a/app/javascript/submission_form/form.vue b/app/javascript/submission_form/form.vue index 45585c4f..1e612b72 100644 --- a/app/javascript/submission_form/form.vue +++ b/app/javascript/submission_form/form.vue @@ -570,12 +570,26 @@ v-if="(currentField.type !== 'payment' && currentField.type !== 'verification' && currentField.type !== 'kba') || submittedValues[currentField.uuid]" :class="currentField.type === 'signature' ? 'mt-2' : 'mt-4 md:mt-6'" > +