mirror of
https://github.com/docusealco/docuseal
synced 2026-11-04 14:42:32 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd18c51384 | ||
|
|
c2014a1549 | ||
|
|
46edc7dc37 | ||
|
|
d62d83ef8e | ||
|
|
79350c8fba | ||
|
|
6702dd52b6 | ||
|
|
c8b74a2c43 | ||
|
|
1746920eb5 | ||
|
|
bacbc4309c | ||
|
|
4429d742b3 | ||
|
|
38b5eccb65 | ||
|
|
d8126c4a47 | ||
|
|
b1c31672ee | ||
|
|
975f3a95fe | ||
|
|
e3bed5ae67 | ||
|
|
4737b103c0 | ||
|
|
c5178b96d3 | ||
|
|
39a2159196 | ||
|
|
5724159b7b | ||
|
|
05b7cc9fa6 | ||
|
|
18b13b5b1e | ||
|
|
d25555b9b0 | ||
|
|
eec266ee83 | ||
|
|
75683631f0 | ||
|
|
36c64d1de4 | ||
|
|
2552b24f21 | ||
|
|
e6ca6dfd85 | ||
|
|
fa2d86b20a | ||
|
|
8e212e4586 | ||
|
|
a59c18f04b | ||
|
|
1ab0f1c90c | ||
|
|
9beaaa0851 | ||
|
|
b86aac86d1 | ||
|
|
c2eb94b571 | ||
|
|
a377e45a63 | ||
|
|
58574abc6b | ||
|
|
cbae888971 | ||
|
|
944e1f31db | ||
|
|
711b3b3190 | ||
|
|
e7abadcefb | ||
|
|
18d60f5522 | ||
|
|
6d5c6e086d | ||
|
|
5a48ab0360 | ||
|
|
599785b6d1 | ||
|
|
f2fd5fb82b | ||
|
|
f2782bd84e | ||
|
|
e52a721fc9 | ||
|
|
b035123ff9 | ||
|
|
ca8de23082 | ||
|
|
f514654c40 | ||
|
|
99bc528a6c | ||
|
|
f3c77d0177 | ||
|
|
db2b5f35bd | ||
|
|
5728381725 | ||
|
|
a7affb1a49 | ||
|
|
21bf5ed9f7 | ||
|
|
8ddd4ee916 | ||
|
|
0e2fd8ee4f | ||
|
|
27901063ed | ||
|
|
ce31ebde1e |
No files matched your search
+2
-2
@@ -60,10 +60,10 @@ RSpec/NestedGroups:
|
|||||||
Max: 6
|
Max: 6
|
||||||
|
|
||||||
RSpec/MultipleExpectations:
|
RSpec/MultipleExpectations:
|
||||||
Max: 20
|
Max: 25
|
||||||
|
|
||||||
RSpec/ExampleLength:
|
RSpec/ExampleLength:
|
||||||
Max: 40
|
Max: 50
|
||||||
|
|
||||||
RSpec/MultipleMemoizedHelpers:
|
RSpec/MultipleMemoizedHelpers:
|
||||||
Max: 9
|
Max: 9
|
||||||
|
|||||||
+7
-7
@@ -298,7 +298,7 @@ GEM
|
|||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.22.0)
|
loofah (2.23.1)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.12.0)
|
nokogiri (>= 1.12.0)
|
||||||
mail (2.8.1)
|
mail (2.8.1)
|
||||||
@@ -311,7 +311,7 @@ GEM
|
|||||||
method_source (1.1.0)
|
method_source (1.1.0)
|
||||||
mini_magick (4.13.2)
|
mini_magick (4.13.2)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.7)
|
mini_portile2 (2.8.8)
|
||||||
minitest (5.25.1)
|
minitest (5.25.1)
|
||||||
msgpack (1.7.3)
|
msgpack (1.7.3)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
@@ -330,12 +330,12 @@ GEM
|
|||||||
net-smtp (0.5.0)
|
net-smtp (0.5.0)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.3)
|
nio4r (2.7.3)
|
||||||
nokogiri (1.16.7)
|
nokogiri (1.16.8)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.16.7-aarch64-linux)
|
nokogiri (1.16.8-aarch64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.16.7-x86_64-linux)
|
nokogiri (1.16.8-x86_64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oj (3.16.6)
|
oj (3.16.6)
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
@@ -400,9 +400,9 @@ GEM
|
|||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
minitest
|
minitest
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.6.0)
|
rails-html-sanitizer (1.6.1)
|
||||||
loofah (~> 2.21)
|
loofah (~> 2.21)
|
||||||
nokogiri (~> 1.14)
|
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||||
rails-i18n (7.0.9)
|
rails-i18n (7.0.9)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 6.0.0, < 8)
|
railties (>= 6.0.0, < 8)
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ class AccountConfigsController < ApplicationController
|
|||||||
AccountConfig::FLATTEN_RESULT_PDF_KEY,
|
AccountConfig::FLATTEN_RESULT_PDF_KEY,
|
||||||
AccountConfig::WITH_SIGNATURE_ID,
|
AccountConfig::WITH_SIGNATURE_ID,
|
||||||
AccountConfig::COMBINE_PDF_RESULT_KEY,
|
AccountConfig::COMBINE_PDF_RESULT_KEY,
|
||||||
AccountConfig::REQUIRE_SIGNING_REASON_KEY
|
AccountConfig::REQUIRE_SIGNING_REASON_KEY,
|
||||||
|
AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
InvalidKey = Class.new(StandardError)
|
InvalidKey = Class.new(StandardError)
|
||||||
|
|||||||
@@ -78,7 +78,9 @@ module Api
|
|||||||
|
|
||||||
submissions.each do |submission|
|
submissions.each do |submission|
|
||||||
submission.submitters.each do |submitter|
|
submission.submitters.each do |submitter|
|
||||||
ProcessSubmitterCompletionJob.perform_async('submitter_id' => submitter.id) if submitter.completed_at?
|
next unless submitter.completed_at?
|
||||||
|
|
||||||
|
ProcessSubmitterCompletionJob.perform_async('submitter_id' => submitter.id, 'send_invitation_email' => false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ module Api
|
|||||||
|
|
||||||
def filter_templates(templates, params)
|
def filter_templates(templates, params)
|
||||||
templates = Templates.search(templates, params[:q])
|
templates = Templates.search(templates, params[:q])
|
||||||
templates = params[:archived] ? templates.archived : templates.active
|
templates = params[:archived].in?(['true', true]) ? templates.archived : templates.active
|
||||||
templates = templates.where(external_id: params[:application_key]) if params[:application_key].present?
|
templates = templates.where(external_id: params[:application_key]) if params[:application_key].present?
|
||||||
templates = templates.where(external_id: params[:external_id]) if params[:external_id].present?
|
templates = templates.where(external_id: params[:external_id]) if params[:external_id].present?
|
||||||
templates = templates.joins(:folder).where(folder: { name: params[:folder] }) if params[:folder].present?
|
templates = templates.joins(:folder).where(folder: { name: params[:folder] }) if params[:folder].present?
|
||||||
@@ -105,7 +105,7 @@ module Api
|
|||||||
:required, :readonly, :default_value,
|
:required, :readonly, :default_value,
|
||||||
:title, :description,
|
:title, :description,
|
||||||
{ preferences: {},
|
{ preferences: {},
|
||||||
conditions: [%i[field_uuid value action]],
|
conditions: [%i[field_uuid value action operation]],
|
||||||
options: [%i[value uuid]],
|
options: [%i[value uuid]],
|
||||||
validation: %i[message pattern],
|
validation: %i[message pattern],
|
||||||
areas: [%i[x y w h cell_w attachment_uuid option_uuid page]] }]]
|
areas: [%i[x y w h cell_w attachment_uuid option_uuid page]] }]]
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
helper_method :button_title,
|
helper_method :button_title,
|
||||||
:current_account,
|
:current_account,
|
||||||
|
:form_link_host,
|
||||||
:svg_icon
|
:svg_icon
|
||||||
|
|
||||||
impersonates :user, with: ->(uuid) { User.find_by(uuid:) }
|
impersonates :user, with: ->(uuid) { User.find_by(uuid:) }
|
||||||
@@ -105,6 +106,10 @@ class ApplicationController < ActionController::Base
|
|||||||
render_to_string(partial: "icons/#{icon_name}", locals: { class: })
|
render_to_string(partial: "icons/#{icon_name}", locals: { class: })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def form_link_host
|
||||||
|
Docuseal.default_url_options[:host]
|
||||||
|
end
|
||||||
|
|
||||||
def maybe_redirect_com
|
def maybe_redirect_com
|
||||||
return if request.domain != 'docuseal.co'
|
return if request.domain != 'docuseal.co'
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ class EsignSettingsController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
prepend_before_action :maybe_redirect_com, only: %i[show]
|
||||||
|
|
||||||
before_action :load_encrypted_config
|
before_action :load_encrypted_config
|
||||||
authorize_resource :encrypted_config, parent: false, only: %i[new create]
|
authorize_resource :encrypted_config, parent: false, only: %i[new create]
|
||||||
authorize_resource :encrypted_config, only: %i[update destroy show]
|
authorize_resource :encrypted_config, only: %i[update destroy show]
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ class PersonalizationSettingsController < ApplicationController
|
|||||||
AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY,
|
AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY,
|
||||||
AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY,
|
AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY,
|
||||||
AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY,
|
AccountConfig::SUBMITTER_COMPLETED_EMAIL_KEY,
|
||||||
AccountConfig::FORM_COMPLETED_MESSAGE_KEY
|
AccountConfig::FORM_COMPLETED_MESSAGE_KEY,
|
||||||
|
*(Docuseal.multitenant? ? [] : [AccountConfig::POLICY_LINKS_KEY])
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
InvalidKey = Class.new(StandardError)
|
InvalidKey = Class.new(StandardError)
|
||||||
|
|||||||
@@ -8,8 +8,18 @@ class SubmissionsArchivedController < ApplicationController
|
|||||||
@submissions = @submissions.where.not(archived_at: nil)
|
@submissions = @submissions.where.not(archived_at: nil)
|
||||||
.or(@submissions.where.not(templates: { archived_at: nil }))
|
.or(@submissions.where.not(templates: { archived_at: nil }))
|
||||||
.preload(:created_by_user, template: :author)
|
.preload(:created_by_user, template: :author)
|
||||||
@submissions = Submissions.search(@submissions, params[:q], search_template: true)
|
|
||||||
|
|
||||||
@pagy, @submissions = pagy(@submissions.preload(:submitters).order(id: :desc))
|
@submissions = @submissions.preload(:template_accesses) unless current_user.role.in?(%w[admin superadmin])
|
||||||
|
|
||||||
|
@submissions = Submissions.search(@submissions, params[:q], search_template: true)
|
||||||
|
@submissions = Submissions::Filter.call(@submissions, current_user, params)
|
||||||
|
|
||||||
|
@submissions = if params[:completed_at_from].present? || params[:completed_at_to].present?
|
||||||
|
@submissions.order(Submitter.arel_table[:completed_at].maximum.desc)
|
||||||
|
else
|
||||||
|
@submissions.order(id: :desc)
|
||||||
|
end
|
||||||
|
|
||||||
|
@pagy, @submissions = pagy(@submissions.preload(submitters: :start_form_submission_events))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -6,6 +6,8 @@ class SubmissionsController < ApplicationController
|
|||||||
|
|
||||||
load_and_authorize_resource :submission, only: %i[show destroy]
|
load_and_authorize_resource :submission, only: %i[show destroy]
|
||||||
|
|
||||||
|
prepend_before_action :maybe_redirect_com, only: %i[show]
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@submission = Submissions.preload_with_pages(@submission)
|
@submission = Submissions.preload_with_pages(@submission)
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,20 @@ class SubmissionsDashboardController < ApplicationController
|
|||||||
.where(templates: { archived_at: nil })
|
.where(templates: { archived_at: nil })
|
||||||
.preload(:created_by_user, template: :author)
|
.preload(:created_by_user, template: :author)
|
||||||
|
|
||||||
|
@submissions = @submissions.preload(:template_accesses) unless current_user.role.in?(%w[admin superadmin])
|
||||||
|
|
||||||
@submissions = Submissions.search(@submissions, params[:q], search_template: true)
|
@submissions = Submissions.search(@submissions, params[:q], search_template: true)
|
||||||
|
@submissions = Submissions::Filter.call(@submissions, current_user, params)
|
||||||
|
|
||||||
@submissions = @submissions.pending if params[:status] == 'pending'
|
@submissions = @submissions.pending if params[:status] == 'pending'
|
||||||
@submissions = @submissions.completed if params[:status] == 'completed'
|
@submissions = @submissions.completed if params[:status] == 'completed'
|
||||||
|
|
||||||
@pagy, @submissions = pagy(@submissions.preload(submitters: :start_form_submission_events).order(id: :desc))
|
@submissions = if params[:completed_at_from].present? || params[:completed_at_to].present?
|
||||||
|
@submissions.order(Submitter.arel_table[:completed_at].maximum.desc)
|
||||||
|
else
|
||||||
|
@submissions.order(id: :desc)
|
||||||
|
end
|
||||||
|
|
||||||
|
@pagy, @submissions = pagy(@submissions.preload(submitters: :start_form_submission_events))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -53,8 +53,15 @@ class SubmissionsDownloadController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def build_urls(submitter)
|
def build_urls(submitter)
|
||||||
|
filename_format = AccountConfig.find_or_initialize_by(account_id: submitter.account_id,
|
||||||
|
key: AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY)&.value
|
||||||
|
|
||||||
Submitters.select_attachments_for_download(submitter).map do |attachment|
|
Submitters.select_attachments_for_download(submitter).map do |attachment|
|
||||||
ActiveStorage::Blob.proxy_url(attachment.blob, expires_at: FILES_TTL.from_now.to_i)
|
ActiveStorage::Blob.proxy_url(
|
||||||
|
attachment.blob,
|
||||||
|
expires_at: FILES_TTL.from_now.to_i,
|
||||||
|
filename: Submitters.build_document_filename(submitter, attachment.blob, filename_format)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -65,6 +72,13 @@ class SubmissionsDownloadController < ApplicationController
|
|||||||
attachment = submitter.submission.combined_document_attachment
|
attachment = submitter.submission.combined_document_attachment
|
||||||
attachment ||= Submissions::GenerateCombinedAttachment.call(submitter)
|
attachment ||= Submissions::GenerateCombinedAttachment.call(submitter)
|
||||||
|
|
||||||
ActiveStorage::Blob.proxy_url(attachment.blob, expires_at: FILES_TTL.from_now.to_i)
|
filename_format = AccountConfig.find_or_initialize_by(account_id: submitter.account_id,
|
||||||
|
key: AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY)&.value
|
||||||
|
|
||||||
|
ActiveStorage::Blob.proxy_url(
|
||||||
|
attachment.blob,
|
||||||
|
expires_at: FILES_TTL.from_now.to_i,
|
||||||
|
filename: Submitters.build_document_filename(submitter, attachment.blob, filename_format)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SubmissionsFiltersController < ApplicationController
|
||||||
|
ALLOWED_NAMES = %w[
|
||||||
|
author
|
||||||
|
completed_at
|
||||||
|
created_at
|
||||||
|
].freeze
|
||||||
|
|
||||||
|
skip_authorization_check
|
||||||
|
|
||||||
|
def show
|
||||||
|
return head :not_found unless ALLOWED_NAMES.include?(params[:name])
|
||||||
|
|
||||||
|
render params[:name]
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,7 +4,7 @@ class SubmissionsPreviewController < ApplicationController
|
|||||||
skip_before_action :authenticate_user!
|
skip_before_action :authenticate_user!
|
||||||
skip_authorization_check
|
skip_authorization_check
|
||||||
|
|
||||||
before_action :maybe_redirect_com, only: %i[show completed]
|
prepend_before_action :maybe_redirect_com, only: %i[show completed]
|
||||||
|
|
||||||
TTL = 40.minutes
|
TTL = 40.minutes
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ class SubmissionsPreviewController < ApplicationController
|
|||||||
|
|
||||||
@submission ||= Submission.find_by!(slug: params[:slug])
|
@submission ||= Submission.find_by!(slug: params[:slug])
|
||||||
|
|
||||||
if !@submission.submitters.all?(&:completed_at?) && current_user.blank?
|
if @submission.account.archived_at? || (!@submission.submitters.all?(&:completed_at?) && current_user.blank?)
|
||||||
raise ActionController::RoutingError, I18n.t('not_found')
|
raise ActionController::RoutingError, I18n.t('not_found')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ class SubmitFormController < ApplicationController
|
|||||||
skip_before_action :authenticate_user!
|
skip_before_action :authenticate_user!
|
||||||
skip_authorization_check
|
skip_authorization_check
|
||||||
|
|
||||||
before_action :maybe_redirect_com, only: %i[show completed]
|
|
||||||
|
|
||||||
CONFIG_KEYS = [].freeze
|
CONFIG_KEYS = [].freeze
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@@ -17,7 +15,9 @@ class SubmitFormController < ApplicationController
|
|||||||
submission = @submitter.submission
|
submission = @submitter.submission
|
||||||
|
|
||||||
return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at?
|
return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at?
|
||||||
return render :archived if submission.template.archived_at? || submission.archived_at?
|
return render :archived if submission.template.archived_at? ||
|
||||||
|
submission.archived_at? ||
|
||||||
|
@submitter.account.archived_at?
|
||||||
return render :expired if submission.expired?
|
return render :expired if submission.expired?
|
||||||
return render :declined if @submitter.declined_at?
|
return render :declined if @submitter.declined_at?
|
||||||
return render :awaiting if submission.template.preferences['submitters_order'] == 'preserved' &&
|
return render :awaiting if submission.template.preferences['submitters_order'] == 'preserved' &&
|
||||||
@@ -27,8 +27,7 @@ class SubmitFormController < ApplicationController
|
|||||||
|
|
||||||
Submitters::MaybeUpdateDefaultValues.call(@submitter, current_user)
|
Submitters::MaybeUpdateDefaultValues.call(@submitter, current_user)
|
||||||
|
|
||||||
@attachments_index = ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments)
|
@attachments_index = build_attachments_index(submission)
|
||||||
.preload(:blob).index_by(&:uuid)
|
|
||||||
|
|
||||||
@form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)
|
@form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)
|
||||||
|
|
||||||
@@ -80,4 +79,11 @@ class SubmitFormController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def success; end
|
def success; end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def build_attachments_index(submission)
|
||||||
|
ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments)
|
||||||
|
.preload(:blob).index_by(&:uuid)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -9,7 +9,8 @@ class SubmittersAutocompleteController < ApplicationController
|
|||||||
def index
|
def index
|
||||||
submitters = search_submitters(@submitters)
|
submitters = search_submitters(@submitters)
|
||||||
|
|
||||||
values = submitters.limit(LIMIT).group(SELECT_COLUMNS.join(', ')).pluck(SELECT_COLUMNS.join(', '))
|
arel_columns = SELECT_COLUMNS.map { |col| Submitter.arel_table[col] }
|
||||||
|
values = submitters.limit(LIMIT).group(arel_columns).pluck(arel_columns)
|
||||||
|
|
||||||
attrs = values.map { |row| SELECT_COLUMNS.zip(row).to_h }
|
attrs = values.map { |row| SELECT_COLUMNS.zip(row).to_h }
|
||||||
attrs = attrs.uniq { |e| e[params[:field]] } if params[:field].present?
|
attrs = attrs.uniq { |e| e[params[:field]] } if params[:field].present?
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class SubmittersSendEmailController < ApplicationController
|
|||||||
def create
|
def create
|
||||||
if Docuseal.multitenant? && SubmissionEvent.exists?(submitter: @submitter,
|
if Docuseal.multitenant? && SubmissionEvent.exists?(submitter: @submitter,
|
||||||
event_type: 'send_email',
|
event_type: 'send_email',
|
||||||
created_at: 24.hours.ago..Time.current)
|
created_at: 10.hours.ago..Time.current)
|
||||||
Rollbar.warning("Already sent: #{@submitter.id}") if defined?(Rollbar)
|
Rollbar.warning("Already sent: #{@submitter.id}") if defined?(Rollbar)
|
||||||
|
|
||||||
return redirect_back(fallback_location: submission_path(@submitter.submission),
|
return redirect_back(fallback_location: submission_path(@submitter.submission),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class TemplateFoldersController < ApplicationController
|
|||||||
load_and_authorize_resource :template_folder
|
load_and_authorize_resource :template_folder
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@templates = @template_folder.templates.active.preload(:author).order(id: :desc)
|
@templates = @template_folder.templates.active.preload(:author, :template_accesses).order(id: :desc)
|
||||||
@templates = Templates.search(@templates, params[:q])
|
@templates = Templates.search(@templates, params[:q])
|
||||||
|
|
||||||
@pagy, @templates = pagy(@templates, limit: 12)
|
@pagy, @templates = pagy(@templates, limit: 12)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class TemplatesArchivedController < ApplicationController
|
|||||||
load_and_authorize_resource :template, parent: false
|
load_and_authorize_resource :template, parent: false
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@templates = @templates.where.not(archived_at: nil).preload(:author, :folder).order(id: :desc)
|
@templates = @templates.where.not(archived_at: nil).preload(:author, :folder, :template_accesses).order(id: :desc)
|
||||||
@templates = Templates.search(@templates, params[:q])
|
@templates = Templates.search(@templates, params[:q])
|
||||||
|
|
||||||
@pagy, @templates = pagy(@templates, limit: 12)
|
@pagy, @templates = pagy(@templates, limit: 12)
|
||||||
|
|||||||
@@ -7,8 +7,15 @@ class TemplatesArchivedSubmissionsController < ApplicationController
|
|||||||
def index
|
def index
|
||||||
@submissions = @submissions.where.not(archived_at: nil)
|
@submissions = @submissions.where.not(archived_at: nil)
|
||||||
@submissions = Submissions.search(@submissions, params[:q], search_values: true)
|
@submissions = Submissions.search(@submissions, params[:q], search_values: true)
|
||||||
|
@submissions = Submissions::Filter.call(@submissions, current_user, params)
|
||||||
|
|
||||||
@pagy, @submissions = pagy(@submissions.preload(:submitters).order(id: :desc))
|
@submissions = if params[:completed_at_from].present? || params[:completed_at_to].present?
|
||||||
|
@submissions.order(Submitter.arel_table[:completed_at].maximum.desc)
|
||||||
|
else
|
||||||
|
@submissions.order(id: :desc)
|
||||||
|
end
|
||||||
|
|
||||||
|
@pagy, @submissions = pagy(@submissions.preload(submitters: :start_form_submission_events))
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
redirect_to root_path
|
redirect_to root_path
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,13 +9,22 @@ class TemplatesController < ApplicationController
|
|||||||
submissions = @template.submissions.accessible_by(current_ability)
|
submissions = @template.submissions.accessible_by(current_ability)
|
||||||
submissions = submissions.active if @template.archived_at.blank?
|
submissions = submissions.active if @template.archived_at.blank?
|
||||||
submissions = Submissions.search(submissions, params[:q], search_values: true)
|
submissions = Submissions.search(submissions, params[:q], search_values: true)
|
||||||
|
submissions = Submissions::Filter.call(submissions, current_user, params)
|
||||||
|
|
||||||
@base_submissions = submissions
|
@base_submissions = submissions
|
||||||
|
|
||||||
submissions = submissions.pending if params[:status] == 'pending'
|
submissions = submissions.pending if params[:status] == 'pending'
|
||||||
submissions = submissions.completed if params[:status] == 'completed'
|
submissions = submissions.completed if params[:status] == 'completed'
|
||||||
|
|
||||||
@pagy, @submissions = pagy(submissions.preload(submitters: :start_form_submission_events).order(id: :desc))
|
submissions = if params[:completed_at_from].present? || params[:completed_at_to].present?
|
||||||
|
submissions.order(Submitter.arel_table[:completed_at].maximum.desc)
|
||||||
|
else
|
||||||
|
submissions.order(id: :desc)
|
||||||
|
end
|
||||||
|
|
||||||
|
submissions = submissions.preload(:template_accesses) unless current_user.role.in?(%w[admin superadmin])
|
||||||
|
|
||||||
|
@pagy, @submissions = pagy(submissions.preload(submitters: :start_form_submission_events))
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
redirect_to root_path
|
redirect_to root_path
|
||||||
end
|
end
|
||||||
@@ -102,13 +111,13 @@ class TemplatesController < ApplicationController
|
|||||||
def template_params
|
def template_params
|
||||||
params.require(:template).permit(
|
params.require(:template).permit(
|
||||||
:name,
|
:name,
|
||||||
{ schema: [%i[attachment_uuid name]],
|
{ schema: [[:attachment_uuid, :name, { conditions: [%i[field_uuid value action operation]] }]],
|
||||||
submitters: [%i[name uuid is_requester linked_to_uuid invite_by_uuid email]],
|
submitters: [%i[name uuid is_requester linked_to_uuid invite_by_uuid email]],
|
||||||
fields: [[:uuid, :submitter_uuid, :name, :type,
|
fields: [[:uuid, :submitter_uuid, :name, :type,
|
||||||
:required, :readonly, :default_value,
|
:required, :readonly, :default_value,
|
||||||
:title, :description,
|
:title, :description,
|
||||||
{ preferences: {},
|
{ preferences: {},
|
||||||
conditions: [%i[field_uuid value action]],
|
conditions: [%i[field_uuid value action operation]],
|
||||||
options: [%i[value uuid]],
|
options: [%i[value uuid]],
|
||||||
validation: %i[message pattern],
|
validation: %i[message pattern],
|
||||||
areas: [%i[x y w h cell_w attachment_uuid option_uuid page]] }]] }
|
areas: [%i[x y w h cell_w attachment_uuid option_uuid page]] }]] }
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class TemplatesDashboardController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def filter_templates(templates)
|
def filter_templates(templates)
|
||||||
rel = templates.active.preload(:author).order(id: :desc)
|
rel = templates.active.preload(:author, :template_accesses).order(id: :desc)
|
||||||
|
|
||||||
if params[:q].blank?
|
if params[:q].blank?
|
||||||
if Docuseal.multitenant? && !current_account.testing?
|
if Docuseal.multitenant? && !current_account.testing?
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class TemplatesPreferencesController < ApplicationController
|
|||||||
preferences: %i[bcc_completed request_email_subject request_email_body
|
preferences: %i[bcc_completed request_email_subject request_email_body
|
||||||
documents_copy_email_subject documents_copy_email_body
|
documents_copy_email_subject documents_copy_email_body
|
||||||
documents_copy_email_enabled documents_copy_email_attach_audit
|
documents_copy_email_enabled documents_copy_email_attach_audit
|
||||||
|
documents_copy_email_attach_documents
|
||||||
completed_notification_email_attach_documents
|
completed_notification_email_attach_documents
|
||||||
completed_redirect_url
|
completed_redirect_url
|
||||||
submitters_order
|
submitters_order
|
||||||
|
|||||||
@@ -55,11 +55,12 @@ class TemplatesUploadsController < ApplicationController
|
|||||||
tempfile.write(DownloadUtils.call(params[:url]).body)
|
tempfile.write(DownloadUtils.call(params[:url]).body)
|
||||||
tempfile.rewind
|
tempfile.rewind
|
||||||
|
|
||||||
|
filename = URI.decode_www_form_component(params[:filename]) if params[:filename].present?
|
||||||
|
filename ||= File.basename(URI.decode_www_form_component(params[:url]))
|
||||||
|
|
||||||
file = ActionDispatch::Http::UploadedFile.new(
|
file = ActionDispatch::Http::UploadedFile.new(
|
||||||
tempfile:,
|
tempfile:,
|
||||||
filename: File.basename(
|
filename:,
|
||||||
URI.decode_www_form_component(params[:filename].presence || params[:url]), '.*'
|
|
||||||
),
|
|
||||||
type: Marcel::MimeType.for(tempfile)
|
type: Marcel::MimeType.for(tempfile)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ class UsersController < ApplicationController
|
|||||||
@user = existing_user
|
@user = existing_user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@user.role = User::ADMIN_ROLE unless role_valid?(@user.role)
|
||||||
|
|
||||||
if @user.save
|
if @user.save
|
||||||
UserMailer.invitation_email(@user).deliver_later!
|
UserMailer.invitation_email(@user).deliver_later!
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import ToggleAttribute from './elements/toggle_attribute'
|
|||||||
import LinkedInput from './elements/linked_input'
|
import LinkedInput from './elements/linked_input'
|
||||||
import CheckboxGroup from './elements/checkbox_group'
|
import CheckboxGroup from './elements/checkbox_group'
|
||||||
import MaskedInput from './elements/masked_input'
|
import MaskedInput from './elements/masked_input'
|
||||||
|
import SetDateButton from './elements/set_date_button'
|
||||||
|
|
||||||
import * as TurboInstantClick from './lib/turbo_instant_click'
|
import * as TurboInstantClick from './lib/turbo_instant_click'
|
||||||
|
|
||||||
@@ -97,6 +98,7 @@ safeRegisterElement('toggle-attribute', ToggleAttribute)
|
|||||||
safeRegisterElement('linked-input', LinkedInput)
|
safeRegisterElement('linked-input', LinkedInput)
|
||||||
safeRegisterElement('checkbox-group', CheckboxGroup)
|
safeRegisterElement('checkbox-group', CheckboxGroup)
|
||||||
safeRegisterElement('masked-input', MaskedInput)
|
safeRegisterElement('masked-input', MaskedInput)
|
||||||
|
safeRegisterElement('set-date-button', SetDateButton)
|
||||||
|
|
||||||
safeRegisterElement('template-builder', class extends HTMLElement {
|
safeRegisterElement('template-builder', class extends HTMLElement {
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
@@ -111,6 +113,7 @@ safeRegisterElement('template-builder', class extends HTMLElement {
|
|||||||
backgroundColor: '#faf7f5',
|
backgroundColor: '#faf7f5',
|
||||||
locale: this.dataset.locale,
|
locale: this.dataset.locale,
|
||||||
withPhone: this.dataset.withPhone === 'true',
|
withPhone: this.dataset.withPhone === 'true',
|
||||||
|
withVerification: ['true', 'false'].includes(this.dataset.withVerification) ? this.dataset.withVerification === 'true' : null,
|
||||||
withLogo: this.dataset.withLogo !== 'false',
|
withLogo: this.dataset.withLogo !== 'false',
|
||||||
editable: this.dataset.editable !== 'false',
|
editable: this.dataset.editable !== 'false',
|
||||||
authenticityToken: document.querySelector('meta[name="csrf-token"]')?.content,
|
authenticityToken: document.querySelector('meta[name="csrf-token"]')?.content,
|
||||||
|
|||||||
@@ -97,6 +97,23 @@ button[disabled] .enabled {
|
|||||||
bottom: auto;
|
bottom: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tooltip-bottom-start:before {
|
||||||
|
transform: translateX(-31%);
|
||||||
|
top: var(--tooltip-offset);
|
||||||
|
left: 100%;
|
||||||
|
right: auto;
|
||||||
|
bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-bottom-start:after {
|
||||||
|
transform: translateX(-25%);
|
||||||
|
border-color: transparent transparent var(--tooltip-color) transparent;
|
||||||
|
top: var(--tooltip-tail-offset);
|
||||||
|
left: 50%;
|
||||||
|
right: auto;
|
||||||
|
bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.autocomplete {
|
.autocomplete {
|
||||||
background: white;
|
background: white;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export default class extends HTMLElement {
|
||||||
|
connectedCallback () {
|
||||||
|
this.button.addEventListener('click', () => {
|
||||||
|
this.fromInput.value = this.dataset.fromValue || ''
|
||||||
|
this.toInput.value = this.dataset.toValue || ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
get button () {
|
||||||
|
return this.querySelector('button')
|
||||||
|
}
|
||||||
|
|
||||||
|
get fromInput () {
|
||||||
|
return document.getElementById(this.dataset.fromId)
|
||||||
|
}
|
||||||
|
|
||||||
|
get toInput () {
|
||||||
|
return document.getElementById(this.dataset.toId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ safeRegisterElement('submission-form', class extends HTMLElement {
|
|||||||
this.app = createApp(Form, {
|
this.app = createApp(Form, {
|
||||||
submitter: JSON.parse(this.dataset.submitter),
|
submitter: JSON.parse(this.dataset.submitter),
|
||||||
inviteSubmitters: JSON.parse(this.dataset.inviteSubmitters),
|
inviteSubmitters: JSON.parse(this.dataset.inviteSubmitters),
|
||||||
|
schema: JSON.parse(this.dataset.schema),
|
||||||
canSendEmail: this.dataset.canSendEmail === 'true',
|
canSendEmail: this.dataset.canSendEmail === 'true',
|
||||||
previousSignatureValue: this.dataset.previousSignatureValue,
|
previousSignatureValue: this.dataset.previousSignatureValue,
|
||||||
goToLast: this.dataset.goToLast === 'true',
|
goToLast: this.dataset.goToLast === 'true',
|
||||||
|
|||||||
@@ -209,7 +209,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { IconTextSize, IconWritingSign, IconCalendarEvent, IconPhoto, IconCheckbox, IconPaperclip, IconSelect, IconCircleDot, IconChecks, IconCheck, IconColumns3, IconPhoneCheck, IconLetterCaseUpper, IconCreditCard, IconRubberStamp, IconSquareNumber1 } from '@tabler/icons-vue'
|
import { IconTextSize, IconWritingSign, IconCalendarEvent, IconPhoto, IconCheckbox, IconPaperclip, IconSelect, IconCircleDot, IconChecks, IconCheck, IconColumns3, IconPhoneCheck, IconLetterCaseUpper, IconCreditCard, IconRubberStamp, IconSquareNumber1, IconId } from '@tabler/icons-vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FieldArea',
|
name: 'FieldArea',
|
||||||
@@ -311,7 +311,8 @@ export default {
|
|||||||
cells: this.t('cells'),
|
cells: this.t('cells'),
|
||||||
stamp: this.t('stamp'),
|
stamp: this.t('stamp'),
|
||||||
payment: this.t('payment'),
|
payment: this.t('payment'),
|
||||||
phone: this.t('phone')
|
phone: this.t('phone'),
|
||||||
|
verification: this.t('verify_id')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
alignClasses () {
|
alignClasses () {
|
||||||
@@ -340,7 +341,8 @@ export default {
|
|||||||
cells: IconColumns3,
|
cells: IconColumns3,
|
||||||
multiple: IconChecks,
|
multiple: IconChecks,
|
||||||
phone: IconPhoneCheck,
|
phone: IconPhoneCheck,
|
||||||
payment: IconCreditCard
|
payment: IconCreditCard,
|
||||||
|
verification: IconId
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
image () {
|
image () {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
<AppearsOn :field="field" />
|
<AppearsOn :field="field" />
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<input
|
<input
|
||||||
|
:id="field.uuid"
|
||||||
ref="input"
|
ref="input"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
class="base-input !text-2xl text-center w-full"
|
class="base-input !text-2xl text-center w-full"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
id="dropzone"
|
||||||
class="flex h-32 w-full"
|
class="flex h-32 w-full"
|
||||||
@dragover.prevent
|
@dragover.prevent
|
||||||
@drop.prevent="onDropFiles"
|
@drop.prevent="onDropFiles"
|
||||||
|
|||||||
@@ -11,12 +11,13 @@
|
|||||||
:with-label="!isAnonymousChecboxes && showFieldNames"
|
:with-label="!isAnonymousChecboxes && showFieldNames"
|
||||||
:current-step="currentStepFields"
|
:current-step="currentStepFields"
|
||||||
:scroll-padding="scrollPadding"
|
:scroll-padding="scrollPadding"
|
||||||
@focus-step="[saveStep(), currentField.type !== 'checkbox' ? isFormVisible = true : '', goToStep($event, false, true)]"
|
@focus-step="[saveStep(), goToStep($event, false, true), currentField.type !== 'checkbox' ? isFormVisible = true : '']"
|
||||||
/>
|
/>
|
||||||
<FieldAreas
|
<FieldAreas
|
||||||
:steps="readonlyConditionalFields.map((e) => [e])"
|
:steps="readonlyConditionalFields.map((e) => [e])"
|
||||||
:values="readonlyConditionalFields.reduce((acc, f) => { acc[f.uuid] = f.default_value; return acc }, {})"
|
:values="readonlyConditionalFields.reduce((acc, f) => { acc[f.uuid] = (values[f.uuid] || f.default_value); return acc }, {})"
|
||||||
:submitter="submitter"
|
:submitter="submitter"
|
||||||
|
:attachments-index="attachmentsIndex"
|
||||||
:submittable="false"
|
:submittable="false"
|
||||||
/>
|
/>
|
||||||
<FormulaFieldAreas
|
<FormulaFieldAreas
|
||||||
@@ -448,9 +449,22 @@
|
|||||||
@focus="scrollIntoField(currentField)"
|
@focus="scrollIntoField(currentField)"
|
||||||
@submit="!isSubmitting && submitStep()"
|
@submit="!isSubmitting && submitStep()"
|
||||||
/>
|
/>
|
||||||
|
<VerificationStep
|
||||||
|
v-else-if="currentField.type === 'verification'"
|
||||||
|
ref="currentStep"
|
||||||
|
:key="currentField.uuid"
|
||||||
|
:locale="language?.toLowerCase() || browserLanguage"
|
||||||
|
:submitter="submitter"
|
||||||
|
:empty-value-required-step="emptyValueRequiredStep"
|
||||||
|
:field="currentField"
|
||||||
|
:submitter-slug="submitterSlug"
|
||||||
|
:values="values"
|
||||||
|
@focus="scrollIntoField(currentField)"
|
||||||
|
@submit="!isSubmitting && submitStep()"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="currentField.type !== 'payment' || submittedValues[currentField.uuid]"
|
v-if="(currentField.type !== 'payment' && currentField.type !== 'verification') || submittedValues[currentField.uuid]"
|
||||||
:class="currentField.type === 'signature' ? 'mt-2' : 'mt-6 md:mt-8'"
|
:class="currentField.type === 'signature' ? 'mt-2' : 'mt-6 md:mt-8'"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
@@ -537,6 +551,7 @@ import AttachmentStep from './attachment_step'
|
|||||||
import MultiSelectStep from './multi_select_step'
|
import MultiSelectStep from './multi_select_step'
|
||||||
import PhoneStep from './phone_step'
|
import PhoneStep from './phone_step'
|
||||||
import PaymentStep from './payment_step'
|
import PaymentStep from './payment_step'
|
||||||
|
import VerificationStep from './verification_step'
|
||||||
import TextStep from './text_step'
|
import TextStep from './text_step'
|
||||||
import NumberStep from './number_step'
|
import NumberStep from './number_step'
|
||||||
import DateStep from './date_step'
|
import DateStep from './date_step'
|
||||||
@@ -579,6 +594,7 @@ export default {
|
|||||||
IconWritingSign,
|
IconWritingSign,
|
||||||
AttachmentStep,
|
AttachmentStep,
|
||||||
InitialsStep,
|
InitialsStep,
|
||||||
|
VerificationStep,
|
||||||
InviteForm,
|
InviteForm,
|
||||||
MultiSelectStep,
|
MultiSelectStep,
|
||||||
IconInnerShadowTop,
|
IconInnerShadowTop,
|
||||||
@@ -636,6 +652,11 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
schema: {
|
||||||
|
type: Array,
|
||||||
|
required: false,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
attachments: {
|
attachments: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -825,6 +846,21 @@ export default {
|
|||||||
isMobile () {
|
isMobile () {
|
||||||
return /android|iphone|ipad/i.test(navigator.userAgent)
|
return /android|iphone|ipad/i.test(navigator.userAgent)
|
||||||
},
|
},
|
||||||
|
attachmentConditionsIndex () {
|
||||||
|
return this.schema.reduce((acc, item) => {
|
||||||
|
if (item.conditions?.length) {
|
||||||
|
if (item.conditions.every((c) => this.fieldsUuidIndex[c.field_uuid])) {
|
||||||
|
acc[item.attachment_uuid] = this.checkFieldConditions(item)
|
||||||
|
} else {
|
||||||
|
acc[item.attachment_uuid] = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
acc[item.attachment_uuid] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
},
|
||||||
emptyValueRequiredStep () {
|
emptyValueRequiredStep () {
|
||||||
return this.stepFields.find((fields, index) => {
|
return this.stepFields.find((fields, index) => {
|
||||||
return fields.some((f) => {
|
return fields.some((f) => {
|
||||||
@@ -905,13 +941,29 @@ export default {
|
|||||||
return this.currentStepFields[0]
|
return this.currentStepFields[0]
|
||||||
},
|
},
|
||||||
readonlyConditionalFields () {
|
readonlyConditionalFields () {
|
||||||
return this.fields.filter((f) => f.readonly && f.conditions?.length && this.checkFieldConditions(f))
|
return this.fields.filter((f) => f.readonly && f.conditions?.length && this.checkFieldConditions(f) && this.checkFieldDocumentsConditions(f))
|
||||||
},
|
},
|
||||||
stepFields () {
|
stepFields () {
|
||||||
return this.fields.filter((f) => !f.readonly).reduce((acc, f) => {
|
const verificationFields = []
|
||||||
|
|
||||||
|
const sortedFields = this.fields.reduce((acc, f) => {
|
||||||
|
if (f.type === 'verification') {
|
||||||
|
verificationFields.push(f)
|
||||||
|
} else if (!f.readonly) {
|
||||||
|
acc.push(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (verificationFields.length) {
|
||||||
|
sortedFields.push(verificationFields.pop())
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortedFields.reduce((acc, f) => {
|
||||||
const prevStep = acc[acc.length - 1]
|
const prevStep = acc[acc.length - 1]
|
||||||
|
|
||||||
if (this.checkFieldConditions(f)) {
|
if (this.checkFieldConditions(f) && this.checkFieldDocumentsConditions(f)) {
|
||||||
if (f.type === 'checkbox' && Array.isArray(prevStep) && prevStep[0].type === 'checkbox' && !f.description) {
|
if (f.type === 'checkbox' && Array.isArray(prevStep) && prevStep[0].type === 'checkbox' && !f.description) {
|
||||||
prevStep.push(f)
|
prevStep.push(f)
|
||||||
} else {
|
} else {
|
||||||
@@ -944,6 +996,23 @@ export default {
|
|||||||
if (isEmpty(value) && this.currentStep > 0) {
|
if (isEmpty(value) && this.currentStep > 0) {
|
||||||
this.currentStep -= 1
|
this.currentStep -= 1
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
attachmentConditionsIndex: {
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
handler (value) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const root = this.$root.$el.parentNode.getRootNode()
|
||||||
|
|
||||||
|
for (const key in value) {
|
||||||
|
const doc = root.querySelector(`[id="document-${key}"`)
|
||||||
|
|
||||||
|
if (doc) {
|
||||||
|
doc.classList.toggle('hidden', !value[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeUnmount () {
|
beforeUnmount () {
|
||||||
@@ -1025,33 +1094,57 @@ export default {
|
|||||||
onOrientationChange (event) {
|
onOrientationChange (event) {
|
||||||
this.orientation = event.target.type
|
this.orientation = event.target.type
|
||||||
},
|
},
|
||||||
|
checkFieldDocumentsConditions (field) {
|
||||||
|
if (field.areas?.length) {
|
||||||
|
return field.areas.some((area) => {
|
||||||
|
return this.attachmentConditionsIndex[area.attachment_uuid]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
},
|
||||||
checkFieldConditions (field) {
|
checkFieldConditions (field) {
|
||||||
if (field.conditions?.length) {
|
if (field.conditions?.length) {
|
||||||
return field.conditions.reduce((acc, c) => {
|
const result = field.conditions.reduce((acc, cond) => {
|
||||||
const field = this.fieldsUuidIndex[c.field_uuid]
|
if (cond.operation === 'or') {
|
||||||
|
acc.push(acc.pop() || this.checkFieldCondition(cond))
|
||||||
if (['not_empty', 'checked', 'equal', 'contains'].includes(c.action) && field && !this.checkFieldConditions(field)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (['empty', 'unchecked'].includes(c.action)) {
|
|
||||||
return acc && isEmpty(this.values[c.field_uuid])
|
|
||||||
} else if (['not_empty', 'checked'].includes(c.action)) {
|
|
||||||
return acc && !isEmpty(this.values[c.field_uuid])
|
|
||||||
} else if (['equal', 'contains'].includes(c.action) && field) {
|
|
||||||
const option = field.options.find((o) => o.uuid === c.value)
|
|
||||||
const values = [this.values[c.field_uuid]].flat()
|
|
||||||
|
|
||||||
return acc && values.includes(this.optionValue(option, field.options.indexOf(option)))
|
|
||||||
} else if (['not_equal', 'does_not_contain'].includes(c.action) && field) {
|
|
||||||
const option = field.options.find((o) => o.uuid === c.value)
|
|
||||||
const values = [this.values[c.field_uuid]].flat()
|
|
||||||
|
|
||||||
return acc && !values.includes(this.optionValue(option, field.options.indexOf(option)))
|
|
||||||
} else {
|
} else {
|
||||||
return acc
|
acc.push(this.checkFieldCondition(cond))
|
||||||
}
|
}
|
||||||
}, true)
|
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return !result.includes(false)
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkFieldCondition (condition) {
|
||||||
|
const field = this.fieldsUuidIndex[condition.field_uuid]
|
||||||
|
|
||||||
|
if (['not_empty', 'checked', 'equal', 'contains'].includes(condition.action) && field && !this.checkFieldConditions(field)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['empty', 'unchecked'].includes(condition.action)) {
|
||||||
|
return isEmpty(this.values[condition.field_uuid])
|
||||||
|
} else if (['not_empty', 'checked'].includes(condition.action)) {
|
||||||
|
return !isEmpty(this.values[condition.field_uuid])
|
||||||
|
} else if (['equal', 'contains'].includes(condition.action) && field) {
|
||||||
|
if (field.options) {
|
||||||
|
const option = field.options.find((o) => o.uuid === condition.value)
|
||||||
|
const values = [this.values[condition.field_uuid]].flat()
|
||||||
|
|
||||||
|
return values.includes(this.optionValue(option, field.options.indexOf(option)))
|
||||||
|
} else {
|
||||||
|
return [this.values[condition.field_uuid]].flat().includes(condition.value)
|
||||||
|
}
|
||||||
|
} else if (['not_equal', 'does_not_contain'].includes(condition.action) && field) {
|
||||||
|
const option = field.options.find((o) => o.uuid === condition.value)
|
||||||
|
const values = [this.values[condition.field_uuid]].flat()
|
||||||
|
|
||||||
|
return !values.includes(this.optionValue(option, field.options.indexOf(option)))
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -1209,7 +1302,7 @@ export default {
|
|||||||
|
|
||||||
const submitStep = this.currentStep
|
const submitStep = this.currentStep
|
||||||
|
|
||||||
const stepPromise = ['signature', 'phone', 'initials', 'payment'].includes(this.currentField.type)
|
const stepPromise = ['signature', 'phone', 'initials', 'payment', 'verification'].includes(this.currentField.type)
|
||||||
? this.$refs.currentStep.submit
|
? this.$refs.currentStep.submit
|
||||||
: () => Promise.resolve({})
|
: () => Promise.resolve({})
|
||||||
|
|
||||||
@@ -1243,9 +1336,13 @@ export default {
|
|||||||
if (response.status === 422 || response.status === 500) {
|
if (response.status === 422 || response.status === 500) {
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
|
|
||||||
const i18nError = data.error ? this.t(data.error.replace(/\s+/g, '_').toLowerCase()) : ''
|
if (data.error) {
|
||||||
|
const i18nKey = data.error.replace(/\s+/g, '_').toLowerCase()
|
||||||
|
|
||||||
alert(i18nError !== data.error ? i18nError : (data.error || this.t('value_is_invalid')))
|
alert(this.t(i18nKey) !== i18nKey ? this.t(i18nKey) : data.error)
|
||||||
|
} else {
|
||||||
|
alert(this.t('value_is_invalid'))
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.reject(new Error(data.error))
|
return Promise.reject(new Error(data.error))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
const en = {
|
const en = {
|
||||||
|
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',
|
||||||
complete: 'Complete',
|
complete: 'Complete',
|
||||||
fill_all_required_fields_to_complete: 'Fill all required fields to complete',
|
fill_all_required_fields_to_complete: 'Fill all required fields to complete',
|
||||||
sign_and_complete: 'Sign and Complete',
|
sign_and_complete: 'Sign and Complete',
|
||||||
@@ -67,7 +70,7 @@ const en = {
|
|||||||
documents_have_been_signed: 'Documents have been signed!',
|
documents_have_been_signed: 'Documents have been signed!',
|
||||||
create_a_free_account: 'Create a Free Account',
|
create_a_free_account: 'Create a Free Account',
|
||||||
powered_by: 'Powered by',
|
powered_by: 'Powered by',
|
||||||
please_check_the_box_to_continue: 'Please check the box to continue',
|
please_check_the_box_to_continue: 'Please check the box to continue.',
|
||||||
open_source_documents_software: 'open source documents software',
|
open_source_documents_software: 'open source documents software',
|
||||||
verified_phone_number: 'Verify Phone Number',
|
verified_phone_number: 'Verify Phone Number',
|
||||||
use_international_format: 'Use international format: +1xxx',
|
use_international_format: 'Use international format: +1xxx',
|
||||||
@@ -89,10 +92,14 @@ const en = {
|
|||||||
pay_with_strip: 'Pay with Stripe',
|
pay_with_strip: 'Pay with Stripe',
|
||||||
reupload: 'Reupload',
|
reupload: 'Reupload',
|
||||||
upload: 'Upload',
|
upload: 'Upload',
|
||||||
files: 'Files'
|
files: 'Files',
|
||||||
|
signature_is_too_small_please_redraw: 'Signature is too small. Please redraw.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const es = {
|
const es = {
|
||||||
|
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',
|
||||||
|
identity_verification: 'Verificación de identidad',
|
||||||
complete: 'Completar',
|
complete: 'Completar',
|
||||||
fill_all_required_fields_to_complete: 'Complete todos los campos requeridos para finalizar',
|
fill_all_required_fields_to_complete: 'Complete todos los campos requeridos para finalizar',
|
||||||
sign_and_complete: 'Firmar y Completar',
|
sign_and_complete: 'Firmar y Completar',
|
||||||
@@ -160,7 +167,7 @@ const es = {
|
|||||||
documents_have_been_signed: '¡Los documentos han sido firmados!',
|
documents_have_been_signed: '¡Los documentos han sido firmados!',
|
||||||
create_a_free_account: 'Crear una Cuenta Gratuita',
|
create_a_free_account: 'Crear una Cuenta Gratuita',
|
||||||
powered_by: 'Desarrollado por',
|
powered_by: 'Desarrollado por',
|
||||||
please_check_the_box_to_continue: 'Por favor marque la casilla para continuar',
|
please_check_the_box_to_continue: 'Por favor marque la casilla para continuar.',
|
||||||
open_source_documents_software: 'software de documentos de código abierto',
|
open_source_documents_software: 'software de documentos de código abierto',
|
||||||
verified_phone_number: 'Verificar número de teléfono',
|
verified_phone_number: 'Verificar número de teléfono',
|
||||||
use_international_format: 'Usar formato internacional: +1xxx',
|
use_international_format: 'Usar formato internacional: +1xxx',
|
||||||
@@ -182,10 +189,14 @@ const es = {
|
|||||||
pay_with_strip: 'Pagar con Stripe',
|
pay_with_strip: 'Pagar con Stripe',
|
||||||
reupload: 'Volver a subir',
|
reupload: 'Volver a subir',
|
||||||
upload: 'Subir',
|
upload: 'Subir',
|
||||||
files: 'Archivos'
|
files: 'Archivos',
|
||||||
|
signature_is_too_small_please_redraw: 'La firma es demasiado pequeña. Por favor, dibújala de nuevo.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const it = {
|
const it = {
|
||||||
|
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',
|
||||||
|
identity_verification: "Verifica dell'identità",
|
||||||
complete: 'Completa',
|
complete: 'Completa',
|
||||||
fill_all_required_fields_to_complete: 'Compila tutti i campi obbligatori per completare',
|
fill_all_required_fields_to_complete: 'Compila tutti i campi obbligatori per completare',
|
||||||
sign_and_complete: 'Firma e Completa',
|
sign_and_complete: 'Firma e Completa',
|
||||||
@@ -253,7 +264,7 @@ const it = {
|
|||||||
documents_have_been_signed: 'I documenti sono stati firmati!',
|
documents_have_been_signed: 'I documenti sono stati firmati!',
|
||||||
create_a_free_account: 'Crea un Account Gratuito',
|
create_a_free_account: 'Crea un Account Gratuito',
|
||||||
powered_by: 'Desarrollado por',
|
powered_by: 'Desarrollado por',
|
||||||
please_check_the_box_to_continue: 'Si prega di spuntare la casella per continuare',
|
please_check_the_box_to_continue: 'Si prega di spuntare la casella per continuare.',
|
||||||
open_source_documents_software: 'software di documenti open source',
|
open_source_documents_software: 'software di documenti open source',
|
||||||
verified_phone_number: 'Verifica numero di telefono',
|
verified_phone_number: 'Verifica numero di telefono',
|
||||||
use_international_format: 'Usa formato internazionale: +1xxx',
|
use_international_format: 'Usa formato internazionale: +1xxx',
|
||||||
@@ -275,10 +286,14 @@ const it = {
|
|||||||
pay_with_strip: 'Paga con Stripe',
|
pay_with_strip: 'Paga con Stripe',
|
||||||
reupload: 'Ricarica',
|
reupload: 'Ricarica',
|
||||||
upload: 'Carica',
|
upload: 'Carica',
|
||||||
files: 'File'
|
files: 'File',
|
||||||
|
signature_is_too_small_please_redraw: 'La firma è troppo piccola. Ridisegnala per favore.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const de = {
|
const de = {
|
||||||
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Vervollständigen Sie alle erforderlichen Felder, um mit der Identitätsverifizierung fortzufahren.',
|
||||||
|
verify_id: 'ID überprüfen',
|
||||||
|
identity_verification: 'Identitätsüberprüfung',
|
||||||
complete: 'Abschließen',
|
complete: 'Abschließen',
|
||||||
fill_all_required_fields_to_complete: 'Alle erforderlichen Felder ausfüllen, um abzuschließen',
|
fill_all_required_fields_to_complete: 'Alle erforderlichen Felder ausfüllen, um abzuschließen',
|
||||||
sign_and_complete: 'Signieren und Abschließen',
|
sign_and_complete: 'Signieren und Abschließen',
|
||||||
@@ -346,7 +361,7 @@ const de = {
|
|||||||
documents_have_been_signed: 'Dokumente wurden unterschrieben!',
|
documents_have_been_signed: 'Dokumente wurden unterschrieben!',
|
||||||
create_a_free_account: 'Kostenloses Konto erstellen',
|
create_a_free_account: 'Kostenloses Konto erstellen',
|
||||||
powered_by: 'Bereitgestellt von',
|
powered_by: 'Bereitgestellt von',
|
||||||
please_check_the_box_to_continue: 'Bitte setzen Sie das Häkchen, um fortzufahren',
|
please_check_the_box_to_continue: 'Bitte setzen Sie das Häkchen, um fortzufahren.',
|
||||||
open_source_documents_software: 'Open-Source-Dokumentensoftware',
|
open_source_documents_software: 'Open-Source-Dokumentensoftware',
|
||||||
verified_phone_number: 'Telefonnummer überprüfen',
|
verified_phone_number: 'Telefonnummer überprüfen',
|
||||||
use_international_format: 'Internationales Format verwenden: +1xxx',
|
use_international_format: 'Internationales Format verwenden: +1xxx',
|
||||||
@@ -368,10 +383,14 @@ const de = {
|
|||||||
pay_with_strip: 'Mit Stripe bezahlen',
|
pay_with_strip: 'Mit Stripe bezahlen',
|
||||||
reupload: 'Erneut hochladen',
|
reupload: 'Erneut hochladen',
|
||||||
upload: 'Hochladen',
|
upload: 'Hochladen',
|
||||||
files: 'Dateien'
|
files: 'Dateien',
|
||||||
|
signature_is_too_small_please_redraw: 'Die Unterschrift ist zu klein. Bitte erneut zeichnen.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const fr = {
|
const fr = {
|
||||||
|
complete_all_required_fields_to_proceed_with_identity_verification: "Veuillez remplir tous les champs obligatoires pour continuer la vérification de l'identité.",
|
||||||
|
verif_id: "Vérification de l'ID",
|
||||||
|
verif_identite: "Vérification de l'identité",
|
||||||
complete: 'Terminer',
|
complete: 'Terminer',
|
||||||
fill_all_required_fields_to_complete: 'Veuillez remplir tous les champs obligatoires pour compléter',
|
fill_all_required_fields_to_complete: 'Veuillez remplir tous les champs obligatoires pour compléter',
|
||||||
sign_and_complete: 'Signer et Terminer',
|
sign_and_complete: 'Signer et Terminer',
|
||||||
@@ -439,7 +458,7 @@ const fr = {
|
|||||||
documents_have_been_signed: 'Les documents ont été signés!',
|
documents_have_been_signed: 'Les documents ont été signés!',
|
||||||
create_a_free_account: 'Créer un Compte Gratuit',
|
create_a_free_account: 'Créer un Compte Gratuit',
|
||||||
powered_by: 'Propulsé par',
|
powered_by: 'Propulsé par',
|
||||||
please_check_the_box_to_continue: 'Veuillez cocher la case pour continuer',
|
please_check_the_box_to_continue: 'Veuillez cocher la case pour continuer.',
|
||||||
open_source_documents_software: 'logiciel de documents open source',
|
open_source_documents_software: 'logiciel de documents open source',
|
||||||
verified_phone_number: 'Vérifier le numéro de téléphone',
|
verified_phone_number: 'Vérifier le numéro de téléphone',
|
||||||
use_international_format: 'Utiliser le format international : +1xxx',
|
use_international_format: 'Utiliser le format international : +1xxx',
|
||||||
@@ -461,10 +480,14 @@ const fr = {
|
|||||||
pay_with_strip: 'Paiement avec Stripe',
|
pay_with_strip: 'Paiement avec Stripe',
|
||||||
reupload: 'Recharger',
|
reupload: 'Recharger',
|
||||||
upload: 'Télécharger',
|
upload: 'Télécharger',
|
||||||
files: 'Fichiers'
|
files: 'Fichiers',
|
||||||
|
signature_is_too_small_please_redraw: 'La signature est trop petite. Veuillez la redessiner.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const pl = {
|
const pl = {
|
||||||
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Uzupełnij wszystkie wymagane pola, aby kontynuować weryfikację tożsamości.',
|
||||||
|
verify_id: 'Zweryfikuj ID',
|
||||||
|
identity_verification: 'Weryfikacja tożsamości',
|
||||||
complete: 'Zakończ',
|
complete: 'Zakończ',
|
||||||
fill_all_required_fields_to_complete: 'Uzupełnij wszystkie wymagane pola, aby zakończyć',
|
fill_all_required_fields_to_complete: 'Uzupełnij wszystkie wymagane pola, aby zakończyć',
|
||||||
sign_and_complete: 'Podpisz i zakończ',
|
sign_and_complete: 'Podpisz i zakończ',
|
||||||
@@ -532,7 +555,7 @@ const pl = {
|
|||||||
documents_have_been_signed: 'Dokumenty zostały podpisane!',
|
documents_have_been_signed: 'Dokumenty zostały podpisane!',
|
||||||
create_a_free_account: 'Utwórz darmowe konto',
|
create_a_free_account: 'Utwórz darmowe konto',
|
||||||
powered_by: 'Napędzany przez',
|
powered_by: 'Napędzany przez',
|
||||||
please_check_the_box_to_continue: 'Proszę zaznaczyć pole, aby kontynuować',
|
please_check_the_box_to_continue: 'Proszę zaznaczyć pole, aby kontynuować.',
|
||||||
open_source_documents_software: 'oprogramowanie do dokumentów open source',
|
open_source_documents_software: 'oprogramowanie do dokumentów open source',
|
||||||
verified_phone_number: 'Zweryfikuj numer telefonu',
|
verified_phone_number: 'Zweryfikuj numer telefonu',
|
||||||
use_international_format: 'Użyj międzynarodowego formatu: +1xxx',
|
use_international_format: 'Użyj międzynarodowego formatu: +1xxx',
|
||||||
@@ -554,10 +577,14 @@ const pl = {
|
|||||||
pay_with_strip: 'Płatność za pomocą Stripe',
|
pay_with_strip: 'Płatność za pomocą Stripe',
|
||||||
reupload: 'Ponowne przesłanie',
|
reupload: 'Ponowne przesłanie',
|
||||||
upload: 'Przesyłanie',
|
upload: 'Przesyłanie',
|
||||||
files: 'Pliki'
|
files: 'Pliki',
|
||||||
|
signature_is_too_small_please_redraw: 'Podpis jest zbyt mały. Proszę narysować go ponownie.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const uk = {
|
const uk = {
|
||||||
|
complete_all_required_fields_to_proceed_with_identity_verification: "Заповніть всі обов'язкові поля, щоб продовжити перевірку особи.",
|
||||||
|
verify_id: 'Підтвердження ідентичності',
|
||||||
|
identity_verification: 'Ідентифікація особи',
|
||||||
complete: 'Завершити',
|
complete: 'Завершити',
|
||||||
fill_all_required_fields_to_complete: "Заповніть всі обов'язкові поля для завершення",
|
fill_all_required_fields_to_complete: "Заповніть всі обов'язкові поля для завершення",
|
||||||
sign_and_complete: 'Підписати і завершити',
|
sign_and_complete: 'Підписати і завершити',
|
||||||
@@ -625,7 +652,7 @@ const uk = {
|
|||||||
documents_have_been_signed: 'Документи були підписані!',
|
documents_have_been_signed: 'Документи були підписані!',
|
||||||
create_a_free_account: 'Створити безкоштовний обліковий запис',
|
create_a_free_account: 'Створити безкоштовний обліковий запис',
|
||||||
powered_by: 'Працює на базі',
|
powered_by: 'Працює на базі',
|
||||||
please_check_the_box_to_continue: 'Будь ласка, позначте прапорець, щоб продовжити',
|
please_check_the_box_to_continue: 'Будь ласка, позначте прапорець, щоб продовжити.',
|
||||||
open_source_documents_software: 'відкритий програмний засіб для документів',
|
open_source_documents_software: 'відкритий програмний засіб для документів',
|
||||||
verified_phone_number: 'Підтвердіть номер телефону',
|
verified_phone_number: 'Підтвердіть номер телефону',
|
||||||
use_international_format: 'Використовуйте міжнародний формат: +1xxx',
|
use_international_format: 'Використовуйте міжнародний формат: +1xxx',
|
||||||
@@ -647,10 +674,14 @@ const uk = {
|
|||||||
pay_with_strip: 'Сплатити за допомогою Stripe',
|
pay_with_strip: 'Сплатити за допомогою Stripe',
|
||||||
reupload: 'Перезавантажити',
|
reupload: 'Перезавантажити',
|
||||||
upload: 'Завантажити',
|
upload: 'Завантажити',
|
||||||
files: 'Файли'
|
files: 'Файли',
|
||||||
|
signature_is_too_small_please_redraw: 'Підпис занадто малий. Будь ласка, перемалюйте його.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const cs = {
|
const cs = {
|
||||||
|
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',
|
||||||
|
identity_verification: 'Ověření identity',
|
||||||
complete: 'Dokončit',
|
complete: 'Dokončit',
|
||||||
fill_all_required_fields_to_complete: 'Please complete all mandatory fields',
|
fill_all_required_fields_to_complete: 'Please complete all mandatory fields',
|
||||||
sign_and_complete: 'Podepsat a dokončit',
|
sign_and_complete: 'Podepsat a dokončit',
|
||||||
@@ -718,7 +749,7 @@ const cs = {
|
|||||||
documents_have_been_signed: 'Dokumenty byly podepsány!',
|
documents_have_been_signed: 'Dokumenty byly podepsány!',
|
||||||
create_a_free_account: 'Vytvořit bezplatný účet',
|
create_a_free_account: 'Vytvořit bezplatný účet',
|
||||||
powered_by: 'Poháněno',
|
powered_by: 'Poháněno',
|
||||||
please_check_the_box_to_continue: 'Prosím, zaškrtněte políčko pro pokračování',
|
please_check_the_box_to_continue: 'Prosím, zaškrtněte políčko pro pokračování.',
|
||||||
open_source_documents_software: 'open source software pro dokumenty',
|
open_source_documents_software: 'open source software pro dokumenty',
|
||||||
verified_phone_number: 'Ověřte telefonní číslo',
|
verified_phone_number: 'Ověřte telefonní číslo',
|
||||||
use_international_format: 'Použijte mezinárodní formát: +1xxx',
|
use_international_format: 'Použijte mezinárodní formát: +1xxx',
|
||||||
@@ -740,12 +771,16 @@ const cs = {
|
|||||||
pay_with_strip: 'Zaplacení přes Stripe',
|
pay_with_strip: 'Zaplacení přes Stripe',
|
||||||
reupload: 'Znovu nahrát',
|
reupload: 'Znovu nahrát',
|
||||||
upload: 'Nahrát',
|
upload: 'Nahrát',
|
||||||
files: 'Soubory'
|
files: 'Soubory',
|
||||||
|
signature_is_too_small_please_redraw: 'Podpis je příliš malý. Prosím, překreslete ho.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const pt = {
|
const pt = {
|
||||||
|
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',
|
||||||
|
identity_verification: 'Verificação de identidade',
|
||||||
complete: 'Completar',
|
complete: 'Completar',
|
||||||
preencher_todos_os_campos_obrigatórios_para_concluir: 'Preencher todos os campos obrigatórios para concluir',
|
fill_all_required_fields_to_complete: 'Preencher todos os campos obrigatórios para concluir',
|
||||||
sign_and_complete: 'Assinar e Completar',
|
sign_and_complete: 'Assinar e Completar',
|
||||||
invite: 'Convidar',
|
invite: 'Convidar',
|
||||||
email: 'E-mail',
|
email: 'E-mail',
|
||||||
@@ -811,7 +846,7 @@ const pt = {
|
|||||||
documents_have_been_signed: 'Os documentos foram assinados!',
|
documents_have_been_signed: 'Os documentos foram assinados!',
|
||||||
create_a_free_account: 'Criar uma Conta Gratuita',
|
create_a_free_account: 'Criar uma Conta Gratuita',
|
||||||
powered_by: 'Desenvolvido por',
|
powered_by: 'Desenvolvido por',
|
||||||
please_check_the_box_to_continue: 'Por favor, marque a caixa para continuar',
|
please_check_the_box_to_continue: 'Por favor, marque a caixa para continuar.',
|
||||||
open_source_documents_software: 'software de documentos de código aberto',
|
open_source_documents_software: 'software de documentos de código aberto',
|
||||||
verified_phone_number: 'Verificar Número de Telefone',
|
verified_phone_number: 'Verificar Número de Telefone',
|
||||||
use_international_format: 'Use formato internacional: +1xxx',
|
use_international_format: 'Use formato internacional: +1xxx',
|
||||||
@@ -833,10 +868,14 @@ const pt = {
|
|||||||
pay_with_strip: 'Pagar com Stripe',
|
pay_with_strip: 'Pagar com Stripe',
|
||||||
reupload: 'Reenviar',
|
reupload: 'Reenviar',
|
||||||
upload: 'Carregar',
|
upload: 'Carregar',
|
||||||
files: 'Arquivos'
|
files: 'Arquivos',
|
||||||
|
signature_is_too_small_please_redraw: 'A assinatura é muito pequena. Por favor, redesenhe-a.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const he = {
|
const he = {
|
||||||
|
complete_all_required_fields_to_proceed_with_identity_verification: 'מלא את כל השדות הנדרשים כדי להמשיך עם אימות זהות.',
|
||||||
|
verify_id: 'אמת מזהה',
|
||||||
|
identity_verification: 'אימות זהות',
|
||||||
complete: 'השלם',
|
complete: 'השלם',
|
||||||
fill_all_required_fields_to_complete: 'נא למלא את כל השדות הנדרשים להשלמה',
|
fill_all_required_fields_to_complete: 'נא למלא את כל השדות הנדרשים להשלמה',
|
||||||
sign_and_complete: 'חתום והשלם',
|
sign_and_complete: 'חתום והשלם',
|
||||||
@@ -905,7 +944,7 @@ const he = {
|
|||||||
documents_have_been_signed: 'המסמכים נחתמו!',
|
documents_have_been_signed: 'המסמכים נחתמו!',
|
||||||
create_a_free_account: 'צור חשבון חינם',
|
create_a_free_account: 'צור חשבון חינם',
|
||||||
powered_by: 'מופעל על ידי',
|
powered_by: 'מופעל על ידי',
|
||||||
please_check_the_box_to_continue: 'אנא סמן את התיבה כדי להמשיך',
|
please_check_the_box_to_continue: 'אנא סמן את התיבה כדי להמשיך.',
|
||||||
open_source_documents_software: 'תוכנה פתוחה למסמכים',
|
open_source_documents_software: 'תוכנה פתוחה למסמכים',
|
||||||
verified_phone_number: 'אימות מספר טלפון',
|
verified_phone_number: 'אימות מספר טלפון',
|
||||||
use_international_format: 'השתמש בפורמט בינלאומי: +1xxx',
|
use_international_format: 'השתמש בפורמט בינלאומי: +1xxx',
|
||||||
@@ -927,12 +966,16 @@ const he = {
|
|||||||
pay_with_strip: 'שלם עם סטרייפ',
|
pay_with_strip: 'שלם עם סטרייפ',
|
||||||
reupload: 'העלה שוב',
|
reupload: 'העלה שוב',
|
||||||
upload: 'העלאה',
|
upload: 'העלאה',
|
||||||
files: 'קבצים'
|
files: 'קבצים',
|
||||||
|
signature_is_too_small_please_redraw: 'החתימה קטנה מדי. אנא צייר מחדש.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const nl = {
|
const nl = {
|
||||||
|
complete_all_required_fields_to_proceed_with_identity_verification: 'Vul alle verplichte velden in om door te gaan met de identiteitsverificatie.',
|
||||||
|
verify_id: 'Verifiëren ID',
|
||||||
|
identity_verification: 'Identiteitsverificatie',
|
||||||
complete: 'Voltooien',
|
complete: 'Voltooien',
|
||||||
vul_alle_verplichte_velden_in_om_te_voltooien: 'Vul alle verplichte velden in om te voltooien',
|
fill_all_required_fields_to_complete: 'Vul alle verplichte velden in om te voltooien',
|
||||||
sign_and_complete: 'Ondertekenen en voltooien',
|
sign_and_complete: 'Ondertekenen en voltooien',
|
||||||
invite: 'Uitnodigen',
|
invite: 'Uitnodigen',
|
||||||
email: 'E-mail',
|
email: 'E-mail',
|
||||||
@@ -999,7 +1042,7 @@ const nl = {
|
|||||||
documents_have_been_signed: 'De documenten zijn ondertekend!',
|
documents_have_been_signed: 'De documenten zijn ondertekend!',
|
||||||
create_a_free_account: 'Maak een gratis account aan',
|
create_a_free_account: 'Maak een gratis account aan',
|
||||||
powered_by: 'Aangedreven door',
|
powered_by: 'Aangedreven door',
|
||||||
please_check_the_box_to_continue: 'Vink het vakje aan om door te gaan',
|
please_check_the_box_to_continue: 'Vink het vakje aan om door te gaan.',
|
||||||
open_source_documents_software: 'Open source documenten software',
|
open_source_documents_software: 'Open source documenten software',
|
||||||
verified_phone_number: 'Geverifieerd telefoonnummer',
|
verified_phone_number: 'Geverifieerd telefoonnummer',
|
||||||
use_international_format: 'Gebruik internationaal formaat: +1xxx',
|
use_international_format: 'Gebruik internationaal formaat: +1xxx',
|
||||||
@@ -1021,10 +1064,14 @@ const nl = {
|
|||||||
pay_with_strip: 'Betalen met Stripe',
|
pay_with_strip: 'Betalen met Stripe',
|
||||||
reupload: 'Opnieuw uploaden',
|
reupload: 'Opnieuw uploaden',
|
||||||
upload: 'Uploaden',
|
upload: 'Uploaden',
|
||||||
files: 'Bestanden'
|
files: 'Bestanden',
|
||||||
|
signature_is_too_small_please_redraw: 'De handtekening is te klein. Teken deze opnieuw, alstublieft.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const ar = {
|
const ar = {
|
||||||
|
complete_all_required_fields_to_proceed_with_identity_verification: 'أكمل جميع الحقول المطلوبة للمتابعة في التحقق من الهوية.',
|
||||||
|
verify_id: 'تحقق من الهوية',
|
||||||
|
identity_verification: 'التحقق من الهوية',
|
||||||
complete: 'اكتمال',
|
complete: 'اكتمال',
|
||||||
fill_all_required_fields_to_complete: 'يرجى ملء جميع الحقول المطلوبة لإكمال',
|
fill_all_required_fields_to_complete: 'يرجى ملء جميع الحقول المطلوبة لإكمال',
|
||||||
sign_and_complete: 'التوقيع والاكتمال',
|
sign_and_complete: 'التوقيع والاكتمال',
|
||||||
@@ -1092,7 +1139,7 @@ const ar = {
|
|||||||
documents_have_been_signed: 'تم توقيع الوثائق!',
|
documents_have_been_signed: 'تم توقيع الوثائق!',
|
||||||
create_a_free_account: 'إنشاء حساب مجاني',
|
create_a_free_account: 'إنشاء حساب مجاني',
|
||||||
powered_by: 'مدعوم من',
|
powered_by: 'مدعوم من',
|
||||||
please_check_the_box_to_continue: 'الرجاء التحقق من الخانة للمتابعة',
|
please_check_the_box_to_continue: 'الرجاء التحقق من الخانة للمتابعة.',
|
||||||
open_source_documents_software: 'برنامج وثائق مفتوح المصدر',
|
open_source_documents_software: 'برنامج وثائق مفتوح المصدر',
|
||||||
verified_phone_number: 'تحقق من رقم الهاتف',
|
verified_phone_number: 'تحقق من رقم الهاتف',
|
||||||
use_international_format: 'استخدم الشكل الدولي: +1xxx',
|
use_international_format: 'استخدم الشكل الدولي: +1xxx',
|
||||||
@@ -1114,10 +1161,14 @@ const ar = {
|
|||||||
pay_with_strip: 'الدفع بواسطة Stripe',
|
pay_with_strip: 'الدفع بواسطة Stripe',
|
||||||
reupload: 'إعادة التحميل',
|
reupload: 'إعادة التحميل',
|
||||||
upload: 'تحميل',
|
upload: 'تحميل',
|
||||||
files: 'الملفات'
|
files: 'الملفات',
|
||||||
|
signature_is_too_small_please_redraw: 'التوقيع صغير جدًا. يرجى إعادة الرسم.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const ko = {
|
const ko = {
|
||||||
|
complete_all_required_fields_to_proceed_with_identity_verification: '신원 확인을 진행하려면 모든 필수 필드를 작성하십시오.',
|
||||||
|
verify_id: '아이디 확인',
|
||||||
|
identity_verification: '신원 확인',
|
||||||
complete: '완료',
|
complete: '완료',
|
||||||
fill_all_required_fields_to_complete: '모든 필수 필드를 작성하여 완료하세요',
|
fill_all_required_fields_to_complete: '모든 필수 필드를 작성하여 완료하세요',
|
||||||
sign_and_complete: '서명하고 완료하기',
|
sign_and_complete: '서명하고 완료하기',
|
||||||
@@ -1184,7 +1235,7 @@ const ko = {
|
|||||||
documents_have_been_signed: '문서가 서명되었습니다!',
|
documents_have_been_signed: '문서가 서명되었습니다!',
|
||||||
create_a_free_account: '무료 계정 생성',
|
create_a_free_account: '무료 계정 생성',
|
||||||
powered_by: '구동',
|
powered_by: '구동',
|
||||||
please_check_the_box_to_continue: '계속하려면 확인란을 선택하십시오',
|
please_check_the_box_to_continue: '계속하려면 확인란을 선택하십시오.',
|
||||||
open_source_documents_software: '오픈 소스 문서 소프트웨어',
|
open_source_documents_software: '오픈 소스 문서 소프트웨어',
|
||||||
verified_phone_number: '전화번호 확인됨',
|
verified_phone_number: '전화번호 확인됨',
|
||||||
use_international_format: '국제 포맷 사용: +1xxx',
|
use_international_format: '국제 포맷 사용: +1xxx',
|
||||||
@@ -1206,7 +1257,8 @@ const ko = {
|
|||||||
pay_with_strip: '스트라이프로 결제',
|
pay_with_strip: '스트라이프로 결제',
|
||||||
reupload: '다시 업로드',
|
reupload: '다시 업로드',
|
||||||
upload: '업로드',
|
upload: '업로드',
|
||||||
files: '파일'
|
files: '파일',
|
||||||
|
signature_is_too_small_please_redraw: '서명이 너무 작습니다. 다시 그려주세요.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const i18n = { en, es, it, de, fr, pl, uk, cs, pt, he, nl, ar, ko }
|
const i18n = { en, es, it, de, fr, pl, uk, cs, pt, he, nl, ar, ko }
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<label
|
<label
|
||||||
v-if="!modelValue && !sessionId"
|
v-if="!modelValue && !sessionId"
|
||||||
:for="field.uuid"
|
|
||||||
class="label text-2xl mb-2"
|
class="label text-2xl mb-2"
|
||||||
>
|
>
|
||||||
<MarkdownContent
|
<MarkdownContent
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -65,11 +65,15 @@
|
|||||||
v-show="!isCodeSent"
|
v-show="!isCodeSent"
|
||||||
class="flex w-full rounded-full outline-neutral-content outline-2 outline-offset-2 focus-within:outline"
|
class="flex w-full rounded-full outline-neutral-content outline-2 outline-offset-2 focus-within:outline"
|
||||||
>
|
>
|
||||||
<div class="relative inline-block">
|
<div
|
||||||
|
id="country_code"
|
||||||
|
class="relative inline-block"
|
||||||
|
>
|
||||||
<div class="btn bg-base-200 border border-neutral-300 text-2xl whitespace-nowrap font-normal rounded-l-full">
|
<div class="btn bg-base-200 border border-neutral-300 text-2xl whitespace-nowrap font-normal rounded-l-full">
|
||||||
{{ selectedCountry.flag }} +{{ selectedCountry.dial }}
|
{{ selectedCountry.flag }} +{{ selectedCountry.dial }}
|
||||||
</div>
|
</div>
|
||||||
<select
|
<select
|
||||||
|
id="country_code_select"
|
||||||
class="absolute top-0 bottom-0 right-0 left-0 opacity-0 w-full h-full cursor-pointer"
|
class="absolute top-0 bottom-0 right-0 left-0 opacity-0 w-full h-full cursor-pointer"
|
||||||
:disabled="!!defaultValue"
|
:disabled="!!defaultValue"
|
||||||
@change="onCountrySelect(countries.find((country) => country.flag === $event.target.value))"
|
@change="onCountrySelect(countries.find((country) => country.flag === $event.target.value))"
|
||||||
@@ -176,8 +180,8 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
countries () {
|
countries () {
|
||||||
return phoneData.map(([name, dial, flag, tz]) => {
|
return phoneData.map(([iso, name, dial, flag, tz]) => {
|
||||||
return { name, dial, flag, tz }
|
return { iso, name, dial, flag, tz }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
countriesDialIndex () {
|
countriesDialIndex () {
|
||||||
|
|||||||
@@ -114,7 +114,9 @@ export default {
|
|||||||
const area = this.field.areas?.[0]
|
const area = this.field.areas?.[0]
|
||||||
|
|
||||||
if (area) {
|
if (area) {
|
||||||
return parseInt(area.w / area.cell_w) + 1
|
const num = area.w / area.cell_w
|
||||||
|
|
||||||
|
return (num % 1) > 0.2 ? parseInt(num) + 1 : parseInt(num)
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
<template>
|
||||||
|
<label
|
||||||
|
class="label text-2xl mb-2"
|
||||||
|
>
|
||||||
|
<MarkdownContent
|
||||||
|
v-if="field.title"
|
||||||
|
:string="field.title"
|
||||||
|
/>
|
||||||
|
<template v-else>{{ field.name || t('identity_verification') }}</template>
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
v-if="field.description"
|
||||||
|
dir="auto"
|
||||||
|
class="mb-4 px-1"
|
||||||
|
>
|
||||||
|
<MarkdownContent :string="field.description" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="emptyValueRequiredStep && emptyValueRequiredStep[0] !== field"
|
||||||
|
class="px-1"
|
||||||
|
>
|
||||||
|
{{ t('complete_all_required_fields_to_proceed_with_identity_verification') }}
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div
|
||||||
|
v-if="isLoading"
|
||||||
|
class="w-full flex space-x-2 justify-center mb-2"
|
||||||
|
>
|
||||||
|
<IconInnerShadowTop
|
||||||
|
width="40"
|
||||||
|
class="animate-spin h-10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
ref="widgetContainer"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MarkdownContent from './markdown_content'
|
||||||
|
import { IconInnerShadowTop } from '@tabler/icons-vue'
|
||||||
|
import phoneData from './phone_data'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VerificationStep',
|
||||||
|
components: {
|
||||||
|
MarkdownContent,
|
||||||
|
IconInnerShadowTop
|
||||||
|
},
|
||||||
|
inject: ['baseUrl', 't'],
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
submitter: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
emptyValueRequiredStep: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
values: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'en'
|
||||||
|
},
|
||||||
|
submitterSlug: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['focus', 'submit', 'update:model-value', 'attached'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isCreatingCheckout: false,
|
||||||
|
isMathLoaded: false,
|
||||||
|
isLoading: false,
|
||||||
|
eidEasyData: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
countryCode () {
|
||||||
|
const browserTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||||
|
const browserTz = browserTimeZone.split('/')[1]
|
||||||
|
const country = phoneData.find(([a, b, c, e, tz]) => tz.includes(browserTz))
|
||||||
|
|
||||||
|
return country[0]
|
||||||
|
},
|
||||||
|
browserCountry () {
|
||||||
|
return (navigator.language || navigator.userLanguage || 'en').split('-')[1]
|
||||||
|
},
|
||||||
|
widgetSettings () {
|
||||||
|
return {
|
||||||
|
clientId: this.eidEasyData.client_id,
|
||||||
|
docId: this.eidEasyData.doc_id,
|
||||||
|
language: this.locale,
|
||||||
|
countryCode: this.countryCode,
|
||||||
|
enabledMethods: {
|
||||||
|
signature: this.eidEasyData.available_methods
|
||||||
|
},
|
||||||
|
selectedMethod: null,
|
||||||
|
enabledCountries: 'all',
|
||||||
|
onSuccess: (data) => {
|
||||||
|
this.$emit('submit')
|
||||||
|
},
|
||||||
|
onFail: (error) => {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
Promise.all([
|
||||||
|
import('@eid-easy/eideasy-widget'),
|
||||||
|
this.start()
|
||||||
|
]).finally(() => {
|
||||||
|
this.isLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
start () {
|
||||||
|
return fetch(this.baseUrl + `/api/identity_verification/${this.field.uuid}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify({
|
||||||
|
submitter_slug: this.submitterSlug
|
||||||
|
}),
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
}).then(async (resp) => {
|
||||||
|
this.eidEasyData = await resp.json()
|
||||||
|
|
||||||
|
const eidEasyWidget = document.createElement('eideasy-widget')
|
||||||
|
|
||||||
|
for (const key in this.widgetSettings) {
|
||||||
|
eidEasyWidget[key] = this.widgetSettings[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.widgetContainer.innerHTML = ''
|
||||||
|
this.$refs.widgetContainer.appendChild(eidEasyWidget)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async submit () {
|
||||||
|
return fetch(this.baseUrl + '/api/identity_verification', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
submitter_slug: this.submitterSlug
|
||||||
|
}),
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
}).then(async (resp) => {
|
||||||
|
return resp
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -237,7 +237,7 @@
|
|||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-if="field?.type && editable"
|
v-if="field?.type && editable"
|
||||||
class="h-4 w-4 md:h-2.5 md:w-2.5 -right-1 rounded-full -bottom-1 border-gray-400 bg-white shadow-md border absolute cursor-nwse-resize"
|
class="h-4 w-4 lg:h-2.5 lg:w-2.5 -right-1 rounded-full -bottom-1 border-gray-400 bg-white shadow-md border absolute cursor-nwse-resize"
|
||||||
@mousedown.stop="startResize"
|
@mousedown.stop="startResize"
|
||||||
@touchstart="startTouchResize"
|
@touchstart="startTouchResize"
|
||||||
/>
|
/>
|
||||||
@@ -257,7 +257,7 @@
|
|||||||
:to="modalContainerEl"
|
:to="modalContainerEl"
|
||||||
>
|
>
|
||||||
<ConditionsModal
|
<ConditionsModal
|
||||||
:field="field"
|
:item="field"
|
||||||
:build-default-name="buildDefaultName"
|
:build-default-name="buildDefaultName"
|
||||||
@close="isShowConditionsModal = false"
|
@close="isShowConditionsModal = false"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
style="max-width: 1600px"
|
style="max-width: 1600px"
|
||||||
class="mx-auto pl-3 md:pl-4 h-full"
|
class="mx-auto pl-3 h-full"
|
||||||
|
:class="isMobile ? 'pl-4' : 'md:pl-4'"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="pendingFieldAttachmentUuids.length"
|
v-if="pendingFieldAttachmentUuids.length && editable"
|
||||||
class="top-1.5 sticky h-0 z-20 max-w-2xl mx-auto"
|
class="top-1.5 sticky h-0 z-20 max-w-2xl mx-auto"
|
||||||
>
|
>
|
||||||
<div class="alert border-base-content/30 py-2 px-2.5">
|
<div class="alert border-base-content/30 py-2 px-2.5">
|
||||||
@@ -163,7 +164,7 @@
|
|||||||
<div
|
<div
|
||||||
id="main_container"
|
id="main_container"
|
||||||
class="flex"
|
class="flex"
|
||||||
:class="$slots.buttons || withTitle ? 'md:max-h-[calc(100%_-_60px)]' : 'md:max-h-[100%]'"
|
:class="$slots.buttons || withTitle ? (isMobile ? 'max-h-[calc(100%_-_60px)]' : 'md:max-h-[calc(100%_-_60px)]') : (isMobile ? 'max-h-[100%]' : 'md:max-h-[100%]')"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="withDocumentsList"
|
v-if="withDocumentsList"
|
||||||
@@ -219,7 +220,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
id="pages_container"
|
id="pages_container"
|
||||||
class="w-full overflow-y-hidden md:overflow-y-auto overflow-x-hidden mt-0.5 pt-0.5"
|
class="w-full overflow-y-hidden overflow-x-hidden mt-0.5 pt-0.5"
|
||||||
|
:class="isMobile ? 'overflow-y-auto' : 'md:overflow-y-auto'"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
ref="documents"
|
ref="documents"
|
||||||
@@ -320,7 +322,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="withFieldsList"
|
v-if="withFieldsList && !isMobile"
|
||||||
id="fields_list_container"
|
id="fields_list_container"
|
||||||
class="relative w-80 flex-none mt-1 pr-4 pl-0.5 hidden md:block"
|
class="relative w-80 flex-none mt-1 pr-4 pl-0.5 hidden md:block"
|
||||||
:class="drawField ? 'overflow-hidden' : 'overflow-y-auto overflow-x-hidden'"
|
:class="drawField ? 'overflow-hidden' : 'overflow-y-auto overflow-x-hidden'"
|
||||||
@@ -362,6 +364,7 @@
|
|||||||
:default-submitters="defaultSubmitters"
|
:default-submitters="defaultSubmitters"
|
||||||
:draw-field-type="drawFieldType"
|
:draw-field-type="drawFieldType"
|
||||||
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
||||||
|
:template="template"
|
||||||
:default-required-fields="defaultRequiredFields"
|
:default-required-fields="defaultRequiredFields"
|
||||||
:field-types="fieldTypes"
|
:field-types="fieldTypes"
|
||||||
:with-sticky-submitters="withStickySubmitters"
|
:with-sticky-submitters="withStickySubmitters"
|
||||||
@@ -378,14 +381,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sticky bottom-0">
|
<div class="sticky bottom-0 z-10">
|
||||||
<MobileDrawField
|
<MobileDrawField
|
||||||
v-if="drawField && isBreakpointLg"
|
v-if="drawField && (isBreakpointLg || isMobile)"
|
||||||
:draw-field="drawField"
|
:draw-field="drawField"
|
||||||
:fields="template.fields"
|
:fields="template.fields"
|
||||||
:submitters="template.submitters"
|
:submitters="template.submitters"
|
||||||
:selected-submitter="selectedSubmitter"
|
:selected-submitter="selectedSubmitter"
|
||||||
class="md:hidden"
|
:class="{ 'md:hidden': !isMobile }"
|
||||||
:editable="editable"
|
:editable="editable"
|
||||||
@cancel="[drawField = null, drawOption = null]"
|
@cancel="[drawField = null, drawOption = null]"
|
||||||
@change-submitter="[selectedSubmitter = $event, drawField.submitter_uuid = $event.uuid]"
|
@change-submitter="[selectedSubmitter = $event, drawField.submitter_uuid = $event.uuid]"
|
||||||
@@ -396,6 +399,7 @@
|
|||||||
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
||||||
:default-required-fields="defaultRequiredFields"
|
:default-required-fields="defaultRequiredFields"
|
||||||
:field-types="fieldTypes"
|
:field-types="fieldTypes"
|
||||||
|
:class="{ 'md:hidden': !isMobile }"
|
||||||
:selected-submitter="selectedSubmitter"
|
:selected-submitter="selectedSubmitter"
|
||||||
@select="startFieldDraw($event)"
|
@select="startFieldDraw($event)"
|
||||||
/>
|
/>
|
||||||
@@ -455,6 +459,7 @@ export default {
|
|||||||
fieldTypes: this.fieldTypes,
|
fieldTypes: this.fieldTypes,
|
||||||
backgroundColor: this.backgroundColor,
|
backgroundColor: this.backgroundColor,
|
||||||
withPhone: this.withPhone,
|
withPhone: this.withPhone,
|
||||||
|
withVerification: this.withVerification,
|
||||||
withPayment: this.withPayment,
|
withPayment: this.withPayment,
|
||||||
isPaymentConnected: this.isPaymentConnected,
|
isPaymentConnected: this.isPaymentConnected,
|
||||||
withFormula: this.withFormula,
|
withFormula: this.withFormula,
|
||||||
@@ -635,6 +640,11 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
withVerification: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
withPayment: {
|
withPayment: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -689,6 +699,9 @@ export default {
|
|||||||
language () {
|
language () {
|
||||||
return this.locale.split('-')[0].toLowerCase()
|
return this.locale.split('-')[0].toLowerCase()
|
||||||
},
|
},
|
||||||
|
isMobile () {
|
||||||
|
return /android|iphone|ipad/i.test(navigator.userAgent)
|
||||||
|
},
|
||||||
defaultDateFormat () {
|
defaultDateFormat () {
|
||||||
const isUsBrowser = Intl.DateTimeFormat().resolvedOptions().locale.endsWith('-US')
|
const isUsBrowser = Intl.DateTimeFormat().resolvedOptions().locale.endsWith('-US')
|
||||||
const isUsTimezone = new Intl.DateTimeFormat('en-US', { timeZoneName: 'short' }).format(new Date()).match(/\s(?:CST|CDT|PST|PDT|EST|EDT)$/)
|
const isUsTimezone = new Intl.DateTimeFormat('en-US', { timeZoneName: 'short' }).format(new Date()).match(/\s(?:CST|CDT|PST|PDT|EST|EDT)$/)
|
||||||
@@ -1017,6 +1030,22 @@ export default {
|
|||||||
|
|
||||||
if (!field.areas.length) {
|
if (!field.areas.length) {
|
||||||
this.template.fields.splice(this.template.fields.indexOf(field), 1)
|
this.template.fields.splice(this.template.fields.indexOf(field), 1)
|
||||||
|
|
||||||
|
this.template.fields.forEach((f) => {
|
||||||
|
(f.conditions || []).forEach((c) => {
|
||||||
|
if (c.field_uuid === field.uuid) {
|
||||||
|
f.conditions.splice(f.conditions.indexOf(c), 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.template.schema.forEach((item) => {
|
||||||
|
(item.conditions || []).forEach((c) => {
|
||||||
|
if (c.field_uuid === field.uuid) {
|
||||||
|
item.conditions.splice(item.conditions.indexOf(c), 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
@@ -1075,7 +1104,7 @@ export default {
|
|||||||
} else if (type === 'image') {
|
} else if (type === 'image') {
|
||||||
area.w = pageMask.clientWidth / 5 / pageMask.clientWidth
|
area.w = pageMask.clientWidth / 5 / pageMask.clientWidth
|
||||||
area.h = (pageMask.clientWidth / 5 / pageMask.clientWidth) * (pageMask.clientWidth / pageMask.clientHeight)
|
area.h = (pageMask.clientWidth / 5 / pageMask.clientWidth) * (pageMask.clientWidth / pageMask.clientHeight)
|
||||||
} else if (type === 'signature' || type === 'stamp') {
|
} else if (type === 'signature' || type === 'stamp' || type === 'verification') {
|
||||||
area.w = pageMask.clientWidth / 5 / pageMask.clientWidth
|
area.w = pageMask.clientWidth / 5 / pageMask.clientWidth
|
||||||
area.h = (pageMask.clientWidth / 5 / pageMask.clientWidth) * (pageMask.clientWidth / pageMask.clientHeight) / 2
|
area.h = (pageMask.clientWidth / 5 / pageMask.clientWidth) * (pageMask.clientWidth / pageMask.clientHeight) / 2
|
||||||
} else if (type === 'initials') {
|
} else if (type === 'initials') {
|
||||||
@@ -1239,7 +1268,7 @@ export default {
|
|||||||
w: area.maskW / 5 / area.maskW,
|
w: area.maskW / 5 / area.maskW,
|
||||||
h: (area.maskW / 5 / area.maskW) * (area.maskW / area.maskH)
|
h: (area.maskW / 5 / area.maskW) * (area.maskW / area.maskH)
|
||||||
}
|
}
|
||||||
} else if (field.type === 'signature' || field.type === 'stamp') {
|
} else if (field.type === 'signature' || field.type === 'stamp' || field.type === 'verification') {
|
||||||
baseArea = {
|
baseArea = {
|
||||||
w: area.maskW / 5 / area.maskW,
|
w: area.maskW / 5 / area.maskW,
|
||||||
h: (area.maskW / 5 / area.maskW) * (area.maskW / area.maskH) / 2
|
h: (area.maskW / 5 / area.maskW) * (area.maskW / area.maskH) / 2
|
||||||
@@ -1342,7 +1371,9 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.previews.scrollTop = this.$refs.previews.scrollHeight
|
if (this.$refs.previews) {
|
||||||
|
this.$refs.previews.scrollTop = this.$refs.previews.scrollHeight
|
||||||
|
}
|
||||||
|
|
||||||
this.scrollIntoDocument(data.schema[0])
|
this.scrollIntoDocument(data.schema[0])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<div class="modal-box pt-4 pb-6 px-6 mt-20 max-h-none w-full max-w-xl">
|
<div class="modal-box pt-4 pb-6 px-6 mt-20 max-h-none w-full max-w-xl">
|
||||||
<div class="flex justify-between items-center border-b pb-2 mb-2 font-medium">
|
<div class="flex justify-between items-center border-b pb-2 mb-2 font-medium">
|
||||||
<span>
|
<span>
|
||||||
{{ t('condition') }} - {{ field.name || buildDefaultName(field, template.fields) }}
|
{{ t('condition') }} - {{ item.name || buildDefaultName(item, template.fields) }}
|
||||||
</span>
|
</span>
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
@@ -29,15 +29,26 @@
|
|||||||
>{{ t('available_in_pro') }}</a>
|
>{{ t('available_in_pro') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<form @submit.prevent="validateSaveAndClose">
|
<form @submit.prevent="validateSaveAndClose">
|
||||||
<div class="my-4 space-y-5">
|
<div class="my-4">
|
||||||
<div
|
<div
|
||||||
v-for="(condition, cindex) in conditions"
|
v-for="(condition, cindex) in conditions"
|
||||||
:key="cindex"
|
:key="cindex"
|
||||||
class="space-y-4 relative"
|
class="space-y-4 relative"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="cindex > 0"
|
||||||
|
class="divider -mb-2 mx-1"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn btn-xs btn-primary w-24"
|
||||||
|
@click.prevent="condition.operation === 'or' ? delete condition.operation : condition.operation = 'or'"
|
||||||
|
>
|
||||||
|
{{ condition.operation === 'or' ? t('or') : t('and') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="conditions.length > 1"
|
v-if="conditions.length > 1"
|
||||||
class="flex justify-between border-b mx-1 -mb-1 pb-1"
|
class="flex justify-between mx-1"
|
||||||
>
|
>
|
||||||
<span class="text-sm">
|
<span class="text-sm">
|
||||||
{{ t('condition') }} {{ cindex + 1 }}
|
{{ t('condition') }} {{ cindex + 1 }}
|
||||||
@@ -127,12 +138,12 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<div
|
<div
|
||||||
v-if="field.conditions?.[0]?.field_uuid"
|
v-if="item.conditions?.[0]?.field_uuid"
|
||||||
class="text-center w-full mt-4"
|
class="text-center w-full mt-4"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="link"
|
class="link"
|
||||||
@click="[conditions = [], delete field.conditions, validateSaveAndClose()]"
|
@click="[conditions = [], delete item.conditions, validateSaveAndClose()]"
|
||||||
>
|
>
|
||||||
{{ t('remove_condition') }}
|
{{ t('remove_condition') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -147,7 +158,7 @@ export default {
|
|||||||
name: 'ConditionModal',
|
name: 'ConditionModal',
|
||||||
inject: ['t', 'save', 'template', 'withConditions'],
|
inject: ['t', 'save', 'template', 'withConditions'],
|
||||||
props: {
|
props: {
|
||||||
field: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
@@ -159,22 +170,26 @@ export default {
|
|||||||
emits: ['close'],
|
emits: ['close'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
conditions: this.field.conditions?.[0] ? JSON.parse(JSON.stringify(this.field.conditions)) : [{}]
|
conditions: this.item.conditions?.[0] ? JSON.parse(JSON.stringify(this.item.conditions)) : [{}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
fields () {
|
fields () {
|
||||||
return this.template.fields.reduce((acc, f) => {
|
if (this.item.submitter_uuid) {
|
||||||
if (f !== this.field && f.submitter_uuid === this.field.submitter_uuid) {
|
return this.template.fields.reduce((acc, f) => {
|
||||||
acc.push(f)
|
if (f !== this.item && f.submitter_uuid === this.item.submitter_uuid) {
|
||||||
}
|
acc.push(f)
|
||||||
|
}
|
||||||
|
|
||||||
return acc
|
return acc
|
||||||
}, [])
|
}, [])
|
||||||
|
} else {
|
||||||
|
return this.template.fields
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
this.field.conditions ||= []
|
this.item.conditions ||= []
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
conditionField (condition) {
|
conditionField (condition) {
|
||||||
@@ -208,9 +223,9 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.conditions.find((f) => f.field_uuid)) {
|
if (this.conditions.find((f) => f.field_uuid)) {
|
||||||
this.field.conditions = this.conditions
|
this.item.conditions = this.conditions
|
||||||
} else {
|
} else {
|
||||||
delete this.field.conditions
|
delete this.item.conditions
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
|
|||||||
@@ -236,7 +236,7 @@
|
|||||||
:to="modalContainerEl"
|
:to="modalContainerEl"
|
||||||
>
|
>
|
||||||
<ConditionsModal
|
<ConditionsModal
|
||||||
:field="field"
|
:item="field"
|
||||||
:build-default-name="buildDefaultName"
|
:build-default-name="buildDefaultName"
|
||||||
@close="isShowConditionsModal = false"
|
@close="isShowConditionsModal = false"
|
||||||
/>
|
/>
|
||||||
@@ -365,7 +365,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
const typeIndex = fields.filter((f) => f.type === field.type).indexOf(field)
|
const typeIndex = fields.filter((f) => f.type === field.type).indexOf(field)
|
||||||
|
|
||||||
if (this.field.type === 'heading') {
|
if (field.type === 'heading') {
|
||||||
return `${this.fieldNames[field.type]} ${typeIndex + 1}`
|
return `${this.fieldNames[field.type]} ${typeIndex + 1}`
|
||||||
} else {
|
} else {
|
||||||
return `${this.fieldLabels[field.type]} ${typeIndex + 1}`
|
return `${this.fieldLabels[field.type]} ${typeIndex + 1}`
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
v-for="(icon, type) in fieldIconsSorted"
|
v-for="(icon, type) in fieldIconsSorted"
|
||||||
:key="type"
|
:key="type"
|
||||||
>
|
>
|
||||||
<li v-if="(fieldTypes.length === 0 || fieldTypes.includes(type)) && (withPhone || type != 'phone') && (withPayment || type != 'payment')">
|
<li v-if="(fieldTypes.length === 0 || fieldTypes.includes(type)) && (withPhone || type != 'phone') && (withPayment || type != 'payment') && (withVerification || type != 'verification')">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="text-sm py-1 px-2"
|
class="text-sm py-1 px-2"
|
||||||
@@ -51,11 +51,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { IconTextSize, IconWritingSign, IconCalendarEvent, IconPhoto, IconCheckbox, IconPaperclip, IconSelect, IconCircleDot, IconChecks, IconColumns3, IconPhoneCheck, IconLetterCaseUpper, IconCreditCard, IconRubberStamp, IconSquareNumber1, IconHeading } from '@tabler/icons-vue'
|
import { IconTextSize, IconWritingSign, IconCalendarEvent, IconPhoto, IconCheckbox, IconPaperclip, IconSelect, IconCircleDot, IconChecks, IconColumns3, IconPhoneCheck, IconLetterCaseUpper, IconCreditCard, IconRubberStamp, IconSquareNumber1, IconHeading, IconId } from '@tabler/icons-vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FiledTypeDropdown',
|
name: 'FiledTypeDropdown',
|
||||||
inject: ['withPhone', 'withPayment', 't', 'fieldTypes'],
|
inject: ['withPhone', 'withPayment', 'withVerification', 't', 'fieldTypes'],
|
||||||
props: {
|
props: {
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -111,7 +111,8 @@ export default {
|
|||||||
cells: this.t('cells'),
|
cells: this.t('cells'),
|
||||||
stamp: this.t('stamp'),
|
stamp: this.t('stamp'),
|
||||||
payment: this.t('payment'),
|
payment: this.t('payment'),
|
||||||
phone: this.t('phone')
|
phone: this.t('phone'),
|
||||||
|
verification: this.t('verify_id')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fieldLabels () {
|
fieldLabels () {
|
||||||
@@ -130,7 +131,8 @@ export default {
|
|||||||
cells: this.t('cells_field'),
|
cells: this.t('cells_field'),
|
||||||
stamp: this.t('stamp_field'),
|
stamp: this.t('stamp_field'),
|
||||||
payment: this.t('payment_field'),
|
payment: this.t('payment_field'),
|
||||||
phone: this.t('phone_field')
|
phone: this.t('phone_field'),
|
||||||
|
verification: this.t('verify_id')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fieldIcons () {
|
fieldIcons () {
|
||||||
@@ -150,7 +152,8 @@ export default {
|
|||||||
cells: IconColumns3,
|
cells: IconColumns3,
|
||||||
stamp: IconRubberStamp,
|
stamp: IconRubberStamp,
|
||||||
payment: IconCreditCard,
|
payment: IconCreditCard,
|
||||||
phone: IconPhoneCheck
|
phone: IconPhoneCheck,
|
||||||
|
verification: IconId
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fieldIconsSorted () {
|
fieldIconsSorted () {
|
||||||
|
|||||||
@@ -111,14 +111,14 @@
|
|||||||
:key="type"
|
:key="type"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
v-if="(fieldTypes.length === 0 || fieldTypes.includes(type)) && (withPhone || type != 'phone') && (withPayment || type != 'payment')"
|
v-if="(fieldTypes.length === 0 || fieldTypes.includes(type)) && (withPhone || type != 'phone') && (withPayment || type != 'payment') && (withVerification || type != 'verification')"
|
||||||
draggable="true"
|
draggable="true"
|
||||||
class="field-type-button group flex items-center justify-center border border-dashed w-full rounded relative"
|
class="field-type-button group flex items-center justify-center border border-dashed w-full rounded relative"
|
||||||
:style="{ backgroundColor }"
|
:style="{ backgroundColor }"
|
||||||
:class="drawFieldType === type ? 'border-base-content/40' : 'border-base-300 hover:border-base-content/20'"
|
:class="drawFieldType === type ? 'border-base-content/40' : 'border-base-300 hover:border-base-content/20'"
|
||||||
@dragstart="onDragstart({ type: type })"
|
@dragstart="onDragstart({ type: type })"
|
||||||
@dragend="$emit('drag-end')"
|
@dragend="$emit('drag-end')"
|
||||||
@click="['file', 'payment'].includes(type) ? $emit('add-field', type) : $emit('set-draw-type', type)"
|
@click="['file', 'payment', 'verification'].includes(type) ? $emit('add-field', type) : $emit('set-draw-type', type)"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex items-console transition-all cursor-grab h-full absolute left-0"
|
class="flex items-console transition-all cursor-grab h-full absolute left-0"
|
||||||
@@ -160,6 +160,32 @@
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="withVerification === false && type == 'verification' && (fieldTypes.length === 0 || fieldTypes.includes(type))"
|
||||||
|
class="tooltip tooltip-bottom flex tooltip-bottom-start"
|
||||||
|
:data-tip="t('obtain_qualified_electronic_signature_with_the_trusted_provider_click_to_learn_more')"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://www.docuseal.com/contact"
|
||||||
|
target="_blank"
|
||||||
|
class="opacity-50 flex items-center justify-center border border-dashed border-base-300 w-full rounded relative"
|
||||||
|
:style="{ backgroundColor }"
|
||||||
|
>
|
||||||
|
<div class="w-0 absolute left-0">
|
||||||
|
<IconLock
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
stroke-width="1.5"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center flex-col px-2 py-2">
|
||||||
|
<component :is="icon" />
|
||||||
|
<span class="text-xs mt-1">
|
||||||
|
{{ fieldNames[type] }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -197,12 +223,16 @@ export default {
|
|||||||
IconDrag,
|
IconDrag,
|
||||||
IconLock
|
IconLock
|
||||||
},
|
},
|
||||||
inject: ['save', 'backgroundColor', 'withPhone', 'withPayment', 't', 'fieldsDragFieldRef'],
|
inject: ['save', 'backgroundColor', 'withPhone', 'withVerification', 'withPayment', 't', 'fieldsDragFieldRef'],
|
||||||
props: {
|
props: {
|
||||||
fields: {
|
fields: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
template: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
withHelp: {
|
withHelp: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -354,6 +384,14 @@ export default {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.template.schema.forEach((item) => {
|
||||||
|
(item.conditions || []).forEach((c) => {
|
||||||
|
if (c.field_uuid === field.uuid) {
|
||||||
|
item.conditions.splice(item.conditions.indexOf(c), 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
const en = {
|
const en = {
|
||||||
|
verify_id: 'Verify ID',
|
||||||
|
obtain_qualified_electronic_signature_with_the_trusted_provider_click_to_learn_more: 'Obtain qualified electronic signature (QeS) with the trusted provider. Click to learn more.',
|
||||||
editable: 'Editable',
|
editable: 'Editable',
|
||||||
recurrent: 'Recurrent',
|
recurrent: 'Recurrent',
|
||||||
one_off: 'One-off',
|
one_off: 'One-off',
|
||||||
@@ -126,7 +128,6 @@ const en = {
|
|||||||
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Unlock SMS-verified phone number field with paid plan. Use text field for phone numbers without verification.',
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Unlock SMS-verified phone number field with paid plan. Use text field for phone numbers without verification.',
|
||||||
available_only_in_pro: 'Available only in Pro',
|
available_only_in_pro: 'Available only in Pro',
|
||||||
failed_to_download_files: 'Failed to download files',
|
failed_to_download_files: 'Failed to download files',
|
||||||
signature_is_too_small_please_redraw: 'Signature is too small - please redraw.',
|
|
||||||
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Please add fields for the {submitter_name}. Or, remove the {submitter_name} if not needed.',
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Please add fields for the {submitter_name}. Or, remove the {submitter_name} if not needed.',
|
||||||
draw_field: 'Draw {field} Field',
|
draw_field: 'Draw {field} Field',
|
||||||
replace: 'Replace',
|
replace: 'Replace',
|
||||||
@@ -149,10 +150,14 @@ const en = {
|
|||||||
preferences: 'Preferences',
|
preferences: 'Preferences',
|
||||||
available_in_pro: 'Available in Pro',
|
available_in_pro: 'Available in Pro',
|
||||||
some_fields_are_missing_in_the_formula: 'Some fields are missing in the formula.',
|
some_fields_are_missing_in_the_formula: 'Some fields are missing in the formula.',
|
||||||
learn_more: 'Learn more'
|
learn_more: 'Learn more',
|
||||||
|
and: 'and',
|
||||||
|
or: 'or'
|
||||||
}
|
}
|
||||||
|
|
||||||
const es = {
|
const es = {
|
||||||
|
verify_id: 'Verificar ID',
|
||||||
|
obtain_qualified_electronic_signature_with_the_trusted_provider_click_to_learn_more: 'Obtenga una firma electrónica cualificada (QeS) con el proveedor de confianza. Haga clic para obtener más información.',
|
||||||
recurrent: 'Recurrente',
|
recurrent: 'Recurrente',
|
||||||
one_off: 'Único',
|
one_off: 'Único',
|
||||||
editable: 'Editable',
|
editable: 'Editable',
|
||||||
@@ -277,7 +282,6 @@ const es = {
|
|||||||
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Desbloquea el campo de número de teléfono verificado por SMS con un plan pago. Usa el campo de texto para números de teléfono sin verificación.',
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Desbloquea el campo de número de teléfono verificado por SMS con un plan pago. Usa el campo de texto para números de teléfono sin verificación.',
|
||||||
available_only_in_pro: 'Disponible solo en Pro',
|
available_only_in_pro: 'Disponible solo en Pro',
|
||||||
failed_to_download_files: 'Error al descargar los archivos',
|
failed_to_download_files: 'Error al descargar los archivos',
|
||||||
signature_is_too_small_please_redraw: 'La firma es demasiado pequeña. Por favor, dibújala de nuevo.',
|
|
||||||
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Por favor, añade campos para {submitter_name} o elimina {submitter_name} si no es necesario.',
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Por favor, añade campos para {submitter_name} o elimina {submitter_name} si no es necesario.',
|
||||||
draw_field: 'Dibujar campo {field}',
|
draw_field: 'Dibujar campo {field}',
|
||||||
replace: 'Reemplazar',
|
replace: 'Reemplazar',
|
||||||
@@ -303,10 +307,14 @@ const es = {
|
|||||||
preferences: 'Preferencias',
|
preferences: 'Preferencias',
|
||||||
available_in_pro: 'Disponible en Pro',
|
available_in_pro: 'Disponible en Pro',
|
||||||
some_fields_are_missing_in_the_formula: 'Faltan algunos campos en la fórmula.',
|
some_fields_are_missing_in_the_formula: 'Faltan algunos campos en la fórmula.',
|
||||||
learn_more: 'Aprende más'
|
learn_more: 'Aprende más',
|
||||||
|
and: 'y',
|
||||||
|
or: 'o'
|
||||||
}
|
}
|
||||||
|
|
||||||
const it = {
|
const it = {
|
||||||
|
verify_id: 'Verifica ID',
|
||||||
|
obtain_qualified_electronic_signature_with_the_trusted_provider_click_to_learn_more: 'Ottieni una firma elettronica qualificata (QeS) con il fornitore di fiducia. Clicca per saperne di più.',
|
||||||
ricorrente: 'Ricorrente',
|
ricorrente: 'Ricorrente',
|
||||||
una_volta: 'Una volta',
|
una_volta: 'Una volta',
|
||||||
editable: 'Modificabile',
|
editable: 'Modificabile',
|
||||||
@@ -434,7 +442,6 @@ const it = {
|
|||||||
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Sblocca il campo numero di telefono verificato tramite SMS con un piano a pagamento. Usa il campo di testo per numeri di telefono senza verifica.',
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Sblocca il campo numero di telefono verificato tramite SMS con un piano a pagamento. Usa il campo di testo per numeri di telefono senza verifica.',
|
||||||
available_only_in_pro: 'Disponibile solo in Pro',
|
available_only_in_pro: 'Disponibile solo in Pro',
|
||||||
failed_to_download_files: 'Impossibile scaricare i file',
|
failed_to_download_files: 'Impossibile scaricare i file',
|
||||||
signature_is_too_small_please_redraw: 'La firma è troppo piccola. Ridisegnala per favore.',
|
|
||||||
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Aggiungi campi per {submitter_name} o rimuovi {submitter_name} se non necessario.',
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Aggiungi campi per {submitter_name} o rimuovi {submitter_name} se non necessario.',
|
||||||
draw_field: 'Disegna il campo {field}',
|
draw_field: 'Disegna il campo {field}',
|
||||||
replace: 'Sostituisci',
|
replace: 'Sostituisci',
|
||||||
@@ -457,10 +464,14 @@ const it = {
|
|||||||
preferences: 'Preferenze',
|
preferences: 'Preferenze',
|
||||||
available_in_pro: 'Disponibile in Pro',
|
available_in_pro: 'Disponibile in Pro',
|
||||||
some_fields_are_missing_in_the_formula: 'Alcuni campi mancano nella formula.',
|
some_fields_are_missing_in_the_formula: 'Alcuni campi mancano nella formula.',
|
||||||
learn_more: 'Scopri di più'
|
learn_more: 'Scopri di più',
|
||||||
|
and: 'e',
|
||||||
|
or: 'o'
|
||||||
}
|
}
|
||||||
|
|
||||||
const pt = {
|
const pt = {
|
||||||
|
verify_id: 'Verificar ID',
|
||||||
|
obtain_qualified_electronic_signature_with_the_trusted_provider_click_to_learn_more: 'Obtenha a assinatura eletrônica qualificada (QeS) com o provedor confiável. Clique para saber mais.',
|
||||||
recurrent: 'Recurrente',
|
recurrent: 'Recurrente',
|
||||||
one_off: 'Único',
|
one_off: 'Único',
|
||||||
editable: 'Editável',
|
editable: 'Editável',
|
||||||
@@ -585,7 +596,6 @@ const pt = {
|
|||||||
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Desbloqueie o campo de número de telefone verificado por SMS com um plano pago. Use o campo de texto para números de telefone sem verificação.',
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Desbloqueie o campo de número de telefone verificado por SMS com um plano pago. Use o campo de texto para números de telefone sem verificação.',
|
||||||
available_only_in_pro: 'Disponível apenas no Pro',
|
available_only_in_pro: 'Disponível apenas no Pro',
|
||||||
failed_to_download_files: 'Falha ao baixar arquivos',
|
failed_to_download_files: 'Falha ao baixar arquivos',
|
||||||
signature_is_too_small_please_redraw: 'A assinatura é muito pequena. Por favor, redesenhe.',
|
|
||||||
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Adicione campos para {submitter_name} ou remova {submitter_name} se não for necessário.',
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Adicione campos para {submitter_name} ou remova {submitter_name} se não for necessário.',
|
||||||
draw_field: 'Desenhar campo {field}',
|
draw_field: 'Desenhar campo {field}',
|
||||||
replace: 'Substituir',
|
replace: 'Substituir',
|
||||||
@@ -611,10 +621,14 @@ const pt = {
|
|||||||
preferences: 'Preferências',
|
preferences: 'Preferências',
|
||||||
available_in_pro: 'Disponível no Pro',
|
available_in_pro: 'Disponível no Pro',
|
||||||
some_fields_are_missing_in_the_formula: 'Faltam alguns campos na fórmula.',
|
some_fields_are_missing_in_the_formula: 'Faltam alguns campos na fórmula.',
|
||||||
learn_more: 'Saiba mais'
|
learn_more: 'Saiba mais',
|
||||||
|
and: 'e',
|
||||||
|
or: 'ou'
|
||||||
}
|
}
|
||||||
|
|
||||||
const fr = {
|
const fr = {
|
||||||
|
verify_id: "Vérifier l'ID",
|
||||||
|
obtain_qualified_electronic_signature_with_the_trusted_provider_click_to_learn_more: 'Obtenez une signature électronique qualifiée (QeS) avec le fournisseur de confiance. Cliquez pour en savoir plus.',
|
||||||
recurrent: 'Récurrent',
|
recurrent: 'Récurrent',
|
||||||
one_off: 'Ponctuel',
|
one_off: 'Ponctuel',
|
||||||
editable: 'Éditable',
|
editable: 'Éditable',
|
||||||
@@ -739,7 +753,6 @@ const fr = {
|
|||||||
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Débloquez le champ de numéro de téléphone vérifié par SMS avec un plan payant. Utilisez un champ texte pour les numéros de téléphone sans vérification.',
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Débloquez le champ de numéro de téléphone vérifié par SMS avec un plan payant. Utilisez un champ texte pour les numéros de téléphone sans vérification.',
|
||||||
available_only_in_pro: 'Disponible uniquement en Pro',
|
available_only_in_pro: 'Disponible uniquement en Pro',
|
||||||
failed_to_download_files: 'Échec du téléchargement des fichiers',
|
failed_to_download_files: 'Échec du téléchargement des fichiers',
|
||||||
signature_is_too_small_please_redraw: 'La signature est trop petite. Veuillez la redessiner.',
|
|
||||||
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Veuillez ajouter des champs pour {submitter_name} ou retirer {submitter_name} si ce n\'est pas nécessaire.',
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Veuillez ajouter des champs pour {submitter_name} ou retirer {submitter_name} si ce n\'est pas nécessaire.',
|
||||||
draw_field: 'Dessiner le champ {field}',
|
draw_field: 'Dessiner le champ {field}',
|
||||||
replace: 'Remplacer',
|
replace: 'Remplacer',
|
||||||
@@ -765,10 +778,14 @@ const fr = {
|
|||||||
preferences: 'Préférences',
|
preferences: 'Préférences',
|
||||||
available_in_pro: 'Disponible en version Pro',
|
available_in_pro: 'Disponible en version Pro',
|
||||||
some_fields_are_missing_in_the_formula: 'Certains champs manquent dans la formule.',
|
some_fields_are_missing_in_the_formula: 'Certains champs manquent dans la formule.',
|
||||||
learn_more: 'En savoir plus'
|
learn_more: 'En savoir plus',
|
||||||
|
and: 'et',
|
||||||
|
or: 'ou'
|
||||||
}
|
}
|
||||||
|
|
||||||
const de = {
|
const de = {
|
||||||
|
verify_id: 'ID überprüfen',
|
||||||
|
obtain_qualified_electronic_signature_with_the_trusted_provider_click_to_learn_more: 'Erhalten Sie eine qualifizierte elektronische Signatur (QeS) beim vertrauenswürdigen Anbieter. Klicken Sie hier, um mehr zu erfahren.',
|
||||||
wiederkehrend: 'Wiederkehrend',
|
wiederkehrend: 'Wiederkehrend',
|
||||||
einmalig: 'Einmalig',
|
einmalig: 'Einmalig',
|
||||||
editable: 'Bearbeitbar',
|
editable: 'Bearbeitbar',
|
||||||
@@ -893,7 +910,6 @@ const de = {
|
|||||||
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Schalte das SMS-verifizierte Telefonnummernfeld mit einem kostenpflichtigen Plan frei. Verwende das Textfeld für Telefonnummern ohne Verifizierung.',
|
unlock_sms_verified_phone_number_field_with_paid_plan_use_text_field_for_phone_numbers_without_verification: 'Schalte das SMS-verifizierte Telefonnummernfeld mit einem kostenpflichtigen Plan frei. Verwende das Textfeld für Telefonnummern ohne Verifizierung.',
|
||||||
available_only_in_pro: 'Nur in Pro verfügbar',
|
available_only_in_pro: 'Nur in Pro verfügbar',
|
||||||
failed_to_download_files: 'Fehler beim Herunterladen der Dateien',
|
failed_to_download_files: 'Fehler beim Herunterladen der Dateien',
|
||||||
signature_is_too_small_please_redraw: 'Die Unterschrift ist zu klein. Bitte erneut zeichnen.',
|
|
||||||
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Bitte füge Felder für {submitter_name} hinzu oder entferne {submitter_name}, falls nicht erforderlich.',
|
please_add_fields_for_the_submitter_name_or_remove_the_submitter_name_if_not_needed: 'Bitte füge Felder für {submitter_name} hinzu oder entferne {submitter_name}, falls nicht erforderlich.',
|
||||||
draw_field: 'Feld {field} zeichnen',
|
draw_field: 'Feld {field} zeichnen',
|
||||||
replace: 'Ersetzen',
|
replace: 'Ersetzen',
|
||||||
@@ -919,7 +935,9 @@ const de = {
|
|||||||
preferences: 'Einstellungen',
|
preferences: 'Einstellungen',
|
||||||
available_in_pro: 'In Pro verfügbar',
|
available_in_pro: 'In Pro verfügbar',
|
||||||
some_fields_are_missing_in_the_formula: 'Einige Felder fehlen in der Formel.',
|
some_fields_are_missing_in_the_formula: 'Einige Felder fehlen in der Formel.',
|
||||||
learn_more: 'Erfahren Sie mehr'
|
learn_more: 'Erfahren Sie mehr',
|
||||||
|
and: 'und',
|
||||||
|
or: 'oder'
|
||||||
}
|
}
|
||||||
|
|
||||||
export { en, es, it, pt, fr, de }
|
export { en, es, it, pt, fr, de }
|
||||||
@@ -279,7 +279,11 @@ export default {
|
|||||||
|
|
||||||
this.mappings.forEach((mapping) => {
|
this.mappings.forEach((mapping) => {
|
||||||
if (mapping.field_name && mapping.column_index != null) {
|
if (mapping.field_name && mapping.column_index != null) {
|
||||||
submittersIndex[mapping.submitter_uuid] ||= { uuid: mapping.submitter_uuid, fields: [] }
|
submittersIndex[mapping.submitter_uuid] ||= {
|
||||||
|
uuid: mapping.submitter_uuid,
|
||||||
|
role: this.submitters.find((s) => s.uuid === mapping.submitter_uuid).name,
|
||||||
|
fields: []
|
||||||
|
}
|
||||||
|
|
||||||
if (['name', 'email', 'phone', 'external_id'].includes(mapping.field_name.toLowerCase())) {
|
if (['name', 'email', 'phone', 'external_id'].includes(mapping.field_name.toLowerCase())) {
|
||||||
submittersIndex[mapping.submitter_uuid][mapping.field_name.toLowerCase()] = row[mapping.column_index]
|
submittersIndex[mapping.submitter_uuid][mapping.field_name.toLowerCase()] = row[mapping.column_index]
|
||||||
@@ -296,7 +300,7 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (Object.keys(submittersIndex).length !== 0) {
|
if (Object.keys(submittersIndex).length !== 0) {
|
||||||
submissions.push({ submitters: Object.values(submittersIndex) })
|
submissions.push({ submitters: this.submitters.map((s) => submittersIndex[s.uuid]).filter(Boolean) })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="absolute text-center w-full bottom-0 pr-3 mb-4">
|
<div class="absolute text-center w-full bottom-0 pr-3 mb-4">
|
||||||
<span class="w-full bg-base-200 px-4 py-2 rounded-md inline-flex space-x-2 mx-auto items-center justify-between mb-2 z-20 md:hidden">
|
<span class="w-full bg-base-200 px-4 py-2 rounded-md inline-flex space-x-2 mx-auto items-center justify-between mb-2 z-20">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<component
|
<component
|
||||||
:is="fieldIcons[drawField.type]"
|
:is="fieldIcons[drawField.type]"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<span
|
<span
|
||||||
class="dropdown dropdown-top dropdown-end absolute bottom-4 right-4 z-10 md:hidden"
|
class="dropdown dropdown-top dropdown-end absolute bottom-4 right-4 z-10"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
class="btn btn-neutral text-white btn-circle btn-lg group"
|
class="btn btn-neutral text-white btn-circle btn-lg group"
|
||||||
@@ -12,9 +12,10 @@
|
|||||||
height="28"
|
height="28"
|
||||||
/>
|
/>
|
||||||
<IconX
|
<IconX
|
||||||
class="hidden group-focus:inline"
|
class="hidden group-focus:inline p-3"
|
||||||
width="28"
|
width="64"
|
||||||
height="28"
|
height="50"
|
||||||
|
@click="closeDropdown"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<ul
|
<ul
|
||||||
@@ -55,7 +56,7 @@
|
|||||||
v-for="(icon, type) in fieldIconsSorted"
|
v-for="(icon, type) in fieldIconsSorted"
|
||||||
:key="type"
|
:key="type"
|
||||||
>
|
>
|
||||||
<li v-if="(fieldTypes.length === 0 || fieldTypes.includes(type)) && (withPhone || type != 'phone') && (withPayment || type != 'payment')">
|
<li v-if="(fieldTypes.length === 0 || fieldTypes.includes(type)) && (withPhone || type != 'phone') && (withPayment || type != 'payment') && (withVerification || type != 'verification')">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="text-sm py-1 px-2"
|
class="text-sm py-1 px-2"
|
||||||
@@ -85,7 +86,7 @@ export default {
|
|||||||
IconPlus,
|
IconPlus,
|
||||||
IconX
|
IconX
|
||||||
},
|
},
|
||||||
inject: ['withPhone', 'withPayment', 'backgroundColor', 't'],
|
inject: ['withPhone', 'withPayment', 'withVerification', 'backgroundColor', 't'],
|
||||||
props: {
|
props: {
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@@ -9,14 +9,30 @@
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="group flex justify-end cursor-pointer top-0 bottom-0 left-0 right-0 absolute p-1"
|
class="group flex justify-end cursor-pointer top-0 bottom-0 left-0 right-0 absolute p-1 hover:bg-black/10 transition-colors"
|
||||||
@click="$emit('scroll-to', item)"
|
@click="$emit('scroll-to', item)"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="editable"
|
v-if="editable"
|
||||||
class="flex justify-between w-full"
|
class="flex justify-between w-full"
|
||||||
>
|
>
|
||||||
<div style="width: 26px" />
|
<div
|
||||||
|
style="width: 26px"
|
||||||
|
class="flex flex-col justify-between group-hover:opacity-100"
|
||||||
|
:class="{'opacity-0': !item.conditions?.length }"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="btn border-base-200 bg-white text-base-content btn-xs rounded hover:text-base-100 hover:bg-base-content hover:border-base-content w-full transition-colors p-0"
|
||||||
|
@click.stop="isShowConditionsModal = true"
|
||||||
|
>
|
||||||
|
<IconRouteAltLeft
|
||||||
|
:width="14"
|
||||||
|
:stroke-width="1.6"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<ReplaceButton
|
<ReplaceButton
|
||||||
v-if="withReplaceButton"
|
v-if="withReplaceButton"
|
||||||
@@ -73,19 +89,36 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Teleport
|
||||||
|
v-if="isShowConditionsModal"
|
||||||
|
:to="modalContainerEl"
|
||||||
|
>
|
||||||
|
<ConditionsModal
|
||||||
|
:item="item"
|
||||||
|
:build-default-name="buildDefaultName"
|
||||||
|
@close="isShowConditionsModal = false"
|
||||||
|
/>
|
||||||
|
</Teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Contenteditable from './contenteditable'
|
import Contenteditable from './contenteditable'
|
||||||
import Upload from './upload'
|
import Upload from './upload'
|
||||||
|
import { IconRouteAltLeft } from '@tabler/icons-vue'
|
||||||
|
import ConditionsModal from './conditions_modal'
|
||||||
import ReplaceButton from './replace'
|
import ReplaceButton from './replace'
|
||||||
|
import Field from './field'
|
||||||
|
import FieldType from './field_type'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DocumentPreview',
|
name: 'DocumentPreview',
|
||||||
components: {
|
components: {
|
||||||
Contenteditable,
|
Contenteditable,
|
||||||
|
IconRouteAltLeft,
|
||||||
|
ConditionsModal,
|
||||||
ReplaceButton
|
ReplaceButton
|
||||||
},
|
},
|
||||||
|
inject: ['t'],
|
||||||
props: {
|
props: {
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -121,13 +154,24 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['scroll-to', 'change', 'remove', 'up', 'down', 'replace'],
|
emits: ['scroll-to', 'change', 'remove', 'up', 'down', 'replace'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isShowConditionsModal: false
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
fieldNames: FieldType.computed.fieldNames,
|
||||||
|
fieldLabels: FieldType.computed.fieldLabels,
|
||||||
previewImage () {
|
previewImage () {
|
||||||
return [...this.document.preview_images].sort((a, b) => parseInt(a.filename) - parseInt(b.filename))[0]
|
return [...this.document.preview_images].sort((a, b) => parseInt(a.filename) - parseInt(b.filename))[0]
|
||||||
|
},
|
||||||
|
modalContainerEl () {
|
||||||
|
return this.$el.getRootNode().querySelector('#docuseal_modal_container')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
upload: Upload.methods.upload,
|
upload: Upload.methods.upload,
|
||||||
|
buildDefaultName: Field.methods.buildDefaultName,
|
||||||
onUpdateName (value) {
|
onUpdateName (value) {
|
||||||
this.item.name = value
|
this.item.name = value
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,6 @@ class ProcessSubmitterCompletionJob
|
|||||||
|
|
||||||
is_all_completed = !submitter.submission.submitters.exists?(completed_at: nil)
|
is_all_completed = !submitter.submission.submitters.exists?(completed_at: nil)
|
||||||
|
|
||||||
if !is_all_completed && submitter.submission.submitters_order_preserved?
|
|
||||||
enqueue_next_submitter_request_notification(submitter)
|
|
||||||
end
|
|
||||||
|
|
||||||
Submissions::EnsureResultGenerated.call(submitter)
|
Submissions::EnsureResultGenerated.call(submitter)
|
||||||
|
|
||||||
if is_all_completed && submitter.completed_at == submitter.submission.submitters.maximum(:completed_at)
|
if is_all_completed && submitter.completed_at == submitter.submission.submitters.maximum(:completed_at)
|
||||||
@@ -28,6 +24,10 @@ class ProcessSubmitterCompletionJob
|
|||||||
|
|
||||||
create_completed_documents!(submitter)
|
create_completed_documents!(submitter)
|
||||||
|
|
||||||
|
if !is_all_completed && submitter.submission.submitters_order_preserved? && params['send_invitation_email'] != false
|
||||||
|
enqueue_next_submitter_request_notification(submitter)
|
||||||
|
end
|
||||||
|
|
||||||
enqueue_completed_webhooks(submitter, is_all_completed:)
|
enqueue_completed_webhooks(submitter, is_all_completed:)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class ApplicationMailer < ActionMailer::Base
|
|||||||
after_action :set_message_uuid
|
after_action :set_message_uuid
|
||||||
|
|
||||||
def default_url_options
|
def default_url_options
|
||||||
Docuseal.default_url_options
|
Docuseal.default_url_options.merge(host: ENV.fetch('EMAIL_HOST', Docuseal.default_url_options[:host]))
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_message_metadata
|
def set_message_metadata
|
||||||
|
|||||||
@@ -106,8 +106,11 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
|
|
||||||
@email_config = AccountConfigs.find_for_account(@current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY)
|
@email_config = AccountConfigs.find_for_account(@current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY)
|
||||||
|
|
||||||
@documents = add_completed_email_attachments!(
|
add_completed_email_attachments!(
|
||||||
submitter, with_audit_log: @submitter.template.preferences['documents_copy_email_attach_audit'] != false &&
|
submitter,
|
||||||
|
with_documents: @submitter.template.preferences['documents_copy_email_attach_documents'] != false &&
|
||||||
|
(@email_config.nil? || @email_config.value['attach_documents'] != false),
|
||||||
|
with_audit_log: @submitter.template.preferences['documents_copy_email_attach_audit'] != false &&
|
||||||
(@email_config.nil? || @email_config.value['attach_audit_log'] != false)
|
(@email_config.nil? || @email_config.value['attach_audit_log'] != false)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -152,6 +155,9 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
def add_completed_email_attachments!(submitter, with_audit_log: true, with_documents: true)
|
def add_completed_email_attachments!(submitter, with_audit_log: true, with_documents: true)
|
||||||
documents = with_documents ? Submitters.select_attachments_for_download(submitter) : []
|
documents = with_documents ? Submitters.select_attachments_for_download(submitter) : []
|
||||||
|
|
||||||
|
filename_format = AccountConfig.find_or_initialize_by(account_id: submitter.account_id,
|
||||||
|
key: AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY)&.value
|
||||||
|
|
||||||
total_size = 0
|
total_size = 0
|
||||||
audit_trail_data = nil
|
audit_trail_data = nil
|
||||||
|
|
||||||
@@ -161,9 +167,14 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
total_size = audit_trail_data.size
|
total_size = audit_trail_data.size
|
||||||
end
|
end
|
||||||
|
|
||||||
total_size = add_attachments_with_size_limit(documents, total_size)
|
total_size = add_attachments_with_size_limit(submitter, documents, total_size, filename_format)
|
||||||
|
|
||||||
attachments[submitter.submission.audit_trail.filename.to_s.tr('"', "'")] = audit_trail_data if audit_trail_data
|
if audit_trail_data
|
||||||
|
audit_trail_filename =
|
||||||
|
Submitters.build_document_filename(submitter, submitter.submission.audit_trail.blob, filename_format)
|
||||||
|
|
||||||
|
attachments[audit_trail_filename.tr('"', "'")] = audit_trail_data
|
||||||
|
end
|
||||||
|
|
||||||
if with_documents
|
if with_documents
|
||||||
file_fields = submitter.submission.template_fields.select { |e| e['type'].in?(%w[file payment]) }
|
file_fields = submitter.submission.template_fields.select { |e| e['type'].in?(%w[file payment]) }
|
||||||
@@ -172,7 +183,7 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
storage_attachments =
|
storage_attachments =
|
||||||
submitter.attachments.where(uuid: submitter.values.values_at(*file_fields.pluck('uuid')).flatten)
|
submitter.attachments.where(uuid: submitter.values.values_at(*file_fields.pluck('uuid')).flatten)
|
||||||
|
|
||||||
add_attachments_with_size_limit(storage_attachments, total_size)
|
add_attachments_with_size_limit(submitter, storage_attachments, total_size)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -183,7 +194,7 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
user.role == 'integration' ? user.friendly_name.sub(/\+\w+@/, '@') : user.friendly_name
|
user.role == 'integration' ? user.friendly_name.sub(/\+\w+@/, '@') : user.friendly_name
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_attachments_with_size_limit(storage_attachments, current_size)
|
def add_attachments_with_size_limit(submitter, storage_attachments, current_size, filename_format = nil)
|
||||||
total_size = current_size
|
total_size = current_size
|
||||||
|
|
||||||
storage_attachments.each do |attachment|
|
storage_attachments.each do |attachment|
|
||||||
@@ -191,7 +202,8 @@ class SubmitterMailer < ApplicationMailer
|
|||||||
|
|
||||||
break if total_size >= MAX_ATTACHMENTS_SIZE
|
break if total_size >= MAX_ATTACHMENTS_SIZE
|
||||||
|
|
||||||
attachments[attachment.filename.to_s.tr('"', "'")] = attachment.download
|
filename = Submitters.build_document_filename(submitter, attachment.blob, filename_format)
|
||||||
|
attachments[filename.to_s.tr('"', "'")] = attachment.download
|
||||||
end
|
end
|
||||||
|
|
||||||
total_size
|
total_size
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ class AccountConfig < ApplicationRecord
|
|||||||
REQUIRE_SIGNING_REASON_KEY = 'require_signing_reason'
|
REQUIRE_SIGNING_REASON_KEY = 'require_signing_reason'
|
||||||
REUSE_SIGNATURE_KEY = 'reuse_signature'
|
REUSE_SIGNATURE_KEY = 'reuse_signature'
|
||||||
COMBINE_PDF_RESULT_KEY = 'combine_pdf_result_key'
|
COMBINE_PDF_RESULT_KEY = 'combine_pdf_result_key'
|
||||||
|
DOCUMENT_FILENAME_FORMAT_KEY = 'document_filename_format'
|
||||||
|
POLICY_LINKS_KEY = 'policy_links'
|
||||||
|
|
||||||
DEFAULT_VALUES = {
|
DEFAULT_VALUES = {
|
||||||
SUBMITTER_INVITATION_EMAIL_KEY => lambda {
|
SUBMITTER_INVITATION_EMAIL_KEY => lambda {
|
||||||
|
|||||||
@@ -57,13 +57,18 @@ class Submission < ApplicationRecord
|
|||||||
|
|
||||||
has_many_attached :preview_documents
|
has_many_attached :preview_documents
|
||||||
|
|
||||||
|
has_many :template_accesses, primary_key: :template_id, foreign_key: :template_id, dependent: nil, inverse_of: false
|
||||||
|
|
||||||
has_many :template_schema_documents,
|
has_many :template_schema_documents,
|
||||||
->(e) { where(uuid: (e.template_schema.presence || e.template.schema).pluck('attachment_uuid')) },
|
->(e) { where(uuid: (e.template_schema.presence || e.template.schema).pluck('attachment_uuid')) },
|
||||||
through: :template, source: :documents_attachments
|
through: :template, source: :documents_attachments
|
||||||
|
|
||||||
scope :active, -> { where(archived_at: nil) }
|
scope :active, -> { where(archived_at: nil) }
|
||||||
scope :pending, -> { joins(:submitters).where(submitters: { completed_at: nil }).distinct }
|
scope :pending, -> { joins(:submitters).where(submitters: { completed_at: nil }).group(:id) }
|
||||||
scope :completed, -> { where.not(id: pending.select(:submission_id)) }
|
scope :completed, lambda {
|
||||||
|
where.not(Submitter.where(Submitter.arel_table[:submission_id].eq(Submission.arel_table[:id])
|
||||||
|
.and(Submitter.arel_table[:completed_at].eq(nil))).select(1).arel.exists)
|
||||||
|
}
|
||||||
|
|
||||||
enum :source, {
|
enum :source, {
|
||||||
invite: 'invite',
|
invite: 'invite',
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ class SubmissionEvent < ApplicationRecord
|
|||||||
click_sms: 'click_sms',
|
click_sms: 'click_sms',
|
||||||
phone_verified: 'phone_verified',
|
phone_verified: 'phone_verified',
|
||||||
start_form: 'start_form',
|
start_form: 'start_form',
|
||||||
|
start_verification: 'start_verification',
|
||||||
|
complete_verification: 'complete_verification',
|
||||||
view_form: 'view_form',
|
view_form: 'view_form',
|
||||||
invite_party: 'invite_party',
|
invite_party: 'invite_party',
|
||||||
complete_form: 'complete_form',
|
complete_form: 'complete_form',
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ class Submitter < ApplicationRecord
|
|||||||
|
|
||||||
has_many_attached :documents
|
has_many_attached :documents
|
||||||
has_many_attached :attachments
|
has_many_attached :attachments
|
||||||
|
has_many_attached :preview_documents
|
||||||
|
has_many :template_accesses, through: :template
|
||||||
|
|
||||||
has_many :document_generation_events, dependent: :destroy
|
has_many :document_generation_events, dependent: :destroy
|
||||||
has_many :submission_events, dependent: :destroy
|
has_many :submission_events, dependent: :destroy
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class Template < ApplicationRecord
|
|||||||
|
|
||||||
has_many :submissions, dependent: :destroy
|
has_many :submissions, dependent: :destroy
|
||||||
has_many :template_sharings, dependent: :destroy
|
has_many :template_sharings, dependent: :destroy
|
||||||
|
has_many :template_accesses, dependent: :destroy
|
||||||
|
|
||||||
scope :active, -> { where(archived_at: nil) }
|
scope :active, -> { where(archived_at: nil) }
|
||||||
scope :archived, -> { where.not(archived_at: nil) }
|
scope :archived, -> { where.not(archived_at: nil) }
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: template_accesses
|
||||||
|
#
|
||||||
|
# id :bigint not null, primary key
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# template_id :bigint not null
|
||||||
|
# user_id :bigint not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_template_accesses_on_template_id_and_user_id (template_id,user_id) UNIQUE
|
||||||
|
#
|
||||||
|
# Foreign Keys
|
||||||
|
#
|
||||||
|
# fk_rails_... (template_id => templates.id)
|
||||||
|
#
|
||||||
|
class TemplateAccess < ApplicationRecord
|
||||||
|
ADMIN_USER_ID = -1
|
||||||
|
|
||||||
|
belongs_to :template
|
||||||
|
belongs_to :user, optional: true
|
||||||
|
end
|
||||||
@@ -164,6 +164,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::DOCUMENT_FILENAME_FORMAT_KEY) %>
|
||||||
|
<% if can?(:manage, account_config) %>
|
||||||
|
<%= form_for account_config, url: account_configs_path, method: :post do |f| %>
|
||||||
|
<%= f.hidden_field :key %>
|
||||||
|
<div class="py-2.5">
|
||||||
|
<span>
|
||||||
|
<%= t('document_download_filename_format') %>
|
||||||
|
</span>
|
||||||
|
<div class="mt-3">
|
||||||
|
<%= f.select :value, [["#{I18n.t('document_name')}.pdf", '{document.name}'], ["#{I18n.t('document_name')} - name@domain.com.pdf", '{document.name} - {submission.submitters}'], ["#{I18n.t('document_name')} - name@domain.com - #{I18n.l(Time.current.beginning_of_year.in_time_zone(current_account.timezone), format: :short)}.pdf", '{document.name} - {submission.submitters} - {submission.completed_at}']], {}, class: 'base-select', onchange: 'this.form.requestSubmit()' %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M11.5 21h-5.5a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v6" />
|
||||||
|
<path d="M16 3v4" />
|
||||||
|
<path d="M8 3v4" />
|
||||||
|
<path d="M4 11h16" />
|
||||||
|
<path d="M15 19l2 2l4 -4" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 464 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M4 4h16v2.172a2 2 0 0 1 -.586 1.414l-4.414 4.414v7l-6 2v-8.5l-4.48 -4.928a2 2 0 0 1 -.52 -1.345v-2.227z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 400 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" width="24" height="24" stroke-width="2">
|
||||||
|
<path d="M18 6l-12 12"></path>
|
||||||
|
<path d="M6 6l12 12"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 290 B |
@@ -1,4 +1,4 @@
|
|||||||
<title>
|
<title>
|
||||||
<%= content_for(:html_title) || 'DocuSeal | Open Source Document Signing' %>
|
<%= content_for(:html_title) || (signed_in? ? 'DocuSeal' : 'DocuSeal | Open Source Document Signing') %>
|
||||||
</title>
|
</title>
|
||||||
<%= render 'shared/meta' %>
|
<%= render 'shared/meta' %>
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="collapse-content">
|
<div class="collapse-content">
|
||||||
<%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
|
<%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
|
||||||
<%= f.hidden_field :key %>
|
<%= f.hidden_field :key %>
|
||||||
<%= f.fields_for :value, Struct.new(:subject, :body, :attach_audit_log).new(*f.object.value.values_at('subject', 'body', 'attach_audit_log')) do |ff| %>
|
<%= f.fields_for :value, Struct.new(:subject, :body, :attach_audit_log, :attach_documents).new(*f.object.value.values_at('subject', 'body', 'attach_audit_log', 'attach_documents')) do |ff| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :subject, t('subject'), class: 'label' %>
|
<%= ff.label :subject, t('subject'), class: 'label' %>
|
||||||
<%= ff.text_field :subject, required: true, class: 'base-input', dir: 'auto' %>
|
<%= ff.text_field :subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
@@ -24,7 +24,13 @@
|
|||||||
<%= ff.text_area :body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
<%= ff.text_area :body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
||||||
</autoresize-textarea>
|
</autoresize-textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between py-2.5 mx-1">
|
<div class="flex items-center justify-between pt-2.5 mx-1">
|
||||||
|
<span>
|
||||||
|
<%= t('attach_documents') %>
|
||||||
|
</span>
|
||||||
|
<%= ff.check_box :attach_documents, { checked: ff.object.attach_documents != false, class: 'toggle' }, 'true', 'false' %>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between pb-2.5 mx-1">
|
||||||
<span>
|
<span>
|
||||||
<%= t('attach_audit_log_pdf') %>
|
<%= t('attach_audit_log_pdf') %>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<% unless Docuseal.multitenant? %>
|
||||||
|
<div class="collapse collapse-plus bg-base-200 mt-4">
|
||||||
|
<input type="checkbox">
|
||||||
|
<div class="collapse-title text-xl font-medium">
|
||||||
|
<div>
|
||||||
|
<%= t('policy_links') %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="collapse-content">
|
||||||
|
<%= form_for AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::POLICY_LINKS_KEY), url: settings_personalization_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
|
||||||
|
<%= f.hidden_field :key %>
|
||||||
|
<div class="form-control">
|
||||||
|
<autoresize-textarea>
|
||||||
|
<%= f.text_area :value, class: 'base-input w-full py-2 font-mono', placeholder: "#{t('markdown_content_e_g')}\n[#{t('privacy_policy')}](https://example.com/privacy)" %>
|
||||||
|
</autoresize-textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-control pt-2">
|
||||||
|
<%= f.button button_title(title: t('save'), disabled_with: t('saving')), class: 'base-button' %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<%= render 'form_completed_message_form' %>
|
<%= render 'form_completed_message_form' %>
|
||||||
<%= render 'form_completed_button_form' %>
|
<%= render 'form_completed_button_form' %>
|
||||||
|
<%= render 'form_policy_links_form' %>
|
||||||
</div>
|
</div>
|
||||||
<%= render 'form_customization_settings' %>
|
<%= render 'form_customization_settings' %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
---
|
---
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<%= t('sent_using_product_name_free_document_signing_html', product_url: "#{Docuseal::PRODUCT_URL}/start", product_name: Docuseal.product_name) %>
|
<%= t('sent_using_product_name_free_document_signing_html', product_url: "#{Docuseal::PRODUCT_EMAIL_URL}/start", product_name: Docuseal.product_name) %>
|
||||||
</p>
|
</p>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<% if Docuseal.demo? || (request.path != '/' && !devise_controller?) %>
|
<% if Docuseal.demo? || (request.path != '/' && !devise_controller?) %>
|
||||||
<meta name="robots" content="noindex">
|
<meta name="robots" content="noindex">
|
||||||
<% end %>
|
<% end %>
|
||||||
<% title = content_for(:html_title) || 'DocuSeal | Open Source Document Filling and Signing' %>
|
<% title = content_for(:html_title) || (signed_in? ? 'DocuSeal' : 'DocuSeal | Open Source Document Signing') %>
|
||||||
<% description = content_for(:html_description) || 'Open source, self-hosted tool to streamline document filling and signing. Create custom PDF forms to complete and sign with an easy to use online tool.' %>
|
<% description = content_for(:html_description) || 'Open source, self-hosted tool to streamline document filling and signing. Create custom PDF forms to complete and sign with an easy to use online tool.' %>
|
||||||
<meta name="description" content="<%= description %>">
|
<meta name="description" content="<%= description %>">
|
||||||
<meta property="og:title" content="<%= title %>">
|
<meta property="og:title" content="<%= title %>">
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
<% if params[:status].present? %>
|
<% if params[:status].present? %>
|
||||||
<input name="status" value="<%= params[:status] %>" class="hidden">
|
<input name="status" value="<%= params[:status] %>" class="hidden">
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% Submissions::Filter::ALLOWED_PARAMS.each do |key| %>
|
||||||
|
<% if params[key].present? %>
|
||||||
|
<input name="<%= key %>" value="<%= params[key] %>" class="hidden">
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
<% if params[:q].present? %>
|
<% if params[:q].present? %>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<a href="<%= url_for(params.to_unsafe_h.except(:q)) %>" title="<%= t('clear') %>" class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-auto text-neutral text-2xl font-extralight">
|
<a href="<%= url_for(params.to_unsafe_h.except(:q)) %>" title="<%= t('clear') %>" class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-auto text-neutral text-2xl font-extralight">
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% unless @template.archived_at? %>
|
<% if !@template.archived_at? && !@template.account.archived_at? %>
|
||||||
<%= form_for @submitter, url: start_form_path(@template.slug), data: { turbo_frame: :_top }, method: :put, html: { class: 'space-y-4' } do |f| %>
|
<%= form_for @submitter, url: start_form_path(@template.slug), data: { turbo_frame: :_top }, method: :put, html: { class: 'space-y-4' } do |f| %>
|
||||||
<div dir="auto" class="form-control !mt-0">
|
<div dir="auto" class="form-control !mt-0">
|
||||||
<%= f.label :email, t('email'), class: 'label' %>
|
<%= f.label :email, t('email'), class: 'label' %>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<% can_send_emails = Accounts.can_send_emails?(current_account) %>
|
<% can_send_emails = Accounts.can_send_emails?(current_account) %>
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<%= f.label :send_email, for: uuid = SecureRandom.uuid, class: 'flex items-center cursor-pointer' do %>
|
<%= f.label :send_email, for: uuid = SecureRandom.uuid, class: 'flex items-center cursor-pointer' do %>
|
||||||
<%= f.check_box :send_email, id: uuid, class: 'base-checkbox', disabled: !can_send_emails, checked: can_send_emails && !local_assigns.key?(:resend_email) %>
|
<%= f.check_box :send_email, id: uuid, class: 'base-checkbox', disabled: !can_send_emails || local_assigns[:disable_email], checked: can_send_emails && !local_assigns.key?(:resend_email) && !local_assigns[:disable_email] %>
|
||||||
<span class="label"><%= local_assigns[:resend_email] ? t('re_send_email') : t('send_email') %></span>
|
<span class="label"><%= local_assigns[:resend_email] ? t('re_send_email') : t('send_email') %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div>
|
<div>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<%= t('configure_smtp_settings_in_order_to_send_emails_') %>
|
<%= t('configure_smtp_settings_in_order_to_send_emails_') %>
|
||||||
<br>
|
<br>
|
||||||
<a class="link font-medium" data-turbo-frame="_top" href="<%= settings_email_index_path %>">
|
<a class="link font-medium" data-turbo-frame="_top" href="<%= settings_email_index_path %>">
|
||||||
<%= t('go_to_smtp_setting') %>
|
<%= t('go_to_smtp_settings') %>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -59,13 +59,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% elsif @submission.submitters.to_a.size == 1 && !@submission.expired? && !@submission.submitters.to_a.first.declined_at? && !@submission.archived_at? %>
|
<% elsif @submission.submitters.to_a.size == 1 && !@submission.expired? && !@submission.submitters.to_a.first.declined_at? && !@submission.archived_at? %>
|
||||||
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: @submission.submitters.to_a.first.slug), class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: t('copy_share_link'), copied_title: t('copied_to_clipboard') %>
|
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: @submission.submitters.to_a.first.slug, host: form_link_host), class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: t('copy_share_link'), copied_title: t('copied_to_clipboard') %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex md:max-h-[calc(100vh-60px)]">
|
<div class="flex md:max-h-[calc(100vh-60px)]">
|
||||||
<div class="overflow-y-auto overflow-x-hidden hidden lg:block w-52 flex-none pr-3 mt-0.5 pt-0.5">
|
<div class="overflow-y-auto overflow-x-hidden hidden lg:block w-52 flex-none pr-3 mt-0.5 pt-0.5">
|
||||||
<% (@submission.template_schema || @submission.template.schema).each do |item| %>
|
<% values = @submission.submitters.reduce({}) { |acc, sub| acc.merge(sub.values) } %>
|
||||||
|
<% schema = Submissions.filtered_conditions_schema(@submission, values:) %>
|
||||||
|
<% schema.each do |item| %>
|
||||||
<% document = @submission.template_schema_documents.find { |a| item['attachment_uuid'] == a.uuid } %>
|
<% document = @submission.template_schema_documents.find { |a| item['attachment_uuid'] == a.uuid } %>
|
||||||
<a href="#<%= "page-#{document.uuid}-0" %>" onclick="[event.preventDefault(), window[event.target.closest('a').href.split('#')[1]].scrollIntoView({ behavior: 'smooth', block: 'start' })]" class="block cursor-pointer">
|
<a href="#<%= "page-#{document.uuid}-0" %>" onclick="[event.preventDefault(), window[event.target.closest('a').href.split('#')[1]].scrollIntoView({ behavior: 'smooth', block: 'start' })]" class="block cursor-pointer">
|
||||||
<img src="<%= Docuseal::URL_CACHE.fetch([document.id, document.uuid, 0].join(':'), expires_in: 10.minutes) { document.preview_images.first.url } %>" width="<%= document.preview_images.first.metadata['width'] %>" height="<%= document.preview_images.first.metadata['height'] %>" class="rounded border" loading="lazy">
|
<img src="<%= Docuseal::URL_CACHE.fetch([document.id, document.uuid, 0].join(':'), expires_in: 10.minutes) { document.preview_images.first.url } %>" width="<%= document.preview_images.first.metadata['width'] %>" height="<%= document.preview_images.first.metadata['height'] %>" class="rounded border" loading="lazy">
|
||||||
@@ -79,10 +81,9 @@
|
|||||||
<div class="pr-3.5 pl-0.5">
|
<div class="pr-3.5 pl-0.5">
|
||||||
<% fields_index = Templates.build_field_areas_index(@submission.template_fields || @submission.template.fields) %>
|
<% fields_index = Templates.build_field_areas_index(@submission.template_fields || @submission.template.fields) %>
|
||||||
<% submitters_index = @submission.submitters.index_by(&:uuid) %>
|
<% submitters_index = @submission.submitters.index_by(&:uuid) %>
|
||||||
<% values = @submission.submitters.reduce({}) { |acc, sub| acc.merge(sub.values) } %>
|
|
||||||
<% attachments_index = ActiveStorage::Attachment.where(record: @submission.submitters, name: :attachments).preload(:blob).index_by(&:uuid) %>
|
<% attachments_index = ActiveStorage::Attachment.where(record: @submission.submitters, name: :attachments).preload(:blob).index_by(&:uuid) %>
|
||||||
<% page_blob_struct = Struct.new(:url, :metadata, keyword_init: true) %>
|
<% page_blob_struct = Struct.new(:url, :metadata, keyword_init: true) %>
|
||||||
<% (@submission.template_schema || @submission.template.schema).each do |item| %>
|
<% schema.each do |item| %>
|
||||||
<% document = @submission.template_schema_documents.find { |e| e.uuid == item['attachment_uuid'] } %>
|
<% document = @submission.template_schema_documents.find { |e| e.uuid == item['attachment_uuid'] } %>
|
||||||
<% document_annots_index = document.metadata.dig('pdf', 'annotations')&.group_by { |e| e['page'] } || {} %>
|
<% document_annots_index = document.metadata.dig('pdf', 'annotations')&.group_by { |e| e['page'] } || {} %>
|
||||||
<% preview_images_index = document.preview_images.loaded? ? document.preview_images.index_by { |e| e.filename.base.to_i } : {} %>
|
<% preview_images_index = document.preview_images.loaded? ? document.preview_images.index_by { |e| e.filename.base.to_i } : {} %>
|
||||||
@@ -121,7 +122,7 @@
|
|||||||
<%= (@submission.template_submitters || @submission.template.submitters).find { |e| e['uuid'] == submitter&.uuid }&.dig('name') || "#{(index + 1).ordinalize} Submitter" %>
|
<%= (@submission.template_submitters || @submission.template.submitters).find { |e| e['uuid'] == submitter&.uuid }&.dig('name') || "#{(index + 1).ordinalize} Submitter" %>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<% if signed_in? && can?(:update, submitter) && !submitter.completed_at? && !submitter.declined_at? && !@submission.archived_at? && !@submission.expired? && !submitter.start_form_submission_events.any? %>
|
<% if signed_in? && can?(:update, @submission) && submitter && !submitter.completed_at? && !submitter.declined_at? && !@submission.archived_at? && !@submission.expired? && !submitter.start_form_submission_events.any? %>
|
||||||
<span class="tooltip tooltip-left" data-tip="<%= t('edit') %>">
|
<span class="tooltip tooltip-left" data-tip="<%= t('edit') %>">
|
||||||
<%= link_to edit_submitter_path(submitter), class: 'shrink-0 inline md:hidden md:group-hover:inline', data: { turbo_frame: 'modal' } do %>
|
<%= link_to edit_submitter_path(submitter), class: 'shrink-0 inline md:hidden md:group-hover:inline', data: { turbo_frame: 'modal' } do %>
|
||||||
<%= svg_icon('pencil', class: 'w-5 h-5') %>
|
<%= svg_icon('pencil', class: 'w-5 h-5') %>
|
||||||
@@ -173,15 +174,15 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if signed_in? && submitter && submitter.email && !submitter.completed_at && !@submission.archived_at? && can?(:update, submitter) && Accounts.can_send_emails?(current_account) && !@submission.expired? && !submitter.declined_at? %>
|
<% if signed_in? && submitter && submitter.email && !submitter.completed_at && !@submission.archived_at? && can?(:update, @submission) && Accounts.can_send_emails?(current_account) && !@submission.expired? && !submitter.declined_at? %>
|
||||||
<div class="mt-2 mb-1">
|
<div class="mt-2 mb-1">
|
||||||
<%= button_to button_title(title: submitter.sent_at? ? t('re_send_email') : t('send_email'), disabled_with: t('sending')), submitter_send_email_index_path(submitter_slug: submitter.slug), class: 'btn btn-sm btn-primary w-full' %>
|
<%= button_to button_title(title: submitter.sent_at? ? t('re_send_email') : t('send_email'), disabled_with: t('sending')), submitter_send_email_index_path(submitter_slug: submitter.slug), class: 'btn btn-sm btn-primary w-full' %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if signed_in? && submitter && submitter.phone && !submitter.completed_at && !@submission.archived_at? && can?(:update, submitter) && !@submission.expired? && !submitter.declined_at? %>
|
<% if signed_in? && submitter && submitter.phone && !submitter.completed_at && !@submission.archived_at? && can?(:update, @submission) && !@submission.expired? && !submitter.declined_at? %>
|
||||||
<%= render 'submissions/send_sms_button', submitter: %>
|
<%= render 'submissions/send_sms_button', submitter: %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if signed_in? && submitter && !submitter.completed_at? && !@submission.archived_at? && can?(:create, submitter) && !@submission.expired? && !submitter.declined_at? %>
|
<% if signed_in? && submitter && !submitter.completed_at? && !@submission.archived_at? && can?(:create, @submission) && !@submission.expired? && !submitter.declined_at? %>
|
||||||
<div class="mt-2 mb-1">
|
<div class="mt-2 mb-1">
|
||||||
<a class="btn btn-sm btn-primary w-full" target="_blank" href="<%= submit_form_path(slug: submitter.slug) %>">
|
<a class="btn btn-sm btn-primary w-full" target="_blank" href="<%= submit_form_path(slug: submitter.slug) %>">
|
||||||
<%= t('sign_in_person') %>
|
<%= t('sign_in_person') %>
|
||||||
@@ -195,6 +196,7 @@
|
|||||||
<% submitter_field_counters[field['type']] += 1 %>
|
<% submitter_field_counters[field['type']] += 1 %>
|
||||||
<% value = values[field['uuid']] %>
|
<% value = values[field['uuid']] %>
|
||||||
<% next if value.blank? %>
|
<% next if value.blank? %>
|
||||||
|
<% next if field['type'] == 'heading' %>
|
||||||
<div class="pt-2.5 border-b border-base-300">
|
<div class="pt-2.5 border-b border-base-300">
|
||||||
<div class="text-xs font-medium uppercase mb-0.5" dir="auto">
|
<div class="text-xs font-medium uppercase mb-0.5" dir="auto">
|
||||||
<%= field['name'].presence || "#{t("#{field['type']}_field")} #{submitter_field_counters[field['type']]}" %>
|
<%= field['name'].presence || "#{t("#{field['type']}_field")} #{submitter_field_counters[field['type']]}" %>
|
||||||
|
|||||||
@@ -1,22 +1,31 @@
|
|||||||
|
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
|
||||||
<div>
|
<div>
|
||||||
<%= link_to root_path do %>
|
<%= link_to root_path do %>
|
||||||
←
|
←
|
||||||
<span><%= t('back_to_active') %></span>
|
<span><%= t('back_to_active') %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between mb-4 items-center">
|
<div class="flex flex-col md:flex-row md:items-center mb-4 gap-3">
|
||||||
<div>
|
<div class="flex w-full justify-between">
|
||||||
<h1 class="text-4xl font-bold md:block <%= 'hidden' if params[:q].present? %>"><%= t('submissions') %> <span class="badge badge-outline badge-lg align-middle"><%= t('archived') %></span></h1>
|
<div>
|
||||||
|
<h1 class="text-4xl font-bold md:block <%= 'hidden' if params[:q].present? %>"><%= t('submissions') %> <span class="badge badge-outline badge-lg align-middle"><%= t('archived') %></span></h1>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<% if params[:q].present? || @pagy.pages > 1 || filter_params.present? %>
|
||||||
|
<%= render 'shared/search_input', placeholder: "#{t('search')}..." %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-end md:flex-row gap-2">
|
||||||
|
<%= render 'submissions_filters/applied_filters', filter_params: %>
|
||||||
|
<%= render 'submissions_filters/filter_button', filter_params: %>
|
||||||
</div>
|
</div>
|
||||||
<% if params[:q].present? || @pagy.pages > 1 %>
|
|
||||||
<%= render 'shared/search_input', placeholder: "#{t('search')}..." %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
</div>
|
||||||
<% if @pagy.count > 0 %>
|
<% if @pagy.count > 0 %>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<%= render partial: 'templates/submission', collection: @submissions, locals: { with_template: true, archived: true } %>
|
<%= render partial: 'templates/submission', collection: @submissions, locals: { with_template: true, archived: true } %>
|
||||||
</div>
|
</div>
|
||||||
<% elsif params[:q].present? %>
|
<% elsif params[:q].present? || filter_params.present? %>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="mt-16 text-3xl font-semibold">
|
<div class="mt-16 text-3xl font-semibold">
|
||||||
<%= t('submissions_not_found') %>
|
<%= t('submissions_not_found') %>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<% is_show_tabs = @pagy.count >= 5 || params[:status].present? %>
|
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
|
||||||
|
<% is_show_tabs = @pagy.count >= 5 || params[:status].present? || filter_params.present? %>
|
||||||
<% if Docuseal.demo? %><%= render 'shared/demo_alert' %><% end %>
|
<% if Docuseal.demo? %><%= render 'shared/demo_alert' %><% end %>
|
||||||
<div class="flex justify-between items-center w-full mb-4">
|
<div class="flex justify-between items-center w-full mb-4">
|
||||||
<div class="flex items-center flex-grow min-w-0">
|
<div class="flex items-center flex-grow min-w-0">
|
||||||
@@ -10,7 +11,7 @@
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<% if params[:q].present? || @pagy.pages > 1 %>
|
<% if params[:q].present? || @pagy.pages > 1 || filter_params.present? %>
|
||||||
<%= render 'shared/search_input' %>
|
<%= render 'shared/search_input' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if can?(:create, ::Template) %>
|
<% if can?(:create, ::Template) %>
|
||||||
@@ -32,25 +33,31 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if is_show_tabs %>
|
<% if is_show_tabs %>
|
||||||
<div class="flex items-center md:items-end flex-col space-y-2 md:space-y-0 md:flex-row md:space-x-2 mb-4">
|
<div class="flex items-center flex-col md:flex-row md:flex-wrap gap-2 mb-4">
|
||||||
<a href="<%= url_for(params.to_unsafe_h.except(:status)) %>" class="<%= params[:status].blank? ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-600">
|
<div class="flex items-center md:items-end flex-col md:flex-row gap-2 w-full md:w-fit">
|
||||||
<div class="flex items-center space-x-1">
|
<a href="<%= url_for(params.to_unsafe_h.except(:status)) %>" class="<%= params[:status].blank? ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-600">
|
||||||
<%= svg_icon('list', class: 'w-5 h-5') %>
|
<div class="flex items-center space-x-1">
|
||||||
<span class="font-normal"><%= t('all') %></span>
|
<%= svg_icon('list', class: 'w-5 h-5') %>
|
||||||
</div>
|
<span class="font-normal"><%= t('all') %></span>
|
||||||
</a>
|
</div>
|
||||||
<a href="<%= url_for(params.to_unsafe_h.merge(status: :pending)) %>" class="<%= params[:status] == 'pending' ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-600">
|
</a>
|
||||||
<div class="flex items-center space-x-1">
|
<a href="<%= url_for(params.to_unsafe_h.merge(status: :pending)) %>" class="<%= params[:status] == 'pending' ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-600">
|
||||||
<%= svg_icon('clock', class: 'w-5 h-5') %>
|
<div class="flex items-center space-x-1">
|
||||||
<span class="font-normal"><%= t('pending') %></span>
|
<%= svg_icon('clock', class: 'w-5 h-5') %>
|
||||||
</div>
|
<span class="font-normal"><%= t('pending') %></span>
|
||||||
</a>
|
</div>
|
||||||
<a href="<%= url_for(params.to_unsafe_h.merge(status: :completed)) %>" class="<%= params[:status] == 'completed' ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-600">
|
</a>
|
||||||
<div class="flex items-center space-x-1">
|
<a href="<%= url_for(params.to_unsafe_h.merge(status: :completed)) %>" class="<%= params[:status] == 'completed' ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-600">
|
||||||
<%= svg_icon('circle_check', class: 'w-5 h-5') %>
|
<div class="flex items-center space-x-1">
|
||||||
<span class="font-normal"><%= t('completed') %></span>
|
<%= svg_icon('circle_check', class: 'w-5 h-5') %>
|
||||||
</div>
|
<span class="font-normal"><%= t('completed') %></span>
|
||||||
</a>
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-end flex-col md:flex-row gap-2 w-full md:w-fit">
|
||||||
|
<%= render 'submissions_filters/applied_filters', filter_params: %>
|
||||||
|
<%= render 'submissions_filters/filter_button', filter_params: %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @pagy.count > 0 %>
|
<% if @pagy.count > 0 %>
|
||||||
@@ -58,10 +65,10 @@
|
|||||||
<%= render partial: 'templates/submission', collection: @submissions, locals: { with_template: true } %>
|
<%= render partial: 'templates/submission', collection: @submissions, locals: { with_template: true } %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if params[:q].blank? && params[:status].blank? && @pagy.count < 5 %>
|
<% if params[:q].blank? && params[:status].blank? && filter_params.blank? && @pagy.count < 5 %>
|
||||||
<%= render 'templates/dropzone' %>
|
<%= render 'templates/dropzone' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @submissions.present? || params[:q].blank? %>
|
<% if @submissions.present? || (params[:q].blank? && filter_params.blank?) %>
|
||||||
<% if @pagy.pages > 1 %>
|
<% if @pagy.pages > 1 %>
|
||||||
<%= render 'shared/pagination', pagy: @pagy, items_name: 'submissions', left_additional_html: view_archived_html %>
|
<%= render 'shared/pagination', pagy: @pagy, items_name: 'submissions', left_additional_html: view_archived_html %>
|
||||||
<% else %>
|
<% else %>
|
||||||
@@ -69,7 +76,7 @@
|
|||||||
<%= view_archived_html %>
|
<%= view_archived_html %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% elsif params[:q].present? %>
|
<% elsif params[:q].present? || filter_params.present? %>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="mt-16 text-3xl font-semibold">
|
<div class="mt-16 text-3xl font-semibold">
|
||||||
<%= t('submissions_not_found') %>
|
<%= t('submissions_not_found') %>
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<% query_params = params.permit(:q, :status).merge(filter_params) %>
|
||||||
|
<% if query_params[:completed_at_from].present? || query_params[:completed_at_to].present? %>
|
||||||
|
<div class="tooltip tooltip-bottom flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-34 border-neutral-700" data-tip="<%= t('completed_at') %>">
|
||||||
|
<%= link_to submissions_filter_path('completed_at', query_params.merge(path: url_for, with_remove: true)), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1 w-full pr-1 md:max-w-[140px]' do %>
|
||||||
|
<%= svg_icon('calendar_check', class: 'w-5 h-5 shrink-0') %>
|
||||||
|
<span class="flex flex-row md:flex-col font-normal text-left md:text-center md:text-xs">
|
||||||
|
<% if query_params[:completed_at_from] == query_params[:completed_at_to] %>
|
||||||
|
<span><%= l(Date.parse(query_params[:completed_at_from]), locale: current_account.locale) %></span>
|
||||||
|
<% else %>
|
||||||
|
<span><%= query_params[:completed_at_from].present? ? l(Date.parse(query_params[:completed_at_from]), locale: current_account.locale) : '∞' %></span>
|
||||||
|
<span class="px-1 md:px-0 md:hidden">-</span>
|
||||||
|
<span><%= query_params[:completed_at_to].present? ? l(Date.parse(query_params[:completed_at_to]), locale: current_account.locale) : t('today') %></span>
|
||||||
|
<% end %>
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
|
<%= link_to url_for(params.to_unsafe_h.except(:completed_at_from, :completed_at_to)), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %>
|
||||||
|
<%= svg_icon('x', class: 'w-5 h-5') %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% if query_params[:created_at_from].present? || query_params[:created_at_to].present? %>
|
||||||
|
<div class="tooltip tooltip-bottom flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-34 border-neutral-700" data-tip="<%= t('created_at') %>">
|
||||||
|
<%= link_to submissions_filter_path('created_at', query_params.merge(path: url_for, with_remove: true)), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1 w-full pr-1 md:max-w-[140px]' do %>
|
||||||
|
<%= svg_icon('calendar', class: 'w-5 h-5 shrink-0') %>
|
||||||
|
<span class="flex flex-row md:flex-col font-normal text-left md:text-center md:text-xs">
|
||||||
|
<% if query_params[:created_at_from] == query_params[:created_at_to] %>
|
||||||
|
<span><%= l(Date.parse(query_params[:created_at_from]), locale: current_account.locale) %></span>
|
||||||
|
<% else %>
|
||||||
|
<span><%= query_params[:created_at_from].present? ? l(Date.parse(query_params[:created_at_from]), locale: current_account.locale) : '∞' %></span>
|
||||||
|
<span class="px-1 md:px-0 md:hidden">-</span>
|
||||||
|
<span><%= query_params[:created_at_to].present? ? l(Date.parse(query_params[:created_at_to]), locale: current_account.locale) : t('today') %></span>
|
||||||
|
<% end %>
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
|
<%= link_to url_for(params.to_unsafe_h.except(:created_at_to, :created_at_from)), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %>
|
||||||
|
<%= svg_icon('x', class: 'w-5 h-5') %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% if params[:author].present? %>
|
||||||
|
<div class="tooltip tooltip-bottom flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-34 border-neutral-700" data-tip="<%= t('author') %>">
|
||||||
|
<%= link_to submissions_filter_path('author', query_params.merge(path: url_for, with_remove: true)), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1 w-full pr-1 md:max-w-[140px]' do %>
|
||||||
|
<%= svg_icon('user', class: 'w-5 h-5 shrink-0') %>
|
||||||
|
<span class="font-normal truncate"><%= current_account.users.accessible_by(current_ability).where(account: current_account).find_by(email: params[:author])&.full_name || 'NA' %></span>
|
||||||
|
<% end %>
|
||||||
|
<%= link_to url_for(params.to_unsafe_h.except(:author)), class: 'rounded-lg ml-1 hover:bg-base-content hover:text-white' do %>
|
||||||
|
<%= svg_icon('x', class: 'w-5 h-5') %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<% current_time = Time.current.in_time_zone(current_account.timezone) %>
|
||||||
|
<% week_start = TimeUtils.timezone_abbr(current_account.timezone, current_time).in?(TimeUtils::US_TIMEZONES) ? :sunday : :monday %>
|
||||||
|
<div class="flex flex-wrap gap-2 mt-4 md:mt-2">
|
||||||
|
<set-date-button data-from-value="<%= current_time.to_date %>" data-to-value="<%= current_time.to_date %>" data-from-id="date_from" data-to-id="date_to">
|
||||||
|
<button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button">
|
||||||
|
<%= t('today') %>
|
||||||
|
</button>
|
||||||
|
</set-date-button>
|
||||||
|
<set-date-button data-from-value="<%= (current_time - 1.day).to_date %>" data-to-value="<%= (current_time - 1.day).to_date %>" data-from-id="date_from" data-to-id="date_to">
|
||||||
|
<button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button">
|
||||||
|
<%= t('yesterday') %>
|
||||||
|
</button>
|
||||||
|
</set-date-button>
|
||||||
|
<set-date-button data-from-value="<%= current_time.beginning_of_week(week_start).to_date %>" data-to-value="<%= current_time.end_of_week(week_start).to_date %>" data-from-id="date_from" data-to-id="date_to">
|
||||||
|
<button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button">
|
||||||
|
<%= t('this_week') %>
|
||||||
|
</button>
|
||||||
|
</set-date-button>
|
||||||
|
<set-date-button data-from-value="<%= (current_time - 1.week).beginning_of_week(week_start).to_date %>" data-to-value="<%= (current_time - 1.week).end_of_week(week_start).to_date %>" data-from-id="date_from" data-to-id="date_to">
|
||||||
|
<button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button">
|
||||||
|
<%= t('last_week') %>
|
||||||
|
</button>
|
||||||
|
</set-date-button>
|
||||||
|
<set-date-button data-from-value="<%= current_time.beginning_of_month.to_date %>" data-to-value="<%= current_time.end_of_month.to_date %>" data-from-id="date_from" data-to-id="date_to">
|
||||||
|
<button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button">
|
||||||
|
<%= t('this_month') %>
|
||||||
|
</button>
|
||||||
|
</set-date-button>
|
||||||
|
<set-date-button data-from-value="<%= (current_time - 1.month).beginning_of_month.to_date %>" data-to-value="<%= (current_time - 1.month).end_of_month.to_date %>" data-from-id="date_from" data-to-id="date_to">
|
||||||
|
<button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button">
|
||||||
|
<%= t('last_month') %>
|
||||||
|
</button>
|
||||||
|
</set-date-button>
|
||||||
|
<set-date-button data-from-value="<%= current_time.beginning_of_year.to_date %>" data-to-value="<%= current_time.end_of_year.to_date %>" data-from-id="date_from" data-to-id="date_to">
|
||||||
|
<button class="btn btn-xs btn-primary font-medium normal-case" data-turbo="false" type="button">
|
||||||
|
<%= t('this_year') %>
|
||||||
|
</button>
|
||||||
|
</set-date-button>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<% query_params = params.permit(:q, :status).merge(filter_params) %>
|
||||||
|
<div class="dropdown dropdown-end">
|
||||||
|
<label tabindex="0" class="cursor-pointer flex h-10 px-3 py-1 space-x-1 text-lg items-center justify-between border text-center text-neutral rounded-xl border-neutral-300 hover:border-neutral-700">
|
||||||
|
<%= svg_icon('filter', class: 'w-5 h-5 flex-shrink-0 stroke-2') %>
|
||||||
|
<span class="<%= filter_params.present? ? 'md:hidden' : '' %>">Filter</span>
|
||||||
|
</label>
|
||||||
|
<ul tabindex="0" class="z-10 dropdown-content p-2 mt-2 shadow menu text-base bg-base-100 rounded-box min-w-[180px] text-right">
|
||||||
|
<li class="flex">
|
||||||
|
<%= link_to submissions_filter_path('completed_at', query_params.merge(path: url_for)), data: { turbo_frame: 'modal' } do %>
|
||||||
|
<%= svg_icon('calendar_check', class: 'w-5 h-5 flex-shrink-0 stroke-2') %>
|
||||||
|
<span><%= t('completed_at') %></span>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
<li class="flex">
|
||||||
|
<%= link_to submissions_filter_path('created_at', query_params.merge(path: url_for)), data: { turbo_frame: 'modal' } do %>
|
||||||
|
<%= svg_icon('calendar', class: 'w-5 h-5 flex-shrink-0 stroke-2') %>
|
||||||
|
<span><%= t('created_at') %></span>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
<li class="flex">
|
||||||
|
<%= link_to submissions_filter_path('author', query_params.merge(path: url_for)), data: { turbo_frame: 'modal' } do %>
|
||||||
|
<%= svg_icon('user', class: 'w-5 h-5 flex-shrink-0 stroke-2') %>
|
||||||
|
<span><%= t('author') %></span>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<%= render 'shared/turbo_modal', title: local_assigns[:title] do %>
|
||||||
|
<%= form_for '', url: params[:path], method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %>
|
||||||
|
<%= hidden_field_tag :status, params[:status] if params[:status].present? %>
|
||||||
|
<%= hidden_field_tag :q, params[:q] if params[:q].present? %>
|
||||||
|
<% local_assigns[:default_params].each do |key, value| %>
|
||||||
|
<%= hidden_field_tag(key, value) if value.present? %>
|
||||||
|
<% end %>
|
||||||
|
<%= yield %>
|
||||||
|
<div class="form-control mt-4">
|
||||||
|
<%= f.button button_title(title: t('apply'), disabled_with: t('applying')), name: nil, class: 'base-button' %>
|
||||||
|
</div>
|
||||||
|
<% if params[:with_remove] %>
|
||||||
|
<div class="text-center w-full mt-4">
|
||||||
|
<%= link_to t('remove_filter'), "#{params[:path]}?#{params.to_unsafe_h.slice(:q, :status).merge(local_assigns[:default_params]).to_query}", class: 'link', data: { turbo_frame: :_top } %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<%= render 'filter_modal', title: t('author'), default_params: params.permit(*(Submissions::Filter::ALLOWED_PARAMS - ['author'])) do %>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div class="form-control mt-6">
|
||||||
|
<%= select_tag :author, options_for_select(current_account.users.accessible_by(current_ability).where.not(role: :integration).where(account: current_account).map { |u| [u.full_name, u.email] }, params[:author].presence || current_user.email), required: true, class: 'base-select' %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<%= render 'filter_modal', title: t('completed_at'), default_params: params.permit(*(Submissions::Filter::ALLOWED_PARAMS - %w[completed_at_to completed_at_from])) do %>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="flex flex-col md:flex-row gap-2">
|
||||||
|
<div class="form-control w-full">
|
||||||
|
<%= label_tag 'completed_at_from', t('from'), for: 'date_from', class: 'label text-sm' %>
|
||||||
|
<%= date_field_tag 'completed_at_from', params[:completed_at_from], id: 'date_from', class: 'base-input !h-10', autocomplete: 'off' %>
|
||||||
|
</div>
|
||||||
|
<div class="form-control w-full">
|
||||||
|
<%= label_tag 'completed_at_to', t('to'), for: 'date_to', class: 'label text-sm' %>
|
||||||
|
<%= date_field_tag 'completed_at_to', params[:completed_at_to], id: 'date_to', class: 'base-input !h-10', autocomplete: 'off' %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%= render 'date_buttons' %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<%= render 'filter_modal', title: t('created_at'), default_params: params.permit(*(Submissions::Filter::ALLOWED_PARAMS - %w[created_at_to created_at_from])) do %>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="flex flex-col md:flex-row gap-2">
|
||||||
|
<div class="form-control w-full">
|
||||||
|
<%= label_tag 'created_at_from', t('from'), for: 'date_from', class: 'label text-sm' %>
|
||||||
|
<%= date_field_tag 'created_at_from', params[:created_at_from], id: 'date_from', class: 'base-input !h-10', autocomplete: 'off' %>
|
||||||
|
</div>
|
||||||
|
<div class="form-control w-full">
|
||||||
|
<%= label_tag 'created_at_to', t('to'), for: 'date_to', class: 'label text-sm' %>
|
||||||
|
<%= date_field_tag 'created_at_to', params[:created_at_to], id: 'date_to', class: 'base-input !h-10', autocomplete: 'off' %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<%= render 'date_buttons' %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<% data_attachments = attachments_index.values.select { |e| e.record_id == submitter.id }.to_json(only: %i[uuid created_at], methods: %i[url filename content_type]) %>
|
<% data_attachments = attachments_index.values.select { |e| e.record_id == submitter.id }.to_json(only: %i[uuid created_at], methods: %i[url filename content_type]) %>
|
||||||
<% data_fields = (submitter.submission.template_fields || submitter.submission.template.fields).select { |f| f['submitter_uuid'] == submitter.uuid }.to_json %>
|
<% data_fields = (submitter.submission.template_fields || submitter.submission.template.fields).select { |f| f['submitter_uuid'] == submitter.uuid }.to_json %>
|
||||||
<% invite_submitters = (submitter.submission.template_submitters || submitter.submission.template.submitters).select { |s| s['invite_by_uuid'] == submitter.uuid && submitter.submission.submitters.none? { |e| e.uuid == s['uuid'] } }.to_json %>
|
<% invite_submitters = (submitter.submission.template_submitters || submitter.submission.template.submitters).select { |s| s['invite_by_uuid'] == submitter.uuid && submitter.submission.submitters.none? { |e| e.uuid == s['uuid'] } }.to_json %>
|
||||||
<submission-form data-is-demo="<%= Docuseal.demo? %>" data-reuse-signature="<%= configs[:reuse_signature] %>" data-require-signing-reason="<%= configs[:require_signing_reason] %>" data-with-signature-id="<%= configs[:with_signature_id] %>" data-with-confetti="<%= configs[:with_confetti] %>" data-completed-redirect-url="<%= submitter.preferences['completed_redirect_url'].presence || submitter.submission.template.preferences['completed_redirect_url'] %>" data-completed-message="<%= (configs[:completed_message]&.compact_blank.presence || submitter.submission.template.preferences['completed_message'] || {}).to_json %>" data-completed-button="<%= configs[:completed_button].to_json %>" data-go-to-last="<%= submitter.preferences.key?('go_to_last') ? submitter.preferences['go_to_last'] : submitter.opened_at? %>" data-submitter="<%= submitter.to_json(only: %i[uuid slug name phone email]) %>" data-can-send-email="<%= Accounts.can_send_emails?(submitter.submission.account) %>" data-invite-submitters="<%= invite_submitters %>" data-attachments="<%= data_attachments %>" data-fields="<%= data_fields %>" data-values="<%= submitter.values.to_json %>" data-with-typed-signature="<%= configs[:with_typed_signature] %>" data-previous-signature-value="<%= local_assigns[:signature_attachment]&.uuid %>" data-remember-signature="<%= configs[:prefill_signature] %>" data-dry-run="<%= local_assigns[:dry_run] %>" data-expand="<%= local_assigns[:expand] %>" data-scroll-padding="<%= local_assigns[:scroll_padding] %>" data-language="<%= I18n.locale.to_s.split('-').first %>"></submission-form>
|
<submission-form data-is-demo="<%= Docuseal.demo? %>" data-schema="<%= schema.to_json %>" data-reuse-signature="<%= configs[:reuse_signature] %>" data-require-signing-reason="<%= configs[:require_signing_reason] %>" data-with-signature-id="<%= configs[:with_signature_id] %>" data-with-confetti="<%= configs[:with_confetti] %>" data-completed-redirect-url="<%= submitter.preferences['completed_redirect_url'].presence || submitter.submission.template.preferences['completed_redirect_url'] %>" data-completed-message="<%= (configs[:completed_message]&.compact_blank.presence || submitter.submission.template.preferences['completed_message'] || {}).to_json %>" data-completed-button="<%= configs[:completed_button].to_json %>" data-go-to-last="<%= submitter.preferences.key?('go_to_last') ? submitter.preferences['go_to_last'] : submitter.opened_at? %>" data-submitter="<%= submitter.to_json(only: %i[uuid slug name phone email]) %>" data-can-send-email="<%= Accounts.can_send_emails?(submitter.submission.account) %>" data-invite-submitters="<%= invite_submitters %>" data-attachments="<%= data_attachments %>" data-fields="<%= data_fields %>" data-values="<%= submitter.values.to_json %>" data-with-typed-signature="<%= configs[:with_typed_signature] %>" data-previous-signature-value="<%= local_assigns[:signature_attachment]&.uuid %>" data-remember-signature="<%= configs[:prefill_signature] %>" data-dry-run="<%= local_assigns[:dry_run] %>" data-expand="<%= local_assigns[:expand] %>" data-scroll-padding="<%= local_assigns[:scroll_padding] %>" data-language="<%= I18n.locale.to_s.split('-').first %>"></submission-form>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<% values = @submitter.submission.submitters.reduce({}) { |acc, sub| acc.merge(sub.values) } %>
|
<% values = @submitter.submission.submitters.reduce({}) { |acc, sub| acc.merge(sub.values) } %>
|
||||||
<% submitters_index = @submitter.submission.submitters.index_by(&:uuid) %>
|
<% submitters_index = @submitter.submission.submitters.index_by(&:uuid) %>
|
||||||
<% page_blob_struct = Struct.new(:url, :metadata, keyword_init: true) %>
|
<% page_blob_struct = Struct.new(:url, :metadata, keyword_init: true) %>
|
||||||
|
<% schema = Submissions.filtered_conditions_schema(@submitter.submission, values:, include_submitter_uuid: @submitter.uuid) %>
|
||||||
<div style="max-height: -webkit-fill-available;">
|
<div style="max-height: -webkit-fill-available;">
|
||||||
<div id="scrollbox">
|
<div id="scrollbox">
|
||||||
<div class="mx-auto block pb-72" style="max-width: 1000px">
|
<div class="mx-auto block pb-72" style="max-width: 1000px">
|
||||||
@@ -35,41 +36,50 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% (@submitter.submission.template_schema || @submitter.submission.template.schema).each do |item| %>
|
<% schema.each do |item| %>
|
||||||
<% document = @submitter.submission.template_schema_documents.find { |a| a.uuid == item['attachment_uuid'] } %>
|
<% document = @submitter.submission.template_schema_documents.find { |a| a.uuid == item['attachment_uuid'] } %>
|
||||||
<% document_annots_index = document.metadata.dig('pdf', 'annotations')&.group_by { |e| e['page'] } || {} %>
|
<div id="document-<%= document.uuid %>">
|
||||||
<% preview_images_index = document.preview_images.loaded? ? document.preview_images.index_by { |e| e.filename.base.to_i } : {} %>
|
<% document_annots_index = document.metadata.dig('pdf', 'annotations')&.group_by { |e| e['page'] } || {} %>
|
||||||
<% lazyload_metadata = document.preview_images.last.metadata %>
|
<% preview_images_index = document.preview_images.loaded? ? document.preview_images.index_by { |e| e.filename.base.to_i } : {} %>
|
||||||
<% (document.metadata.dig('pdf', 'number_of_pages') || (document.preview_images.loaded? ? preview_images_index.size : document.preview_images.size)).times do |index| %>
|
<% lazyload_metadata = document.preview_images.last.metadata %>
|
||||||
<% page = preview_images_index[index] || page_blob_struct.new(metadata: lazyload_metadata, url: preview_document_page_path(document.signed_uuid, "#{index}.jpg")) %>
|
<% (document.metadata.dig('pdf', 'number_of_pages') || (document.preview_images.loaded? ? preview_images_index.size : document.preview_images.size)).times do |index| %>
|
||||||
<div class="relative my-4 shadow-md">
|
<% page = preview_images_index[index] || page_blob_struct.new(metadata: lazyload_metadata, url: preview_document_page_path(document.signed_uuid, "#{index}.jpg")) %>
|
||||||
<img loading="lazy" src="<%= page.url %>" width="<%= page.metadata['width'] %>" height="<%= page.metadata['height'] %>">
|
<div class="relative my-4 shadow-md">
|
||||||
<div id="page-<%= [document.uuid, index].join('-') %>" class="top-0 bottom-0 left-0 right-0 absolute">
|
<img loading="lazy" src="<%= page.url %>" width="<%= page.metadata['width'] %>" height="<%= page.metadata['height'] %>">
|
||||||
<% document_annots_index[index]&.each do |annot| %>
|
<div id="page-<%= [document.uuid, index].join('-') %>" class="top-0 bottom-0 left-0 right-0 absolute">
|
||||||
<%= render 'submissions/annotation', annot: %>
|
<% document_annots_index[index]&.each do |annot| %>
|
||||||
<% end %>
|
<%= render 'submissions/annotation', annot: %>
|
||||||
<% fields_index.dig(document.uuid, index)&.each do |(area, field)| %>
|
<% end %>
|
||||||
<% value = values[field['uuid']].presence || (field['default_value'].present? ? Submitters::SubmitValues.template_default_value_for_submitter(field['default_value'], @submitter.submission.submitters.find { |e| e.uuid == field['submitter_uuid'] }, with_time: false) : nil) %>
|
<% fields_index.dig(document.uuid, index)&.each do |(area, field)| %>
|
||||||
<% next if value.blank? %>
|
<% value = values[field['uuid']].presence || (field['default_value'].present? ? Submitters::SubmitValues.template_default_value_for_submitter(field['default_value'], @submitter.submission.submitters.find { |e| e.uuid == field['submitter_uuid'] }, with_time: false) : nil) %>
|
||||||
<% next if !field['readonly'] && field['submitter_uuid'] == @submitter.uuid %>
|
<% next if value.blank? %>
|
||||||
<% next if value == '{{date}}' && field['submitter_uuid'] != @submitter.uuid %>
|
<% next if !field['readonly'] && field['submitter_uuid'] == @submitter.uuid %>
|
||||||
<% next if field['conditions'].present? && values[field['uuid']].blank? && field['submitter_uuid'] != @submitter.uuid %>
|
<% next if value == '{{date}}' && field['submitter_uuid'] != @submitter.uuid %>
|
||||||
<% next if field['conditions'].present? && field['submitter_uuid'] == @submitter.uuid %>
|
<% next if field['conditions'].present? && values[field['uuid']].blank? && field['submitter_uuid'] != @submitter.uuid %>
|
||||||
<% next if field.dig('preferences', 'formula').present? && field['submitter_uuid'] == @submitter.uuid %>
|
<% next if field['conditions'].present? && field['submitter_uuid'] == @submitter.uuid %>
|
||||||
<%= render 'submissions/value', area:, field:, attachments_index: @attachments_index, value:, locale: @submitter.account.locale, timezone: @submitter.account.timezone, submitter: submitters_index[field['submitter_uuid']], with_signature_id: @form_configs[:with_signature_id] %>
|
<% next if field.dig('preferences', 'formula').present? && field['submitter_uuid'] == @submitter.uuid %>
|
||||||
<% end %>
|
<%= render 'submissions/value', area:, field:, attachments_index: @attachments_index, value:, locale: @submitter.account.locale, timezone: @submitter.account.timezone, submitter: submitters_index[field['submitter_uuid']], with_signature_id: @form_configs[:with_signature_id] %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<% end %>
|
||||||
<% end %>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= render 'shared/attribution', link_path: '/start', account: @submitter.account, with_style: false %>
|
<%= render 'shared/attribution', link_path: '/start', account: @submitter.account, with_style: false %>
|
||||||
|
<% if @form_configs[:policy_links].present? %>
|
||||||
|
<div class="text-center md:text-neutral-500 md:pr-3 md:pb-3 md:text-sm md:text-left mt-2 md:mt-0 md:fixed md:bottom-0 md:right-0">
|
||||||
|
<div class="md:max-w-[8rem] flex flex-wrap md:flex-col justify-center md:justify-start md:items-start space-x-2 md:space-x-0">
|
||||||
|
<%= auto_link(MarkdownToHtml.call(@form_configs[:policy_links])) %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="fixed bottom-0 w-full h-0 z-20">
|
<div class="fixed bottom-0 w-full h-0 z-20">
|
||||||
<div class="mx-auto" style="max-width: 1000px">
|
<div class="mx-auto" style="max-width: 1000px">
|
||||||
<div class="relative md:mx-32">
|
<div class="relative md:mx-32">
|
||||||
<%= render 'submit_form/submission_form', attachments_index: @attachments_index, submitter: @submitter, signature_attachment: @signature_attachment, configs: @form_configs, dry_run: local_assigns[:dry_run], expand: local_assigns[:expand], scroll_padding: local_assigns.fetch(:scroll_padding, '-110px') %>
|
<%= render 'submit_form/submission_form', attachments_index: @attachments_index, submitter: @submitter, signature_attachment: @signature_attachment, configs: @form_configs, dry_run: local_assigns[:dry_run], expand: local_assigns[:expand], scroll_padding: local_assigns.fetch(:scroll_padding, '-110px'), schema: %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
<%= render 'custom_content', content: @body, submitter: @submitter %>
|
<%= render 'custom_content', content: @body, submitter: @submitter %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p><%= t('hi_there') %>,</p>
|
<p><%= t('hi_there') %>,</p>
|
||||||
<p><%= I18n.t(:name_has_been_completed_by_submitters, name: @submitter.submission.template.name, submitters: @submitter.submission.submitters.order(:completed_at).map { |e| e.name || e.email || e.phone }.join(', ')) %></p>
|
<p><%= I18n.t(:name_has_been_completed_by_submitters, name: @submitter.submission.template.name, submitters: @submitter.submission.submitters.order(:completed_at).map { |e| e.name || e.email || e.phone }.uniq.join(', ')) %></p>
|
||||||
<p><%= link_to submission_url(@submitter.submission), submission_url(@submitter.submission) %></p>
|
<p><%= link_to submission_url(@submitter.submission), submission_url(@submitter.submission) %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
<% else %>
|
<% else %>
|
||||||
<p><%= t('hi_there') %>,</p>
|
<p><%= t('hi_there') %>,</p>
|
||||||
<p><%= I18n.t(@submitter.with_signature_fields? ? :you_have_been_invited_to_sign_the_name : :you_have_been_invited_to_submit_the_name_form, name: @submitter.submission.template.name) %></p>
|
<p><%= I18n.t(@submitter.with_signature_fields? ? :you_have_been_invited_to_sign_the_name : :you_have_been_invited_to_submit_the_name_form, name: @submitter.submission.template.name) %></p>
|
||||||
<p><%= link_to I18n.t(@submitter.with_signature_fields? ? :review_and_sign : :review_and_submit), submit_form_url(slug: @submitter.slug, t: SubmissionEvents.build_tracking_param(@submitter, 'click_email')) %></p>
|
<p><%= link_to I18n.t(@submitter.with_signature_fields? ? :review_and_sign : :review_and_submit), submit_form_url(slug: @submitter.slug, t: SubmissionEvents.build_tracking_param(@submitter, 'click_email'), host: ENV.fetch('EMAIL_HOST', Docuseal.default_url_options[:host])) %></p>
|
||||||
<p><%= t('please_contact_us_by_replying_to_this_email_if_you_didn_t_request_this') %></p>
|
<p><%= t('please_contact_us_by_replying_to_this_email_if_you_didn_t_request_this') %></p>
|
||||||
<p>
|
<p>
|
||||||
<%= t('thanks') %>,<br><%= @current_account.name %>
|
<%= t('thanks') %>,<br><%= @current_account.name %>
|
||||||
|
|||||||
Whitespace-only changes.
@@ -51,7 +51,7 @@
|
|||||||
<a href="<%= submission_path(submission) %>" class="text-lg break-all peer">
|
<a href="<%= submission_path(submission) %>" class="text-lg break-all peer">
|
||||||
<%= submitter.name || submitter.email || submitter.phone %>
|
<%= submitter.name || submitter.email || submitter.phone %>
|
||||||
</a>
|
</a>
|
||||||
<% if can?(:update, submitter) && !submitter.start_form_submission_events.any? && !submission.archived_at? && !submission.expired? && !submitter.declined_at? %>
|
<% if can?(:update, submission) && !submitter.start_form_submission_events.any? && !submission.archived_at? && !submission.expired? && !submitter.declined_at? %>
|
||||||
<span class="pl-0.5 tooltip tooltip-top md:opacity-0 md:hover:opacity-100 md:peer-hover:opacity-100" data-tip="<%= t('edit') %>">
|
<span class="pl-0.5 tooltip tooltip-top md:opacity-0 md:hover:opacity-100 md:peer-hover:opacity-100" data-tip="<%= t('edit') %>">
|
||||||
<%= link_to edit_submitter_path(submitter), class: 'shrink-0', data: { turbo_frame: 'modal' } do %>
|
<%= link_to edit_submitter_path(submitter), class: 'shrink-0', data: { turbo_frame: 'modal' } do %>
|
||||||
<%= svg_icon('pencil', class: 'w-5 h-5') %>
|
<%= svg_icon('pencil', class: 'w-5 h-5') %>
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
<div class="flex-1 md:flex-none">
|
<div class="flex-1 md:flex-none">
|
||||||
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug), class: 'btn btn-sm btn-neutral text-white md:w-36 flex z-[1]', icon_class: 'w-6 h-6 text-white', copy_title: t('copy_link').length < 10 ? t('copy_link') : t('copy'), copy_title_md: t('copy'), copied_title_md: t('copied') %>
|
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug, host: form_link_host), class: 'btn btn-sm btn-neutral text-white md:w-36 flex z-[1]', icon_class: 'w-6 h-6 text-white', copy_title: t('copy_link').length < 10 ? t('copy_link') : t('copy'), copy_title_md: t('copy'), copied_title_md: t('copied') %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
<a href="<%= submission_path(submission) %>" class="text-lg break-all peer">
|
<a href="<%= submission_path(submission) %>" class="text-lg break-all peer">
|
||||||
<%= submitter.name || submitter.email || submitter.phone %>
|
<%= submitter.name || submitter.email || submitter.phone %>
|
||||||
</a>
|
</a>
|
||||||
<% if can?(:update, submitter) && !submitter.start_form_submission_events.any? && !submission.archived_at? && !submission.expired? && !submitter.declined_at? %>
|
<% if can?(:update, submission) && !submitter.start_form_submission_events.any? && !submission.archived_at? && !submission.expired? && !submitter.declined_at? %>
|
||||||
<span class="pl-0.5 tooltip tooltip-top md:opacity-0 md:hover:opacity-100 md:peer-hover:opacity-100" data-tip="<%= t('edit') %>">
|
<span class="pl-0.5 tooltip tooltip-top md:opacity-0 md:hover:opacity-100 md:peer-hover:opacity-100" data-tip="<%= t('edit') %>">
|
||||||
<%= link_to edit_submitter_path(submitter), class: 'shrink-0', data: { turbo_frame: 'modal' } do %>
|
<%= link_to edit_submitter_path(submitter), class: 'shrink-0', data: { turbo_frame: 'modal' } do %>
|
||||||
<%= svg_icon('pencil', class: 'w-5 h-5') %>
|
<%= svg_icon('pencil', class: 'w-5 h-5') %>
|
||||||
@@ -176,7 +176,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug), class: 'absolute md:relative top-0 right-0 btn btn-xs text-xs btn-neutral text-white w-28 md:w-36 flex z-[1]', icon_class: 'w-4 h-4 text-white', copy_title: t('copy_link'), copy_title_md: t('copy_link').length < 10 ? t('copy_link') : t('copy'), copied_title_md: t('copied') %>
|
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug, host: form_link_host), class: 'absolute md:relative top-0 right-0 btn btn-xs text-xs btn-neutral text-white w-28 md:w-36 flex z-[1]', icon_class: 'w-4 h-4 text-white', copy_title: t('copy_link'), copy_title_md: t('copy_link').length < 10 ? t('copy_link') : t('copy'), copied_title_md: t('copied') %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<div class="h-36 relative group">
|
<div class="h-36 relative group">
|
||||||
<a href="<%= template_path(template) %>" class="flex h-full flex-col justify-between rounded-2xl pt-6 px-7 w-full bg-base-200 peer">
|
<a href="<%= template_path(template) %>" class="flex h-full flex-col justify-between rounded-2xl pt-6 px-7 w-full bg-base-200 peer">
|
||||||
<div class="pb-4 text-xl font-semibold" style="overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;">
|
<div class="pb-4 text-xl font-semibold" style="overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;">
|
||||||
|
<% if template.template_accesses.present? %>
|
||||||
|
<%= svg_icon('lock', class: 'w-6 h-6 inline -translate-y-[4px]') %>
|
||||||
|
<% end %>
|
||||||
<% template.name.split(/(_)/).each do |item| %><%= item %><wbr><% end %>
|
<% template.name.split(/(_)/).each do |item| %><%= item %><wbr><% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="pb-6 pt-1 space-y-1">
|
<div class="pb-6 pt-1 space-y-1">
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
<div class="flex flex-col items-start md:flex-row space-y-2 md:space-y-0 md:space-x-2 md:justify-between md:items-start mb-6 md:mb-3">
|
<div class="flex flex-col items-start md:flex-row space-y-2 md:space-y-0 md:space-x-2 md:justify-between md:items-start mb-6 md:mb-3">
|
||||||
<div class="relative flex items-start justify-between w-full space-x-0">
|
<div class="relative flex items-start justify-between w-full space-x-0">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-3xl md:text-4xl font-semibold" style="overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;">
|
<div id="template_title" class="flex">
|
||||||
<% template.name.split(/(_)/).each do |item| %><%= item %><wbr><% end %>
|
<h1 class="text-3xl md:text-[2em] font-semibold" style="overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;">
|
||||||
<% if template.archived_at? %>
|
<% template.name.split(/(_)/).each do |item| %><%= item %><wbr><% end %>
|
||||||
<span class="ml-1 badge badge-outline badge-lg align-middle"><%= t('archived') %></span>
|
<% if template.archived_at? %>
|
||||||
<% end %>
|
<span class="ml-1 badge badge-outline badge-lg align-middle"><%= t('archived') %></span>
|
||||||
</h1>
|
<% end %>
|
||||||
|
</h1>
|
||||||
|
<%= render 'templates/access_icon', template: @template %>
|
||||||
|
</div>
|
||||||
<% if @template.account_id == current_account.id %>
|
<% if @template.account_id == current_account.id %>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<%= render 'title', template: @template %>
|
<%= render 'title', template: @template %>
|
||||||
<% is_show_tabs = @pagy.pages > 1 || params[:status].present? %>
|
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
|
||||||
<% if !@pagy.count.zero? || params[:q].present? || params[:status].present? %>
|
<% is_show_tabs = @pagy.pages > 1 || params[:q].present? || params[:status].present? || filter_params.present? %>
|
||||||
|
<% if !@pagy.count.zero? || params[:q].present? || params[:status].present? || filter_params.present? %>
|
||||||
<div class="<%= is_show_tabs ? 'mb-4' : 'mb-6' %>">
|
<div class="<%= is_show_tabs ? 'mb-4' : 'mb-6' %>">
|
||||||
<div class="flex justify-between items-center md:items-end">
|
<div class="flex justify-between items-center md:items-end">
|
||||||
<div>
|
<div>
|
||||||
@@ -9,7 +10,7 @@
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end space-x-2">
|
<div class="flex justify-end space-x-2">
|
||||||
<% if params[:q].present? || params[:status].present? || @pagy.pages > 1 %>
|
<% if params[:q].present? || params[:status].present? || filter_params.present? || @pagy.pages > 1 %>
|
||||||
<%= render 'shared/search_input', title_selector: 'h2' %>
|
<%= render 'shared/search_input', title_selector: 'h2' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= link_to new_template_submissions_export_path(@template), class: 'hidden md:flex btn btn-ghost text-base', data: { turbo_frame: 'modal' } do %>
|
<%= link_to new_template_submissions_export_path(@template), class: 'hidden md:flex btn btn-ghost text-base', data: { turbo_frame: 'modal' } do %>
|
||||||
@@ -27,34 +28,40 @@
|
|||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if is_show_tabs %>
|
<% if is_show_tabs %>
|
||||||
<div class="flex items-center md:items-end flex-col space-y-2 md:space-y-0 md:flex-row md:space-x-2 mb-4">
|
<div class="flex items-center flex-col md:flex-row md:flex-wrap gap-2 mb-4">
|
||||||
<a href="<%= url_for(params.to_unsafe_h.except(:status)) %>" class="<%= params[:status].blank? ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-600">
|
<div class="flex items-center md:items-end flex-col md:flex-row gap-2 w-full md:w-fit">
|
||||||
<div class="flex items-center space-x-1">
|
<a href="<%= url_for(params.to_unsafe_h.except(:status)) %>" class="<%= params[:status].blank? ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-700">
|
||||||
<%= svg_icon('list', class: 'w-5 h-5') %>
|
<div class="flex items-center space-x-1">
|
||||||
<span class="font-normal"><%= t('all') %></span>
|
<%= svg_icon('list', class: 'w-5 h-5') %>
|
||||||
</div>
|
<span class="font-normal"><%= t('all') %></span>
|
||||||
<div class="badge badge-neutral badge-outline font-medium">
|
</div>
|
||||||
<%= params[:status].blank? ? @pagy.count : @base_submissions.count %>
|
<div class="badge badge-neutral badge-outline font-medium">
|
||||||
</div>
|
<%= params[:status].blank? && filter_params.blank? ? @pagy.count : @base_submissions.unscope(:group, :order).select(:id).distinct.count %>
|
||||||
</a>
|
</div>
|
||||||
<a href="<%= url_for(params.to_unsafe_h.merge(status: :pending)) %>" class="<%= params[:status] == 'pending' ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-600">
|
</a>
|
||||||
<div class="flex items-center space-x-1">
|
<a href="<%= url_for(params.to_unsafe_h.merge(status: :pending)) %>" class="<%= params[:status] == 'pending' ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-700">
|
||||||
<%= svg_icon('clock', class: 'w-5 h-5') %>
|
<div class="flex items-center space-x-1">
|
||||||
<span class="font-normal"><%= t('pending') %></span>
|
<%= svg_icon('clock', class: 'w-5 h-5') %>
|
||||||
</div>
|
<span class="font-normal"><%= t('pending') %></span>
|
||||||
<div class="badge badge-neutral badge-outline font-medium">
|
</div>
|
||||||
<%= params[:status] == 'pending' ? @pagy.count : @base_submissions.pending.count %>
|
<div class="badge badge-neutral badge-outline font-medium">
|
||||||
</div>
|
<%= params[:status] == 'pending' && filter_params.blank? ? @pagy.count : @base_submissions.pending.unscope(:group, :order).select(:id).distinct.count %>
|
||||||
</a>
|
</div>
|
||||||
<a href="<%= url_for(params.to_unsafe_h.merge(status: :completed)) %>" class="<%= params[:status] == 'completed' ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-600">
|
</a>
|
||||||
<div class="flex items-center space-x-1">
|
<a href="<%= url_for(params.to_unsafe_h.merge(status: :completed)) %>" class="<%= params[:status] == 'completed' ? 'border-neutral-700' : 'border-neutral-300' %> flex h-10 px-2 py-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl w-full md:w-48 hover:border-neutral-700">
|
||||||
<%= svg_icon('circle_check', class: 'w-5 h-5') %>
|
<div class="flex items-center space-x-1">
|
||||||
<span class="font-normal"><%= t('completed') %></span>
|
<%= svg_icon('circle_check', class: 'w-5 h-5') %>
|
||||||
</div>
|
<span class="font-normal"><%= t('completed') %></span>
|
||||||
<div class="badge badge-neutral badge-outline font-medium">
|
</div>
|
||||||
<%= params[:status] == 'completed' ? @pagy.count : @base_submissions.completed.count %>
|
<div class="badge badge-neutral badge-outline font-medium">
|
||||||
</div>
|
<%= params[:status] == 'completed' && filter_params.blank? ? @pagy.count : @base_submissions.completed.unscope(:group, :order).select(:id).distinct.count %>
|
||||||
</a>
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-end flex-col md:flex-row gap-2 w-full md:w-fit">
|
||||||
|
<%= render 'submissions_filters/applied_filters', filter_params: %>
|
||||||
|
<%= render 'submissions_filters/filter_button', filter_params: %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if @submissions.present? %>
|
<% if @submissions.present? %>
|
||||||
@@ -65,31 +72,33 @@
|
|||||||
<div class="card bg-base-200">
|
<div class="card bg-base-200">
|
||||||
<div class="card-body text-center px-4 py-16">
|
<div class="card-body text-center px-4 py-16">
|
||||||
<div class="max-w-lg mx-auto">
|
<div class="max-w-lg mx-auto">
|
||||||
<p class="text-3xl font-bold text-base-content mb-4">
|
<p class="text-3xl font-bold text-base-content">
|
||||||
<%= t('there_are_no_submissions') %>
|
<%= t('there_are_no_submissions') %>
|
||||||
</p>
|
</p>
|
||||||
<% if @template.archived_at.blank? && params[:q].blank? %>
|
<% if @template.archived_at.blank? && params[:q].blank? && filter_params.blank? %>
|
||||||
<p><%= t('send_an_invitation_to_fill_and_complete_the_form') %></p>
|
<div class="mt-4">
|
||||||
<div class="space-y-2 flex flex-col">
|
<p><%= t('send_an_invitation_to_fill_and_complete_the_form') %></p>
|
||||||
<% if can?(:create, Submission) %>
|
<div class="space-y-2 flex flex-col">
|
||||||
<%= link_to new_template_submission_path(@template, with_link: true), class: 'base-button mt-6', data: { turbo_frame: 'modal' } do %>
|
<% if can?(:create, Submission) %>
|
||||||
<%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %>
|
<%= link_to new_template_submission_path(@template, with_link: true), class: 'base-button mt-6', data: { turbo_frame: 'modal' } do %>
|
||||||
<span class="mr-1"><%= t('send_to_recipients') %></span>
|
<%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %>
|
||||||
|
<span class="mr-1"><%= t('send_to_recipients') %></span>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% if @template.submitters.size == 1 %>
|
||||||
<% if @template.submitters.size == 1 %>
|
<%= link_to start_form_url(slug: @template.slug), class: 'white-button mt-6', target: '_blank', rel: 'noopener' do %>
|
||||||
<%= link_to start_form_url(slug: @template.slug), class: 'white-button mt-6', target: '_blank', rel: 'noopener' do %>
|
<%= svg_icon('writing', class: 'w-6 h-6') %>
|
||||||
<%= svg_icon('writing', class: 'w-6 h-6') %>
|
<span class="mr-1"><%= t('sign_it_yourself') %></span>
|
||||||
<span class="mr-1"><%= t('sign_it_yourself') %></span>
|
<% end %>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to new_template_submission_path(@template, selfsign: true), class: 'white-button mt-6', data: { turbo_frame: 'modal' } do %>
|
||||||
|
<%= svg_icon('writing', class: 'w-6 h-6') %>
|
||||||
|
<span class="mr-1"><%= t('sign_it_yourself') %></span>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% else %>
|
</div>
|
||||||
<%= link_to new_template_submission_path(@template, selfsign: true), class: 'white-button mt-6', data: { turbo_frame: 'modal' } do %>
|
</div>
|
||||||
<%= svg_icon('writing', class: 'w-6 h-6') %>
|
<% end %>
|
||||||
<span class="mr-1"><%= t('sign_it_yourself') %></span>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
|
||||||
|
<% with_filters = @pagy.pages > 1 || params[:q].present? || filter_params.present? %>
|
||||||
<%= render 'templates/title', template: @template %>
|
<%= render 'templates/title', template: @template %>
|
||||||
<div>
|
<div>
|
||||||
<%= link_to template_path(@template) do %>
|
<%= link_to template_path(@template) do %>
|
||||||
@@ -5,23 +7,33 @@
|
|||||||
<span><%= t('back_to_active') %></span>
|
<span><%= t('back_to_active') %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between mb-6 md:items-end flex-col md:flex-row">
|
<div class="flex flex-col md:flex-row md:items-center mb-6 gap-3">
|
||||||
<div>
|
<div class="flex w-full justify-between md:items-end items-center">
|
||||||
<h1 class="text-3xl font-bold md:block"><%= t('submissions') %> <span class="badge badge-outline badge-lg align-middle"><%= t('archived') %></span></h1>
|
<div>
|
||||||
</div>
|
<h1 class="text-3xl font-bold md:block"><%= t('submissions') %> <span class="badge badge-outline badge-lg align-middle"><%= t('archived') %></span></h1>
|
||||||
<div class="flex space-x-2 mt-3 md:mt-0 justify-end">
|
</div>
|
||||||
<%= render 'shared/search_input' %>
|
<div class="flex space-x-2 justify-end">
|
||||||
<%= link_to new_template_submissions_export_path(@template), class: 'order-3 md:order-1 btn btn-ghost text-base', data: { turbo_frame: 'modal' } do %>
|
<% if with_filters %>
|
||||||
<%= svg_icon('download', class: 'w-6 h-6 stroke-2') %>
|
<%= render 'shared/search_input' %>
|
||||||
<span><%= t('export') %></span>
|
<% end %>
|
||||||
<% end %>
|
<%= link_to new_template_submissions_export_path(@template), class: 'btn btn-ghost text-base', data: { turbo_frame: 'modal' } do %>
|
||||||
|
<%= svg_icon('download', class: 'w-6 h-6 stroke-2') %>
|
||||||
|
<span><%= t('export') %></span>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<% if with_filters %>
|
||||||
|
<div class="flex flex-col items-end md:flex-row gap-2">
|
||||||
|
<%= render 'submissions_filters/applied_filters', filter_params: %>
|
||||||
|
<%= render 'submissions_filters/filter_button', filter_params: %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% if @pagy.count > 0 %>
|
<% if @pagy.count > 0 %>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<%= render partial: 'templates/submission', collection: @submissions, locals: { template: @template, archived: true } %>
|
<%= render partial: 'templates/submission', collection: @submissions, locals: { template: @template, archived: true } %>
|
||||||
</div>
|
</div>
|
||||||
<% elsif params[:q].present? %>
|
<% elsif params[:q].present? || filter_params.present? %>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="mt-16 text-3xl font-semibold">
|
<div class="mt-16 text-3xl font-semibold">
|
||||||
<%= t('submissions_not_found') %>
|
<%= t('submissions_not_found') %>
|
||||||
|
|||||||
Whitespace-only changes.
@@ -19,6 +19,7 @@
|
|||||||
</toggle-visible>
|
</toggle-visible>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div id="general" class="px-5 mb-4">
|
<div id="general" class="px-5 mb-4">
|
||||||
|
<%= render 'access' %>
|
||||||
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-2' }, data: { close_on_submit: false } do |f| %>
|
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-2' }, data: { close_on_submit: false } do |f| %>
|
||||||
<toggle-on-submit data-element-id="bcc_saved_alert"></toggle-on-submit>
|
<toggle-on-submit data-element-id="bcc_saved_alert"></toggle-on-submit>
|
||||||
<%= f.fields_for :preferences, Struct.new(:bcc_completed).new(@template.preferences['bcc_completed']) do |ff| %>
|
<%= f.fields_for :preferences, Struct.new(:bcc_completed).new(@template.preferences['bcc_completed']) do |ff| %>
|
||||||
@@ -117,7 +118,7 @@
|
|||||||
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
|
<%= form_for @template, url: template_preferences_path(@template), method: :post, html: { autocomplete: 'off', class: 'mt-1' }, data: { close_on_submit: false } do |f| %>
|
||||||
<toggle-on-submit data-element-id="email_saved_alert2"></toggle-on-submit>
|
<toggle-on-submit data-element-id="email_saved_alert2"></toggle-on-submit>
|
||||||
<% configs = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY).value %>
|
<% configs = AccountConfigs.find_or_initialize_for_key(current_account, AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY).value %>
|
||||||
<%= f.fields_for :preferences, Struct.new(:documents_copy_email_subject, :documents_copy_email_body, :documents_copy_email_enabled, :documents_copy_email_attach_audit).new(@template.preferences['documents_copy_email_subject'].presence || configs['subject'], @template.preferences['documents_copy_email_body'].presence || configs['body'], @template.preferences['documents_copy_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['documents_copy_email_attach_audit'] != false) do |ff| %>
|
<%= f.fields_for :preferences, Struct.new(:documents_copy_email_subject, :documents_copy_email_body, :documents_copy_email_enabled, :documents_copy_email_attach_audit, :documents_copy_email_attach_documents).new(@template.preferences['documents_copy_email_subject'].presence || configs['subject'], @template.preferences['documents_copy_email_body'].presence || configs['body'], @template.preferences['documents_copy_email_enabled'], configs['attach_audit_log'] != false && @template.preferences['documents_copy_email_attach_audit'] != false, configs['attach_documents'] != false && @template.preferences['documents_copy_email_attach_documents'] != false) do |ff| %>
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
<%= ff.label :documents_copy_email_subject, t('email_subject'), class: 'label' %>
|
<%= ff.label :documents_copy_email_subject, t('email_subject'), class: 'label' %>
|
||||||
<%= ff.text_field :documents_copy_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
<%= ff.text_field :documents_copy_email_subject, required: true, class: 'base-input', dir: 'auto' %>
|
||||||
@@ -133,6 +134,12 @@
|
|||||||
<%= ff.text_area :documents_copy_email_body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
<%= ff.text_area :documents_copy_email_body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
||||||
</autoresize-textarea>
|
</autoresize-textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center justify-between pt-2.5 px-1 mb-2">
|
||||||
|
<span>
|
||||||
|
<%= t('attach_documents_to_the_email') %>
|
||||||
|
</span>
|
||||||
|
<%= ff.check_box :documents_copy_email_attach_documents, { checked: ff.object.documents_copy_email_attach_documents != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
|
||||||
|
</div>
|
||||||
<div class="flex items-center justify-between pt-2.5 px-1 mb-2">
|
<div class="flex items-center justify-between pt-2.5 px-1 mb-2">
|
||||||
<span>
|
<span>
|
||||||
<%= t('attach_audit_log_pdf_to_the_email') %>
|
<%= t('attach_audit_log_pdf_to_the_email') %>
|
||||||
@@ -180,24 +187,24 @@
|
|||||||
<%= ff.text_area :completed_notification_email_body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
<%= ff.text_area :completed_notification_email_body, required: true, class: 'base-input w-full py-2', dir: 'auto' %>
|
||||||
</autoresize-textarea>
|
</autoresize-textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between pt-2.5 px-1 mb-2">
|
|
||||||
<span>
|
|
||||||
<%= t('send_emails_automatically_on_completion') %>
|
|
||||||
</span>
|
|
||||||
<%= ff.check_box :completed_notification_email_enabled, { checked: ff.object.completed_notification_email_enabled != false, class: 'toggle', onchange: 'this.form.requestSubmit()' }, 'true', 'false' %>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between pt-2.5 px-1 mb-2">
|
<div class="flex items-center justify-between pt-2.5 px-1 mb-2">
|
||||||
<span>
|
<span>
|
||||||
<%= t('attach_documents_to_the_email') %>
|
<%= t('attach_documents_to_the_email') %>
|
||||||
</span>
|
</span>
|
||||||
<%= ff.check_box :completed_notification_email_attach_documents, { checked: ff.object.completed_notification_email_attach_documents != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
|
<%= ff.check_box :completed_notification_email_attach_documents, { checked: ff.object.completed_notification_email_attach_documents != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between py-2.5 px-1 mb-2">
|
<div class="flex items-center justify-between pt-2.5 px-1 mb-2">
|
||||||
<span>
|
<span>
|
||||||
<%= t('attach_audit_log_pdf_to_the_email') %>
|
<%= t('attach_audit_log_pdf_to_the_email') %>
|
||||||
</span>
|
</span>
|
||||||
<%= ff.check_box :completed_notification_email_attach_audit, { checked: ff.object.completed_notification_email_attach_audit != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
|
<%= ff.check_box :completed_notification_email_attach_audit, { checked: ff.object.completed_notification_email_attach_audit != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center justify-between py-2.5 px-1 mb-2">
|
||||||
|
<span>
|
||||||
|
<%= t('send_emails_automatically_on_completion') %>
|
||||||
|
</span>
|
||||||
|
<%= ff.check_box :completed_notification_email_enabled, { checked: ff.object.completed_notification_email_enabled != false, class: 'toggle', onchange: 'this.form.requestSubmit()' }, 'true', 'false' %>
|
||||||
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="form-control pt-2">
|
<div class="form-control pt-2">
|
||||||
<%= f.button button_title(title: t('save'), disabled_with: t('saving')), class: 'base-button' %>
|
<%= f.button button_title(title: t('save'), disabled_with: t('saving')), class: 'base-button' %>
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ production:
|
|||||||
username: <%= ENV['DATABASE_USER'] %>
|
username: <%= ENV['DATABASE_USER'] %>
|
||||||
password: <%= ENV['DATABASE_PASSWORD'] %>
|
password: <%= ENV['DATABASE_PASSWORD'] %>
|
||||||
database: <%= ENV['DATABASE_NAME'] %>
|
database: <%= ENV['DATABASE_NAME'] %>
|
||||||
|
<% if !ENV['DATABASE_SEARCH_PATH'].to_s.empty? %>
|
||||||
|
search_path: <%= ENV['DATABASE_SEARCH_PATH'] %>
|
||||||
|
<% end %>
|
||||||
<% elsif ENV['DATABASE_URL'].to_s.empty? %>
|
<% elsif ENV['DATABASE_URL'].to_s.empty? %>
|
||||||
adapter: sqlite3
|
adapter: sqlite3
|
||||||
database: <%= ENV['WORKDIR'] || '.' %>/db.sqlite3
|
database: <%= ENV['WORKDIR'] || '.' %>/db.sqlite3
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ end
|
|||||||
|
|
||||||
ActiveSupport.on_load(:active_storage_blob) do
|
ActiveSupport.on_load(:active_storage_blob) do
|
||||||
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
attribute :uuid, :string, default: -> { SecureRandom.uuid }
|
||||||
|
attribute :io_data, :string, default: ''
|
||||||
|
|
||||||
def self.proxy_url(blob, expires_at: nil)
|
def self.proxy_url(blob, expires_at: nil, filename: nil, host: nil)
|
||||||
Rails.application.routes.url_helpers.blobs_proxy_url(
|
Rails.application.routes.url_helpers.blobs_proxy_url(
|
||||||
signed_uuid: blob.signed_uuid(expires_at:), filename: blob.filename,
|
signed_uuid: blob.signed_uuid(expires_at:), filename: filename || blob.filename,
|
||||||
**Docuseal.default_url_options
|
**Docuseal.default_url_options,
|
||||||
|
**{ host: }.compact
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+193
-7
@@ -22,6 +22,18 @@ en: &en
|
|||||||
thanks: Thanks
|
thanks: Thanks
|
||||||
unarchive: Unarchive
|
unarchive: Unarchive
|
||||||
first_party: 'First Party'
|
first_party: 'First Party'
|
||||||
|
remove_filter: Remove filter
|
||||||
|
add: Add
|
||||||
|
adding: Adding
|
||||||
|
owner: Owner
|
||||||
|
select_user: Select user
|
||||||
|
team_member_permissions: Team member permissions
|
||||||
|
entire_team: Entire team
|
||||||
|
admin_only: Admin only
|
||||||
|
accessiable_by: Accessiable by
|
||||||
|
team_access: Team access
|
||||||
|
document_download_filename_format: Document download filename format
|
||||||
|
document_name: Document Name
|
||||||
docuseal_trusted_signature: DocuSeal Trusted Signature
|
docuseal_trusted_signature: DocuSeal Trusted Signature
|
||||||
hello_name: Hello %{name}
|
hello_name: Hello %{name}
|
||||||
you_are_invited_to_product_name: You are invited to %{product_name}
|
you_are_invited_to_product_name: You are invited to %{product_name}
|
||||||
@@ -344,7 +356,7 @@ en: &en
|
|||||||
edit_message: Edit message
|
edit_message: Edit message
|
||||||
smtp_not_configured: SMTP not Configured
|
smtp_not_configured: SMTP not Configured
|
||||||
configure_smtp_settings_in_order_to_send_emails_: 'Configure SMTP settings in order to send emails:'
|
configure_smtp_settings_in_order_to_send_emails_: 'Configure SMTP settings in order to send emails:'
|
||||||
go_to_smtp_setting: Go to SMTP setting
|
go_to_smtp_settings: Go to SMTP settings
|
||||||
save_as_default_template_message: Save as default template message
|
save_as_default_template_message: Save as default template message
|
||||||
re_send_sms: Re-send SMS
|
re_send_sms: Re-send SMS
|
||||||
send_sms: Send SMS
|
send_sms: Send SMS
|
||||||
@@ -615,11 +627,13 @@ en: &en
|
|||||||
stamp_field: Stamp Field
|
stamp_field: Stamp Field
|
||||||
payment_field: Payment Field
|
payment_field: Payment Field
|
||||||
phone_field: Phone Field
|
phone_field: Phone Field
|
||||||
|
verification_field: Identity Verification
|
||||||
|
identity_verification: Identity verification
|
||||||
paid_price: 'Paid %{price}'
|
paid_price: 'Paid %{price}'
|
||||||
verified: Verified
|
verified: Verified
|
||||||
unverified: Unverified
|
unverified: Unverified
|
||||||
document: Document
|
document: Document
|
||||||
completed_at: Completed At
|
completed_at: Completed at
|
||||||
edit_recipient: Edit Recipient
|
edit_recipient: Edit Recipient
|
||||||
update_recipient: Update Recipient
|
update_recipient: Update Recipient
|
||||||
use_international_format_1xxx_: 'Use internatioanl format: +1xxx...'
|
use_international_format_1xxx_: 'Use internatioanl format: +1xxx...'
|
||||||
@@ -631,6 +645,21 @@ en: &en
|
|||||||
key: Key
|
key: Key
|
||||||
value: Value
|
value: Value
|
||||||
webhook_secret: Webhook Secret
|
webhook_secret: Webhook Secret
|
||||||
|
author: Author
|
||||||
|
to: To
|
||||||
|
created_at: Created at
|
||||||
|
apply: Apply
|
||||||
|
applying: Applying
|
||||||
|
today: Today
|
||||||
|
yesterday: Yesterday
|
||||||
|
this_week: This week
|
||||||
|
last_week: Last week
|
||||||
|
this_month: This month
|
||||||
|
last_month: Last month
|
||||||
|
this_year: This year
|
||||||
|
policy_links: Policy Links
|
||||||
|
markdown_content_e_g: Markdown content, e.g.
|
||||||
|
privacy_policy: Privacy Policy
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>Email sent</b> to %{submitter_name}'
|
send_email_to_html: '<b>Email sent</b> to %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>Reminder email sent</b> to %{submitter_name}'
|
send_reminder_email_to_html: '<b>Reminder email sent</b> to %{submitter_name}'
|
||||||
@@ -644,6 +673,8 @@ en: &en
|
|||||||
view_form_by_html: '<b>Form viewed</b> by %{submitter_name}'
|
view_form_by_html: '<b>Form viewed</b> by %{submitter_name}'
|
||||||
invite_party_by_html: '<b>Invited</b> %{invited_submitter_name} by %{submitter_name}'
|
invite_party_by_html: '<b>Invited</b> %{invited_submitter_name} by %{submitter_name}'
|
||||||
complete_form_by_html: '<b>Submission completed</b> by %{submitter_name}'
|
complete_form_by_html: '<b>Submission completed</b> by %{submitter_name}'
|
||||||
|
start_verification_by_html: '<b>Identity verification started</b> by %{submitter_name}'
|
||||||
|
complete_verification_by_html: '<b>Identity verification completed</b> by %{submitter_name} with %{provider}'
|
||||||
api_complete_form_by_html: '<b>Submission completed via API</b> by %{submitter_name}'
|
api_complete_form_by_html: '<b>Submission completed via API</b> by %{submitter_name}'
|
||||||
import_list:
|
import_list:
|
||||||
select_worksheet: Select Worksheet
|
select_worksheet: Select Worksheet
|
||||||
@@ -667,6 +698,18 @@ en: &en
|
|||||||
read: Read your data
|
read: Read your data
|
||||||
|
|
||||||
es: &es
|
es: &es
|
||||||
|
add: Agregar
|
||||||
|
adding: Agregando
|
||||||
|
owner: Propietario
|
||||||
|
select_user: Seleccionar usuario
|
||||||
|
team_member_permissions: Permisos de miembros del equipo
|
||||||
|
entire_team: Todo el equipo
|
||||||
|
admin_only: Solo administrador
|
||||||
|
accessiable_by: Accesible por
|
||||||
|
team_access: Acceso del equipo
|
||||||
|
remove_filter: Eliminar filtro
|
||||||
|
document_download_filename_format: Formato del nombre del archivo de descarga del documento
|
||||||
|
document_name: Nombre del documento
|
||||||
unarchive: Desarchivar
|
unarchive: Desarchivar
|
||||||
awaiting_completion_by_the_other_party: "Esperando la finalización por la otra parte"
|
awaiting_completion_by_the_other_party: "Esperando la finalización por la otra parte"
|
||||||
enforce_recipients_order: 'Hacer cumplir el orden de los destinatarios'
|
enforce_recipients_order: 'Hacer cumplir el orden de los destinatarios'
|
||||||
@@ -993,7 +1036,7 @@ es: &es
|
|||||||
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:'
|
||||||
go_to_smtp_setting: Ir a la configuración de SMTP
|
go_to_smtp_settings: Ir a la configuración de SMTP
|
||||||
save_as_default_template_message: Guardar como mensaje de plantilla predeterminado
|
save_as_default_template_message: Guardar como mensaje de plantilla predeterminado
|
||||||
re_send_sms: Reenviar SMS
|
re_send_sms: Reenviar SMS
|
||||||
send_sms: Enviar SMS
|
send_sms: Enviar SMS
|
||||||
@@ -1264,6 +1307,8 @@ es: &es
|
|||||||
stamp_field: Campo de Sello
|
stamp_field: Campo de Sello
|
||||||
payment_field: Campo de Pago
|
payment_field: Campo de Pago
|
||||||
phone_field: Campo de Teléfono
|
phone_field: Campo de Teléfono
|
||||||
|
verification_field: Verificación de Identidad
|
||||||
|
identity_verification: Verificación de Identidad
|
||||||
paid_price: 'Pagado %{price}'
|
paid_price: 'Pagado %{price}'
|
||||||
verified: Verificado
|
verified: Verificado
|
||||||
unverified: No verificado
|
unverified: No verificado
|
||||||
@@ -1280,6 +1325,21 @@ es: &es
|
|||||||
key: Clave
|
key: Clave
|
||||||
value: Valor
|
value: Valor
|
||||||
webhook_secret: Secreto del Webhook
|
webhook_secret: Secreto del Webhook
|
||||||
|
author: Autor
|
||||||
|
to: A
|
||||||
|
created_at: Creado el
|
||||||
|
apply: Aplicar
|
||||||
|
applying: Aplicando
|
||||||
|
today: Hoy
|
||||||
|
yesterday: Ayer
|
||||||
|
this_week: Esta Semana
|
||||||
|
last_week: La Semana Pasada
|
||||||
|
this_month: Este Mes
|
||||||
|
last_month: El Mes Pasado
|
||||||
|
this_year: Este Año
|
||||||
|
policy_links: Enlaces de Políticas
|
||||||
|
markdown_content_e_g: Contenido Markdown, por ej.
|
||||||
|
privacy_policy: Política de Privacidad
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>Correo electrónico enviado</b> a %{submitter_name}'
|
send_email_to_html: '<b>Correo electrónico enviado</b> a %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>Correo de recordatorio enviado</b> a %{submitter_name}'
|
send_reminder_email_to_html: '<b>Correo de recordatorio enviado</b> a %{submitter_name}'
|
||||||
@@ -1294,6 +1354,8 @@ es: &es
|
|||||||
invite_party_by_html: '<b>Invitado</b> %{invited_submitter_name} por %{submitter_name}'
|
invite_party_by_html: '<b>Invitado</b> %{invited_submitter_name} por %{submitter_name}'
|
||||||
complete_form_by_html: '<b>Envío completado</b> por %{submitter_name}'
|
complete_form_by_html: '<b>Envío completado</b> por %{submitter_name}'
|
||||||
api_complete_form_by_html: '<b>Envío completado vía API</b> por %{submitter_name}'
|
api_complete_form_by_html: '<b>Envío completado vía API</b> por %{submitter_name}'
|
||||||
|
start_verification_by_html: '<b>Verificación de identidad iniciada</b> por %{submitter_name}'
|
||||||
|
complete_verification_by_html: '<b>Verificación de identidad completada</b> por %{submitter_name} con %{provider}'
|
||||||
import_list:
|
import_list:
|
||||||
select_worksheet: Seleccionar hoja de cálculo
|
select_worksheet: Seleccionar hoja de cálculo
|
||||||
open: Abrir
|
open: Abrir
|
||||||
@@ -1316,6 +1378,18 @@ es: &es
|
|||||||
read: Leer tus datos
|
read: Leer tus datos
|
||||||
|
|
||||||
it: &it
|
it: &it
|
||||||
|
add: Aggiungi
|
||||||
|
adding: Aggiungendo
|
||||||
|
owner: Proprietario
|
||||||
|
select_user: Seleziona utente
|
||||||
|
team_member_permissions: Permessi membri del team
|
||||||
|
entire_team: Intero team
|
||||||
|
admin_only: Solo amministratore
|
||||||
|
accessiable_by: Accessibile da
|
||||||
|
team_access: Accesso al team
|
||||||
|
remove_filter: Rimuovi filtro
|
||||||
|
document_download_filename_format: Formato del nome file scaricato
|
||||||
|
document_name: Nome del Documento
|
||||||
unarchive: Ripristina
|
unarchive: Ripristina
|
||||||
awaiting_completion_by_the_other_party: "In attesa di completamento da parte dell'altra parte"
|
awaiting_completion_by_the_other_party: "In attesa di completamento da parte dell'altra parte"
|
||||||
enforce_recipients_order: Aplicar el orden de los destinatarios
|
enforce_recipients_order: Aplicar el orden de los destinatarios
|
||||||
@@ -1642,7 +1716,7 @@ it: &it
|
|||||||
edit_message: Modifica messaggio
|
edit_message: Modifica messaggio
|
||||||
smtp_not_configured: SMTP non configurato
|
smtp_not_configured: SMTP non configurato
|
||||||
configure_smtp_settings_in_order_to_send_emails_: 'Configura le impostazioni SMTP per inviare email:'
|
configure_smtp_settings_in_order_to_send_emails_: 'Configura le impostazioni SMTP per inviare email:'
|
||||||
go_to_smtp_setting: Vai alle impostazioni SMTP
|
go_to_smtp_settings: Vai alle impostazioni SMTP
|
||||||
save_as_default_template_message: Salva come messaggio modello predefinito
|
save_as_default_template_message: Salva come messaggio modello predefinito
|
||||||
re_send_sms: Reinvio SMS
|
re_send_sms: Reinvio SMS
|
||||||
send_sms: Invia SMS
|
send_sms: Invia SMS
|
||||||
@@ -1913,6 +1987,8 @@ it: &it
|
|||||||
stamp_field: Campo Timbro
|
stamp_field: Campo Timbro
|
||||||
payment_field: Campo Pagamento
|
payment_field: Campo Pagamento
|
||||||
phone_field: Campo Telefono
|
phone_field: Campo Telefono
|
||||||
|
verification_field: "Verifica dell'identità"
|
||||||
|
identity_verification: "Verifica dell'identità"
|
||||||
paid_price: 'Pagato %{price}'
|
paid_price: 'Pagato %{price}'
|
||||||
verified: Verificato
|
verified: Verificato
|
||||||
unverified: Non verificato
|
unverified: Non verificato
|
||||||
@@ -1929,6 +2005,21 @@ it: &it
|
|||||||
key: Chiave
|
key: Chiave
|
||||||
value: Valore
|
value: Valore
|
||||||
webhook_secret: Segreto del Webhook
|
webhook_secret: Segreto del Webhook
|
||||||
|
author: Autore
|
||||||
|
to: A
|
||||||
|
created_at: Creato il
|
||||||
|
apply: Applica
|
||||||
|
applying: Applicazione
|
||||||
|
today: Oggi
|
||||||
|
yesterday: Ieri
|
||||||
|
this_week: Questa Settimana
|
||||||
|
last_week: Settimana Scorsa
|
||||||
|
this_month: Questo Mese
|
||||||
|
last_month: Mese Scorso
|
||||||
|
this_year: "Quest'Anno"
|
||||||
|
policy_links: Collegamenti alle Politiche
|
||||||
|
markdown_content_e_g: Contenuto Markdown, ad es.
|
||||||
|
privacy_policy: Politica sulla Privacy
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>E-mail inviato</b> a %{submitter_name}'
|
send_email_to_html: '<b>E-mail inviato</b> a %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>E-mail di promemoria inviato</b> a %{submitter_name}'
|
send_reminder_email_to_html: '<b>E-mail di promemoria inviato</b> a %{submitter_name}'
|
||||||
@@ -1943,6 +2034,8 @@ it: &it
|
|||||||
invite_party_by_html: '<b>Invitato</b> %{invited_submitter_name} da %{submitter_name}'
|
invite_party_by_html: '<b>Invitato</b> %{invited_submitter_name} da %{submitter_name}'
|
||||||
complete_form_by_html: '<b>Invio completato</b> da %{submitter_name}'
|
complete_form_by_html: '<b>Invio completato</b> da %{submitter_name}'
|
||||||
api_complete_form_by_html: '<b>Invio completato tramite API</b> da %{submitter_name}'
|
api_complete_form_by_html: '<b>Invio completato tramite API</b> da %{submitter_name}'
|
||||||
|
start_verification_by_html: "<b>Verifica dell'identità iniziata</b> da %{submitter_name}"
|
||||||
|
complete_verification_by_html: "<b>Verifica dell'identità completata</b> da %{submitter_name} con %{provider}"
|
||||||
import_list:
|
import_list:
|
||||||
select_worksheet: Seleziona il foglio di lavoro
|
select_worksheet: Seleziona il foglio di lavoro
|
||||||
open: Apri
|
open: Apri
|
||||||
@@ -1965,6 +2058,18 @@ it: &it
|
|||||||
read: Leggi i tuoi dati
|
read: Leggi i tuoi dati
|
||||||
|
|
||||||
fr: &fr
|
fr: &fr
|
||||||
|
add: Ajouter
|
||||||
|
adding: Ajout
|
||||||
|
owner: Propriétaire
|
||||||
|
select_user: Sélectionner un utilisateur
|
||||||
|
team_member_permissions: Permissions des membres de l'équipe
|
||||||
|
entire_team: Équipe entière
|
||||||
|
admin_only: Administrateur uniquement
|
||||||
|
accessiable_by: Accessible par
|
||||||
|
team_access: Accès à l'équipe
|
||||||
|
remove_filter: Supprimer le filtre
|
||||||
|
document_download_filename_format: Format du nom de fichier du téléchargement de document
|
||||||
|
document_name: Nom du document
|
||||||
unarchive: Désarchiver
|
unarchive: Désarchiver
|
||||||
awaiting_completion_by_the_other_party: "En attente de la complétion par l'autre partie"
|
awaiting_completion_by_the_other_party: "En attente de la complétion par l'autre partie"
|
||||||
enforce_recipients_order: "Respecter l'ordre des destinataires"
|
enforce_recipients_order: "Respecter l'ordre des destinataires"
|
||||||
@@ -2292,7 +2397,7 @@ fr: &fr
|
|||||||
edit_message: Modifier le message
|
edit_message: Modifier le message
|
||||||
smtp_not_configured: SMTP non configuré
|
smtp_not_configured: SMTP non configuré
|
||||||
configure_smtp_settings_in_order_to_send_emails_: 'Configurez les paramètres SMTP pour envoyer des e-mails:'
|
configure_smtp_settings_in_order_to_send_emails_: 'Configurez les paramètres SMTP pour envoyer des e-mails:'
|
||||||
go_to_smtp_setting: Aller aux paramètres SMTP
|
go_to_smtp_settings: Aller aux paramètres SMTP
|
||||||
save_as_default_template_message: Enregistrer comme modèle de message par défaut
|
save_as_default_template_message: Enregistrer comme modèle de message par défaut
|
||||||
re_send_sms: Renvoyer le SMS
|
re_send_sms: Renvoyer le SMS
|
||||||
send_sms: Envoyer SMS
|
send_sms: Envoyer SMS
|
||||||
@@ -2563,6 +2668,8 @@ fr: &fr
|
|||||||
stamp_field: Champ de Tampon
|
stamp_field: Champ de Tampon
|
||||||
payment_field: Champ de Paiement
|
payment_field: Champ de Paiement
|
||||||
phone_field: Champ de Téléphone
|
phone_field: Champ de Téléphone
|
||||||
|
verification_field: "Vérification d'Identité"
|
||||||
|
identity_verification: "Vérification d'identité"
|
||||||
paid_price: 'Payé %{price}'
|
paid_price: 'Payé %{price}'
|
||||||
verified: Vérifié
|
verified: Vérifié
|
||||||
unverified: Non vérifié
|
unverified: Non vérifié
|
||||||
@@ -2579,6 +2686,21 @@ fr: &fr
|
|||||||
key: Clé
|
key: Clé
|
||||||
value: Valeur
|
value: Valeur
|
||||||
webhook_secret: Secret du Webhook
|
webhook_secret: Secret du Webhook
|
||||||
|
author: Auteur
|
||||||
|
to: À
|
||||||
|
created_at: Créé le
|
||||||
|
apply: Appliquer
|
||||||
|
applying: Application en cours
|
||||||
|
today: "Aujourd'hui"
|
||||||
|
yesterday: Hier
|
||||||
|
this_week: Cette Semaine
|
||||||
|
last_week: La Semaine Dernière
|
||||||
|
this_month: Ce Mois-ci
|
||||||
|
last_month: Le Mois Dernier
|
||||||
|
this_year: Cette Année
|
||||||
|
policy_links: Liens des Politiques
|
||||||
|
markdown_content_e_g: Contenu Markdown, par ex.
|
||||||
|
privacy_policy: Politique de Confidentialité
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>E-mail envoyé</b> à %{submitter_name}'
|
send_email_to_html: '<b>E-mail envoyé</b> à %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>E-mail de rappel envoyé</b> à %{submitter_name}'
|
send_reminder_email_to_html: '<b>E-mail de rappel envoyé</b> à %{submitter_name}'
|
||||||
@@ -2592,6 +2714,8 @@ fr: &fr
|
|||||||
view_form_by_html: '<b>Formulaire consulté</b> par %{submitter_name}'
|
view_form_by_html: '<b>Formulaire consulté</b> par %{submitter_name}'
|
||||||
invite_party_by_html: '<b>Invité</b> %{invited_submitter_name} par %{submitter_name}'
|
invite_party_by_html: '<b>Invité</b> %{invited_submitter_name} par %{submitter_name}'
|
||||||
complete_form_by_html: '<b>Soumission terminée</b> par %{submitter_name}'
|
complete_form_by_html: '<b>Soumission terminée</b> par %{submitter_name}'
|
||||||
|
start_verification_by_html: "<b>Vérification d'identité commencée</b> par %{submitter_name}"
|
||||||
|
complete_verification_by_html: "<b>Vérification d'identité terminée</b> par %{submitter_name} avec %{provider}"
|
||||||
api_complete_form_by_html: "<b>Soumission terminée via l'API</b> par %{submitter_name}"
|
api_complete_form_by_html: "<b>Soumission terminée via l'API</b> par %{submitter_name}"
|
||||||
import_list:
|
import_list:
|
||||||
select_worksheet: Sélectionner la feuille de calcul
|
select_worksheet: Sélectionner la feuille de calcul
|
||||||
@@ -2615,6 +2739,18 @@ fr: &fr
|
|||||||
read: Lire vos données
|
read: Lire vos données
|
||||||
|
|
||||||
pt: &pt
|
pt: &pt
|
||||||
|
add: Adicionar
|
||||||
|
adding: Adicionando
|
||||||
|
owner: Proprietário
|
||||||
|
select_user: Selecionar usuário
|
||||||
|
team_member_permissions: Permissões de membro da equipe
|
||||||
|
entire_team: Toda a equipe
|
||||||
|
admin_only: Somente administrador
|
||||||
|
accessiable_by: Acessível por
|
||||||
|
team_access: Acesso à equipe
|
||||||
|
remove_filter: Remover filtro
|
||||||
|
document_download_filename_format: Formato do nome do arquivo de download do documento
|
||||||
|
document_name: Nome do documento
|
||||||
unarchive: Desarquivar
|
unarchive: Desarquivar
|
||||||
awaiting_completion_by_the_other_party: "Aguardando a conclusão pela outra parte"
|
awaiting_completion_by_the_other_party: "Aguardando a conclusão pela outra parte"
|
||||||
enforce_recipients_order: 'Forçar a ordem dos recipientes'
|
enforce_recipients_order: 'Forçar a ordem dos recipientes'
|
||||||
@@ -2941,7 +3077,7 @@ pt: &pt
|
|||||||
edit_message: Editar mensagem
|
edit_message: Editar mensagem
|
||||||
smtp_not_configured: SMTP não configurado
|
smtp_not_configured: SMTP não configurado
|
||||||
configure_smtp_settings_in_order_to_send_emails_: 'Configure as configurações de SMTP para enviar e-mails:'
|
configure_smtp_settings_in_order_to_send_emails_: 'Configure as configurações de SMTP para enviar e-mails:'
|
||||||
go_to_smtp_setting: Ir para a configuração de SMTP
|
go_to_smtp_settings: Ir para a configuração de SMTP
|
||||||
save_as_default_template_message: Salvar como mensagem de modelo padrão
|
save_as_default_template_message: Salvar como mensagem de modelo padrão
|
||||||
re_send_sms: Reenviar SMS
|
re_send_sms: Reenviar SMS
|
||||||
send_sms: Enviar SMS
|
send_sms: Enviar SMS
|
||||||
@@ -3212,6 +3348,8 @@ pt: &pt
|
|||||||
stamp_field: Campo de Carimbo
|
stamp_field: Campo de Carimbo
|
||||||
payment_field: Campo de Pagamento
|
payment_field: Campo de Pagamento
|
||||||
phone_field: Campo de Telefone
|
phone_field: Campo de Telefone
|
||||||
|
verification_field: "Verificação de Identidade"
|
||||||
|
identity_verification: "Verificação de identidade"
|
||||||
paid_price: 'Pago %{price}'
|
paid_price: 'Pago %{price}'
|
||||||
verified: Verificado
|
verified: Verificado
|
||||||
unverified: Não verificado
|
unverified: Não verificado
|
||||||
@@ -3228,6 +3366,21 @@ pt: &pt
|
|||||||
key: Chave
|
key: Chave
|
||||||
value: Valor
|
value: Valor
|
||||||
webhook_secret: Segredo do Webhook
|
webhook_secret: Segredo do Webhook
|
||||||
|
author: Autor
|
||||||
|
to: Para
|
||||||
|
created_at: Criado em
|
||||||
|
apply: Aplicar
|
||||||
|
applying: Aplicando
|
||||||
|
today: Hoje
|
||||||
|
yesterday: Ontem
|
||||||
|
this_week: Esta Semana
|
||||||
|
last_week: Semana Passada
|
||||||
|
this_month: Este Mês
|
||||||
|
last_month: Mês Passado
|
||||||
|
this_year: Este Ano
|
||||||
|
policy_links: Links de Políticas
|
||||||
|
markdown_content_e_g: Conteúdo Markdown, ex.
|
||||||
|
privacy_policy: Política de Privacidade
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>E-mail enviado</b> para %{submitter_name}'
|
send_email_to_html: '<b>E-mail enviado</b> para %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>E-mail de lembrete enviado</b> para %{submitter_name}'
|
send_reminder_email_to_html: '<b>E-mail de lembrete enviado</b> para %{submitter_name}'
|
||||||
@@ -3241,6 +3394,8 @@ pt: &pt
|
|||||||
view_form_by_html: '<b>Formulário visualizado</b> por %{submitter_name}'
|
view_form_by_html: '<b>Formulário visualizado</b> por %{submitter_name}'
|
||||||
invite_party_by_html: '<b>Convidado</b> %{invited_submitter_name} por %{submitter_name}'
|
invite_party_by_html: '<b>Convidado</b> %{invited_submitter_name} por %{submitter_name}'
|
||||||
complete_form_by_html: '<b>Submissão concluída</b> por %{submitter_name}'
|
complete_form_by_html: '<b>Submissão concluída</b> por %{submitter_name}'
|
||||||
|
start_verification_by_html: '<b>Verificação de identidade iniciada</b> por %{submitter_name}'
|
||||||
|
complete_verification_by_html: '<b>Verificação de identidade concluída</b> por %{submitter_name} com %{provider}'
|
||||||
api_complete_form_by_html: '<b>Submissão concluída via API</b> por %{submitter_name}'
|
api_complete_form_by_html: '<b>Submissão concluída via API</b> por %{submitter_name}'
|
||||||
import_list:
|
import_list:
|
||||||
select_worksheet: Selecionar planilha
|
select_worksheet: Selecionar planilha
|
||||||
@@ -3264,6 +3419,18 @@ pt: &pt
|
|||||||
read: Ler seus dados
|
read: Ler seus dados
|
||||||
|
|
||||||
de: &de
|
de: &de
|
||||||
|
add: Hinzufügen
|
||||||
|
adding: Hinzufügen
|
||||||
|
owner: Eigentümer
|
||||||
|
select_user: Benutzer auswählen
|
||||||
|
team_member_permissions: Berechtigungen für Teammitglieder
|
||||||
|
entire_team: Gesamtes Team
|
||||||
|
admin_only: Nur Administratoren
|
||||||
|
accessiable_by: Zugänglich für
|
||||||
|
team_access: Teamzugang
|
||||||
|
remove_filter: Filter entfernen
|
||||||
|
document_download_filename_format: Format des Dateinamens beim Herunterladen von Dokumenten
|
||||||
|
document_name: Dokumentname
|
||||||
unarchive: Wiederherstellen
|
unarchive: Wiederherstellen
|
||||||
awaiting_completion_by_the_other_party: "Warten auf die Fertigstellung durch die andere Partei"
|
awaiting_completion_by_the_other_party: "Warten auf die Fertigstellung durch die andere Partei"
|
||||||
enforce_recipients_order: 'Empfängerreihenfolge durchsetzen'
|
enforce_recipients_order: 'Empfängerreihenfolge durchsetzen'
|
||||||
@@ -3590,7 +3757,7 @@ de: &de
|
|||||||
edit_message: Nachricht bearbeiten
|
edit_message: Nachricht bearbeiten
|
||||||
smtp_not_configured: SMTP nicht konfiguriert
|
smtp_not_configured: SMTP nicht konfiguriert
|
||||||
configure_smtp_settings_in_order_to_send_emails_: 'Konfiguriere die SMTP-Einstellungen, um E-Mails zu senden:'
|
configure_smtp_settings_in_order_to_send_emails_: 'Konfiguriere die SMTP-Einstellungen, um E-Mails zu senden:'
|
||||||
go_to_smtp_setting: Zu den SMTP-Einstellungen gehen
|
go_to_smtp_settings: Zu den SMTP-Einstellungen gehen
|
||||||
save_as_default_template_message: Als Standardvorlage speichern
|
save_as_default_template_message: Als Standardvorlage speichern
|
||||||
re_send_sms: SMS erneut senden
|
re_send_sms: SMS erneut senden
|
||||||
send_sms: SMS senden
|
send_sms: SMS senden
|
||||||
@@ -3861,6 +4028,8 @@ de: &de
|
|||||||
stamp_field: Stempelfeld
|
stamp_field: Stempelfeld
|
||||||
payment_field: Zahlungsfeld
|
payment_field: Zahlungsfeld
|
||||||
phone_field: Telefonfeld
|
phone_field: Telefonfeld
|
||||||
|
verification_field: Identitätsüberprüfung
|
||||||
|
identity_verification: Identitätsüberprüfung
|
||||||
paid_price: 'Bezahlt %{price}'
|
paid_price: 'Bezahlt %{price}'
|
||||||
verified: Verifiziert
|
verified: Verifiziert
|
||||||
unverified: Nicht verifiziert
|
unverified: Nicht verifiziert
|
||||||
@@ -3877,6 +4046,21 @@ de: &de
|
|||||||
key: Schlüssel
|
key: Schlüssel
|
||||||
value: Wert
|
value: Wert
|
||||||
webhook_secret: Webhook-Geheimnis
|
webhook_secret: Webhook-Geheimnis
|
||||||
|
author: Autor
|
||||||
|
to: An
|
||||||
|
created_at: Erstellt am
|
||||||
|
apply: Anwenden
|
||||||
|
applying: Anwenden
|
||||||
|
today: Heute
|
||||||
|
yesterday: Gestern
|
||||||
|
this_week: Diese Woche
|
||||||
|
last_week: Letzte Woche
|
||||||
|
this_month: Dieser Monat
|
||||||
|
last_month: Letzter Monat
|
||||||
|
this_year: Dieses Jahr
|
||||||
|
policy_links: Richtlinien-Links
|
||||||
|
markdown_content_e_g: Markdown-Inhalt, z. B.
|
||||||
|
privacy_policy: Datenschutzrichtlinie
|
||||||
submission_event_names:
|
submission_event_names:
|
||||||
send_email_to_html: '<b>E-Mail gesendet</b> an %{submitter_name}'
|
send_email_to_html: '<b>E-Mail gesendet</b> an %{submitter_name}'
|
||||||
send_reminder_email_to_html: '<b>Erinnerungs-E-Mail gesendet</b> an %{submitter_name}'
|
send_reminder_email_to_html: '<b>Erinnerungs-E-Mail gesendet</b> an %{submitter_name}'
|
||||||
@@ -3890,6 +4074,8 @@ de: &de
|
|||||||
view_form_by_html: '<b>Formular angesehen</b> von %{submitter_name}'
|
view_form_by_html: '<b>Formular angesehen</b> von %{submitter_name}'
|
||||||
invite_party_by_html: '<b>Eingeladen</b> %{invited_submitter_name} von %{submitter_name}'
|
invite_party_by_html: '<b>Eingeladen</b> %{invited_submitter_name} von %{submitter_name}'
|
||||||
complete_form_by_html: '<b>Einreichung abgeschlossen</b> von %{submitter_name}'
|
complete_form_by_html: '<b>Einreichung abgeschlossen</b> von %{submitter_name}'
|
||||||
|
start_verification_by_html: '<b>Identitätsüberprüfung gestartet</b> von %{submitter_name}'
|
||||||
|
complete_verification_by_html: '<b>Identitätsüberprüfung abgeschlossen</b> von %{submitter_name} mit %{provider}'
|
||||||
api_complete_form_by_html: '<b>Einreichung über API abgeschlossen</b> von %{submitter_name}'
|
api_complete_form_by_html: '<b>Einreichung über API abgeschlossen</b> von %{submitter_name}'
|
||||||
import_list:
|
import_list:
|
||||||
select_worksheet: Arbeitsblatt auswählen
|
select_worksheet: Arbeitsblatt auswählen
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ Rails.application.routes.draw do
|
|||||||
resources :folders, only: %i[show edit update destroy], controller: 'template_folders'
|
resources :folders, only: %i[show edit update destroy], controller: 'template_folders'
|
||||||
resources :template_sharings_testing, only: %i[create]
|
resources :template_sharings_testing, only: %i[create]
|
||||||
resources :templates, only: %i[index], controller: 'templates_dashboard'
|
resources :templates, only: %i[index], controller: 'templates_dashboard'
|
||||||
|
resources :submissions_filters, only: %i[show], param: 'name'
|
||||||
resources :templates, only: %i[new create edit update show destroy] do
|
resources :templates, only: %i[new create edit update show destroy] do
|
||||||
resource :debug, only: %i[show], controller: 'templates_debug' if Rails.env.development?
|
resource :debug, only: %i[show], controller: 'templates_debug' if Rails.env.development?
|
||||||
resources :documents, only: %i[create], controller: 'template_documents'
|
resources :documents, only: %i[create], controller: 'template_documents'
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CreateTemplateAccesses < ActiveRecord::Migration[7.2]
|
||||||
|
def change
|
||||||
|
create_table :template_accesses do |t|
|
||||||
|
t.references :template, null: false, foreign_key: true, index: false
|
||||||
|
t.references :user, null: false, foreign_key: false, index: false
|
||||||
|
|
||||||
|
t.index %i[template_id user_id], unique: true
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
+10
-1
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.2].define(version: 2024_10_29_192232) do
|
ActiveRecord::Schema[7.2].define(version: 2024_12_07_172237) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
||||||
@@ -275,6 +275,14 @@ ActiveRecord::Schema[7.2].define(version: 2024_10_29_192232) do
|
|||||||
t.index ["submission_id"], name: "index_submitters_on_submission_id"
|
t.index ["submission_id"], name: "index_submitters_on_submission_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "template_accesses", force: :cascade do |t|
|
||||||
|
t.bigint "template_id", null: false
|
||||||
|
t.bigint "user_id", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["template_id", "user_id"], name: "index_template_accesses_on_template_id_and_user_id", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
create_table "template_folders", force: :cascade do |t|
|
create_table "template_folders", force: :cascade do |t|
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.bigint "author_id", null: false
|
t.bigint "author_id", null: false
|
||||||
@@ -393,6 +401,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_10_29_192232) do
|
|||||||
add_foreign_key "submissions", "templates"
|
add_foreign_key "submissions", "templates"
|
||||||
add_foreign_key "submissions", "users", column: "created_by_user_id"
|
add_foreign_key "submissions", "users", column: "created_by_user_id"
|
||||||
add_foreign_key "submitters", "submissions"
|
add_foreign_key "submitters", "submissions"
|
||||||
|
add_foreign_key "template_accesses", "templates"
|
||||||
add_foreign_key "template_folders", "accounts"
|
add_foreign_key "template_folders", "accounts"
|
||||||
add_foreign_key "template_folders", "users", column: "author_id"
|
add_foreign_key "template_folders", "users", column: "author_id"
|
||||||
add_foreign_key "template_sharings", "templates"
|
add_foreign_key "template_sharings", "templates"
|
||||||
|
|||||||
Loaded 100 of 126 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user