diff --git a/app/controllers/email_settings_controller.rb b/app/controllers/email_smtp_settings_controller.rb similarity index 94% rename from app/controllers/email_settings_controller.rb rename to app/controllers/email_smtp_settings_controller.rb index 2c39053c..a8c76692 100644 --- a/app/controllers/email_settings_controller.rb +++ b/app/controllers/email_smtp_settings_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class EmailSettingsController < ApplicationController +class EmailSmtpSettingsController < ApplicationController before_action :load_encrypted_config authorize_resource :encrypted_config, only: :index authorize_resource :encrypted_config, parent: false, only: :create diff --git a/app/controllers/notifications_settings_controller.rb b/app/controllers/notifications_settings_controller.rb new file mode 100644 index 00000000..2189ccda --- /dev/null +++ b/app/controllers/notifications_settings_controller.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +class NotificationsSettingsController < ApplicationController + before_action :load_bcc_config, only: :index + before_action :load_reminder_config, only: :index + authorize_resource :bcc_config, only: :index + authorize_resource :reminder_config, only: :index + + before_action :build_account_config, only: :create + authorize_resource :account_config, only: :create + + def index; end + + def create + if @account_config.save + redirect_back fallback_location: settings_notifications_path, notice: 'Changes have been saved' + else + redirect_back fallback_location: settings_notifications_path, alert: 'Unable to save' + end + end + + private + + def build_account_config + @account_config = + AccountConfig.find_or_initialize_by(account: current_account, key: email_config_params[:key]) + + @account_config.assign_attributes(email_config_params) + end + + def load_bcc_config + @bcc_config = + AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::BCC_EMAILS) + end + + def load_reminder_config + @reminder_config = + AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::SUBMITTER_REMAILERS) + end + + def email_config_params + params.require(:account_config).permit!.tap do |attrs| + attrs[:key] = nil unless attrs[:key].in?([AccountConfig::BCC_EMAILS, AccountConfig::SUBMITTER_REMAILERS]) + end + end +end diff --git a/app/jobs/process_submitter_completion_job.rb b/app/jobs/process_submitter_completion_job.rb index 3f3da35c..1da7a6c5 100644 --- a/app/jobs/process_submitter_completion_job.rb +++ b/app/jobs/process_submitter_completion_job.rb @@ -26,7 +26,8 @@ class ProcessSubmitterCompletionJob < ApplicationJob user = submitter.submission.created_by_user || submitter.template.author if submitter.template.account.users.exists?(id: user.id) - bcc = submitter.submission.template.account.account_configs.find_by(key: 'bcc_emails')&.value + bcc = submitter.submission.template.account.account_configs + .find_by(key: AccountConfig::BCC_EMAILS)&.value SubmitterMailer.completed_email(submitter, user, bcc:).deliver_later! end diff --git a/app/models/account_config.rb b/app/models/account_config.rb index 45109be3..6f08c2e5 100644 --- a/app/models/account_config.rb +++ b/app/models/account_config.rb @@ -24,6 +24,8 @@ class AccountConfig < ApplicationRecord SUBMITTER_INVITATION_EMAIL_KEY = 'submitter_invitation_email' SUBMITTER_COMPLETED_EMAIL_KEY = 'submitter_completed_email' SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY = 'submitter_documents_copy_email' + BCC_EMAILS = 'bcc_emails' + SUBMITTER_REMAILERS = 'submitter_reminders' DEFAULT_VALUES = { SUBMITTER_INVITATION_EMAIL_KEY => { diff --git a/app/models/submission_event.rb b/app/models/submission_event.rb index 3756b382..c5be0526 100644 --- a/app/models/submission_event.rb +++ b/app/models/submission_event.rb @@ -25,6 +25,7 @@ # class SubmissionEvent < ApplicationRecord belongs_to :submission + has_one :account, through: :submission belongs_to :submitter, optional: true attribute :data, :string, default: -> { {} } @@ -36,6 +37,7 @@ class SubmissionEvent < ApplicationRecord enum :event_type, { send_email: 'send_email', + send_reminder_email: 'send_reminder_email', send_sms: 'send_sms', open_email: 'open_email', click_email: 'click_email', diff --git a/app/views/email_settings/index.html.erb b/app/views/email_smtp_settings/index.html.erb similarity index 100% rename from app/views/email_settings/index.html.erb rename to app/views/email_smtp_settings/index.html.erb diff --git a/app/views/notifications_settings/_bcc_form.html.erb b/app/views/notifications_settings/_bcc_form.html.erb new file mode 100644 index 00000000..2459c6e4 --- /dev/null +++ b/app/views/notifications_settings/_bcc_form.html.erb @@ -0,0 +1,19 @@ +<%= form_for config, url: settings_notifications_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %> + <%= f.hidden_field :key %> +
+ <%= f.label :value, class: 'label' do %> + + + Completed documents BCC address + + + <%= svg_icon('info_circle', class: 'w-4 h-4') %> + + + <% end %> + <%= f.email_field :value, autocomplete: 'off', class: 'base-input' %> +
+
+ <%= f.button button_title(title: 'Save', disabled_with: 'Updating'), class: 'base-button' %> +
+<% end %> diff --git a/app/views/notifications_settings/_email_stats.html.erb b/app/views/notifications_settings/_email_stats.html.erb new file mode 100644 index 00000000..e69de29b diff --git a/app/views/notifications_settings/_reminder_banner.html.erb b/app/views/notifications_settings/_reminder_banner.html.erb new file mode 100644 index 00000000..926e952d --- /dev/null +++ b/app/views/notifications_settings/_reminder_banner.html.erb @@ -0,0 +1 @@ +<%= render 'reminder_placeholder' %> diff --git a/app/views/notifications_settings/_reminder_form.html.erb b/app/views/notifications_settings/_reminder_form.html.erb new file mode 100644 index 00000000..5c4254c3 --- /dev/null +++ b/app/views/notifications_settings/_reminder_form.html.erb @@ -0,0 +1,29 @@ +<%= form_for config, url: settings_notifications_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %> + <%= f.hidden_field :key %> +
+ <% record = Struct.new(:first_duration, :second_duration, :third_duration).new(*(f.object.value || {}).values_at('first_duration', 'second_duration', 'third_duration')) %> +
+
+ <%= f.fields_for :value, record do |ff| %> + <%= ff.label :first_duration, 'First reminder in', class: 'label' %> + <%= ff.select :first_duration, AccountConfigs::REMINDER_DURATIONS.invert, { include_blank: 'None' }, class: 'base-select' %> + <% end %> +
+
+ <%= f.fields_for :value, record do |ff| %> + <%= ff.label :second_duration, 'Second reminder in', class: 'label' %> + <%= ff.select :second_duration, AccountConfigs::REMINDER_DURATIONS.invert, { include_blank: 'None' }, class: 'base-select' %> + <% end %> +
+
+ <%= f.fields_for :value, record do |ff| %> + <%= ff.label :third_duration, 'Third reminder in', class: 'label' %> + <%= ff.select :third_duration, AccountConfigs::REMINDER_DURATIONS.invert, { include_blank: 'None' }, class: 'base-select' %> + <% end %> +
+
+
+
+ <%= f.button button_title(title: 'Save', disabled_with: 'Updating'), class: 'base-button' %> +
+<% end %> diff --git a/app/views/notifications_settings/_reminder_placeholder.html.erb b/app/views/notifications_settings/_reminder_placeholder.html.erb new file mode 100644 index 00000000..9414771e --- /dev/null +++ b/app/views/notifications_settings/_reminder_placeholder.html.erb @@ -0,0 +1,11 @@ +
+ <%= svg_icon('info_circle', class: 'w-6 h-6') %> +
+

Unlock with DocuSeal Pro

+

+ Send automatic email reminders to your recipients. +
+ ">Learn More +

+
+
diff --git a/app/views/notifications_settings/index.html.erb b/app/views/notifications_settings/index.html.erb new file mode 100644 index 00000000..a106337a --- /dev/null +++ b/app/views/notifications_settings/index.html.erb @@ -0,0 +1,14 @@ +
+ <%= render 'shared/settings_nav' %> +
+

Email Notifications

+ <%= render 'email_stats' %> + <%= render 'bcc_form', config: @bcc_config %> +
+

Signature Email Reminders

+
+ <%= render 'reminder_banner' %> + <%= render 'reminder_form', config: @reminder_config %> +
+
+
diff --git a/app/views/shared/_settings_nav.html.erb b/app/views/shared/_settings_nav.html.erb index 15d3ec4a..b4a18b2d 100644 --- a/app/views/shared/_settings_nav.html.erb +++ b/app/views/shared/_settings_nav.html.erb @@ -26,6 +26,11 @@ <% end %> <% end %> + <% if can?(:read, AccountConfig) %> +
  • + <%= link_to 'Notifications', settings_notifications_path, class: 'text-base hover:bg-base-300' %> +
  • + <% end %> <% if can?(:read, EncryptedConfig.new(key: EncryptedConfig::ESIGN_CERTS_KEY, account: current_account)) %>
  • <%= link_to 'E-Signature', settings_esign_path, class: 'text-base hover:bg-base-300' %> diff --git a/app/views/submissions/_email_stats.html.erb b/app/views/submissions/_email_stats.html.erb new file mode 100644 index 00000000..e69de29b diff --git a/app/views/submissions/_send_email.html.erb b/app/views/submissions/_send_email.html.erb index 1bee1be9..a2d197fb 100644 --- a/app/views/submissions/_send_email.html.erb +++ b/app/views/submissions/_send_email.html.erb @@ -1,9 +1,12 @@
    <% is_smtp_configured = Accounts.can_send_emails?(current_account) %> - <%= f.label :send_email, for: uuid = SecureRandom.uuid, class: 'flex items-center cursor-pointer' do %> - <%= f.check_box :send_email, id: uuid, class: 'base-checkbox', disabled: !is_smtp_configured, checked: is_smtp_configured %> - Send emails - <% end %> +
    + <%= f.label :send_email, for: uuid = SecureRandom.uuid, class: 'flex items-center cursor-pointer' do %> + <%= f.check_box :send_email, id: uuid, class: 'base-checkbox', disabled: !is_smtp_configured, checked: is_smtp_configured %> + Send emails + <% end %> + <%= render 'email_stats' %> +
    <% unless is_smtp_configured %>
    <%= svg_icon('info_circle', class: 'w-6 h-6') %> diff --git a/config/routes.rb b/config/routes.rb index de9beea5..51eca223 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -78,9 +78,10 @@ Rails.application.routes.draw do scope '/settings', as: :settings do unless Docuseal.multitenant? resources :storage, only: %i[index create], controller: 'storage_settings' - resources :email, only: %i[index create], controller: 'email_settings' + resources :email, only: %i[index create], controller: 'email_smtp_settings' resources :sms, only: %i[index], controller: 'sms_settings' end + resources :notifications, only: %i[index create], controller: 'notifications_settings' resource :esign, only: %i[show create new update destroy], controller: 'esign_settings' resources :users, only: %i[index] resource :personalization, only: %i[show create], controller: 'personalization_settings' diff --git a/config/sidekiq.yml b/config/sidekiq.yml index 36e2a6f3..70450bc2 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -1,6 +1,7 @@ queues: - [default, 1] - [mailers, 1] + - [recurrent, 1] production: :concurrency: 15 diff --git a/lib/account_configs.rb b/lib/account_configs.rb index 6eaa79a7..4d17acfc 100644 --- a/lib/account_configs.rb +++ b/lib/account_configs.rb @@ -1,6 +1,19 @@ # frozen_string_literal: true module AccountConfigs + REMINDER_DURATIONS = { + 'one_hour' => '1 hour', + 'two_hours' => '2 hours', + 'four_hours' => '4 hours', + 'eight_hours' => '8 hours', + 'twelve_hours' => '12 hours', + 'twenty_four_hours' => '24 hours', + 'two_days' => '2 days', + 'four_days' => '4 days', + 'eight_days' => '8 days', + 'fifteen_days' => '15 days' + }.freeze + module_function def find_or_initialize_for_key(account, key) diff --git a/lib/submission_events.rb b/lib/submission_events.rb index 9ec2a6a1..7425f131 100644 --- a/lib/submission_events.rb +++ b/lib/submission_events.rb @@ -5,6 +5,7 @@ module SubmissionEvents EVENT_NAMES = { send_email: 'Email sent', + send_reminder_email: 'Reminder email sent', send_sms: 'SMS sent', open_email: 'Email opened', click_email: 'Email link clicked',