mirror of
https://github.com/docusealco/docuseal.git
synced 2026-08-07 07:14:43 +00:00
customize template email per party
This commit is contained in:
@@ -28,8 +28,10 @@ class TemplatesPreferencesController < ApplicationController
|
||||
submitters_order
|
||||
completed_notification_email_subject completed_notification_email_body
|
||||
completed_notification_email_enabled completed_notification_email_attach_audit] +
|
||||
[completed_message: %i[title body]]
|
||||
[completed_message: %i[title body],
|
||||
submitters: [%i[uuid request_email_subject request_email_body]]]
|
||||
).tap do |attrs|
|
||||
attrs[:preferences].delete(:submitters) if params[:request_email_per_submitter] != '1'
|
||||
attrs[:preferences] = attrs[:preferences].transform_values do |value|
|
||||
if %w[true false].include?(value)
|
||||
value == 'true'
|
||||
|
||||
@@ -3,6 +3,8 @@ export default class extends HTMLElement {
|
||||
this.resize()
|
||||
|
||||
this.textarea.addEventListener('input', () => this.resize())
|
||||
|
||||
this.observeVisibility()
|
||||
}
|
||||
|
||||
resize () {
|
||||
@@ -11,6 +13,28 @@ export default class extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
observeVisibility () {
|
||||
this.observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
this.resize()
|
||||
this.observer.unobserve(this.textarea)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
threshold: 0.1
|
||||
}
|
||||
)
|
||||
|
||||
this.observer.observe(this.textarea)
|
||||
}
|
||||
|
||||
disconnectedCallback () {
|
||||
this.observer.unobserve(this.textarea)
|
||||
}
|
||||
|
||||
get textarea () {
|
||||
return this.querySelector('textarea')
|
||||
}
|
||||
|
||||
@@ -14,8 +14,20 @@ class SubmitterMailer < ApplicationMailer
|
||||
@email_message = submitter.account.email_messages.find_by(uuid: submitter.preferences['email_message_uuid'])
|
||||
end
|
||||
|
||||
@body = @email_message&.body.presence || @submitter.template.preferences['request_email_body'].presence
|
||||
@subject = @email_message&.subject.presence || @submitter.template.preferences['request_email_subject'].presence
|
||||
template_submitters_index =
|
||||
if @email_message.blank?
|
||||
build_submitter_preferences_index(@submitter)
|
||||
else
|
||||
{}
|
||||
end
|
||||
|
||||
@body = @email_message&.body.presence ||
|
||||
template_submitters_index.dig(@submitter.uuid, 'request_email_body').presence ||
|
||||
@submitter.template.preferences['request_email_body'].presence
|
||||
|
||||
@subject = @email_message&.subject.presence ||
|
||||
template_submitters_index.dig(@submitter.uuid, 'request_email_subject').presence ||
|
||||
@submitter.template.preferences['request_email_subject'].presence
|
||||
|
||||
@email_config = AccountConfigs.find_for_account(@current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY)
|
||||
|
||||
@@ -24,14 +36,7 @@ class SubmitterMailer < ApplicationMailer
|
||||
reply_to = build_submitter_reply_to(@submitter)
|
||||
|
||||
I18n.with_locale(@current_account.locale) do
|
||||
subject =
|
||||
if @email_config || @subject
|
||||
ReplaceEmailVariables.call(@subject || @email_config.value['subject'], submitter:)
|
||||
elsif @submitter.with_signature_fields?
|
||||
I18n.t(:you_are_invited_to_sign_a_document)
|
||||
else
|
||||
I18n.t(:you_are_invited_to_submit_a_form)
|
||||
end
|
||||
subject = build_invite_subject(@subject, @email_config, submitter)
|
||||
|
||||
mail(
|
||||
to: @submitter.friendly_name,
|
||||
@@ -196,6 +201,20 @@ class SubmitterMailer < ApplicationMailer
|
||||
user.role == 'integration' ? user.friendly_name.sub(/\+\w+@/, '@') : user.friendly_name
|
||||
end
|
||||
|
||||
def build_invite_subject(subject, email_config, submitter)
|
||||
if email_config || subject
|
||||
ReplaceEmailVariables.call(subject || email_config.value['subject'], submitter:)
|
||||
elsif submitter.with_signature_fields?
|
||||
I18n.t(:you_are_invited_to_sign_a_document)
|
||||
else
|
||||
I18n.t(:you_are_invited_to_submit_a_form)
|
||||
end
|
||||
end
|
||||
|
||||
def build_submitter_preferences_index(submitter)
|
||||
submitter.template.preferences['submitters'].to_a.index_by { |e| e['uuid'] }
|
||||
end
|
||||
|
||||
def add_attachments_with_size_limit(submitter, storage_attachments, current_size, filename_format = nil)
|
||||
total_size = current_size
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<% submitter_preferences_index = template.preferences['submitters'].to_a.index_by { |e| e['uuid'] } %>
|
||||
<div class="form-control">
|
||||
<% can_send_emails = Accounts.can_send_emails?(current_account) %>
|
||||
<div class="flex justify-between items-center">
|
||||
@@ -36,10 +37,18 @@
|
||||
<% config = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY) %>
|
||||
<div id="message_field" class="card card-compact bg-base-300/40 hidden">
|
||||
<div class="card-body">
|
||||
<div class="form-control space-y-2">
|
||||
<%= tag.input id: 'request_email_per_submitter', value: '1', name: 'request_email_per_submitter', class: 'peer', type: 'checkbox', hidden: true, checked: local_assigns[:message_per_submitter] != false && template.preferences['submitters'].to_a.size > 1 %>
|
||||
<div class="peer-checked:hidden form-control space-y-2">
|
||||
<div class="form-control">
|
||||
<%= f.label :subject, t('subject'), class: 'label' %>
|
||||
<%= f.text_field :subject, value: local_assigns[:submitter_email_message]&.subject.presence || template.preferences['request_email_subject'].presence || config.value['subject'], required: true, class: '!text-sm base-input w-full', dir: 'auto' %>
|
||||
<div class="flex justify-between">
|
||||
<%= f.label :subject, t('subject'), class: 'label' %>
|
||||
<% if template.submitters.size > 1 && template.submitters.size < 5 && local_assigns[:message_per_submitter] != false %>
|
||||
<label for="request_email_per_submitter" class="label underline">
|
||||
<%= t('edit_per_party') %>
|
||||
</label>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= f.text_field :subject, value: local_assigns[:submitter_email_message]&.subject.presence || submitter_preferences_index.dig(local_assigns[:submitter]&.uuid, 'request_email_subject').presence || template.preferences['request_email_subject'].presence || config.value['subject'], required: true, class: '!text-sm base-input w-full', dir: 'auto' %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<div class="flex items-center">
|
||||
@@ -49,7 +58,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<autoresize-textarea>
|
||||
<%= f.text_area :body, value: local_assigns[:submitter_email_message]&.body.presence || template.preferences['request_email_body'].presence || config.value['body'], required: true, class: 'base-textarea w-full', rows: 10, dir: 'auto' %>
|
||||
<%= f.text_area :body, value: local_assigns[:submitter_email_message]&.body.presence || submitter_preferences_index.dig(local_assigns[:submitter]&.uuid, 'request_email_body').presence || template.preferences['request_email_body'].presence || config.value['body'], required: true, class: 'base-textarea w-full', rows: 10, dir: 'auto' %>
|
||||
</autoresize-textarea>
|
||||
<% unless local_assigns.fetch(:disable_save_as_default_template_option, false) %>
|
||||
<label for="<%= uuid = SecureRandom.uuid %>" class="flex items-center cursor-pointer">
|
||||
@@ -60,5 +69,43 @@
|
||||
</div>
|
||||
<%= render 'submissions/message_fields' %>
|
||||
</div>
|
||||
<% if template.submitters.size > 1 && template.submitters.size < 5 && local_assigns[:message_per_submitter] != false %>
|
||||
<div class="hidden peer-checked:block form-control space-y-2">
|
||||
<% options = template.submitters.map { |e| [e['name'], "request_email_#{e['uuid']}"] } %>
|
||||
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="flex relative px-1">
|
||||
<ul class="tabs w-full flex flex-nowrap">
|
||||
<% options.each_with_index do |(label, val), index| %>
|
||||
<div class="w-full">
|
||||
<%= f.radio_button :selected, val, checked: index.zero?, id: "#{val}_radio", data: { action: 'click:toggle-visible#trigger' }, class: 'hidden peer' %>
|
||||
<%= f.label :selected, label, value: val, for: "#{val}_radio", class: 'tab w-full tab-lifted peer-checked:tab-active !bg-transparent' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</ul>
|
||||
</toggle-visible>
|
||||
<% template.submitters.each_with_index do |submitter, index| %>
|
||||
<%= fields_for :submitter_preferences, nil, index: submitter['uuid'] do |ff| %>
|
||||
<div id="request_email_<%= submitter['uuid'] %>" class="<%= 'hidden' if index != 0 %>">
|
||||
<div class="form-control">
|
||||
<div class="flex justify-between">
|
||||
<%= ff.label :subject, t('subject'), class: 'label' %>
|
||||
</div>
|
||||
<%= ff.text_field :subject, value: local_assigns[:submitter_email_message]&.subject.presence || submitter_preferences_index.dig(submitter['uuid'], 'request_email_subject').presence || template.preferences['request_email_subject'].presence || config.value['subject'], required: true, class: '!text-sm base-input w-full', dir: 'auto' %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<div class="flex items-center">
|
||||
<%= ff.label :message, t('body'), class: 'label' %>
|
||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
||||
</span>
|
||||
</div>
|
||||
<autoresize-textarea>
|
||||
<%= ff.text_area :body, value: local_assigns[:submitter_email_message]&.body.presence || submitter_preferences_index.dig(submitter['uuid'], 'request_email_body').presence || template.preferences['request_email_body'].presence || config.value['body'], required: true, class: 'base-textarea w-full', rows: 10, dir: 'auto' %>
|
||||
</autoresize-textarea>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</submitter-item>
|
||||
</div>
|
||||
<div>
|
||||
<%= render 'submissions/send_email', f:, template: @submitter.template, submitter: @submitter, resend_email: @submitter.sent_at?, submitter_email_message: @submitter_email_message, disable_save_as_default_template_option: true %>
|
||||
<%= render 'submissions/send_email', f:, template: @submitter.template, submitter: @submitter, resend_email: @submitter.sent_at?, submitter_email_message: @submitter_email_message, disable_save_as_default_template_option: true, message_per_submitter: false %>
|
||||
<%= render 'submissions/send_sms', f:, resend_sms: @submitter.sent_at? %>
|
||||
</div>
|
||||
<div class="form-control mt-4">
|
||||
|
||||
@@ -83,21 +83,71 @@
|
||||
<div class="collapse-content">
|
||||
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
|
||||
<toggle-on-submit data-element-id="email_saved_alert1"></toggle-on-submit>
|
||||
<%= f.fields_for :preferences, Struct.new(:request_email_subject, :request_email_body).new(*(@template.preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence || AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY).value.values_at('subject', 'body'))) do |ff| %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :request_email_subject, t('email_subject'), class: 'label' %>
|
||||
<%= ff.text_field :request_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<div class="flex items-center">
|
||||
<%= ff.label :request_email_body, t('email_body'), class: 'label' %>
|
||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
||||
</span>
|
||||
<%= tag.input id: 'request_email_per_submitter', value: '1', name: 'request_email_per_submitter', class: 'peer', type: 'checkbox', hidden: true, checked: @template.preferences['submitters'].to_a.size > 1 %>
|
||||
<div class="peer-checked:hidden">
|
||||
<%= f.fields_for :preferences, Struct.new(:request_email_subject, :request_email_body).new(*(@template.preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence || AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY).value.values_at('subject', 'body'))) do |ff| %>
|
||||
<div class="form-control">
|
||||
<div class="flex justify-between">
|
||||
<%= ff.label :request_email_subject, t('email_subject'), class: 'label' %>
|
||||
<% if @template.submitters.size > 1 && @template.submitters.size < 5 %>
|
||||
<label for="request_email_per_submitter" class="label underline">
|
||||
<%= t('edit_per_party') %>
|
||||
</label>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= ff.text_field :request_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||
</div>
|
||||
<autoresize-textarea>
|
||||
<%= ff.text_area :request_email_body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
||||
</autoresize-textarea>
|
||||
<div class="form-control">
|
||||
<div class="flex items-center">
|
||||
<%= ff.label :request_email_body, t('email_body'), class: 'label' %>
|
||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
||||
</span>
|
||||
</div>
|
||||
<autoresize-textarea>
|
||||
<%= ff.text_area :request_email_body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
||||
</autoresize-textarea>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if @template.submitters.size > 1 && @template.submitters.size < 5 %>
|
||||
<div class="hidden peer-checked:block">
|
||||
<% options = @template.submitters.map { |e| [e['name'], "request_email_#{e['uuid']}"] } %>
|
||||
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="flex relative px-1">
|
||||
<ul class="tabs w-full flex flex-nowrap mb-2">
|
||||
<% options.each_with_index do |(label, val), index| %>
|
||||
<div class="w-full">
|
||||
<%= f.radio_button :selected, val, checked: index.zero?, id: "#{val}_radio", data: { action: 'click:toggle-visible#trigger' }, class: 'hidden peer' %>
|
||||
<%= f.label :selected, label, value: val, for: "#{val}_radio", class: 'tab w-full tab-lifted peer-checked:tab-active' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</ul>
|
||||
</toggle-visible>
|
||||
<%= f.fields_for :preferences do |ff| %>
|
||||
<% @template.submitters.each_with_index do |submitter, index| %>
|
||||
<div id="request_email_<%= submitter['uuid'] %>" class="<%= 'hidden' if index != 0 %>">
|
||||
<% submitter_preferences = f.object.preferences['submitters'].to_a.find { |e| e['uuid'] == submitter['uuid'] } || {} %>
|
||||
<%= ff.fields_for :submitters, Struct.new(:request_email_subject, :request_email_body).new(*(submitter_preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence || @template.preferences.values_at('request_email_subject', 'request_email_body').compact_blank.presence || AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY).value.values_at('subject', 'body'))), index: nil do |fff| %>
|
||||
<%= fff.hidden_field :uuid, value: submitter['uuid'] %>
|
||||
<div class="form-control">
|
||||
<%= fff.label :request_email_subject, t('email_subject'), class: 'label' %>
|
||||
<%= fff.text_field :request_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<div class="flex items-center">
|
||||
<%= fff.label :request_email_body, t('email_body'), class: 'label' %>
|
||||
<span class="tooltip tooltip-right" data-tip="<%= t('use_following_placeholders_text_') %> <%= AccountConfig::DEFAULT_VALUES[AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY].call['body'].scan(/{.*?}/).join(', ') %>">
|
||||
<%= svg_icon('info_circle', class: 'w-4 h-4') %>
|
||||
</span>
|
||||
</div>
|
||||
<autoresize-textarea>
|
||||
<%= fff.text_area :request_email_body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
||||
</autoresize-textarea>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="form-control pt-2">
|
||||
|
||||
@@ -20,6 +20,7 @@ en: &en
|
||||
language_ko: 한국어
|
||||
hi_there: Hi there
|
||||
thanks: Thanks
|
||||
edit_per_party: Edit per party
|
||||
reply_to: Reply to
|
||||
pending_by_me: Pending by me
|
||||
partially_completed: Partially completed
|
||||
@@ -732,6 +733,7 @@ en: &en
|
||||
read: Read your data
|
||||
|
||||
es: &es
|
||||
edit_per_party: Editar por parte
|
||||
signed: Firmado
|
||||
reply_to: Responder a
|
||||
partially_completed: Parcialmente completado
|
||||
@@ -1446,6 +1448,7 @@ es: &es
|
||||
read: Leer tus datos
|
||||
|
||||
it: &it
|
||||
edit_per_party: Modifica per partito
|
||||
signed: Firmato
|
||||
reply_to: Rispondi a
|
||||
pending_by_me: In sospeso da me
|
||||
@@ -2159,6 +2162,7 @@ it: &it
|
||||
read: Leggi i tuoi dati
|
||||
|
||||
fr: &fr
|
||||
edit_per_party: Éditer par partie
|
||||
signed: Signé
|
||||
reply_to: Répondre à
|
||||
partially_completed: Partiellement complété
|
||||
@@ -2874,6 +2878,7 @@ fr: &fr
|
||||
read: Lire vos données
|
||||
|
||||
pt: &pt
|
||||
edit_per_party: Edita por festa
|
||||
signed: Assinado
|
||||
reply_to: Responder a
|
||||
partially_completed: Parcialmente concluído
|
||||
@@ -3588,6 +3593,7 @@ pt: &pt
|
||||
read: Ler seus dados
|
||||
|
||||
de: &de
|
||||
edit_per_party: Bearbeiten pro Partei
|
||||
signed: Unterschrieben
|
||||
reply_to: Antworten auf
|
||||
partially_completed: Teilweise abgeschlossen
|
||||
|
||||
@@ -36,8 +36,8 @@ module Submissions
|
||||
|
||||
is_order_sent = submitters_order == 'random' || index.zero?
|
||||
|
||||
build_submitter(submission:, attrs: submitter_attrs, uuid:,
|
||||
is_order_sent:, user:,
|
||||
build_submitter(submission:, attrs: submitter_attrs,
|
||||
uuid:, is_order_sent:, user:, params:,
|
||||
preferences: preferences.merge(submission_preferences))
|
||||
end
|
||||
|
||||
@@ -69,6 +69,16 @@ module Submissions
|
||||
end
|
||||
end
|
||||
|
||||
def submitter_message_preferences(uuid, params)
|
||||
return {} if params[:request_email_per_submitter] != '1'
|
||||
return {} if params[:is_custom_message] != '1'
|
||||
|
||||
{
|
||||
'subject' => params.dig('submitter_preferences', uuid, 'subject'),
|
||||
'body' => params.dig('submitter_preferences', uuid, 'body')
|
||||
}.compact_blank
|
||||
end
|
||||
|
||||
def maybe_set_template_fields(submission, submitters_attrs, default_submitter_uuid: nil)
|
||||
template_fields = (submission.template_fields || submission.template.fields).deep_dup
|
||||
|
||||
@@ -175,9 +185,10 @@ module Submissions
|
||||
uuid || template.submitters[index]&.dig('uuid')
|
||||
end
|
||||
|
||||
def build_submitter(submission:, attrs:, uuid:, is_order_sent:, user:, preferences:)
|
||||
def build_submitter(submission:, attrs:, uuid:, is_order_sent:, user:, preferences:, params:)
|
||||
email = Submissions.normalize_email(attrs[:email])
|
||||
submitter_preferences = Submitters.normalize_preferences(submission.account, user, attrs)
|
||||
submitter_preferences = Submitters.normalize_preferences(submission.account, user,
|
||||
attrs.merge(submitter_message_preferences(uuid, params)))
|
||||
values = attrs[:values] || {}
|
||||
|
||||
phone_field_uuid = find_phone_field(submission, values)&.dig('uuid')
|
||||
|
||||
Reference in New Issue
Block a user