fix refactor expire at

pull/480/head
Pete Matsyburka 6 months ago
parent 7b6fc7d06f
commit 050224a10d

@ -97,6 +97,7 @@ class StartFormController < ApplicationController
submitter.submission ||= Submission.new(template:, submitter.submission ||= Submission.new(template:,
account_id: template.account_id, account_id: template.account_id,
template_submitters: template.submitters, template_submitters: template.submitters,
expire_at: Templates.build_default_expire_at(template),
submitters: [submitter], submitters: [submitter],
source: :link) source: :link)

@ -34,6 +34,12 @@ class TemplatesPreferencesController < ApplicationController
submitters: [%i[uuid request_email_subject request_email_body]]] submitters: [%i[uuid request_email_subject request_email_body]]]
).tap do |attrs| ).tap do |attrs|
attrs[:preferences].delete(:submitters) if params[:request_email_per_submitter] != '1' attrs[:preferences].delete(:submitters) if params[:request_email_per_submitter] != '1'
if (default_expire_at = attrs.dig(:preferences, :default_expire_at).presence)
attrs[:preferences][:default_expire_at] =
(ActiveSupport::TimeZone[current_account.timezone] || Time.zone).parse(default_expire_at).utc
end
attrs[:preferences] = attrs[:preferences].transform_values do |value| attrs[:preferences] = attrs[:preferences].transform_values do |value|
if %w[true false].include?(value) if %w[true false].include?(value)
value == 'true' value == 'true'

