diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 454ac39b..daeb44cc 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -50,7 +50,7 @@ class AccountsController < ApplicationController # rubocop:disable Layout/LineLength render turbo_stream: turbo_stream.replace( :account_delete_button, - html: helpers.tag.p(I18n.t('your_account_removal_request_will_be_processed_within_2_weeks_please_contact_us_if_you_want_to_keep_your_account')) + html: helpers.tag.p(I18n.t('your_account_removal_request_will_be_processed_within_2_months_please_contact_us_if_you_want_to_keep_your_account')) ) # rubocop:enable Layout/LineLength end diff --git a/app/controllers/start_form_controller.rb b/app/controllers/start_form_controller.rb index 209c81b4..4512e018 100644 --- a/app/controllers/start_form_controller.rb +++ b/app/controllers/start_form_controller.rb @@ -64,6 +64,7 @@ class StartFormController < ApplicationController .or(template.submissions.where(expire_at: nil)).where(archived_at: nil)) .order(id: :desc) .where(declined_at: nil) + .where(external_id: nil) .then { |rel| params[:resubmit].present? ? rel.where(completed_at: nil) : rel } .find_or_initialize_by(**submitter_params.compact_blank) end diff --git a/app/controllers/submissions_preview_controller.rb b/app/controllers/submissions_preview_controller.rb index 0d61cb00..862b45d9 100644 --- a/app/controllers/submissions_preview_controller.rb +++ b/app/controllers/submissions_preview_controller.rb @@ -20,7 +20,10 @@ class SubmissionsPreviewController < ApplicationController @submission ||= Submission.find_by!(slug: params[:slug]) - if @submission.account.archived_at? || (!@submission.submitters.all?(&:completed_at?) && current_user.blank?) + raise ActionController::RoutingError if @submission.account.archived_at? + + if !@submission.submitters.all?(&:completed_at?) && !signature_valid && + (!current_user || !current_ability.can?(:read, @submission)) raise ActionController::RoutingError, I18n.t('not_found') end diff --git a/app/controllers/submitters_resubmit_controller.rb b/app/controllers/submitters_resubmit_controller.rb new file mode 100644 index 00000000..fb893d98 --- /dev/null +++ b/app/controllers/submitters_resubmit_controller.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +class SubmittersResubmitController < ApplicationController + load_and_authorize_resource :submitter, parent: false + + def update + return redirect_to submit_form_path(slug: @submitter.slug) if @submitter.email != current_user.email + + submission = @submitter.template.submissions.new(created_by_user: current_user, + submitters_order: :preserved, + **@submitter.submission.slice(:template_fields, + :account_id, + :template_schema, + :template_submitters, + :preferences)) + + @submitter.submission.submitters.each do |submitter| + new_submitter = submission.submitters.new(submitter.slice(:uuid, :email, :phone, :name, + :preferences, :metadata, :account_id)) + + next unless submitter.uuid == @submitter.uuid + + assign_submitter_values(new_submitter, submitter) + + @new_submitter ||= new_submitter + end + + submission.save! + + redirect_to submit_form_path(slug: @new_submitter.slug) + end + + private + + def assign_submitter_values(new_submitter, submitter) + attachments_index = submitter.attachments.index_by(&:uuid) + + submitter.submission.template_fields.each do |field| + next if field['submitter_uuid'] != submitter.uuid + next if field['default_value'] == '{{date}}' + next if field['type'] == 'stamp' + next if field['type'] == 'signature' + next if field.dig('preferences', 'formula').present? + + value = submitter.values[field['uuid']] + + next if value.blank? + + if field['type'].in?(%w[image file initials]) + Array.wrap(value).each do |attachment_uuid| + new_submitter.attachments << attachments_index[attachment_uuid].dup + end + end + + new_submitter.values[field['uuid']] = value + end + end +end diff --git a/app/javascript/submission_form/dropzone.vue b/app/javascript/submission_form/dropzone.vue index 19285c4e..fafcd4ed 100644 --- a/app/javascript/submission_form/dropzone.vue +++ b/app/javascript/submission_form/dropzone.vue @@ -128,7 +128,7 @@ export default { } }) } else { - if (file.type === 'image/bmp') { + if (file.type === 'image/bmp' || file.type === 'image/vnd.microsoft.icon') { file = await this.convertBmpToPng(file) } diff --git a/app/javascript/template_builder/area.vue b/app/javascript/template_builder/area.vue index ccb62ab9..1ada02dc 100644 --- a/app/javascript/template_builder/area.vue +++ b/app/javascript/template_builder/area.vue @@ -361,6 +361,7 @@ export default { isMoved: false, renderDropdown: false, isNameFocus: false, + isHeadingSelected: false, textOverflowChars: 0, dragFrom: { x: 0, y: 0 } } @@ -377,7 +378,7 @@ export default { } }, isValueInput () { - return (this.field.type === 'heading' && this.isSelected) || this.isContenteditable || (this.inputMode && ['text', 'number', 'date'].includes(this.field.type)) + return (this.field.type === 'heading' && this.isHeadingSelected) || this.isContenteditable || (this.inputMode && ['text', 'number', 'date'].includes(this.field.type)) }, modalContainerEl () { return this.$el.getRootNode().querySelector('#docuseal_modal_container') @@ -485,7 +486,7 @@ export default { if (['text', 'number'].includes(this.field.type)) { this.isContenteditable = true - this.$nextTick(() => this.focusValueInput()) + this.focusValueInput() } else if (this.field.type === 'checkbox') { this.field.readonly = !this.field.readonly this.field.default_value === true ? delete this.field.default_value : this.field.default_value = true @@ -507,16 +508,18 @@ export default { } }, focusValueInput (e) { - if (this.$refs.defaultValue !== document.activeElement) { - this.$refs.defaultValue.focus() - - if (this.$refs.defaultValue.innerText.length && this.$refs.defaultValue !== e?.target) { - window.getSelection().collapse( - this.$refs.defaultValue.firstChild, - this.$refs.defaultValue.innerText.length - ) + this.$nextTick(() => { + if (this.$refs.defaultValue && this.$refs.defaultValue !== document.activeElement) { + this.$refs.defaultValue.focus() + + if (this.$refs.defaultValue.innerText.length && this.$refs.defaultValue !== e?.target) { + window.getSelection().collapse( + this.$refs.defaultValue.firstChild, + this.$refs.defaultValue.innerText.length + ) + } } - } + }) }, formatNumber (number, format) { if (format === 'comma') { @@ -632,6 +635,7 @@ export default { const text = this.$refs.defaultValue.innerText.trim() this.isContenteditable = false + this.isHeadingSelected = false if (text) { if (this.field.type === 'number') { @@ -749,10 +753,6 @@ export default { this.selectedAreaRef.value = this.area - if (this.field.type === 'heading') { - this.$nextTick(() => this.focusValueInput()) - } - this.dragFrom = { x: rect.left - e.clientX, y: rect.top - e.clientY } this.$el.getRootNode().addEventListener('mousemove', this.mouseMove) @@ -787,6 +787,12 @@ export default { this.save() } + if (this.field.type === 'heading') { + this.isHeadingSelected = !this.isMoved + + this.focusValueInput() + } + this.isDragged = false this.isMoved = false diff --git a/app/javascript/template_builder/builder.vue b/app/javascript/template_builder/builder.vue index 70e9b0f6..6e8bae2a 100644 --- a/app/javascript/template_builder/builder.vue +++ b/app/javascript/template_builder/builder.vue @@ -1427,6 +1427,8 @@ export default { const documentRef = this.documentRefs.find((e) => e.document.uuid === area.attachment_uuid) const areaRef = documentRef.pageRefs[area.page].areaRefs.find((ref) => ref.area === this.selectedAreaRef.value) + areaRef.isHeadingSelected = true + areaRef.focusValueInput() }) } diff --git a/app/javascript/template_builder/field_submitter.vue b/app/javascript/template_builder/field_submitter.vue index b5949e55..e1015835 100644 --- a/app/javascript/template_builder/field_submitter.vue +++ b/app/javascript/template_builder/field_submitter.vue @@ -143,6 +143,7 @@