Merge from docusealco/wip
This commit is contained in:
+6
-6
@@ -116,7 +116,7 @@ GEM
|
|||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
parser (>= 2.4)
|
parser (>= 2.4)
|
||||||
smart_properties
|
smart_properties
|
||||||
bigdecimal (4.1.0)
|
bigdecimal (4.1.2)
|
||||||
bindex (0.8.1)
|
bindex (0.8.1)
|
||||||
bootsnap (1.23.0)
|
bootsnap (1.23.0)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
@@ -161,7 +161,7 @@ GEM
|
|||||||
irb (~> 1.10)
|
irb (~> 1.10)
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
declarative (0.0.20)
|
declarative (0.0.20)
|
||||||
devise (5.0.3)
|
devise (5.0.4)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
railties (>= 7.0)
|
railties (>= 7.0)
|
||||||
@@ -268,13 +268,13 @@ GEM
|
|||||||
mini_magick (>= 4.9.5, < 6)
|
mini_magick (>= 4.9.5, < 6)
|
||||||
ruby-vips (>= 2.0.17, < 3)
|
ruby-vips (>= 2.0.17, < 3)
|
||||||
io-console (0.8.2)
|
io-console (0.8.2)
|
||||||
irb (1.17.0)
|
irb (1.18.0)
|
||||||
pp (>= 0.6.0)
|
pp (>= 0.6.0)
|
||||||
prism (>= 1.3.0)
|
prism (>= 1.3.0)
|
||||||
rdoc (>= 4.0.0)
|
rdoc (>= 4.0.0)
|
||||||
reline (>= 0.4.2)
|
reline (>= 0.4.2)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.19.3)
|
json (2.19.5)
|
||||||
jwt (3.1.2)
|
jwt (3.1.2)
|
||||||
base64
|
base64
|
||||||
language_server-protocol (3.17.0.5)
|
language_server-protocol (3.17.0.5)
|
||||||
@@ -311,7 +311,7 @@ GEM
|
|||||||
mini_magick (5.3.1)
|
mini_magick (5.3.1)
|
||||||
logger
|
logger
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
minitest (6.0.3)
|
minitest (6.0.6)
|
||||||
drb (~> 2.0)
|
drb (~> 2.0)
|
||||||
prism (~> 1.5)
|
prism (~> 1.5)
|
||||||
msgpack (1.8.0)
|
msgpack (1.8.0)
|
||||||
@@ -429,7 +429,7 @@ GEM
|
|||||||
tsort (>= 0.2)
|
tsort (>= 0.2)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.3.1)
|
rake (13.4.2)
|
||||||
rdoc (7.2.0)
|
rdoc (7.2.0)
|
||||||
erb
|
erb
|
||||||
psych (>= 4.0.0)
|
psych (>= 4.0.0)
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SubmissionsResendEmailController < ApplicationController
|
||||||
|
load_and_authorize_resource :submission
|
||||||
|
|
||||||
|
before_action do
|
||||||
|
authorize!(:manage, :resend_all)
|
||||||
|
authorize!(:update, @submission)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
submitters = @submission.submitters.reject(&:completed_at?).select { |s| s.email.present? && !s.declined_at? }
|
||||||
|
|
||||||
|
if Docuseal.multitenant?
|
||||||
|
recent_submitter_ids =
|
||||||
|
SubmissionEvent.where(submitter_id: submitters.map(&:id),
|
||||||
|
event_type: 'send_email',
|
||||||
|
created_at: 10.hours.ago..Time.current).pluck(:submitter_id).to_set
|
||||||
|
|
||||||
|
submitters = submitters.reject { |s| recent_submitter_ids.include?(s.id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
submitters.each do |submitter|
|
||||||
|
SendSubmitterInvitationEmailJob.perform_async('submitter_id' => submitter.id)
|
||||||
|
|
||||||
|
submitter.sent_at ||= Time.current
|
||||||
|
submitter.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
notice =
|
||||||
|
if submitters.empty?
|
||||||
|
I18n.t('email_has_been_sent_already')
|
||||||
|
else
|
||||||
|
I18n.t('emails_have_been_sent_to_n_recipients', count: submitters.size)
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_back(fallback_location: submission_path(@submission), notice:)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,6 +4,8 @@ class SubmissionsUnarchiveController < ApplicationController
|
|||||||
load_and_authorize_resource :submission
|
load_and_authorize_resource :submission
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
authorize!(:update, @submission)
|
||||||
|
|
||||||
@submission.update!(archived_at: nil)
|
@submission.update!(archived_at: nil)
|
||||||
|
|
||||||
redirect_to submission_path(@submission), notice: I18n.t('submission_has_been_unarchived')
|
redirect_to submission_path(@submission), notice: I18n.t('submission_has_been_unarchived')
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ class SubmittersSendEmailController < ApplicationController
|
|||||||
load_and_authorize_resource :submitter
|
load_and_authorize_resource :submitter
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
authorize!(:update, @submitter)
|
||||||
|
|
||||||
if Docuseal.multitenant? && SubmissionEvent.exists?(submitter: @submitter,
|
if Docuseal.multitenant? && SubmissionEvent.exists?(submitter: @submitter,
|
||||||
event_type: 'send_email',
|
event_type: 'send_email',
|
||||||
created_at: 10.hours.ago..Time.current)
|
created_at: 10.hours.ago..Time.current)
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ class TemplateDocumentsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
authorize!(:update, @template)
|
||||||
|
|
||||||
if params[:blobs].blank? && params[:files].blank?
|
if params[:blobs].blank? && params[:files].blank?
|
||||||
return render json: { error: I18n.t('file_is_missing') }, status: :unprocessable_content
|
return render json: { error: I18n.t('file_is_missing') }, status: :unprocessable_content
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ class TemplatesCloneAndReplaceController < ApplicationController
|
|||||||
|
|
||||||
cloned_template = Templates::Clone.call(@template, author: current_user)
|
cloned_template = Templates::Clone.call(@template, author: current_user)
|
||||||
cloned_template.name = File.basename(params[:files].first.original_filename, '.*')
|
cloned_template.name = File.basename(params[:files].first.original_filename, '.*')
|
||||||
|
|
||||||
|
authorize!(:create, cloned_template)
|
||||||
|
|
||||||
cloned_template.save!
|
cloned_template.save!
|
||||||
|
|
||||||
documents = Templates::ReplaceAttachments.call(cloned_template, params, extract_fields: true)
|
documents = Templates::ReplaceAttachments.call(cloned_template, params, extract_fields: true)
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ class TemplatesController < ApplicationController
|
|||||||
|
|
||||||
WebhookUrls.enqueue_events(@template, 'template.updated')
|
WebhookUrls.enqueue_events(@template, 'template.updated')
|
||||||
|
|
||||||
TemplateVersions.find_or_create_for(@template, author: current_user) if params[:revision]
|
|
||||||
|
|
||||||
head :ok
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ class TemplatesFoldersController < ApplicationController
|
|||||||
def edit; end
|
def edit; end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
authorize!(:update, @template)
|
||||||
|
|
||||||
name = [params[:parent_name], params[:name]].compact_blank.join(' / ')
|
name = [params[:parent_name], params[:name]].compact_blank.join(' / ')
|
||||||
|
|
||||||
@template.folder = TemplateFolders.find_or_create_by_name(current_user, name)
|
@template.folder = TemplateFolders.find_or_create_by_name(current_user, name)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ class TemplatesRestoreController < ApplicationController
|
|||||||
load_and_authorize_resource :template
|
load_and_authorize_resource :template
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
authorize!(:update, @template)
|
||||||
|
|
||||||
@template.update!(archived_at: nil)
|
@template.update!(archived_at: nil)
|
||||||
|
|
||||||
WebhookUrls.enqueue_events(@template, 'template.updated')
|
WebhookUrls.enqueue_events(@template, 'template.updated')
|
||||||
|
|||||||
@@ -14,4 +14,12 @@ class TemplatesVersionsController < ApplicationController
|
|||||||
|
|
||||||
render json: TemplateVersions.serialize(version)
|
render json: TemplateVersions.serialize(version)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
authorize!(:update, @template)
|
||||||
|
|
||||||
|
TemplateVersions.find_or_create_for(@template, author: current_user)
|
||||||
|
|
||||||
|
head :ok
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ import ScrollTo from './elements/scroll_to'
|
|||||||
import SetValue from './elements/set_value'
|
import SetValue from './elements/set_value'
|
||||||
import ReviewForm from './elements/review_form'
|
import ReviewForm from './elements/review_form'
|
||||||
import ShowOnValue from './elements/show_on_value'
|
import ShowOnValue from './elements/show_on_value'
|
||||||
import CustomValidation from './elements/custom_validation'
|
|
||||||
import ToggleClasses from './elements/toggle_classes'
|
import ToggleClasses from './elements/toggle_classes'
|
||||||
import AutosizeField from './elements/autosize_field'
|
import AutosizeField from './elements/autosize_field'
|
||||||
import GoogleDriveFilePicker from './elements/google_drive_file_picker'
|
import GoogleDriveFilePicker from './elements/google_drive_file_picker'
|
||||||
@@ -139,7 +138,6 @@ safeRegisterElement('scroll-to', ScrollTo)
|
|||||||
safeRegisterElement('set-value', SetValue)
|
safeRegisterElement('set-value', SetValue)
|
||||||
safeRegisterElement('review-form', ReviewForm)
|
safeRegisterElement('review-form', ReviewForm)
|
||||||
safeRegisterElement('show-on-value', ShowOnValue)
|
safeRegisterElement('show-on-value', ShowOnValue)
|
||||||
safeRegisterElement('custom-validation', CustomValidation)
|
|
||||||
safeRegisterElement('toggle-classes', ToggleClasses)
|
safeRegisterElement('toggle-classes', ToggleClasses)
|
||||||
safeRegisterElement('autosize-field', AutosizeField)
|
safeRegisterElement('autosize-field', AutosizeField)
|
||||||
safeRegisterElement('google-drive-file-picker', GoogleDriveFilePicker)
|
safeRegisterElement('google-drive-file-picker', GoogleDriveFilePicker)
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
export default class extends HTMLElement {
|
|
||||||
connectedCallback () {
|
|
||||||
const input = this.querySelector('input')
|
|
||||||
const invalidMessage = this.dataset.invalidMessage || ''
|
|
||||||
|
|
||||||
input.addEventListener('invalid', () => {
|
|
||||||
input.setCustomValidity(input.value ? invalidMessage : '')
|
|
||||||
})
|
|
||||||
|
|
||||||
input.addEventListener('input', () => {
|
|
||||||
input.setCustomValidity('')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -52,7 +52,9 @@ safeRegisterElement('submission-form', class extends HTMLElement {
|
|||||||
completedMessage: JSON.parse(this.dataset.completedMessage || '{}'),
|
completedMessage: JSON.parse(this.dataset.completedMessage || '{}'),
|
||||||
completedRedirectUrl: this.dataset.completedRedirectUrl,
|
completedRedirectUrl: this.dataset.completedRedirectUrl,
|
||||||
attachments: reactive(JSON.parse(this.dataset.attachments)),
|
attachments: reactive(JSON.parse(this.dataset.attachments)),
|
||||||
fields: JSON.parse(this.dataset.fields)
|
fields: JSON.parse(this.dataset.fields),
|
||||||
|
completeButtonContainer: document.getElementById('complete_button_container'),
|
||||||
|
completeButtonScrollContainer: document.getElementById('complete_button_container_scroll')
|
||||||
})
|
})
|
||||||
|
|
||||||
this.app.mount(this.appElem)
|
this.app.mount(this.appElem)
|
||||||
|
|||||||
@@ -643,6 +643,10 @@ export default {
|
|||||||
return new Intl.NumberFormat('de-DE').format(number)
|
return new Intl.NumberFormat('de-DE').format(number)
|
||||||
} else if (format === 'space') {
|
} else if (format === 'space') {
|
||||||
return new Intl.NumberFormat('fr-FR').format(number)
|
return new Intl.NumberFormat('fr-FR').format(number)
|
||||||
|
} else if (format === 'percent') {
|
||||||
|
return `${number}%`
|
||||||
|
} else if (format === 'percent_space') {
|
||||||
|
return `${String(number).replace('.', ',')} %`
|
||||||
} else {
|
} else {
|
||||||
return number
|
return number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,31 @@
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
<Teleport
|
||||||
|
v-for="ref in (showCompleteButton ? [completeButtonContainer, completeButtonScrollContainer].filter(Boolean) : [])"
|
||||||
|
:key="ref"
|
||||||
|
:to="ref"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="complete-button btn btn-sm btn-neutral text-white px-4"
|
||||||
|
form="steps_form"
|
||||||
|
type="submit"
|
||||||
|
name="completed"
|
||||||
|
value="true"
|
||||||
|
:disabled="isSubmittingComplete"
|
||||||
|
>
|
||||||
|
<span class="flex items-center">
|
||||||
|
<IconInnerShadowTop
|
||||||
|
v-if="isSubmittingComplete"
|
||||||
|
class="mr-1 animate-spin w-5 h-5"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
{{ t('complete') }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</Teleport>
|
||||||
<button
|
<button
|
||||||
v-if="!isFormVisible"
|
v-if="!isFormVisible"
|
||||||
id="expand_form_button"
|
id="expand_form_button"
|
||||||
@@ -791,6 +816,16 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
completeButtonContainer: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
completeButtonScrollContainer: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
schema: {
|
schema: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -1008,6 +1043,7 @@ export default {
|
|||||||
isSubmitting: false,
|
isSubmitting: false,
|
||||||
isSubmittingComplete: false,
|
isSubmittingComplete: false,
|
||||||
submittedValues: {},
|
submittedValues: {},
|
||||||
|
isFormStarted: false,
|
||||||
recalculateButtonDisabledKey: '',
|
recalculateButtonDisabledKey: '',
|
||||||
isAccessibilityMode: false
|
isAccessibilityMode: false
|
||||||
}
|
}
|
||||||
@@ -1056,6 +1092,10 @@ export default {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
showCompleteButton () {
|
||||||
|
return this.completeButtonContainer && !this.isCompleted && !this.isInvite && this.isFormStarted &&
|
||||||
|
!this.stepFields.find((fields) => fields.some((f) => f.required && isEmpty(this.submittedValues[f.uuid])))
|
||||||
|
},
|
||||||
submitButtonText () {
|
submitButtonText () {
|
||||||
if (this.alwaysMinimize) {
|
if (this.alwaysMinimize) {
|
||||||
return this.t('submit')
|
return this.t('submit')
|
||||||
@@ -1657,6 +1697,8 @@ export default {
|
|||||||
return Promise.reject(new Error(data.error))
|
return Promise.reject(new Error(data.error))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isFormStarted = true
|
||||||
|
|
||||||
const nextStep = (isLastStep && emptyRequiredField) || (forceComplete ? null : this.findNextStep(submitStepIndex))
|
const nextStep = (isLastStep && emptyRequiredField) || (forceComplete ? null : this.findNextStep(submitStepIndex))
|
||||||
|
|
||||||
if (nextStep) {
|
if (nextStep) {
|
||||||
@@ -1693,6 +1735,7 @@ export default {
|
|||||||
},
|
},
|
||||||
async performComplete (resp) {
|
async performComplete (resp) {
|
||||||
this.isCompleted = true
|
this.isCompleted = true
|
||||||
|
this.isFormVisible = true
|
||||||
|
|
||||||
if (resp?.text) {
|
if (resp?.text) {
|
||||||
const respData = await resp.text()
|
const respData = await resp.text()
|
||||||
|
|||||||
@@ -7,6 +7,13 @@ const en = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Please upload an image file',
|
please_upload_an_image_file: 'Please upload an image file',
|
||||||
must_be_characters_length: 'Must be {number} characters long',
|
must_be_characters_length: 'Must be {number} characters long',
|
||||||
|
must_be_valid_ssn: 'Must be a valid SSN (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Must be a valid EIN (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Must be a valid email address',
|
||||||
|
must_be_valid_url: 'Must be a valid URL (starting with http:// or https://)',
|
||||||
|
must_be_valid_zip: 'Must be a valid ZIP code (XXXXX or XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Must contain numbers only',
|
||||||
|
must_contain_letters_only: 'Must contain letters only',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'Complete all required fields to proceed with identity verification.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Complete all required fields to proceed with identity verification.',
|
||||||
verify_id: 'Verify ID',
|
verify_id: 'Verify ID',
|
||||||
identity_verification: 'Identity verification',
|
identity_verification: 'Identity verification',
|
||||||
@@ -116,6 +123,13 @@ const es = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Por favor, sube un archivo de imagen',
|
please_upload_an_image_file: 'Por favor, sube un archivo de imagen',
|
||||||
must_be_characters_length: 'Debe tener {number} caracteres de longitud',
|
must_be_characters_length: 'Debe tener {number} caracteres de longitud',
|
||||||
|
must_be_valid_ssn: 'Debe ser un SSN válido (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Debe ser un EIN válido (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Debe ser una dirección de correo electrónico válida',
|
||||||
|
must_be_valid_url: 'Debe ser una URL válida (que comience con http:// o https://)',
|
||||||
|
must_be_valid_zip: 'Debe ser un ZIP válido (XXXXX o XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Debe contener solo números',
|
||||||
|
must_contain_letters_only: 'Debe contener solo letras',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'Complete todos los campos requeridos para continuar con la verificación de identidad.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Complete todos los campos requeridos para continuar con la verificación de identidad.',
|
||||||
verify_id: 'Verificar ID',
|
verify_id: 'Verificar ID',
|
||||||
identity_verification: 'Verificación de identidad',
|
identity_verification: 'Verificación de identidad',
|
||||||
@@ -225,6 +239,13 @@ const it = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Per favore carica un file immagine',
|
please_upload_an_image_file: 'Per favore carica un file immagine',
|
||||||
must_be_characters_length: 'Deve essere lungo {number} caratteri',
|
must_be_characters_length: 'Deve essere lungo {number} caratteri',
|
||||||
|
must_be_valid_ssn: 'Deve essere un SSN valido (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Deve essere un EIN valido (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Deve essere un indirizzo email valido',
|
||||||
|
must_be_valid_url: 'Deve essere un URL valido (che inizia con http:// o https://)',
|
||||||
|
must_be_valid_zip: 'Deve essere uno ZIP valido (XXXXX o XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Deve contenere solo numeri',
|
||||||
|
must_contain_letters_only: 'Deve contenere solo lettere',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: "Compila tutti i campi obbligatori per procedere con la verifica dell'identità.",
|
complete_all_required_fields_to_proceed_with_identity_verification: "Compila tutti i campi obbligatori per procedere con la verifica dell'identità.",
|
||||||
verify_id: 'Verifica ID',
|
verify_id: 'Verifica ID',
|
||||||
identity_verification: "Verifica dell'identità",
|
identity_verification: "Verifica dell'identità",
|
||||||
@@ -334,6 +355,13 @@ const de = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Bitte laden Sie eine Bilddatei hoch',
|
please_upload_an_image_file: 'Bitte laden Sie eine Bilddatei hoch',
|
||||||
must_be_characters_length: 'Muss {number} Zeichen lang sein',
|
must_be_characters_length: 'Muss {number} Zeichen lang sein',
|
||||||
|
must_be_valid_ssn: 'Muss eine gültige SSN sein (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Muss eine gültige EIN sein (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Muss eine gültige E-Mail-Adresse sein',
|
||||||
|
must_be_valid_url: 'Muss eine gültige URL sein (beginnend mit http:// oder https://)',
|
||||||
|
must_be_valid_zip: 'Muss eine gültige ZIP sein (XXXXX oder XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Darf nur Zahlen enthalten',
|
||||||
|
must_contain_letters_only: 'Darf nur Buchstaben enthalten',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'Füllen Sie alle Pflichtfelder aus, um mit der Identitätsprüfung fortzufahren.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Füllen Sie alle Pflichtfelder aus, um mit der Identitätsprüfung fortzufahren.',
|
||||||
verify_id: 'ID überprüfen',
|
verify_id: 'ID überprüfen',
|
||||||
identity_verification: 'Identitätsprüfung',
|
identity_verification: 'Identitätsprüfung',
|
||||||
@@ -443,6 +471,13 @@ const fr = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Veuillez téléverser un fichier image',
|
please_upload_an_image_file: 'Veuillez téléverser un fichier image',
|
||||||
must_be_characters_length: 'Doit comporter {number} caractères',
|
must_be_characters_length: 'Doit comporter {number} caractères',
|
||||||
|
must_be_valid_ssn: 'Doit être un SSN valide (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Doit être un EIN valide (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Doit être une adresse e-mail valide',
|
||||||
|
must_be_valid_url: 'Doit être une URL valide (commençant par http:// ou https://)',
|
||||||
|
must_be_valid_zip: 'Doit être un ZIP valide (XXXXX ou XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Doit contenir uniquement des chiffres',
|
||||||
|
must_contain_letters_only: 'Doit contenir uniquement des lettres',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: "Veuillez remplir tous les champs obligatoires pour poursuivre la vérification d'identité.",
|
complete_all_required_fields_to_proceed_with_identity_verification: "Veuillez remplir tous les champs obligatoires pour poursuivre la vérification d'identité.",
|
||||||
verify_id: "Vérifier l'ID",
|
verify_id: "Vérifier l'ID",
|
||||||
identity_verification: "Vérification d'identité",
|
identity_verification: "Vérification d'identité",
|
||||||
@@ -552,6 +587,13 @@ const pl = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Proszę przesłać plik obrazu',
|
please_upload_an_image_file: 'Proszę przesłać plik obrazu',
|
||||||
must_be_characters_length: 'Musi mieć długość {number} znaków',
|
must_be_characters_length: 'Musi mieć długość {number} znaków',
|
||||||
|
must_be_valid_ssn: 'Musi być prawidłowym numerem SSN (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Musi być prawidłowym numerem EIN (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Musi być prawidłowym adresem e-mail',
|
||||||
|
must_be_valid_url: 'Musi być prawidłowym adresem URL (zaczynającym się od http:// lub https://)',
|
||||||
|
must_be_valid_zip: 'Musi być prawidłowym ZIP (XXXXX lub XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Może zawierać tylko cyfry',
|
||||||
|
must_contain_letters_only: 'Może zawierać tylko litery',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'Uzupełnij wszystkie wymagane pola, aby kontynuować weryfikację tożsamości.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Uzupełnij wszystkie wymagane pola, aby kontynuować weryfikację tożsamości.',
|
||||||
verify_id: 'Zweryfikuj ID',
|
verify_id: 'Zweryfikuj ID',
|
||||||
identity_verification: 'Weryfikacja tożsamości',
|
identity_verification: 'Weryfikacja tożsamości',
|
||||||
@@ -661,6 +703,13 @@ const uk = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Будь ласка, завантажте файл зображення',
|
please_upload_an_image_file: 'Будь ласка, завантажте файл зображення',
|
||||||
must_be_characters_length: 'Має містити {number} символів',
|
must_be_characters_length: 'Має містити {number} символів',
|
||||||
|
must_be_valid_ssn: 'Має бути дійсним SSN (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Має бути дійсним EIN (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Має бути дійсною адресою електронної пошти',
|
||||||
|
must_be_valid_url: 'Має бути дійсним URL (починаючи з http:// або https://)',
|
||||||
|
must_be_valid_zip: 'Має бути дійсним ZIP (XXXXX або XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Має містити лише цифри',
|
||||||
|
must_contain_letters_only: 'Має містити лише літери',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: "Заповніть всі обов'язкові поля, щоб продовжити перевірку особи.",
|
complete_all_required_fields_to_proceed_with_identity_verification: "Заповніть всі обов'язкові поля, щоб продовжити перевірку особи.",
|
||||||
verify_id: 'Підтвердження ідентичності',
|
verify_id: 'Підтвердження ідентичності',
|
||||||
identity_verification: 'Ідентифікація особи',
|
identity_verification: 'Ідентифікація особи',
|
||||||
@@ -770,6 +819,13 @@ const cs = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Nahrajte prosím obrázkový soubor',
|
please_upload_an_image_file: 'Nahrajte prosím obrázkový soubor',
|
||||||
must_be_characters_length: 'Musí mít délku {number} znaků',
|
must_be_characters_length: 'Musí mít délku {number} znaků',
|
||||||
|
must_be_valid_ssn: 'Musí být platné SSN (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Musí být platné EIN (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Musí být platná e-mailová adresa',
|
||||||
|
must_be_valid_url: 'Musí být platná URL (začínající http:// nebo https://)',
|
||||||
|
must_be_valid_zip: 'Musí být platný ZIP (XXXXX nebo XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Musí obsahovat pouze čísla',
|
||||||
|
must_contain_letters_only: 'Musí obsahovat pouze písmena',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'Vyplňte všechna povinná pole, abyste mohli pokračovat v ověření identity.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Vyplňte všechna povinná pole, abyste mohli pokračovat v ověření identity.',
|
||||||
verify_id: 'Ověřit ID',
|
verify_id: 'Ověřit ID',
|
||||||
identity_verification: 'Ověření identity',
|
identity_verification: 'Ověření identity',
|
||||||
@@ -879,6 +935,13 @@ const pt = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Por favor, envie um arquivo de imagem',
|
please_upload_an_image_file: 'Por favor, envie um arquivo de imagem',
|
||||||
must_be_characters_length: 'Deve ter {number} caracteres',
|
must_be_characters_length: 'Deve ter {number} caracteres',
|
||||||
|
must_be_valid_ssn: 'Deve ser um SSN válido (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Deve ser um EIN válido (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Deve ser um endereço de e-mail válido',
|
||||||
|
must_be_valid_url: 'Deve ser uma URL válida (começando com http:// ou https://)',
|
||||||
|
must_be_valid_zip: 'Deve ser um ZIP válido (XXXXX ou XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Deve conter apenas números',
|
||||||
|
must_contain_letters_only: 'Deve conter apenas letras',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'Preencha todos os campos obrigatórios para prosseguir com a verificação de identidade.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Preencha todos os campos obrigatórios para prosseguir com a verificação de identidade.',
|
||||||
verify_id: 'Verificar ID',
|
verify_id: 'Verificar ID',
|
||||||
identity_verification: 'Verificação de identidade',
|
identity_verification: 'Verificação de identidade',
|
||||||
@@ -988,6 +1051,13 @@ const he = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'אנא העלה קובץ תמונה',
|
please_upload_an_image_file: 'אנא העלה קובץ תמונה',
|
||||||
must_be_characters_length: 'חייב להיות באורך של {number} תווים',
|
must_be_characters_length: 'חייב להיות באורך של {number} תווים',
|
||||||
|
must_be_valid_ssn: 'חייב להיות SSN חוקי (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'חייב להיות EIN חוקי (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'חייבת להיות כתובת אימייל חוקית',
|
||||||
|
must_be_valid_url: 'חייבת להיות כתובת URL חוקית (המתחילה ב-http:// או https://)',
|
||||||
|
must_be_valid_zip: 'חייב להיות ZIP חוקי (XXXXX או XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'חייב להכיל מספרים בלבד',
|
||||||
|
must_contain_letters_only: 'חייב להכיל אותיות בלבד',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'מלא את כל השדות הנדרשים כדי להמשיך עם אימות זהות.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'מלא את כל השדות הנדרשים כדי להמשיך עם אימות זהות.',
|
||||||
verify_id: 'אמת מזהה',
|
verify_id: 'אמת מזהה',
|
||||||
identity_verification: 'אימות זהות',
|
identity_verification: 'אימות זהות',
|
||||||
@@ -1097,6 +1167,13 @@ const nl = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'Upload alstublieft een afbeeldingsbestand',
|
please_upload_an_image_file: 'Upload alstublieft een afbeeldingsbestand',
|
||||||
must_be_characters_length: 'Moet {number} tekens lang zijn',
|
must_be_characters_length: 'Moet {number} tekens lang zijn',
|
||||||
|
must_be_valid_ssn: 'Moet een geldig SSN zijn (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'Moet een geldig EIN zijn (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'Moet een geldig e-mailadres zijn',
|
||||||
|
must_be_valid_url: 'Moet een geldige URL zijn (beginnend met http:// of https://)',
|
||||||
|
must_be_valid_zip: 'Moet een geldige ZIP zijn (XXXXX of XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'Mag alleen cijfers bevatten',
|
||||||
|
must_contain_letters_only: 'Mag alleen letters bevatten',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'Vul alle verplichte velden in om door te gaan met de identiteitsverificatie.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Vul alle verplichte velden in om door te gaan met de identiteitsverificatie.',
|
||||||
verify_id: 'ID verifiëren',
|
verify_id: 'ID verifiëren',
|
||||||
identity_verification: 'Identiteitsverificatie',
|
identity_verification: 'Identiteitsverificatie',
|
||||||
@@ -1206,6 +1283,13 @@ const ar = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: 'يرجى تحميل ملف صورة',
|
please_upload_an_image_file: 'يرجى تحميل ملف صورة',
|
||||||
must_be_characters_length: 'يجب أن يكون الطول {number} حرفًا',
|
must_be_characters_length: 'يجب أن يكون الطول {number} حرفًا',
|
||||||
|
must_be_valid_ssn: 'يجب أن يكون SSN صالحًا (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: 'يجب أن يكون EIN صالحًا (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: 'يجب أن يكون عنوان بريد إلكتروني صالحًا',
|
||||||
|
must_be_valid_url: 'يجب أن يكون عنوان URL صالحًا (يبدأ بـ http:// أو https://)',
|
||||||
|
must_be_valid_zip: 'يجب أن يكون ZIP صالحًا (XXXXX أو XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: 'يجب أن يحتوي على أرقام فقط',
|
||||||
|
must_contain_letters_only: 'يجب أن يحتوي على أحرف فقط',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: 'أكمل جميع الحقول المطلوبة للمتابعة في التحقق من الهوية.',
|
complete_all_required_fields_to_proceed_with_identity_verification: 'أكمل جميع الحقول المطلوبة للمتابعة في التحقق من الهوية.',
|
||||||
verify_id: 'تحقق من الهوية',
|
verify_id: 'تحقق من الهوية',
|
||||||
identity_verification: 'التحقق من الهوية',
|
identity_verification: 'التحقق من الهوية',
|
||||||
@@ -1315,6 +1399,13 @@ const ko = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: '이미지 파일을 업로드해 주세요',
|
please_upload_an_image_file: '이미지 파일을 업로드해 주세요',
|
||||||
must_be_characters_length: '{number}자여야 합니다',
|
must_be_characters_length: '{number}자여야 합니다',
|
||||||
|
must_be_valid_ssn: '유효한 SSN이어야 합니다 (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: '유효한 EIN이어야 합니다 (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: '유효한 이메일 주소여야 합니다',
|
||||||
|
must_be_valid_url: '유효한 URL이어야 합니다 (http:// 또는 https://로 시작)',
|
||||||
|
must_be_valid_zip: '유효한 ZIP이어야 합니다 (XXXXX 또는 XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: '숫자만 포함해야 합니다',
|
||||||
|
must_contain_letters_only: '문자만 포함해야 합니다',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: '신원 확인을 진행하려면 모든 필수 필드를 작성하십시오.',
|
complete_all_required_fields_to_proceed_with_identity_verification: '신원 확인을 진행하려면 모든 필수 필드를 작성하십시오.',
|
||||||
verify_id: '아이디 확인',
|
verify_id: '아이디 확인',
|
||||||
identity_verification: '신원 확인',
|
identity_verification: '신원 확인',
|
||||||
@@ -1424,6 +1515,13 @@ const ja = {
|
|||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
please_upload_an_image_file: '画像ファイルをアップロードしてください',
|
please_upload_an_image_file: '画像ファイルをアップロードしてください',
|
||||||
must_be_characters_length: '{number}文字でなければなりません',
|
must_be_characters_length: '{number}文字でなければなりません',
|
||||||
|
must_be_valid_ssn: '有効なSSNである必要があります (XXX-XX-XXXX)',
|
||||||
|
must_be_valid_ein: '有効なEINである必要があります (XX-XXXXXXX)',
|
||||||
|
must_be_valid_email: '有効なメールアドレスである必要があります',
|
||||||
|
must_be_valid_url: '有効なURLである必要があります (http://またはhttps://で始まる)',
|
||||||
|
must_be_valid_zip: '有効なZIPである必要があります (XXXXX または XXXXX-XXXX)',
|
||||||
|
must_contain_numbers_only: '数字のみを含む必要があります',
|
||||||
|
must_contain_letters_only: '文字のみを含む必要があります',
|
||||||
complete_all_required_fields_to_proceed_with_identity_verification: '本人確認を進めるには、すべての必須項目を入力してください。',
|
complete_all_required_fields_to_proceed_with_identity_verification: '本人確認を進めるには、すべての必須項目を入力してください。',
|
||||||
verify_id: '本人確認',
|
verify_id: '本人確認',
|
||||||
identity_verification: '本人確認',
|
identity_verification: '本人確認',
|
||||||
|
|||||||
@@ -41,12 +41,11 @@
|
|||||||
:class="{ '!pr-11 -mr-10': !field.validation?.pattern }"
|
:class="{ '!pr-11 -mr-10': !field.validation?.pattern }"
|
||||||
:required="field.required"
|
:required="field.required"
|
||||||
:pattern="field.validation?.pattern"
|
:pattern="field.validation?.pattern"
|
||||||
|
:title="validationMessage"
|
||||||
:aria-describedby="field.description ? field.uuid + '-desc' : undefined"
|
:aria-describedby="field.description ? field.uuid + '-desc' : undefined"
|
||||||
:placeholder="`${t('type_here_')}${field.required ? '' : ` (${t('optional')})`}`"
|
:placeholder="`${t('type_here_')}${field.required ? '' : ` (${t('optional')})`}`"
|
||||||
type="text"
|
type="text"
|
||||||
:name="`values[${field.uuid}]`"
|
:name="`values[${field.uuid}]`"
|
||||||
@invalid="validationMessage ? $event.target.setCustomValidity(validationMessage) : ''"
|
|
||||||
@input="validationMessage ? $event.target.setCustomValidity('') : ''"
|
|
||||||
@focus="$emit('focus')"
|
@focus="$emit('focus')"
|
||||||
>
|
>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -138,6 +137,17 @@ export default {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
patternMessageKeys () {
|
||||||
|
return {
|
||||||
|
'^[0-9]{3}-[0-9]{2}-[0-9]{4}$': 'must_be_valid_ssn',
|
||||||
|
'^[0-9]{2}-[0-9]{7}$': 'must_be_valid_ein',
|
||||||
|
'^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$': 'must_be_valid_email',
|
||||||
|
'^https?://.*': 'must_be_valid_url',
|
||||||
|
'^[0-9]{5}(?:-[0-9]{4})?$': 'must_be_valid_zip',
|
||||||
|
'^[0-9]+$': 'must_contain_numbers_only',
|
||||||
|
'^[a-zA-Z]+$': 'must_contain_letters_only'
|
||||||
|
}
|
||||||
|
},
|
||||||
validationMessage () {
|
validationMessage () {
|
||||||
if (this.field.validation?.message) {
|
if (this.field.validation?.message) {
|
||||||
return this.field.validation.message
|
return this.field.validation.message
|
||||||
@@ -149,6 +159,10 @@ export default {
|
|||||||
.join('-')
|
.join('-')
|
||||||
|
|
||||||
return this.t('must_be_characters_length').replace('{number}', number)
|
return this.t('must_be_characters_length').replace('{number}', number)
|
||||||
|
} else if (this.field.validation?.pattern) {
|
||||||
|
const key = this.patternMessageKeys[this.field.validation.pattern]
|
||||||
|
|
||||||
|
return key ? this.t(key) : ''
|
||||||
} else {
|
} else {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -620,6 +620,10 @@ export default {
|
|||||||
return new Intl.NumberFormat('de-DE').format(number)
|
return new Intl.NumberFormat('de-DE').format(number)
|
||||||
} else if (format === 'space') {
|
} else if (format === 'space') {
|
||||||
return new Intl.NumberFormat('fr-FR').format(number)
|
return new Intl.NumberFormat('fr-FR').format(number)
|
||||||
|
} else if (format === 'percent') {
|
||||||
|
return `${number}%`
|
||||||
|
} else if (format === 'percent_space') {
|
||||||
|
return `${String(number).replace('.', ',')} %`
|
||||||
} else {
|
} else {
|
||||||
return number
|
return number
|
||||||
}
|
}
|
||||||
@@ -716,14 +720,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
drag (e) {
|
|
||||||
if (e.target.id === 'mask' && this.editable) {
|
|
||||||
this.isDragged = true
|
|
||||||
|
|
||||||
this.area.x = (e.offsetX - this.dragFrom.x) / e.target.clientWidth
|
|
||||||
this.area.y = (e.offsetY - this.dragFrom.y) / e.target.clientHeight
|
|
||||||
}
|
|
||||||
},
|
|
||||||
startTouchDrag (e) {
|
startTouchDrag (e) {
|
||||||
if (e.target !== this.$refs.touchTarget && e.target !== this.$refs.touchValueTarget) {
|
if (e.target !== this.$refs.touchTarget && e.target !== this.$refs.touchValueTarget) {
|
||||||
return
|
return
|
||||||
@@ -769,6 +765,8 @@ export default {
|
|||||||
|
|
||||||
this.maybeChangeAreaPage(this.area)
|
this.maybeChangeAreaPage(this.area)
|
||||||
|
|
||||||
|
this.clampAreaBounds(this.area)
|
||||||
|
|
||||||
if (this.isDragged) {
|
if (this.isDragged) {
|
||||||
this.save()
|
this.save()
|
||||||
}
|
}
|
||||||
@@ -836,6 +834,8 @@ export default {
|
|||||||
|
|
||||||
this.maybeChangeAreaPage(this.area)
|
this.maybeChangeAreaPage(this.area)
|
||||||
|
|
||||||
|
this.clampAreaBounds(this.area)
|
||||||
|
|
||||||
if (this.isMoved) {
|
if (this.isMoved) {
|
||||||
this.save()
|
this.save()
|
||||||
}
|
}
|
||||||
@@ -860,18 +860,6 @@ export default {
|
|||||||
area.y = area.y - 1 - (16.0 / this.$parent.$refs.mask.previousSibling.offsetHeight)
|
area.y = area.y - 1 - (16.0 / this.$parent.$refs.mask.previousSibling.offsetHeight)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
stopDrag () {
|
|
||||||
this.$el.getRootNode().removeEventListener('mousemove', this.drag)
|
|
||||||
this.$el.getRootNode().removeEventListener('mouseup', this.stopDrag)
|
|
||||||
|
|
||||||
if (this.isDragged) {
|
|
||||||
this.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isDragged = false
|
|
||||||
|
|
||||||
this.$emit('stop-drag')
|
|
||||||
},
|
|
||||||
startResize () {
|
startResize () {
|
||||||
if (!this.selectedAreasRef.value.includes(this.area)) {
|
if (!this.selectedAreasRef.value.includes(this.area)) {
|
||||||
this.selectedAreasRef.value = [this.area]
|
this.selectedAreasRef.value = [this.area]
|
||||||
@@ -886,6 +874,8 @@ export default {
|
|||||||
this.$el.getRootNode().removeEventListener('mousemove', this.resize)
|
this.$el.getRootNode().removeEventListener('mousemove', this.resize)
|
||||||
this.$el.getRootNode().removeEventListener('mouseup', this.stopResize)
|
this.$el.getRootNode().removeEventListener('mouseup', this.stopResize)
|
||||||
|
|
||||||
|
this.clampAreaBounds(this.area)
|
||||||
|
|
||||||
this.$emit('stop-resize')
|
this.$emit('stop-resize')
|
||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
@@ -924,9 +914,17 @@ export default {
|
|||||||
this.$el.getRootNode().removeEventListener('touchmove', this.touchResize)
|
this.$el.getRootNode().removeEventListener('touchmove', this.touchResize)
|
||||||
this.$el.getRootNode().removeEventListener('touchend', this.stopTouchResize)
|
this.$el.getRootNode().removeEventListener('touchend', this.stopTouchResize)
|
||||||
|
|
||||||
|
this.clampAreaBounds(this.area)
|
||||||
|
|
||||||
this.$emit('stop-resize')
|
this.$emit('stop-resize')
|
||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
|
},
|
||||||
|
clampAreaBounds (area) {
|
||||||
|
area.x = Math.min(Math.max(area.x, 0), 1)
|
||||||
|
area.y = Math.min(Math.max(area.y, 0), 1)
|
||||||
|
area.w = Math.min(Math.max(area.w, 0), 1)
|
||||||
|
area.h = Math.min(Math.max(area.h, 0), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2512,6 +2512,11 @@ export default {
|
|||||||
|
|
||||||
this.selectedAreasRef.value = [area]
|
this.selectedAreasRef.value = [area]
|
||||||
|
|
||||||
|
area.x = Math.min(Math.max(area.x, 0), 1)
|
||||||
|
area.y = Math.min(Math.max(area.y, 0), 1)
|
||||||
|
area.w = Math.min(Math.max(area.w, 0), 1)
|
||||||
|
area.h = Math.min(Math.max(area.h, 0), 1)
|
||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
} else {
|
} else {
|
||||||
const documentRef = this.documentRefs.find((e) => e.document.uuid === area.attachment_uuid)
|
const documentRef = this.documentRefs.find((e) => e.document.uuid === area.attachment_uuid)
|
||||||
@@ -3141,7 +3146,11 @@ export default {
|
|||||||
|
|
||||||
const dynamicDocumentSaves = dynamicDocumentRefs.map((ref) => ref.saveBody())
|
const dynamicDocumentSaves = dynamicDocumentRefs.map((ref) => ref.saveBody())
|
||||||
|
|
||||||
Promise.all([this.save({ force: true, revision: this.withRevisions }), ...dynamicDocumentSaves]).then(() => {
|
Promise.all([this.save({ force: true }), ...dynamicDocumentSaves]).then(() => {
|
||||||
|
if (this.withRevisions) {
|
||||||
|
this.captureRevision()
|
||||||
|
}
|
||||||
|
|
||||||
window.Turbo.visit(`/templates/${this.template.id}`)
|
window.Turbo.visit(`/templates/${this.template.id}`)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.isSaving = false
|
this.isSaving = false
|
||||||
@@ -3372,7 +3381,7 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
save ({ force = false, revision = false } = {}) {
|
save ({ force = false } = {}) {
|
||||||
this.pendingFieldAttachmentUuids = []
|
this.pendingFieldAttachmentUuids = []
|
||||||
|
|
||||||
if (this.beforeRevisionSnapshot) {
|
if (this.beforeRevisionSnapshot) {
|
||||||
@@ -3404,8 +3413,7 @@ export default {
|
|||||||
submitters: this.template.submitters,
|
submitters: this.template.submitters,
|
||||||
fields: this.template.fields,
|
fields: this.template.fields,
|
||||||
variables_schema: this.template.variables_schema
|
variables_schema: this.template.variables_schema
|
||||||
},
|
}
|
||||||
...(revision ? { revision: true } : {})
|
|
||||||
}),
|
}),
|
||||||
headers: { 'Content-Type': 'application/json' }
|
headers: { 'Content-Type': 'application/json' }
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
@@ -3414,6 +3422,12 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
captureRevision () {
|
||||||
|
return this.baseFetch(`/templates/${this.template.id}/versions`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
})
|
||||||
|
},
|
||||||
onDynamicDocumentUpdate () {
|
onDynamicDocumentUpdate () {
|
||||||
this.rebuildVariablesSchema()
|
this.rebuildVariablesSchema()
|
||||||
|
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ export default {
|
|||||||
FieldType,
|
FieldType,
|
||||||
IconSettings
|
IconSettings
|
||||||
},
|
},
|
||||||
inject: ['t', 'save', 'backgroundColor', 'dateFormats'],
|
inject: ['t', 'save', 'backgroundColor', 'dateFormats', 'locale'],
|
||||||
provide () {
|
provide () {
|
||||||
return {
|
return {
|
||||||
fieldTypes: ['text', 'number', 'date', 'checkbox', 'radio', 'select']
|
fieldTypes: ['text', 'number', 'date', 'checkbox', 'radio', 'select']
|
||||||
@@ -308,15 +308,18 @@ export default {
|
|||||||
return { text: 'string', number: 'number', date: 'date', checkbox: 'boolean', radio: 'string', select: 'string' }
|
return { text: 'string', number: 'number', date: 'date', checkbox: 'boolean', radio: 'string', select: 'string' }
|
||||||
},
|
},
|
||||||
numberFormats () {
|
numberFormats () {
|
||||||
return [
|
const formats = ['none', 'usd', 'eur', 'gbp', 'comma', 'dot', 'space']
|
||||||
'none',
|
const spaceLocales = ['fr-FR', 'es-ES', 'pt-PT', 'de-DE', 'it-IT', 'nl-NL']
|
||||||
'usd',
|
|
||||||
'eur',
|
formats.push(spaceLocales.includes(this.locale) ? 'percent_space' : 'percent')
|
||||||
'gbp',
|
|
||||||
'comma',
|
const selectedFormat = this.schema.format
|
||||||
'dot',
|
|
||||||
'space'
|
if (selectedFormat && !formats.includes(selectedFormat)) {
|
||||||
]
|
formats.push(selectedFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
return formats
|
||||||
},
|
},
|
||||||
availableDateFormats () {
|
availableDateFormats () {
|
||||||
const formats = this.dateFormats.length
|
const formats = this.dateFormats.length
|
||||||
@@ -397,6 +400,10 @@ export default {
|
|||||||
return new Intl.NumberFormat('de-DE').format(number)
|
return new Intl.NumberFormat('de-DE').format(number)
|
||||||
} else if (format === 'space') {
|
} else if (format === 'space') {
|
||||||
return new Intl.NumberFormat('fr-FR').format(number)
|
return new Intl.NumberFormat('fr-FR').format(number)
|
||||||
|
} else if (format === 'percent') {
|
||||||
|
return `${number}%`
|
||||||
|
} else if (format === 'percent_space') {
|
||||||
|
return `${String(number).replace('.', ',')} %`
|
||||||
} else {
|
} else {
|
||||||
return number
|
return number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -514,7 +514,7 @@ export default {
|
|||||||
ContextSubmenu,
|
ContextSubmenu,
|
||||||
ContextModal
|
ContextModal
|
||||||
},
|
},
|
||||||
inject: ['t', 'getFieldTypeIndex', 'template', 'withCustomFields', 'currencies', 'dateFormats'],
|
inject: ['t', 'getFieldTypeIndex', 'template', 'withCustomFields', 'currencies', 'dateFormats', 'locale'],
|
||||||
props: {
|
props: {
|
||||||
contextMenu: {
|
contextMenu: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -610,7 +610,7 @@ export default {
|
|||||||
IconTypography,
|
IconTypography,
|
||||||
IconX
|
IconX
|
||||||
},
|
},
|
||||||
inject: ['template', 't', 'dateFormats'],
|
inject: ['template', 't', 'dateFormats', 'locale'],
|
||||||
props: {
|
props: {
|
||||||
field: {
|
field: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -691,15 +691,18 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
numberFormats () {
|
numberFormats () {
|
||||||
return [
|
const formats = ['none', 'usd', 'eur', 'gbp', 'comma', 'dot', 'space']
|
||||||
'none',
|
const spaceLocales = ['fr-FR', 'es-ES', 'pt-PT', 'de-DE', 'it-IT', 'nl-NL']
|
||||||
'usd',
|
|
||||||
'eur',
|
formats.push(spaceLocales.includes(this.locale) ? 'percent_space' : 'percent')
|
||||||
'gbp',
|
|
||||||
'comma',
|
const selectedFormat = this.field.preferences?.format
|
||||||
'dot',
|
|
||||||
'space'
|
if (selectedFormat && !formats.includes(selectedFormat)) {
|
||||||
]
|
formats.push(selectedFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
return formats
|
||||||
},
|
},
|
||||||
availableDateFormats () {
|
availableDateFormats () {
|
||||||
const formats = this.dateFormats.length
|
const formats = this.dateFormats.length
|
||||||
@@ -824,6 +827,10 @@ export default {
|
|||||||
return new Intl.NumberFormat('de-DE').format(number)
|
return new Intl.NumberFormat('de-DE').format(number)
|
||||||
} else if (format === 'space') {
|
} else if (format === 'space') {
|
||||||
return new Intl.NumberFormat('fr-FR').format(number)
|
return new Intl.NumberFormat('fr-FR').format(number)
|
||||||
|
} else if (format === 'percent') {
|
||||||
|
return `${number}%`
|
||||||
|
} else if (format === 'percent_space') {
|
||||||
|
return `${String(number).replace('.', ',')} %`
|
||||||
} else {
|
} else {
|
||||||
return number
|
return number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -679,7 +679,7 @@ const pt = {
|
|||||||
analyzing_: 'Analisando...',
|
analyzing_: 'Analisando...',
|
||||||
download: 'Baixar',
|
download: 'Baixar',
|
||||||
downloading_: 'Baixando...',
|
downloading_: 'Baixando...',
|
||||||
view: 'Visualizar',
|
view: 'Ver',
|
||||||
payment_link: 'Link de pagamento',
|
payment_link: 'Link de pagamento',
|
||||||
strikeout: 'Tachado',
|
strikeout: 'Tachado',
|
||||||
draw_strikethrough_the_document: 'Desenhe uma linha de tachado no documento',
|
draw_strikethrough_the_document: 'Desenhe uma linha de tachado no documento',
|
||||||
|
|||||||
@@ -52,9 +52,7 @@
|
|||||||
<% if link_form_fields.include?('phone') %>
|
<% if link_form_fields.include?('phone') %>
|
||||||
<div dir="auto" class="form-control !mt-0">
|
<div dir="auto" class="form-control !mt-0">
|
||||||
<%= f.label :phone, t('phone'), class: 'label' %>
|
<%= f.label :phone, t('phone'), class: 'label' %>
|
||||||
<custom-validation data-invalid-message="<%= t('use_international_format_1xxx_') %>">
|
<%= f.telephone_field :phone, value: params[:phone] || @submitter.phone, pattern: '^\+[0-9\s\-]+$', required: true, title: t('use_international_format_1xxx_'), class: 'base-input w-full', placeholder: t(multiple_fields ? 'provide_your_phone_in_international_format' : 'provide_your_phone_in_international_format_to_start') %>
|
||||||
<%= f.telephone_field :phone, value: params[:phone] || @submitter.phone, pattern: '^\+[0-9\s\-]+$', required: true, class: 'base-input w-full', placeholder: t(multiple_fields ? 'provide_your_phone_in_international_format' : 'provide_your_phone_in_international_format_to_start') %>
|
|
||||||
</custom-validation>
|
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<toggle-submit dir="auto" class="form-control">
|
<toggle-submit dir="auto" class="form-control">
|
||||||
|
|||||||
@@ -34,13 +34,11 @@
|
|||||||
</linked-input>
|
</linked-input>
|
||||||
</submitters-autocomplete>
|
</submitters-autocomplete>
|
||||||
<% has_phone_field = true %>
|
<% has_phone_field = true %>
|
||||||
<custom-validation data-invalid-message="<%= t('use_international_format_1xxx_') %>">
|
<submitters-autocomplete data-field="phone">
|
||||||
<submitters-autocomplete data-field="phone">
|
<linked-input data-target-id="<%= "detailed_phone_#{item['linked_to_uuid']}" if item['linked_to_uuid'].present? %>">
|
||||||
<linked-input data-target-id="<%= "detailed_phone_#{item['linked_to_uuid']}" if item['linked_to_uuid'].present? %>">
|
<%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', name: 'submission[1][submitters][][phone]', autocomplete: 'off', title: t('use_international_format_1xxx_'), class: 'base-input !h-10 mt-1.5 w-full', placeholder: local_assigns[:require_phone_2fa] == true || local_assigns[:prefillable_fields].present? ? t(:phone) : "#{t('phone')} (#{t('optional')})", id: "detailed_phone_#{item['uuid']}", required: local_assigns[:require_phone_2fa] == true && index.zero? %>
|
||||||
<%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', name: 'submission[1][submitters][][phone]', autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: local_assigns[:require_phone_2fa] == true || local_assigns[:prefillable_fields].present? ? t(:phone) : "#{t('phone')} (#{t('optional')})", id: "detailed_phone_#{item['uuid']}", required: local_assigns[:require_phone_2fa] == true && index.zero? %>
|
</linked-input>
|
||||||
</linked-input>
|
</submitters-autocomplete>
|
||||||
</submitters-autocomplete>
|
|
||||||
</custom-validation>
|
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if prefillable_fields.present? %>
|
<% if prefillable_fields.present? %>
|
||||||
@@ -51,13 +49,11 @@
|
|||||||
</submitters-autocomplete>
|
</submitters-autocomplete>
|
||||||
<% if local_assigns[:require_phone_2fa] == true || prefillable_fields.any? { |f| f['type'] == 'phone' } %>
|
<% if local_assigns[:require_phone_2fa] == true || prefillable_fields.any? { |f| f['type'] == 'phone' } %>
|
||||||
<% has_phone_field = true %>
|
<% has_phone_field = true %>
|
||||||
<custom-validation data-invalid-message="<%= t('use_international_format_1xxx_') %>">
|
<submitters-autocomplete data-field="phone">
|
||||||
<submitters-autocomplete data-field="phone">
|
<linked-input data-target-id="<%= "detailed_phone_#{item['linked_to_uuid']}" if item['linked_to_uuid'].present? %>">
|
||||||
<linked-input data-target-id="<%= "detailed_phone_#{item['linked_to_uuid']}" if item['linked_to_uuid'].present? %>">
|
<%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', name: 'submission[1][submitters][][phone]', autocomplete: 'off', title: t('use_international_format_1xxx_'), class: 'base-input !h-10 mt-1.5 w-full', placeholder: t(:phone), id: "detailed_phone_#{item['uuid']}", required: true %>
|
||||||
<%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', name: 'submission[1][submitters][][phone]', autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: t(:phone), id: "detailed_phone_#{item['uuid']}", required: true %>
|
</linked-input>
|
||||||
</linked-input>
|
</submitters-autocomplete>
|
||||||
</submitters-autocomplete>
|
|
||||||
</custom-validation>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<% prefillable_fields.each do |field| %>
|
<% prefillable_fields.each do |field| %>
|
||||||
<% field_id = "detailed_field_#{index}_#{field['uuid'] || field['name'].parameterize}" %>
|
<% field_id = "detailed_field_#{index}_#{field['uuid'] || field['name'].parameterize}" %>
|
||||||
|
|||||||
@@ -19,13 +19,11 @@
|
|||||||
</label>
|
</label>
|
||||||
<% end %>
|
<% end %>
|
||||||
<input type="hidden" name="submission[1][submitters][][uuid]" value="<%= item['uuid'] %>">
|
<input type="hidden" name="submission[1][submitters][][uuid]" value="<%= item['uuid'] %>">
|
||||||
<custom-validation data-invalid-message="<%= t('use_international_format_1xxx_') %>">
|
<submitters-autocomplete data-field="phone">
|
||||||
<submitters-autocomplete data-field="phone">
|
<linked-input data-target-id="<%= "phone_phone_#{item['linked_to_uuid']}" if item['linked_to_uuid'].present? %>">
|
||||||
<linked-input data-target-id="<%= "phone_phone_#{item['linked_to_uuid']}" if item['linked_to_uuid'].present? %>">
|
<%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', name: 'submission[1][submitters][][phone]', autocomplete: 'off', title: t('use_international_format_1xxx_'), class: 'base-input !h-10 w-full', placeholder: t('phone'), required: index.zero? || template.preferences['require_all_submitters'], id: "phone_phone_#{item['uuid']}" %>
|
||||||
<%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', name: 'submission[1][submitters][][phone]', autocomplete: 'off', class: 'base-input !h-10 w-full', placeholder: t('phone'), required: index.zero? || template.preferences['require_all_submitters'], id: "phone_phone_#{item['uuid']}" %>
|
</linked-input>
|
||||||
</linked-input>
|
</submitters-autocomplete>
|
||||||
</submitters-autocomplete>
|
|
||||||
</custom-validation>
|
|
||||||
<% if submitters.size > 1 %>
|
<% if submitters.size > 1 %>
|
||||||
<submitters-autocomplete data-field="name">
|
<submitters-autocomplete data-field="name">
|
||||||
<linked-input data-target-id="<%= "phone_name_#{item['linked_to_uuid']}" if item['linked_to_uuid'].present? %>">
|
<linked-input data-target-id="<%= "phone_name_#{item['linked_to_uuid']}" if item['linked_to_uuid'].present? %>">
|
||||||
|
|||||||
@@ -30,6 +30,12 @@
|
|||||||
<span class="hidden md:block"><%= t('event_log') %></span>
|
<span class="hidden md:block"><%= t('event_log') %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% if signed_in? && !is_all_completed && can?(:manage, :resend_all) && @submission.submitters.to_a.size > 3 && !@submission.archived_at? && !@submission.template&.archived_at? && !@submission.expired? && can?(:update, @submission) %>
|
||||||
|
<% pending_submitters_count = @submission.submitters.to_a.count { |s| !s.completed_at? && s.email.present? && !s.declined_at? } %>
|
||||||
|
<% if pending_submitters_count.positive? %>
|
||||||
|
<%= button_to button_title(title: t('re_send_emails'), title_class: 'hidden md:inline', disabled_with: t('sending'), icon: svg_icon('mail_forward', class: 'w-6 h-6')), submission_resend_email_index_path(@submission), class: 'white-button', data: { turbo_confirm: t('are_you_sure_you_want_to_re_send_email_to_n_recipients', count: pending_submitters_count) } %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
<% if @submission.submitters.to_a.any?(&:completed_at?) %>
|
<% if @submission.submitters.to_a.any?(&:completed_at?) %>
|
||||||
<% if is_all_completed || !is_combined_enabled %>
|
<% if is_all_completed || !is_combined_enabled %>
|
||||||
<div class="join relative">
|
<div class="join relative">
|
||||||
|
|||||||
@@ -21,20 +21,31 @@
|
|||||||
<h1 class="text-xl md:text-2xl font-medium focus:text-clip" style="width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
<h1 class="text-xl md:text-2xl font-medium focus:text-clip" style="width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||||
<%= @submitter.submission.name || @submitter.submission.template.name %>
|
<%= @submitter.submission.name || @submitter.submission.template.name %>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="flex items-center space-x-2" style="margin-left: 20px; flex-shrink: 0">
|
<div class="flex items-center gap-2 group" style="margin-left: 20px; flex-shrink: 0">
|
||||||
|
<% if @form_configs[:with_decline] %>
|
||||||
|
<modal-button data-target="<%= decline_modal_id = SecureRandom.uuid %>" class="hidden group-has-[.complete-button]:flex">
|
||||||
|
<button type="button" class="btn btn-sm md:!px-5 px-2" aria-label="<%= t(:decline) %>">
|
||||||
|
<span class="hidden md:inline"><%= t(:decline) %></span>
|
||||||
|
<span class="inline md:hidden">
|
||||||
|
<%= svg_icon('x', class: 'w-5 h-5') %>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</modal-button>
|
||||||
|
<% end %>
|
||||||
|
<span id="complete_button_container" class="peer contents"></span>
|
||||||
<% if @form_configs[:with_delegate] %>
|
<% if @form_configs[:with_delegate] %>
|
||||||
<modal-button data-target="<%= delegate_modal_id = SecureRandom.uuid %>">
|
<modal-button data-target="<%= delegate_modal_id = SecureRandom.uuid %>" class="hidden peer-empty:flex">
|
||||||
<button id="delegate_button" type="button" class="btn btn-sm !px-5"><%= t(:delegate) %></button>
|
<button id="delegate_button" type="button" class="btn btn-sm !px-5"><%= t(:delegate) %></button>
|
||||||
</modal-button>
|
</modal-button>
|
||||||
<% if @form_configs[:with_decline] %>
|
<% if @form_configs[:with_decline] %>
|
||||||
<modal-button data-target="<%= decline_modal_id = SecureRandom.uuid %>">
|
<modal-button data-target="<%= decline_modal_id %>" class="hidden peer-empty:flex">
|
||||||
<button id="decline_button" type="button" class="btn btn-sm px-2" aria-label="<%= t(:decline) %>">
|
<button id="decline_button" type="button" class="btn btn-sm px-2" aria-label="<%= t(:decline) %>">
|
||||||
<%= svg_icon('x', class: 'w-5 h-5') %>
|
<%= svg_icon('x', class: 'w-5 h-5') %>
|
||||||
</button>
|
</button>
|
||||||
</modal-button>
|
</modal-button>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @form_configs[:with_partial_download] %>
|
<% if @form_configs[:with_partial_download] %>
|
||||||
<download-button role="button" tabindex="0" data-src="<%= submit_form_download_index_path(@submitter.slug) %>" class="btn btn-neutral text-white btn-sm px-2" title="<%= t('download') %>" aria-label="<%= t('download') %>">
|
<download-button role="button" tabindex="0" data-src="<%= submit_form_download_index_path(@submitter.slug) %>" class="btn btn-neutral text-white btn-sm px-2 hidden peer-empty:flex" title="<%= t('download') %>" aria-label="<%= t('download') %>">
|
||||||
<span data-target="download-button.defaultButton">
|
<span data-target="download-button.defaultButton">
|
||||||
<%= svg_icon('download', class: 'w-5 h-5') %>
|
<%= svg_icon('download', class: 'w-5 h-5') %>
|
||||||
</span>
|
</span>
|
||||||
@@ -45,12 +56,12 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<% if @form_configs[:with_decline] %>
|
<% if @form_configs[:with_decline] %>
|
||||||
<modal-button data-target="<%= decline_modal_id = SecureRandom.uuid %>">
|
<modal-button data-target="<%= decline_modal_id %>" class="hidden peer-empty:flex">
|
||||||
<button id="decline_button" type="button" class="btn btn-sm !px-5"><%= t(:decline) %></button>
|
<button id="decline_button" type="button" class="btn btn-sm !px-5"><%= t(:decline) %></button>
|
||||||
</modal-button>
|
</modal-button>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @form_configs[:with_partial_download] %>
|
<% if @form_configs[:with_partial_download] %>
|
||||||
<download-button role="button" tabindex="0" data-src="<%= submit_form_download_index_path(@submitter.slug) %>" class="btn btn-neutral text-white btn-sm !px-4" aria-label="<%= t('download') %>">
|
<download-button role="button" tabindex="0" data-src="<%= submit_form_download_index_path(@submitter.slug) %>" class="btn btn-neutral text-white btn-sm !px-4 hidden peer-empty:flex" aria-label="<%= t('download') %>">
|
||||||
<span class="flex items-center justify-center" data-target="download-button.defaultButton">
|
<span class="flex items-center justify-center" data-target="download-button.defaultButton">
|
||||||
<%= svg_icon('download', class: 'w-6 h-6 inline md:hidden') %>
|
<%= svg_icon('download', class: 'w-6 h-6 inline md:hidden') %>
|
||||||
<span class="hidden md:inline"><%= t('download') %></span>
|
<span class="hidden md:inline"><%= t('download') %></span>
|
||||||
@@ -64,9 +75,17 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<scroll-buttons inert class="fixed right-5 top-2 hidden md:flex gap-1 z-50 ease-in-out opacity-0 -translate-y-10">
|
<scroll-buttons inert class="fixed right-5 top-2 hidden md:flex gap-1 z-50 ease-in-out opacity-0 -translate-y-10 group">
|
||||||
|
<% if @form_configs[:with_decline] %>
|
||||||
|
<modal-button data-target="<%= decline_modal_id %>" class="hidden group-has-[.complete-button]:flex">
|
||||||
|
<button type="button" class="btn btn-sm px-2" aria-label="<%= t(:decline) %>">
|
||||||
|
<%= svg_icon('x', class: 'w-5 h-5') %>
|
||||||
|
</button>
|
||||||
|
</modal-button>
|
||||||
|
<% end %>
|
||||||
|
<span id="complete_button_container_scroll" class="peer contents"></span>
|
||||||
<% if @form_configs[:with_delegate] %>
|
<% if @form_configs[:with_delegate] %>
|
||||||
<modal-button data-target="<%= delegate_modal_id %>">
|
<modal-button data-target="<%= delegate_modal_id %>" class="hidden peer-empty:flex">
|
||||||
<button id="delegate_button_mobile" type="button" class="btn btn-sm px-0" aria-label="<%= t(:delegate) %>">
|
<button id="delegate_button_mobile" type="button" class="btn btn-sm px-0" aria-label="<%= t(:delegate) %>">
|
||||||
<span class="min-[1366px]:inline hidden px-3">
|
<span class="min-[1366px]:inline hidden px-3">
|
||||||
<%= t(:delegate) %>
|
<%= t(:delegate) %>
|
||||||
@@ -77,23 +96,15 @@
|
|||||||
</button>
|
</button>
|
||||||
</modal-button>
|
</modal-button>
|
||||||
<% if @form_configs[:with_decline] %>
|
<% if @form_configs[:with_decline] %>
|
||||||
<modal-button data-target="<%= decline_modal_id %>">
|
<modal-button data-target="<%= decline_modal_id %>" class="hidden peer-empty:flex">
|
||||||
<button id="decline_button_mobile" type="button" class="btn btn-sm px-2" aria-label="<%= t(:decline) %>">
|
<button id="decline_button_mobile" type="button" class="btn btn-sm px-2" aria-label="<%= t(:decline) %>">
|
||||||
<%= svg_icon('x', class: 'w-5 h-5') %>
|
<%= svg_icon('x', class: 'w-5 h-5') %>
|
||||||
</button>
|
</button>
|
||||||
</modal-button>
|
</modal-button>
|
||||||
<% end %>
|
<% end %>
|
||||||
<download-button role="button" tabindex="0" data-src="<%= submit_form_download_index_path(@submitter.slug) %>" class="btn btn-neutral text-white btn-sm px-2" aria-label="<%= t('download') %>">
|
|
||||||
<span data-target="download-button.defaultButton">
|
|
||||||
<%= svg_icon('download', class: 'w-5 h-5') %>
|
|
||||||
</span>
|
|
||||||
<span class="hidden" data-target="download-button.loadingButton">
|
|
||||||
<%= svg_icon('loader', class: 'w-5 h-5 animate-spin') %>
|
|
||||||
</span>
|
|
||||||
</download-button>
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<% if @form_configs[:with_decline] %>
|
<% if @form_configs[:with_decline] %>
|
||||||
<modal-button data-target="<%= decline_modal_id %>">
|
<modal-button data-target="<%= decline_modal_id %>" class="hidden peer-empty:flex">
|
||||||
<button id="decline_button_mobile" type="button" class="btn btn-sm px-0" aria-label="<%= t(:decline) %>">
|
<button id="decline_button_mobile" type="button" class="btn btn-sm px-0" aria-label="<%= t(:decline) %>">
|
||||||
<span class="min-[1366px]:inline hidden px-3">
|
<span class="min-[1366px]:inline hidden px-3">
|
||||||
<%= t(:decline) %>
|
<%= t(:decline) %>
|
||||||
@@ -104,7 +115,9 @@
|
|||||||
</button>
|
</button>
|
||||||
</modal-button>
|
</modal-button>
|
||||||
<% end %>
|
<% end %>
|
||||||
<download-button role="button" tabindex="0" data-src="<%= submit_form_download_index_path(@submitter.slug) %>" class="btn btn-neutral text-white btn-sm px-2" aria-label="<%= t('download') %>">
|
<% end %>
|
||||||
|
<% if @form_configs[:with_partial_download] %>
|
||||||
|
<download-button role="button" tabindex="0" data-src="<%= submit_form_download_index_path(@submitter.slug) %>" class="btn btn-neutral text-white btn-sm px-2 hidden peer-empty:flex" aria-label="<%= t('download') %>">
|
||||||
<span data-target="download-button.defaultButton">
|
<span data-target="download-button.defaultButton">
|
||||||
<%= svg_icon('download', class: 'w-5 h-5') %>
|
<%= svg_icon('download', class: 'w-5 h-5') %>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -10,11 +10,9 @@
|
|||||||
<submitters-autocomplete data-field="email">
|
<submitters-autocomplete data-field="email">
|
||||||
<%= email_field_tag 'submitter[email]', @submitter.email, autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: "#{t('email')} (#{t('optional')})" %>
|
<%= email_field_tag 'submitter[email]', @submitter.email, autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: "#{t('email')} (#{t('optional')})" %>
|
||||||
</submitters-autocomplete>
|
</submitters-autocomplete>
|
||||||
<custom-validation data-invalid-message="<%= t('use_international_format_1xxx_') %>">
|
<submitters-autocomplete data-field="phone">
|
||||||
<submitters-autocomplete data-field="phone">
|
<%= telephone_field_tag 'submitter[phone]', @submitter.phone, autocomplete: 'off', pattern: '^\+[0-9\s\-]+$', title: t('use_international_format_1xxx_'), class: 'base-input !h-10 mt-1.5 w-full', placeholder: "#{t('phone')} (#{t('optional')})" %>
|
||||||
<%= telephone_field_tag 'submitter[phone]', @submitter.phone, autocomplete: 'off', pattern: '^\+[0-9\s\-]+$', class: 'base-input !h-10 mt-1.5 w-full', placeholder: "#{t('phone')} (#{t('optional')})" %>
|
</submitters-autocomplete>
|
||||||
</submitters-autocomplete>
|
|
||||||
</custom-validation>
|
|
||||||
</div>
|
</div>
|
||||||
</submitter-item>
|
</submitter-item>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+26
-5
@@ -658,6 +658,9 @@ en: &en
|
|||||||
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.
|
||||||
re_send_email: Re-send Email
|
re_send_email: Re-send Email
|
||||||
|
re_send_emails: Re-send Emails
|
||||||
|
are_you_sure_you_want_to_re_send_email_to_n_recipients: Are you sure you want to re-send the invitation email to %{count} recipients?
|
||||||
|
emails_have_been_sent_to_n_recipients: Emails have been sent to %{count} recipients.
|
||||||
send_email: Send Email
|
send_email: Send Email
|
||||||
copy_share_link: Copy Share Link
|
copy_share_link: Copy Share Link
|
||||||
copied_to_clipboard: Copied to Clipboard
|
copied_to_clipboard: Copied to Clipboard
|
||||||
@@ -1464,7 +1467,7 @@ es: &es
|
|||||||
type_emails_here: Escribe correos electrónicos aquí
|
type_emails_here: Escribe correos electrónicos aquí
|
||||||
or_embed_on_your_website: O integra en tu sitio web
|
or_embed_on_your_website: O integra en tu sitio web
|
||||||
phone: Teléfono
|
phone: Teléfono
|
||||||
send_emails: Enviar correos electrónicos
|
send_emails: Enviar emails
|
||||||
edit_message: Editar mensaje
|
edit_message: Editar mensaje
|
||||||
smtp_not_configured: SMTP no configurado
|
smtp_not_configured: SMTP no configurado
|
||||||
configure_smtp_settings_in_order_to_send_emails_: 'Configura los ajustes de SMTP para enviar correos electrónicos:'
|
configure_smtp_settings_in_order_to_send_emails_: 'Configura los ajustes de SMTP para enviar correos electrónicos:'
|
||||||
@@ -1707,8 +1710,11 @@ es: &es
|
|||||||
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.
|
||||||
re_send_email: Reenviar correo electrónico
|
re_send_email: Reenviar email
|
||||||
send_email: Enviar correo electrónico
|
re_send_emails: Reenviar emails
|
||||||
|
are_you_sure_you_want_to_re_send_email_to_n_recipients: ¿Estás seguro de que quieres reenviar el email de invitación a %{count} destinatarios?
|
||||||
|
emails_have_been_sent_to_n_recipients: Los emails han sido enviados a %{count} destinatarios.
|
||||||
|
send_email: Enviar email
|
||||||
copy_share_link: Copiar enlace de compartir
|
copy_share_link: Copiar enlace de compartir
|
||||||
copied_to_clipboard: Copiado al portapapeles
|
copied_to_clipboard: Copiado al portapapeles
|
||||||
link: Enlace
|
link: Enlace
|
||||||
@@ -2754,7 +2760,10 @@ it: &it
|
|||||||
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.
|
||||||
re_send_email: Invia di nuovo l'email
|
re_send_email: Reinvia email
|
||||||
|
re_send_emails: Reinvia le email
|
||||||
|
are_you_sure_you_want_to_re_send_email_to_n_recipients: Sei sicuro di voler inviare di nuovo l'email di invito a %{count} destinatari?
|
||||||
|
emails_have_been_sent_to_n_recipients: Le email sono state inviate a %{count} destinatari.
|
||||||
send_email: Invia email
|
send_email: Invia email
|
||||||
copy_share_link: Copia link di condivisione
|
copy_share_link: Copia link di condivisione
|
||||||
copied_to_clipboard: Copiato negli appunti
|
copied_to_clipboard: Copiato negli appunti
|
||||||
@@ -3802,6 +3811,9 @@ fr: &fr
|
|||||||
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éez un nouveau modèle</a> de document ou <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">soumettez 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éez un nouveau modèle</a> de document ou <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">soumettez l’existant</a>
|
||||||
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Envoyer une copie e‑mail avec les documents complétés à une adresse Cci spécifiée.
|
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Envoyer une copie e‑mail avec les documents complétés à une adresse Cci spécifiée.
|
||||||
re_send_email: Renvoyer l’e‑mail
|
re_send_email: Renvoyer l’e‑mail
|
||||||
|
re_send_emails: Renvoyer e‑mails
|
||||||
|
are_you_sure_you_want_to_re_send_email_to_n_recipients: Êtes‑vous sûr de vouloir renvoyer l’e‑mail d’invitation à %{count} destinataires ?
|
||||||
|
emails_have_been_sent_to_n_recipients: Les e‑mails ont été envoyés à %{count} destinataires.
|
||||||
send_email: Envoyer l’e‑mail
|
send_email: Envoyer l’e‑mail
|
||||||
copy_share_link: Copier le lien de partage
|
copy_share_link: Copier le lien de partage
|
||||||
copied_to_clipboard: Copié dans le presse‑papiers
|
copied_to_clipboard: Copié dans le presse‑papiers
|
||||||
@@ -4321,7 +4333,7 @@ pt: &pt
|
|||||||
|
|
||||||
Obrigado,
|
Obrigado,
|
||||||
{account.name}
|
{account.name}
|
||||||
view: Visualizar
|
view: Ver
|
||||||
email: Email
|
email: Email
|
||||||
form_expired_at_html: 'O formulário expirou em <span class="font-semibold">%{time}</span>'
|
form_expired_at_html: 'O formulário expirou em <span class="font-semibold">%{time}</span>'
|
||||||
verification_code_code: 'Código de verificação: %{code}'
|
verification_code_code: 'Código de verificação: %{code}'
|
||||||
@@ -4846,6 +4858,9 @@ pt: &pt
|
|||||||
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.
|
||||||
re_send_email: Reenviar e-mail
|
re_send_email: Reenviar e-mail
|
||||||
|
re_send_emails: Reenviar e-mails
|
||||||
|
are_you_sure_you_want_to_re_send_email_to_n_recipients: Tem certeza de que deseja reenviar o e-mail de convite para %{count} destinatários?
|
||||||
|
emails_have_been_sent_to_n_recipients: Os e-mails foram enviados para %{count} destinatários.
|
||||||
send_email: Enviar e-mail
|
send_email: Enviar e-mail
|
||||||
copy_share_link: Copiar link de compartilhamento
|
copy_share_link: Copiar link de compartilhamento
|
||||||
copied_to_clipboard: Copiado para a área de transferência
|
copied_to_clipboard: Copiado para a área de transferência
|
||||||
@@ -5893,6 +5908,9 @@ de: &de
|
|||||||
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">bestehende 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">bestehende 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.
|
||||||
re_send_email: E-Mail erneut senden
|
re_send_email: E-Mail erneut senden
|
||||||
|
re_send_emails: E-Mails senden
|
||||||
|
are_you_sure_you_want_to_re_send_email_to_n_recipients: Sind Sie sicher, dass Sie die Einladungs-E-Mail erneut an %{count} Empfänger senden möchten?
|
||||||
|
emails_have_been_sent_to_n_recipients: Die E-Mails wurden an %{count} Empfänger gesendet.
|
||||||
send_email: E-Mail senden
|
send_email: E-Mail senden
|
||||||
copy_share_link: Freigabelink kopieren
|
copy_share_link: Freigabelink kopieren
|
||||||
copied_to_clipboard: In die Zwischenablage kopiert
|
copied_to_clipboard: In die Zwischenablage kopiert
|
||||||
@@ -7345,6 +7363,9 @@ nl: &nl
|
|||||||
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">Maak een nieuw sjabloon</a> voor een documentformulier of <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">dien het bestaande in</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">Maak een nieuw sjabloon</a> voor een documentformulier of <a href="%{start_form_link}" target="_blank" class="inline underline font-medium">dien het bestaande in</a>
|
||||||
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Stuur een e-mailkopie met voltooide documenten naar een opgegeven BCC-adres.
|
send_email_copy_with_completed_documents_to_a_specified_bcc_address: Stuur een e-mailkopie met voltooide documenten naar een opgegeven BCC-adres.
|
||||||
re_send_email: E-mail opnieuw verzenden
|
re_send_email: E-mail opnieuw verzenden
|
||||||
|
re_send_emails: E-mails verzenden
|
||||||
|
are_you_sure_you_want_to_re_send_email_to_n_recipients: Weet je zeker dat je de uitnodigings-e-mail opnieuw wilt verzenden naar %{count} ontvangers?
|
||||||
|
emails_have_been_sent_to_n_recipients: De e-mails zijn verzonden naar %{count} ontvangers.
|
||||||
send_email: E-mail verzenden
|
send_email: E-mail verzenden
|
||||||
copy_share_link: Deellink kopiëren
|
copy_share_link: Deellink kopiëren
|
||||||
copied_to_clipboard: Gekopieerd naar klembord
|
copied_to_clipboard: Gekopieerd naar klembord
|
||||||
|
|||||||
+2
-1
@@ -72,6 +72,7 @@ Rails.application.routes.draw do
|
|||||||
resources :unarchive, only: %i[create], controller: 'submissions_unarchive'
|
resources :unarchive, only: %i[create], controller: 'submissions_unarchive'
|
||||||
resources :events, only: %i[index], controller: 'submission_events'
|
resources :events, only: %i[index], controller: 'submission_events'
|
||||||
resources :download, only: %i[index], controller: 'submissions_download'
|
resources :download, only: %i[index], controller: 'submissions_download'
|
||||||
|
resources :resend_email, only: %i[create], controller: 'submissions_resend_email'
|
||||||
end
|
end
|
||||||
resources :submitters, only: %i[edit update]
|
resources :submitters, only: %i[edit update]
|
||||||
resources :console_redirect, only: %i[index]
|
resources :console_redirect, only: %i[index]
|
||||||
@@ -108,7 +109,7 @@ Rails.application.routes.draw do
|
|||||||
resource :form, only: %i[show], controller: 'templates_form_preview'
|
resource :form, only: %i[show], controller: 'templates_form_preview'
|
||||||
resource :code_modal, only: %i[show], controller: 'templates_code_modal'
|
resource :code_modal, only: %i[show], controller: 'templates_code_modal'
|
||||||
resource :preferences, only: %i[show create destroy], controller: 'templates_preferences'
|
resource :preferences, only: %i[show create destroy], controller: 'templates_preferences'
|
||||||
resources :versions, only: %i[index show], controller: 'templates_versions'
|
resources :versions, only: %i[index show create], controller: 'templates_versions'
|
||||||
resource :share_link, only: %i[show create], controller: 'templates_share_link'
|
resource :share_link, only: %i[show create], controller: 'templates_share_link'
|
||||||
resource :share_link_qr, only: %i[show], controller: 'templates_share_link_qr'
|
resource :share_link_qr, only: %i[show], controller: 'templates_share_link_qr'
|
||||||
resources :recipients, only: %i[create], controller: 'templates_recipients'
|
resources :recipients, only: %i[create], controller: 'templates_recipients'
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ module NumberUtils
|
|||||||
ApplicationController.helpers.number_to_currency(number, locale:, precision: 2, unit: CURRENCY_SYMBOLS[format])
|
ApplicationController.helpers.number_to_currency(number, locale:, precision: 2, unit: CURRENCY_SYMBOLS[format])
|
||||||
elsif locale
|
elsif locale
|
||||||
ApplicationController.helpers.number_with_delimiter(number, locale:)
|
ApplicationController.helpers.number_with_delimiter(number, locale:)
|
||||||
|
elsif format == 'percent'
|
||||||
|
"#{number}%"
|
||||||
|
elsif format == 'percent_space'
|
||||||
|
"#{number.to_s.tr('.', ',')} %"
|
||||||
else
|
else
|
||||||
number
|
number
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ module SendWebhookRequest
|
|||||||
data: data
|
data: data
|
||||||
}.to_json
|
}.to_json
|
||||||
|
|
||||||
req.headers['X-Docuseal-Signature'] = WebhookUrls::Signatures.sign(webhook_url.hmac_secret, body: req.body)
|
if req.headers['X-Docuseal-Signature'].blank?
|
||||||
|
req.headers['X-Docuseal-Signature'] = WebhookUrls::Signatures.sign(webhook_url.hmac_secret, body: req.body)
|
||||||
|
end
|
||||||
|
|
||||||
req.options.read_timeout = 15
|
req.options.read_timeout = 15
|
||||||
req.options.open_timeout = 8
|
req.options.open_timeout = 8
|
||||||
|
|||||||
@@ -374,7 +374,13 @@ module Submissions
|
|||||||
scale = [600.0 / image.width, 600.0 / image.height].min
|
scale = [600.0 / image.width, 600.0 / image.height].min
|
||||||
|
|
||||||
resized_image = image.resize([scale, 1].min)
|
resized_image = image.resize([scale, 1].min)
|
||||||
io = StringIO.new(resized_image.write_to_buffer('.png'))
|
|
||||||
|
io =
|
||||||
|
if field['type'] == 'image' && !resized_image.has_alpha?
|
||||||
|
StringIO.new(resized_image.colourspace(:srgb).write_to_buffer('.jpg', strip: true))
|
||||||
|
else
|
||||||
|
StringIO.new(resized_image.write_to_buffer('.png'))
|
||||||
|
end
|
||||||
|
|
||||||
width = field['type'] == 'initials' ? 50 : 200
|
width = field['type'] == 'initials' ? 50 : 200
|
||||||
height = resized_image.height * (width.to_f / resized_image.width)
|
height = resized_image.height * (width.to_f / resized_image.width)
|
||||||
|
|||||||
@@ -462,7 +462,14 @@ module Submissions
|
|||||||
scale = [(area['w'] * width) / image.width,
|
scale = [(area['w'] * width) / image.width,
|
||||||
(area['h'] * height) / image.height].min
|
(area['h'] * height) / image.height].min
|
||||||
|
|
||||||
io = StringIO.new(image.resize([scale * 4, 1].select(&:positive?).min).write_to_buffer('.png'))
|
resized_image = image.resize([scale * 4, 1].select(&:positive?).min)
|
||||||
|
|
||||||
|
io =
|
||||||
|
if field_type == 'image' && !resized_image.has_alpha?
|
||||||
|
StringIO.new(resized_image.colourspace(:srgb).write_to_buffer('.jpg', strip: true))
|
||||||
|
else
|
||||||
|
StringIO.new(resized_image.write_to_buffer('.png'))
|
||||||
|
end
|
||||||
|
|
||||||
canvas.image(
|
canvas.image(
|
||||||
io,
|
io,
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
|
|
||||||
# Cell step
|
# Cell step
|
||||||
fill_in 'Cell code', with: '123'
|
fill_in 'Cell code', with: '123'
|
||||||
click_on 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_button('Download')
|
expect(page).to have_button('Download')
|
||||||
expect(page).to have_content('Document has been signed!')
|
expect(page).to have_content('Document has been signed!')
|
||||||
@@ -220,7 +220,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
|
|
||||||
# Cell step
|
# Cell step
|
||||||
fill_in 'Cell code', with: '123'
|
fill_in 'Cell code', with: '123'
|
||||||
click_on 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_button('Download')
|
expect(page).to have_button('Download')
|
||||||
expect(page).to have_content('Document has been signed!')
|
expect(page).to have_content('Document has been signed!')
|
||||||
@@ -308,7 +308,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
click_button 'next'
|
click_button 'next'
|
||||||
|
|
||||||
fill_in 'Cell code', with: '123'
|
fill_in 'Cell code', with: '123'
|
||||||
click_on 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_button('Download')
|
expect(page).to have_button('Download')
|
||||||
expect(page).to have_content('Document has been signed!')
|
expect(page).to have_content('Document has been signed!')
|
||||||
@@ -398,7 +398,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
|
|
||||||
# Cell step
|
# Cell step
|
||||||
fill_in 'Cell code', with: '123'
|
fill_in 'Cell code', with: '123'
|
||||||
click_on 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_button('Download')
|
expect(page).to have_button('Download')
|
||||||
expect(page).to have_content('Document has been signed!')
|
expect(page).to have_content('Document has been signed!')
|
||||||
@@ -443,7 +443,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
expect(input[:placeholder]).to eq 'Type here...'
|
expect(input[:placeholder]).to eq 'Type here...'
|
||||||
|
|
||||||
fill_in 'First Name', with: 'Mary'
|
fill_in 'First Name', with: 'Mary'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -468,7 +468,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
expect(page).not_to have_selector(:css, 'div[data-tip="Toggle Multiline Text"]')
|
expect(page).not_to have_selector(:css, 'div[data-tip="Toggle Multiline Text"]')
|
||||||
|
|
||||||
fill_in 'First Name', with: 'Very long text'
|
fill_in 'First Name', with: 'Very long text'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -494,7 +494,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
expect(input[:required]).to be_truthy
|
expect(input[:required]).to be_truthy
|
||||||
|
|
||||||
fill_in 'Birthday', with: I18n.l(25.years.ago, format: '%Y-%m-%d')
|
fill_in 'Birthday', with: I18n.l(25.years.ago, format: '%Y-%m-%d')
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -517,7 +517,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
|
|
||||||
expect(input[:value]).to eq Time.zone.now.strftime('%Y-%m-%d')
|
expect(input[:value]).to eq Time.zone.now.strftime('%Y-%m-%d')
|
||||||
|
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -539,7 +539,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
visit submit_form_path(slug: submitter.slug)
|
visit submit_form_path(slug: submitter.slug)
|
||||||
|
|
||||||
check 'Do you agree?'
|
check 'Do you agree?'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -563,7 +563,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
%w[Girl Boy].map { |v| find_field(v) }.each { |input| expect(input[:required]).to be_truthy }
|
%w[Girl Boy].map { |v| find_field(v) }.each { |input| expect(input[:required]).to be_truthy }
|
||||||
|
|
||||||
choose 'Boy'
|
choose 'Boy'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -670,7 +670,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
expect(input[:placeholder]).to eq 'Type here...'
|
expect(input[:placeholder]).to eq 'Type here...'
|
||||||
|
|
||||||
fill_in 'House number', with: '4'
|
fill_in 'House number', with: '4'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -692,7 +692,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
visit submit_form_path(slug: submitter.slug)
|
visit submit_form_path(slug: submitter.slug)
|
||||||
|
|
||||||
%w[Red Green].each { |color| check color }
|
%w[Red Green].each { |color| check color }
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -715,7 +715,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
|
|
||||||
select 'Female', from: 'Gender'
|
select 'Female', from: 'Gender'
|
||||||
|
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -738,7 +738,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
|
|
||||||
find('#expand_form_button').click
|
find('#expand_form_button').click
|
||||||
fill_in 'initials_text_input', with: 'John Doe'
|
fill_in 'initials_text_input', with: 'John Doe'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Document has been signed!')
|
expect(page).to have_content('Document has been signed!')
|
||||||
|
|
||||||
@@ -754,7 +754,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
find('#expand_form_button').click
|
find('#expand_form_button').click
|
||||||
click_button 'Draw'
|
click_button 'Draw'
|
||||||
draw_canvas
|
draw_canvas
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Document has been signed!')
|
expect(page).to have_content('Document has been signed!')
|
||||||
|
|
||||||
@@ -773,7 +773,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
|
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
|
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Document has been signed!')
|
expect(page).to have_content('Document has been signed!')
|
||||||
|
|
||||||
@@ -797,7 +797,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
find('#expand_form_button').click
|
find('#expand_form_button').click
|
||||||
find('#dropzone').click
|
find('#dropzone').click
|
||||||
find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-image.png'))
|
find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-image.png'))
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -821,7 +821,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
find('#expand_form_button').click
|
find('#expand_form_button').click
|
||||||
find('#dropzone').click
|
find('#dropzone').click
|
||||||
find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-document.pdf'))
|
find('input[type="file"]', visible: false).attach_file(Rails.root.join('spec/fixtures/sample-document.pdf'))
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -848,7 +848,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
expect(input[:placeholder]).to eq 'Type here...'
|
expect(input[:placeholder]).to eq 'Type here...'
|
||||||
|
|
||||||
fill_in 'Cell code', with: '456'
|
fill_in 'Cell code', with: '456'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -967,7 +967,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
click_button 'next'
|
click_button 'next'
|
||||||
|
|
||||||
fill_in 'Comment', with: 'This is a comment'
|
fill_in 'Comment', with: 'This is a comment'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -992,7 +992,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
click_button 'next'
|
click_button 'next'
|
||||||
|
|
||||||
fill_in 'Comment', with: 'This is a comment'
|
fill_in 'Comment', with: 'This is a comment'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -1015,7 +1015,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
click_button 'next'
|
click_button 'next'
|
||||||
|
|
||||||
fill_in 'Phone (optional)', with: ''
|
fill_in 'Phone (optional)', with: ''
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -1038,7 +1038,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
click_button 'next'
|
click_button 'next'
|
||||||
|
|
||||||
fill_in 'Phone (optional)', with: '+1 (773) 229-8825'
|
fill_in 'Phone (optional)', with: '+1 (773) 229-8825'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -1068,7 +1068,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
visit submit_form_path(slug: first_submitter.slug)
|
visit submit_form_path(slug: first_submitter.slug)
|
||||||
|
|
||||||
fill_in 'First Name', with: 'Jahn'
|
fill_in 'First Name', with: 'Jahn'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
visit submit_form_path(slug: second_submitter.slug)
|
visit submit_form_path(slug: second_submitter.slug)
|
||||||
|
|
||||||
@@ -1229,7 +1229,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
click_button 'Submit'
|
click_button 'Submit'
|
||||||
|
|
||||||
fill_in 'First Name', with: 'Mary'
|
fill_in 'First Name', with: 'Mary'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -1264,7 +1264,7 @@ RSpec.describe 'Signing Form' do
|
|||||||
click_button 'Submit'
|
click_button 'Submit'
|
||||||
|
|
||||||
fill_in 'First Name', with: 'Mary'
|
fill_in 'First Name', with: 'Mary'
|
||||||
click_button 'Complete'
|
find('#submit_form_button').click
|
||||||
|
|
||||||
expect(page).to have_content('Form has been completed!')
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
@@ -1274,4 +1274,47 @@ RSpec.describe 'Signing Form' do
|
|||||||
expect(field_value(submitter, 'First Name')).to eq 'Mary'
|
expect(field_value(submitter, 'First Name')).to eq 'Mary'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when header complete button' do
|
||||||
|
let(:template) { create(:template, account:, author:, only_field_types: %w[text date]) }
|
||||||
|
let(:submission) { create(:submission, :with_submitters, template:) }
|
||||||
|
let(:submitter) { submission.submitters.first }
|
||||||
|
|
||||||
|
before do
|
||||||
|
template.fields.second['required'] = false
|
||||||
|
template.save!
|
||||||
|
submission.update(template_fields: template.fields)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows header complete button and hides download after filling required fields' do
|
||||||
|
visit submit_form_path(slug: submitter.slug)
|
||||||
|
|
||||||
|
expect(page).to have_button('Decline')
|
||||||
|
expect(page).to have_css('download-button[aria-label="Download"]', visible: true)
|
||||||
|
expect(page).not_to have_css('#complete_button_container button')
|
||||||
|
|
||||||
|
fill_in 'First Name', with: 'John Doe'
|
||||||
|
click_button 'next'
|
||||||
|
|
||||||
|
expect(page).to have_css('#complete_button_container button')
|
||||||
|
expect(page).to have_button('Decline')
|
||||||
|
expect(page).to have_css('download-button[aria-label="Download"]', visible: :hidden)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'completes the form via header complete button skipping optional fields' do
|
||||||
|
visit submit_form_path(slug: submitter.slug)
|
||||||
|
|
||||||
|
fill_in 'First Name', with: 'John Doe'
|
||||||
|
click_button 'next'
|
||||||
|
|
||||||
|
find('#complete_button_container button').click
|
||||||
|
|
||||||
|
expect(page).to have_content('Form has been completed!')
|
||||||
|
|
||||||
|
submitter.reload
|
||||||
|
|
||||||
|
expect(submitter.completed_at).to be_present
|
||||||
|
expect(field_value(submitter, 'First Name')).to eq 'John Doe'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user