@ -108,7 +108,6 @@ export default targetable(class extends HTMLElement {
redirect: 'manual', redirect: 'manual',
body: formData, body: formData,
headers: { headers: {
Accept: 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
} }
}).finally(() => { }).finally(() => {

@ -23,13 +23,14 @@
<component <component
:is="icon" :is="icon"
v-else v-else
class="stroke-[1.5px]"
:width="40" :width="40"
:height="40" :height="40"
/> />
<div <div
v-if="message" v-if="message"
class="font-medium text-lg mb-1" class="text-lg mb-1"
:class="{ 'mt-1': !withDescription }" :class="{ 'mt-1': !withDescription, 'font-medium': withDescription }"
> >
{{ message }} {{ message }}
</div> </div>

@ -36,24 +36,6 @@
# #
class Template < ApplicationRecord class Template < ApplicationRecord
DEFAULT_SUBMITTER_NAME = 'First Party' DEFAULT_SUBMITTER_NAME = 'First Party'
EXPIRATION_DURATIONS = {
one_day: 1.day,
two_days: 2.days,
three_days: 3.days,
four_days: 4.days,
five_days: 5.days,
six_days: 6.days,
seven_days: 7.days,
eight_days: 8.days,
nine_days: 9.days,
ten_days: 10.days,
two_weeks: 14.days,
three_weeks: 21.days,
four_weeks: 28.days,
one_month: 1.month,
two_months: 2.months,
three_months: 3.months
}.with_indifferent_access.freeze
belongs_to :author, class_name: 'User' belongs_to :author, class_name: 'User'
belongs_to :account belongs_to :account

@ -0,0 +1,3 @@
<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="M20.986 12.502a9 9 0 1 0 -5.973 7.98" /><path d="M12 7v5l3 3" /><path d="M19 16v3" /><path d="M19 22v.01" />
</svg>

After

Width:  |  Height:  |  Size: 400 B

@ -172,12 +172,26 @@
</div> </div>
<% end %> <% end %>
<div class="flex items-center space-x-1 mt-1"> <div class="flex items-center space-x-1 mt-1">
<% if @submission.expire_at? && submitter && !submitter.completed_at? %>
<%= svg_icon('clock_exclamation', class: 'w-5 h-5') %>
<% else %>
<%= svg_icon('writing', class: 'w-5 h-5') %> <%= svg_icon('writing', class: 'w-5 h-5') %>
<% end %>
<span> <span>
<% if submitter&.declined_at? %> <% if submitter&.declined_at? %>
<%= t('declined_on_time', time: l(submitter.declined_at.in_time_zone(@submission.account.timezone), format: :short, locale: @submission.account.locale)) %> <%= t('declined_on_time', time: l(submitter.declined_at.in_time_zone(@submission.account.timezone), format: :short, locale: @submission.account.locale)) %>
<% elsif submitter %> <% elsif submitter %>
<%= submitter.completed_at? ? l(submitter.completed_at.in_time_zone(@submission.account.timezone), format: :long, locale: @submission.account.locale) : t('not_completed_yet') %> <% if submitter.completed_at? %>
<%= l(submitter.completed_at.in_time_zone(@submission.account.timezone), format: :long, locale: @submission.account.locale) %>
<% elsif @submission.expire_at? %>
<% if @submission.expired? %>
<%= t(:expired) %>
<% else %>
<%= t('expire_on_time', time: l(@submission.expire_at.in_time_zone(@submission.account.timezone), format: :short, locale: @submission.account.locale)) %>
<% end %>
<% else %>
<%= t('not_completed_yet') %>
<% end %>
<% else %> <% else %>
<%= t('not_invited_yet') %> <%= t('not_invited_yet') %>
<% end %> <% end %>

@ -41,25 +41,18 @@
</div> </div>
</div> </div>
<% end %> <% end %>
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mb-2' }, data: { close_on_submit: false } do |f| %> <%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mb-5' }, data: { close_on_submit: false } do |f| %>
<toggle-on-submit data-element-id="default_expiration_form_saved_alert"></toggle-on-submit> <%= f.fields_for :preferences, Struct.new(:default_expire_at_duration, :default_expire_at).new(@template.preferences['default_expire_at_duration'], @template.preferences['default_expire_at'] ? Time.zone.parse(@template.preferences['default_expire_at']).in_time_zone(current_account.timezone) : nil) do |ff| %>
<%= f.fields_for :preferences, Struct.new(:default_expire_at_duration, :default_expire_at).new(*@template.preferences.values_at('default_expire_at_duration', 'default_expire_at').compact_blank) do |ff| %>
<div class="form-control"> <div class="form-control">
<% duration_options = ::Template::EXPIRATION_DURATIONS.keys.map { |duration| [t(duration), duration] } + [[t('specified_date'), 'specified_date']] %> <% duration_options = Templates::EXPIRATION_DURATIONS.keys.map { |duration| [t(duration), duration] } + [[t('specified_date'), 'specified_date']] %>
<%= ff.label :default_expire_at_duration, t('default_expiration'), class: 'label' %> <%= ff.label :default_expire_at_duration, t('default_expiration'), class: 'label pt-0' %>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<%= ff.select :default_expire_at_duration, duration_options, { include_blank: t('none') }, required: false, class: 'base-select flex-1', dir: 'auto', autocomplete: 'off', onchange: "this.value == 'specified_date' ? window.template_preferences_default_expire_at.classList.remove('hidden') : [window.template_preferences_default_expire_at.classList.add('hidden'), window.template_preferences_default_expire_at.value = '', this.form.requestSubmit()]" %> <%= ff.select :default_expire_at_duration, duration_options, { include_blank: t('none') }, required: false, class: 'base-select flex-1', dir: 'auto', autocomplete: 'off', onchange: "this.value == 'specified_date' ? window.template_preferences_default_expire_at.classList.remove('hidden') : [window.template_preferences_default_expire_at.classList.add('hidden'), window.template_preferences_default_expire_at.value = '', this.form.requestSubmit()]" %>
<%= ff.datetime_field :default_expire_at, required: false, class: ['base-input flex-1', ff.object.default_expire_at.blank? && 'hidden'].compact_blank.join(' '), dir: 'auto', autocomplete: 'off', onchange: 'this.value && this.form.requestSubmit()' %> <%= ff.datetime_field :default_expire_at, required: false, class: ['base-input flex-1', ff.object.default_expire_at.blank? && 'hidden'].compact_blank.join(' '), dir: 'auto', autocomplete: 'off', onchange: 'this.value && this.form.requestSubmit()' %>
</div> </div>
</div> </div>
<div class="form-control">
<div class="flex justify-center">
<span id="default_expiration_form_saved_alert" class="text-sm invisible font-normal mt-0.5"><%= t('changes_have_been_saved') %></span>
</div>
</div>
<% end %> <% end %>
<% end %> <% end %>
<%= render 'templates_code_modal/preferences' %>
<div class="collapse collapse-arrow join-item border border-base-300 mb-2"> <div class="collapse collapse-arrow join-item border border-base-300 mb-2">
<input type="checkbox" name="accordion"> <input type="checkbox" name="accordion">
<div class="collapse-title text-xl font-medium"> <div class="collapse-title text-xl font-medium">
@ -291,6 +284,7 @@
</div> </div>
</div> </div>
</div> </div>
<%= render 'templates_code_modal/preferences', class: 'pt-2' %>
</div> </div>
<% if show_recipients %> <% if show_recipients %>
<div id="recipients" class="hidden mt-2 mb-4 px-5"> <div id="recipients" class="hidden mt-2 mb-4 px-5">

@ -597,6 +597,7 @@ en: &en
not_invited_yet: Not invited yet not_invited_yet: Not invited yet
not_completed_yet: Not completed yet not_completed_yet: Not completed yet
declined_on_time: 'Declined on %{time}' declined_on_time: 'Declined on %{time}'
expire_on_time: 'Expire on %{time}'
sign_in_person: Sign In-person sign_in_person: Sign In-person
create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Create a new template</a> document form or <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">submit the existing one</a> create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Create a new template</a> document form or <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">submit the existing one</a>
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Send email copy with completed documents to a specified BCC address. send_email_copy_with_completed_documents_to_a_specified_bcc_address: Send email copy with completed documents to a specified BCC address.
@ -1400,6 +1401,7 @@ es: &es
not_invited_yet: Aún no invitado not_invited_yet: Aún no invitado
not_completed_yet: Aún no completado not_completed_yet: Aún no completado
declined_on_time: 'Rechazado el %{time}' declined_on_time: 'Rechazado el %{time}'
expire_on_time: 'Expira el %{time}'
sign_in_person: Firma en persona sign_in_person: Firma en persona
create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Crear una nueva plantilla</a> de documento o <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">enviar el existente</a> create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Crear una nueva plantilla</a> de documento o <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">enviar el existente</a>
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Enviar una copia del correo electrónico con los documentos completados a una dirección BCC especificada. send_email_copy_with_completed_documents_to_a_specified_bcc_address: Enviar una copia del correo electrónico con los documentos completados a una dirección BCC especificada.
@ -2202,6 +2204,7 @@ it: &it
not_invited_yet: Non ancora invitato not_invited_yet: Non ancora invitato
not_completed_yet: Non ancora completato not_completed_yet: Non ancora completato
declined_on_time: 'Rifiutato il %{time}' declined_on_time: 'Rifiutato il %{time}'
expire_on_time: 'Scade il %{time}'
sign_in_person: Firma di persona sign_in_person: Firma di persona
create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Crea un nuovo modello</a> di documento o <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">invia quello esistente</a> create_a_new_template_document_form_or_submit_the_existing_one_html: <a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Crea un nuovo modello</a> di documento o <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">invia quello esistente</a>
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Invia una copia dell'email con i documenti completati a un indirizzo BCC specificato. send_email_copy_with_completed_documents_to_a_specified_bcc_address: Invia una copia dell'email con i documenti completati a un indirizzo BCC specificato.
@ -3006,6 +3009,7 @@ fr: &fr
not_invited_yet: Pas encore invité not_invited_yet: Pas encore invité
not_completed_yet: Pas encore terminé not_completed_yet: Pas encore terminé
declined_on_time: 'Refusé le %{time}' declined_on_time: 'Refusé le %{time}'
expire_on_time: 'Expire le %{time}'
sign_in_person: Signature en personne sign_in_person: Signature en personne
create_a_new_template_document_form_or_submit_the_existing_one_html: "<a href=\"%{new_template_link}\" data-turbo-frame=\"modal\" class=\"inline underline font-medium\">Créer un nouveau modèle</a> de document ou <a href=\"%{start_form_link}\" target=\"_blank\" class=\"inline underline font-medium\">soumettre l'existant</a>" create_a_new_template_document_form_or_submit_the_existing_one_html: "<a href=\"%{new_template_link}\" data-turbo-frame=\"modal\" class=\"inline underline font-medium\">Créer un nouveau modèle</a> de document ou <a href=\"%{start_form_link}\" target=\"_blank\" class=\"inline underline font-medium\">soumettre l'existant</a>"
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Envoyer une copie de l'e-mail avec les documents complétés à une adresse BCC spécifiée. send_email_copy_with_completed_documents_to_a_specified_bcc_address: Envoyer une copie de l'e-mail avec les documents complétés à une adresse BCC spécifiée.
@ -3809,6 +3813,7 @@ pt: &pt
not_invited_yet: Ainda não convidado not_invited_yet: Ainda não convidado
not_completed_yet: Ainda não concluído not_completed_yet: Ainda não concluído
declined_on_time: 'Recusado em %{time}' declined_on_time: 'Recusado em %{time}'
expire_on_time: 'Expira em %{time}'
sign_in_person: Assinar pessoalmente sign_in_person: Assinar pessoalmente
create_a_new_template_document_form_or_submit_the_existing_one_html: '<a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Criar um novo modelo</a> de documento ou <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">submeter o existente</a>' create_a_new_template_document_form_or_submit_the_existing_one_html: '<a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Criar um novo modelo</a> de documento ou <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">submeter o existente</a>'
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Envie uma cópia do e-mail com documentos concluídos para um endereço BCC especificado. send_email_copy_with_completed_documents_to_a_specified_bcc_address: Envie uma cópia do e-mail com documentos concluídos para um endereço BCC especificado.
@ -4613,6 +4618,7 @@ de: &de
not_invited_yet: Noch nicht eingeladen not_invited_yet: Noch nicht eingeladen
not_completed_yet: Noch nicht abgeschlossen not_completed_yet: Noch nicht abgeschlossen
declined_on_time: 'Abgelehnt am %{time}' declined_on_time: 'Abgelehnt am %{time}'
expire_on_time: 'Ablauf am %{time}'
sign_in_person: Persönlich unterschreiben sign_in_person: Persönlich unterschreiben
create_a_new_template_document_form_or_submit_the_existing_one_html: '<a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Neue Vorlage erstellen</a> oder <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">vorhandene einreichen</a>' create_a_new_template_document_form_or_submit_the_existing_one_html: '<a href="%{new_template_link}" data-turbo-frame="modal" class="inline underline font-medium">Neue Vorlage erstellen</a> oder <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">vorhandene einreichen</a>'
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Senden Sie eine E-Mail-Kopie mit abgeschlossenen Dokumenten an eine angegebene BCC-Adresse. send_email_copy_with_completed_documents_to_a_specified_bcc_address: Senden Sie eine E-Mail-Kopie mit abgeschlossenen Dokumenten an eine angegebene BCC-Adresse.

@ -15,6 +15,7 @@ module ReplaceEmailVariables
SUBMITTER_SLUG = /\{+submitter\.slug\}+/i SUBMITTER_SLUG = /\{+submitter\.slug\}+/i
SUBMISSION_LINK = /\{+submission\.link\}+/i SUBMISSION_LINK = /\{+submission\.link\}+/i
SUBMISSION_ID = /\{+submission\.id\}+/i SUBMISSION_ID = /\{+submission\.id\}+/i
SUBMISSION_EXPIRE_AT = /\{+submission\.expire_at\}+/i
SUBMITTERS = /\{+(?:submission\.)?submitters\}+/i SUBMITTERS = /\{+(?:submission\.)?submitters\}+/i
SUBMITTERS_N_EMAIL = /\{+submitters\[(?<index>\d+)\]\.email\}+/i SUBMITTERS_N_EMAIL = /\{+submitters\[(?<index>\d+)\]\.email\}+/i
SUBMITTERS_N_NAME = /\{+submitters\[(?<index>\d+)\]\.name\}+/i SUBMITTERS_N_NAME = /\{+submitters\[(?<index>\d+)\]\.name\}+/i
@ -48,6 +49,13 @@ module ReplaceEmailVariables
text = replace(text, SENDER_NAME, html_escape:) { submitter.submission.created_by_user&.full_name } text = replace(text, SENDER_NAME, html_escape:) { submitter.submission.created_by_user&.full_name }
text = replace(text, SENDER_FIRST_NAME, html_escape:) { submitter.submission.created_by_user&.first_name } text = replace(text, SENDER_FIRST_NAME, html_escape:) { submitter.submission.created_by_user&.first_name }
text = replace(text, SUBMISSION_EXPIRE_AT, html_escape:) do
if submitter.submission.expire_at
I18n.l(submitter.submission.expire_at.in_time_zone(submitter.submission.account.timezone),
format: :short, locale: submitter.submission.account.locale)
end
end
text = replace(text, SUBMITTERS_N_NAME, html_escape:) do |match| text = replace(text, SUBMITTERS_N_NAME, html_escape:) do |match|
build_submitters_n_field(submitter.submission, match[:index].to_i - 1, :name) build_submitters_n_field(submitter.submission, match[:index].to_i - 1, :name)
end end

@ -59,11 +59,13 @@ module Submissions
def create_from_emails(template:, user:, emails:, source:, mark_as_sent: false, params: {}) def create_from_emails(template:, user:, emails:, source:, mark_as_sent: false, params: {})
preferences = Submitters.normalize_preferences(user.account, user, params) preferences = Submitters.normalize_preferences(user.account, user, params)
expire_at = params[:expire_at].presence || Templates.build_default_expire_at(template)
parse_emails(emails, user).uniq.map do |email| parse_emails(emails, user).uniq.map do |email|
submission = template.submissions.new(created_by_user: user, submission = template.submissions.new(created_by_user: user,
account_id: user.account_id, account_id: user.account_id,
source:, source:,
expire_at: params[:expire_at].presence || build_default_expire_at(template), expire_at:,
template_submitters: template.submitters) template_submitters: template.submitters)
submission.submitters.new(email: normalize_email(email), submission.submitters.new(email: normalize_email(email),
@ -208,17 +210,4 @@ module Submissions
Submissions::GenerateCombinedAttachment.call(submission.submitters.completed.order(:completed_at).last) Submissions::GenerateCombinedAttachment.call(submission.submitters.completed.order(:completed_at).last)
end end
def build_default_expire_at(template)
default_expire_at_duration = template.preferences['default_expire_at_duration'].presence
default_expire_at = template.preferences['default_expire_at'].presence
return if default_expire_at_duration.blank?
if default_expire_at_duration == 'specified_date' && default_expire_at.present?
Time.zone.parse(default_expire_at)
elsif Template::EXPIRATION_DURATIONS[default_expire_at_duration]
Time.current.in_time_zone(template.account.timezone) + Template::EXPIRATION_DURATIONS[default_expire_at_duration]
end
end
end end

@ -16,7 +16,7 @@ module Submissions
set_submission_preferences = submission_preferences.slice('send_email', 'bcc_completed') set_submission_preferences = submission_preferences.slice('send_email', 'bcc_completed')
set_submission_preferences['send_email'] = true if params['send_completed_email'] set_submission_preferences['send_email'] = true if params['send_completed_email']
expire_at = attrs[:expire_at] || Submissions.build_default_expire_at(template) expire_at = attrs[:expire_at] || Templates.build_default_expire_at(template)
submission = template.submissions.new(created_by_user: user, source:, submission = template.submissions.new(created_by_user: user, source:,
account_id: user.account_id, account_id: user.account_id,

@ -1,6 +1,25 @@
# frozen_string_literal: true # frozen_string_literal: true
module Templates module Templates
EXPIRATION_DURATIONS = {
one_day: 1.day,
two_days: 2.days,
three_days: 3.days,
four_days: 4.days,
five_days: 5.days,
six_days: 6.days,
seven_days: 7.days,
eight_days: 8.days,
nine_days: 9.days,
ten_days: 10.days,
two_weeks: 14.days,
three_weeks: 21.days,
four_weeks: 28.days,
one_month: 1.month,
two_months: 2.months,
three_months: 3.months
}.with_indifferent_access.freeze
module_function module_function
def build_field_areas_index(fields) def build_field_areas_index(fields)
@ -30,4 +49,17 @@ module Templates
item['linked_to_uuid'].blank? && item['is_requester'].blank? && item['email'].blank? item['linked_to_uuid'].blank? && item['is_requester'].blank? && item['email'].blank?
end end
end end
def build_default_expire_at(template)
default_expire_at_duration = template.preferences['default_expire_at_duration'].presence
default_expire_at = template.preferences['default_expire_at'].presence
return if default_expire_at_duration.blank?
if default_expire_at_duration == 'specified_date' && default_expire_at.present?
Time.zone.parse(default_expire_at)
elsif EXPIRATION_DURATIONS[default_expire_at_duration]
Time.current + EXPIRATION_DURATIONS[default_expire_at_duration]
end
end
end end

Loading…
Cancel
Save