update send modal

This commit is contained in:
Pete Matsyburka committed 2026-10-10 15:57:08 +03:00
1 parent a69fb81429
commit 5d86a08b5f
18 files changed
+256 -44

No files matched your search

+4
View File
@@ -35,6 +35,8 @@ import PromptPassword from './elements/prompt_password'
import EmailsTextarea from './elements/emails_textarea'
import ToggleSubmit from './elements/toggle_submit'
import ToggleOnSubmit from './elements/toggle_on_submit'
import ToggleOnChecked from './elements/toggle_on_checked'
import AppendTemplate from './elements/append_template'
import CheckOnClick from './elements/check_on_click'
import PasswordInput from './elements/password_input'
import SearchInput from './elements/search_input'
@@ -159,6 +161,8 @@ safeRegisterElement('emails-textarea', EmailsTextarea)
safeRegisterElement('toggle-cookies', ToggleCookies)
safeRegisterElement('toggle-submit', ToggleSubmit)
safeRegisterElement('toggle-on-submit', ToggleOnSubmit)
safeRegisterElement('toggle-on-checked', ToggleOnChecked)
safeRegisterElement('append-template', AppendTemplate)
safeRegisterElement('password-input', PasswordInput)
safeRegisterElement('search-input', SearchInput)
safeRegisterElement('toggle-attribute', ToggleAttribute)
@@ -0,0 +1,29 @@
export default class extends HTMLElement {
connectedCallback () {
this.addEventListener('click', this.onClick)
}
disconnectedCallback () {
this.removeEventListener('click', this.onClick)
}
onClick = (e) => {
e.preventDefault()
const target = document.getElementById(this.dataset.targetId)
const item = this.querySelector('template').content.firstElementChild.cloneNode(true)
item.querySelector('a').addEventListener('click', (e) => {
e.preventDefault()
item.remove()
target.classList.toggle('hidden', !target.childElementCount)
})
target.append(item)
target.classList.remove('hidden')
item.querySelector('input').focus()
}
}
+18 -1
View File
@@ -2,7 +2,7 @@ import { actionable } from '@github/catalyst/lib/actionable'
import { targets, targetable } from '@github/catalyst/lib/targetable'
export default actionable(targetable(class extends HTMLElement {
static [targets.static] = ['items']
static [targets.static] = ['items', 'groups']
addItem (e) {
e.preventDefault()
@@ -24,11 +24,28 @@ export default actionable(targetable(class extends HTMLElement {
duplicateItem.querySelectorAll('a.hidden').forEach((button) => button.classList.toggle('hidden'))
originalItem.parentNode.append(duplicateItem)
this.toggleMultipleClasses()
duplicateItem.querySelector("input:not([type='hidden'])")?.focus()
}
removeItem (e) {
e.preventDefault()
this.items.find((item) => item.contains(e.target))?.remove()
this.toggleMultipleClasses()
}
toggleMultipleClasses () {
const isMultiple = this.items.length > 1
const elements = [...this.items, ...this.groups]
elements.forEach((element) => {
const classes = element.dataset.multipleClasses || this.dataset.multipleClasses
classes?.split(' ').forEach((cls) => element.classList.toggle(cls, isMultiple))
})
}
}))
@@ -0,0 +1,23 @@
export default class extends HTMLElement {
connectedCallback () {
this.form.addEventListener('change', this.toggle)
this.toggle()
}
disconnectedCallback () {
this.form.removeEventListener('change', this.toggle)
}
toggle = () => {
const selector = this.dataset.names.split(' ').map((name) => `[name="${name}"]:checked:enabled`).join(', ')
const isChecked = !!this.form.querySelector(selector)
this.firstElementChild.classList.toggle('hidden', !isChecked)
this.lastElementChild.classList.toggle('hidden', isChecked)
}
get form () {
return this.closest('form')
}
}
+3
View File
@@ -24,6 +24,9 @@ const ICONS = {
user: 'person',
users: 'person.2',
users_plus: 'person.badge.plus',
user_plus: 'person.badge.plus',
eye_plus: 'eye',
mail_plus: 'envelope',
photo: 'photo',
settings: 'gearshape',
logout: 'rectangle.portrait.and.arrow.right',
+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
<path d="M12 18c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6" />
<path d="M16 19h6" />
<path d="M19 16v6" />
</svg>

After

Width:  |  Height:  |  Size: 460 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 19h-7a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v5.5" />
<path d="M16 19h6" />
<path d="M19 16v6" />
<path d="M3 7l9 6l9 -6" />
</svg>

After

Width:  |  Height:  |  Size: 441 B

+2 -3
View File
@@ -1,8 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" />
<path d="M3 21v-2a4 4 0 0 1 4 -4h4c.96 0 1.84 .338 2.53 .901" />
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
<path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" />
<path d="M16 19h6" />
<path d="M19 16v6" />
<path d="M6 21v-2a4 4 0 0 1 4 -4h4" />
</svg>

Before

Width:  |  Height:  |  Size: 488 B

After

Width:  |  Height:  |  Size: 421 B

+70
View File
@@ -0,0 +1,70 @@
<% fields_id = "add_new_fields_#{SecureRandom.hex(3)}" %>
<div id="<%= fields_id %>" class="space-y-3 mt-4 hidden" data-targets="dynamic-list.groups" data-multiple-classes="px-3 pt-3 pb-4 rounded-xl border border-dashed border-base-300"></div>
<native-menu class="<%= turbo_native_app? ? 'block' : 'dropdown block max-sm:hidden' %> mt-4 -mb-2">
<label tabindex="0" class="btn btn-ghost btn-sm normal-case font-normal w-full flex items-center justify-center border-dashed border-base-300 hover:border-base-content/20 !bg-transparent">
<%= svg_icon('users_plus', class: 'w-4 h-4 stroke-2') %>
<span><%= t('add_new') %></span>
</label>
<ul tabindex="0" class="<%= turbo_native_app? ? 'hidden' : 'z-10 dropdown-content p-2 mt-1 shadow menu bg-base-100 rounded-box' %>" style="left: 50%; --tw-translate-x: -50%">
<li>
<native-menu-action data-icon="user_plus" data-label="<%= t('recipients') %>" class="grid-cols-1 p-0">
<a href="#" class="flex items-center gap-2 px-4 py-2" data-action="click:dynamic-list#addItem">
<%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
<span class="whitespace-nowrap"><%= t('recipients') %></span>
</a>
</native-menu-action>
</li>
<append-template class="contents" data-target-id="<%= fields_id %>">
<li>
<native-menu-action data-icon="eye_plus" data-label="<%= t('cc_view_only') %>" class="grid-cols-1 p-0">
<a href="#" class="flex items-center gap-2 px-4 py-2">
<%= svg_icon('eye_plus', class: 'w-4 h-4 stroke-2') %>
<span class="whitespace-nowrap"><%= t('cc_view_only') %></span>
</a>
</native-menu-action>
</li>
<template>
<submitter-item class="form-control">
<label class="label pt-0 pb-1">
<span class="label-text"><%= t('cc_view_only') %></span>
</label>
<div class="relative">
<submitters-autocomplete data-field="email">
<input type="email" name="cc_recipients[]" autocomplete="off" class="base-input !h-10 w-full pr-10" placeholder="<%= t('email') %>">
</submitters-autocomplete>
<a href="#" class="absolute right-2 top-2 block w-6 h-6 text-neutral-700 p-1 hover:text-base-content">
<%= svg_icon('trash', class: 'w-4 h-4') %>
</a>
</div>
</submitter-item>
</template>
</append-template>
<append-template class="contents" data-target-id="<%= fields_id %>">
<li>
<native-menu-action data-icon="mail_plus" data-label="<%= t('bcc_completed') %>" class="grid-cols-1 p-0">
<a href="#" class="flex items-center gap-2 px-4 py-2">
<%= svg_icon('mail_plus', class: 'w-4 h-4 stroke-2') %>
<span class="whitespace-nowrap"><%= t('bcc_completed') %></span>
</a>
</native-menu-action>
</li>
<template>
<div class="form-control">
<label class="label pt-0 pb-1">
<span class="label-text"><%= t('bcc_completed') %></span>
</label>
<div class="relative">
<input type="email" name="bcc_completed[]" autocomplete="off" class="base-input !h-10 w-full pr-10" placeholder="<%= t('email') %>">
<a href="#" class="absolute right-2 top-2 block w-6 h-6 text-neutral-700 p-1 hover:text-base-content">
<%= svg_icon('trash', class: 'w-4 h-4') %>
</a>
</div>
<% default_bcc_completed = template.preferences['bcc_completed'].presence || current_account.account_configs.find_by(key: AccountConfig::BCC_EMAILS)&.value %>
<% if default_bcc_completed.present? %>
<input type="hidden" name="bcc_completed[]" value="<%= default_bcc_completed %>">
<% end %>
</div>
</template>
</append-template>
</ul>
</native-menu>
+14 -12
View File
@@ -1,12 +1,12 @@
<% has_phone_field = false %>
<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
<%= form_for '', url: template_submissions_path(template), html: { autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
<% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? || e['invite_via_field_uuid'].present? } %>
<dynamic-list class="space-y-4">
<dynamic-list class="block" data-multiple-classes="px-3 <%= submitters.size > 1 ? 'pt-3 pb-4' : 'py-4' %> rounded-xl border border-dashed border-base-300">
<div class="space-y-4">
<div class="relative <%= 'p-4 rounded-xl bg-base-300/40 max-sm:p-0 max-sm:bg-transparent' unless local_assigns[:variables_form] %>" data-targets="dynamic-list.items">
<div class="relative" data-targets="dynamic-list.items">
<div>
<div class="absolute right-4 top-5">
<a href="#" data-action="click:dynamic-list#removeItem" class="<%= submitters.size == 1 ? 'right-2 top-1' : '-top-3' %> relative block w-6 h-6 rounded-lg text-neutral-700 text-center bg-base-300 p-1 hidden hover:bg-neutral hover:text-white">
<div class="absolute top-5" style="right: 12px">
<a href="#" data-action="click:dynamic-list#removeItem" class="<%= submitters.size == 1 ? 'right-2 top-1' : '-top-3' %> relative block w-6 h-6 text-neutral-700 p-1 hidden hover:text-base-content">
<%= svg_icon('trash', class: 'w-4 h-4') %>
</a>
</div>
@@ -86,14 +86,11 @@
</div>
</div>
<% if params[:selfsign].blank? && local_assigns[:prefillable_fields].blank? && local_assigns[:recipient_form_fields].blank? && local_assigns[:variables_form].blank? %>
<a href="#" class="btn btn-primary btn-sm w-full flex items-center justify-center max-sm:hidden" data-action="click:dynamic-list#addItem">
<%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
<span><%= t('add_new') %></span>
</a>
<%= render 'add_new', template: %>
<% end %>
</dynamic-list>
<%= local_assigns[:variables_form] %>
<div>
<div class="mt-4">
<%= render('submitters_order', f:, template:) if can_send_emails %>
<%= render 'send_email', f:, template:, can_send_emails:, viewer_submitter_uuids: local_assigns[:viewer_submitter_uuids] %>
<% if has_phone_field %>
@@ -101,7 +98,12 @@
<% end %>
<%= render 'extra_fields', f: %>
</div>
<div class="form-control">
<%= f.button button_title(title: t('add_recipients')), class: 'base-button' %>
<div class="form-control mt-4">
<%= f.button class: 'base-button' do %>
<toggle-on-checked data-names="send_email send_sms">
<span><%= button_title(title: t('send'), disabled_with: t('sending')) %></span>
<span class="hidden"><%= button_title(title: t('add_recipients')) %></span>
</toggle-on-checked>
<% end %>
</div>
<% end %>
+15 -13
View File
@@ -1,4 +1,4 @@
<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
<%= form_for '', url: template_submissions_path(template), html: { autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
<% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? || e['invite_via_field_uuid'].present? } %>
<% if submitters.size == 1 && local_assigns[:variables_form] %>
<% item = submitters.first %>
@@ -26,18 +26,18 @@
<emails-textarea data-bulk-enabled="<%= Docuseal.demo? || !Docuseal.multitenant? || can?(:manage, :bulk_send) %>" data-limit="<%= Docuseal.multitenant? ? (can?(:manage, :bulk_send) ? 40 : 1) : nil %>">
<submitters-autocomplete data-field="email" class="block relative">
<autoresize-textarea>
<%= f.text_area :emails, required: true, class: 'base-textarea w-full !text-lg', placeholder: "#{t('type_emails_here')}...", rows: 2 %>
<%= f.text_area :emails, required: true, class: 'base-textarea block w-full !text-lg', placeholder: "#{t('type_emails_here')}...", rows: 2 %>
</autoresize-textarea>
</submitters-autocomplete>
</emails-textarea>
</submitter-item>
<% else %>
<dynamic-list class="space-y-4">
<dynamic-list class="block" data-multiple-classes="px-3 pt-3 pb-4 rounded-xl border border-dashed border-base-300">
<div class="space-y-4">
<div class="relative <%= 'p-4 rounded-xl bg-base-300/40 max-sm:p-0 max-sm:bg-transparent' unless local_assigns[:variables_form] %>" data-targets="dynamic-list.items">
<div class="relative" data-targets="dynamic-list.items">
<div>
<div class="absolute right-4 top-5">
<a href="#" data-action="click:dynamic-list#removeItem" class="-top-3 relative block w-6 h-6 rounded-lg text-neutral-700 text-center bg-base-300 p-1 hidden hover:bg-neutral hover:text-white">
<div class="absolute top-5" style="right: 12px">
<a href="#" data-action="click:dynamic-list#removeItem" class="-top-3 relative block w-6 h-6 text-neutral-700 p-1 hidden hover:text-base-content">
<%= svg_icon('trash', class: 'w-4 h-4') %>
</a>
</div>
@@ -60,22 +60,24 @@
</div>
</div>
<% if params[:selfsign].blank? && local_assigns[:variables_form].blank? %>
<a href="#" class="btn btn-primary btn-sm w-full flex items-center justify-center max-sm:hidden" data-action="click:dynamic-list#addItem">
<%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
<span><%= t('add_new') %></span>
</a>
<%= render 'add_new', template: %>
<% end %>
</dynamic-list>
<% end %>
<%= local_assigns[:variables_form] %>
<div>
<div class="mt-4">
<%= render('submitters_order', f:, template:) if can_send_emails %>
<%= render 'send_email', f:, template:, can_send_emails:, viewer_submitter_uuids: local_assigns[:viewer_submitter_uuids] %>
<%= render 'extra_fields', f: %>
</div>
<div class="form-control">
<div class="form-control mt-4">
<%= content_for(:submit_button) || capture do %>
<%= f.button button_title(title: t('add_recipients')), class: 'base-button' %>
<%= f.button class: 'base-button' do %>
<toggle-on-checked data-names="send_email send_sms">
<span><%= button_title(title: t('send'), disabled_with: t('sending')) %></span>
<span class="hidden"><%= button_title(title: t('add_recipients')) %></span>
</toggle-on-checked>
<% end %>
<% end %>
</div>
<% end %>
+14 -12
View File
@@ -1,11 +1,11 @@
<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
<%= form_for '', url: template_submissions_path(template), html: { autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
<% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? || e['invite_via_field_uuid'].present? } %>
<dynamic-list class="space-y-4">
<dynamic-list class="block" data-multiple-classes="px-3 <%= submitters.size > 1 ? 'pt-3 pb-4' : 'py-4' %> rounded-xl border border-dashed border-base-300">
<div class="space-y-4">
<div class="relative <%= 'p-4 rounded-xl bg-base-300/40 max-sm:p-0 max-sm:bg-transparent' unless local_assigns[:variables_form] %>" data-targets="dynamic-list.items">
<div class="relative" data-targets="dynamic-list.items">
<div>
<div class="absolute right-4 top-5">
<a href="#" data-action="click:dynamic-list#removeItem" class="<%= submitters.size == 1 ? 'right-2 top-1' : '-top-3' %> relative block w-6 h-6 rounded-lg text-neutral-700 text-center bg-base-300 p-1 hidden hover:bg-neutral hover:text-white">
<div class="absolute top-5" style="right: 12px">
<a href="#" data-action="click:dynamic-list#removeItem" class="<%= submitters.size == 1 ? 'right-2 top-1' : '-top-3' %> relative block w-6 h-6 text-neutral-700 p-1 hidden hover:text-base-content">
<%= svg_icon('trash', class: 'w-4 h-4') %>
</a>
</div>
@@ -48,19 +48,21 @@
</div>
</div>
<% if params[:selfsign].blank? && local_assigns[:variables_form].blank? %>
<a href="#" class="btn btn-primary btn-sm w-full flex items-center justify-center max-sm:hidden" data-action="click:dynamic-list#addItem">
<%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
<span><%= t('add_new') %></span>
</a>
<%= render 'add_new', template: %>
<% end %>
</dynamic-list>
<%= local_assigns[:variables_form] %>
<div>
<div class="mt-4">
<%= render 'submitters_order', f:, template: %>
<%= render 'send_sms', f:, checked: true %>
<%= render 'extra_phone_fields', f: %>
</div>
<div class="form-control">
<%= f.button button_title(title: t('add_recipients')), class: 'base-button' %>
<div class="form-control mt-4">
<%= f.button class: 'base-button' do %>
<toggle-on-checked data-names="send_email send_sms">
<span><%= button_title(title: t('send'), disabled_with: t('sending')) %></span>
<span class="hidden"><%= button_title(title: t('add_recipients')) %></span>
</toggle-on-checked>
<% end %>
</div>
<% end %>
@@ -14,7 +14,7 @@
<toggle-visible data-element-ids="<%= [message_field_id].to_json %>" class="flex">
<label>
<%= f.check_box :is_custom_message, checked: false, class: 'hidden peer', data: { action: 'change:toggle-visible#trigger', type: 'checkbox' } %>
<span class="link peer-checked:hidden"><%= t('edit_message') %></span>
<span class="link link-hover peer-checked:hidden"><%= t('edit_message') %></span>
</label>
</toggle-visible>
<% end %>
+2
View File
@@ -1,5 +1,7 @@
<% unless turbo_native_ios? %>
<toggle-on-checked data-names="is_custom_message" class="block">
<div class="form-control">
<%= render 'sms_settings/placeholder' %>
</div>
</toggle-on-checked>
<% end %>
+1 -1
View File
@@ -26,7 +26,7 @@
</div>
</toggle-visible>
<% end %>
<div class="px-5 mb-5 mt-4">
<div class="px-5 mb-5 mt-5">
<% unless only_detailed %>
<div id="email" class="<%= 'hidden' if default_tab != 'email' %>">
<%= render 'email_form', template: @template, variables_form:, can_send_emails:, viewer_submitter_uuids: %>
+14
View File
@@ -1028,6 +1028,8 @@ en: &en
failed_to_scan_the_document: Failed to scan the document
document_scanning_is_not_available_on_this_device: Document scanning is not available on this device
click_to_upload: Click to upload
cc_view_only: CC View-only
bcc_completed: BCC Completed
devise:
confirmations:
confirmed: Your email address has been successfully confirmed.
@@ -2176,6 +2178,8 @@ es: &es
failed_to_save_the_scan: No se pudo guardar el escaneo
failed_to_scan_the_document: No se pudo escanear el documento
document_scanning_is_not_available_on_this_device: El escaneo de documentos no está disponible en este dispositivo
cc_view_only: CC Solo lectura
bcc_completed: CCO Completado
devise:
confirmations:
confirmed: Tu dirección de correo electrónico ha sido confirmada correctamente.
@@ -3338,6 +3342,8 @@ it: &it
failed_to_save_the_scan: Impossibile salvare la scansione
failed_to_scan_the_document: Impossibile scansionare il documento
document_scanning_is_not_available_on_this_device: La scansione dei documenti non è disponibile su questo dispositivo
cc_view_only: CC Sola lettura
bcc_completed: BCC Completato
devise:
confirmations:
confirmed: Il tuo indirizzo email è stato confermato con successo.
@@ -4483,6 +4489,8 @@ fr: &fr
failed_to_save_the_scan: Impossible d’enregistrer la numérisation
failed_to_scan_the_document: Impossible de numériser le document
document_scanning_is_not_available_on_this_device: La numérisation de documents n’est pas disponible sur cet appareil
cc_view_only: Cc Lecture seule
bcc_completed: Cci Terminé
devise:
confirmations:
confirmed: Votre adresse e-mail a été confirmée avec succès.
@@ -5644,6 +5652,8 @@ pt: &pt
failed_to_save_the_scan: Não foi possível salvar a digitalização
failed_to_scan_the_document: Não foi possível digitalizar o documento
document_scanning_is_not_available_on_this_device: A digitalização de documentos não está disponível neste dispositivo
cc_view_only: CC Somente leitura
bcc_completed: BCC Concluído
devise:
confirmations:
confirmed: Seu endereço de e-mail foi confirmado com sucesso.
@@ -6805,6 +6815,8 @@ de: &de
failed_to_save_the_scan: Scan konnte nicht gespeichert werden
failed_to_scan_the_document: Dokument konnte nicht gescannt werden
document_scanning_is_not_available_on_this_device: Das Scannen von Dokumenten ist auf diesem Gerät nicht verfügbar
cc_view_only: CC Nur Ansicht
bcc_completed: BCC Abgeschlossen
devise:
confirmations:
confirmed: Ihre E-Mail-Adresse wurde erfolgreich bestätigt.
@@ -8490,6 +8502,8 @@ nl: &nl
failed_to_save_the_scan: Scan kon niet worden opgeslagen
failed_to_scan_the_document: Document kon niet worden gescand
document_scanning_is_not_available_on_this_device: Documenten scannen is niet beschikbaar op dit apparaat
cc_view_only: CC Alleen bekijken
bcc_completed: BCC Voltooid
devise:
confirmations:
confirmed: Uw e-mailadres is succesvol bevestigd.
+23
View File
@@ -90,6 +90,10 @@ module Submissions
maybe_add_invite_submitters(submission, template, attrs[:submitters])
maybe_add_cc_submitters(submission, params[:cc_recipients],
submitters_order:, user:, params:,
preferences: preferences.merge(submission_preferences))
assign_submitters_is_viewer(submission)
submission.template = nil unless with_template
@@ -211,6 +215,25 @@ module Submissions
end
end
def maybe_add_cc_submitters(submission, recipients, submitters_order:, user:, params:, preferences:)
order = submission.template_submitters.filter_map { |s| s['order'] }.max
Array.wrap(recipients).each do |recipient|
attrs = recipient.is_a?(String) ? { email: recipient } : recipient.slice(:name, :email, :phone)
next if attrs.compact_blank.blank?
uuid = SecureRandom.uuid
submission.template_submitters <<
{ 'name' => 'CC', 'uuid' => uuid, 'is_viewer' => true, 'order' => order }.compact
build_submitter(submission:, attrs:, uuid:, user:, params:,
is_order_sent: submitters_order == 'random',
preferences: preferences.except('email_message_uuid'))
end
end
def submitter_message_preferences(uuid, params)
return {} if params[:request_email_per_submitter] != '1'
return {} if params[:is_custom_message] != '1'
+9 -1
View File
@@ -152,7 +152,7 @@ module Submitters
preferences['send_sms'] = params['send_sms'].in?(TRUE_VALUES) if params.key?('send_sms')
preferences['require_phone_2fa'] = params['require_phone_2fa'].in?(TRUE_VALUES) if params.key?('require_phone_2fa')
preferences['require_email_2fa'] = params['require_email_2fa'].in?(TRUE_VALUES) if params.key?('require_email_2fa')
preferences['bcc_completed'] = params['bcc_completed'] if params.key?('bcc_completed')
preferences['bcc_completed'] = normalize_bcc_completed(params['bcc_completed']) if params.key?('bcc_completed')
preferences['reply_to'] = params['reply_to'] if params.key?('reply_to')
preferences['go_to_last'] = params['go_to_last'] if params.key?('go_to_last')
preferences['completed_redirect_url'] = params['completed_redirect_url'] if params.key?('completed_redirect_url')
@@ -160,6 +160,14 @@ module Submitters
preferences
end
def normalize_bcc_completed(value)
if value.is_a?(Array)
value.compact_blank.uniq.join(', ')
else
value
end
end
def fetch_values_for_delegate(submitter)
fields = submitter.submission.template_fields || submitter.template.fields
default_values = submitter.preferences['default_values'] || {}