diff --git a/app/controllers/submission_events_controller.rb b/app/controllers/submission_events_controller.rb new file mode 100644 index 00000000..044b9319 --- /dev/null +++ b/app/controllers/submission_events_controller.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +class SubmissionEventsController < ApplicationController + SUBMISSION_EVENT_ICONS = { + 'view_form' => 'eye', + 'start_form' => 'player_play', + 'complete_form' => 'check', + 'send_email' => 'mail_forward', + 'click_email' => 'hand_click', + 'api_complete_form' => 'check', + 'send_reminder_email' => 'mail_forward', + 'send_2fa_sms' => '2fa', + 'send_sms' => 'send', + 'phone_verified' => 'phone_check', + 'click_sms' => 'hand_click', + 'decline_form' => 'x', + 'start_verification' => 'player_play', + 'complete_verification' => 'check', + 'invite_party' => 'user_plus' + }.freeze + + load_and_authorize_resource :submission + + # rubocop:disable Metrics + def index + submitters = @submission.submitters + submitters_uuids = (@submission.template_submitters || @submission.template.submitters).pluck('uuid') + + @events_data = @submission.submission_events.sort_by(&:event_timestamp).map do |event| + submitter = submitters.find { |e| e.id == event.submitter_id } + submitter_name = + if event.event_type.include?('sms') || event.event_type.include?('phone') + event.data['phone'] || submitter.phone + else + submitter.name || submitter.email || submitter.phone + end + + text = + if event.event_type == 'complete_verification' + helpers.t('submission_event_names.complete_verification_by_html', provider: event.data['method'], + submitter_name:) + elsif event.event_type == 'invite_party' && + (invited_submitter = submitters.find { |e| e.uuid == event.data['uuid'] }) && + (name = submission.template_submitters.find { |e| e['uuid'] == event.data['uuid'] }&.dig('name')) + invited_submitter_name = [invited_submitter.name || invited_submitter.email || invited_submitter.phone, + name].join(' ') + helpers.t('submission_event_names.invite_party_by_html', invited_submitter_name:, + submitter_name:) + elsif event.event_type.include?('send_') + helpers.t("submission_event_names.#{event.event_type}_to_html", submitter_name:) + else + helpers.t("submission_event_names.#{event.event_type}_by_html", submitter_name:) + end + + { + timestamp: event.event_timestamp.in_time_zone(current_account.timezone), + event_type: event.event_type, + submitter_index: submitters_uuids.index(submitter.uuid), + text: + } + end + end + # rubocop:enable Metrics +end diff --git a/app/views/icons/_2fa.html.erb b/app/views/icons/_2fa.html.erb new file mode 100644 index 00000000..5dfebef1 --- /dev/null +++ b/app/views/icons/_2fa.html.erb @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/views/icons/_circle_dot.html.erb b/app/views/icons/_circle_dot.html.erb new file mode 100644 index 00000000..b6b36b41 --- /dev/null +++ b/app/views/icons/_circle_dot.html.erb @@ -0,0 +1,5 @@ + + + + + diff --git a/app/views/icons/_hand_click.html.erb b/app/views/icons/_hand_click.html.erb new file mode 100644 index 00000000..016556b9 --- /dev/null +++ b/app/views/icons/_hand_click.html.erb @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/views/icons/_logs.html.erb b/app/views/icons/_logs.html.erb new file mode 100644 index 00000000..88ecf439 --- /dev/null +++ b/app/views/icons/_logs.html.erb @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/views/icons/_phone_check.html.erb b/app/views/icons/_phone_check.html.erb new file mode 100644 index 00000000..8b57c41e --- /dev/null +++ b/app/views/icons/_phone_check.html.erb @@ -0,0 +1,4 @@ + + + + diff --git a/app/views/icons/_player_play.html.erb b/app/views/icons/_player_play.html.erb new file mode 100644 index 00000000..947124b3 --- /dev/null +++ b/app/views/icons/_player_play.html.erb @@ -0,0 +1,3 @@ + + + diff --git a/app/views/submission_events/index.html.erb b/app/views/submission_events/index.html.erb new file mode 100644 index 00000000..00392cbf --- /dev/null +++ b/app/views/submission_events/index.html.erb @@ -0,0 +1,38 @@ +<% event_colors = %w[bg-red-200 bg-sky-200 bg-emerald-200 bg-yellow-300 bg-purple-200 bg-pink-200 bg-cyan-200 bg-orange-200 bg-lime-200 bg-indigo-200] %> +<%= render 'shared/turbo_modal_large', title: t('event_log') do %> +
+
    +
  1. + + <%= svg_icon('file_text', class: 'w-3.5 h-3.5') %> + +

    + <%= l(@submission.created_at.in_time_zone(current_account.timezone), format: :long, locale: current_account.locale) %> +

    +

    + <% if @submission.source == 'invite' %> + <%= t('submission_created_by_email_invite_html', email: @submission.created_by_user.email) %> + <% elsif @submission.created_by_user %> + <%= t('submission_created_by_email_via_source_html', email: @submission.created_by_user.email, source: t("submission_sources.#{@submission.source}")) %> + <% else %> + <%= t('submission_created_via_source_html', source: t("submission_sources.#{@submission.source}")) %> + <% end %> +

    +
  2. + <% @events_data.each do |row| %> + <% bg_class = event_colors[row[:submitter_index] % event_colors.length] %> +
  3. + + <%= svg_icon(SubmissionEventsController::SUBMISSION_EVENT_ICONS.fetch(row[:event_type], 'circle_dot'), class: 'w-3.5 h-3.5') %> + +

    + <%= l(row[:timestamp], format: :long, locale: current_account.locale) %> +

    +

    + <%= row[:text] %> +

    +
  4. + <% end %> +
+
+<% end %> diff --git a/app/views/submissions/show.html.erb b/app/views/submissions/show.html.erb index fff9f56f..3256ad36 100644 --- a/app/views/submissions/show.html.erb +++ b/app/views/submissions/show.html.erb @@ -19,6 +19,11 @@ <%= svg_icon('external_link', class: 'w-6 h-6') %> + <% else %> + <%= link_to submission_events_path(@submission), class: 'white-button', data: { turbo_frame: :modal } do %> + <%= svg_icon('logs', class: 'w-6 h-6') %> + + <% end %> <% end %> <% if last_submitter %> <% if is_all_completed || !is_combined_enabled %> diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml index 924d46fd..44d04f02 100644 --- a/config/locales/i18n.yml +++ b/config/locales/i18n.yml @@ -695,6 +695,15 @@ en: &en overdue_payment: Overdue Payment your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Your Pro Plan has been suspended due to unpaid invoices. You can update your payment details to settle the invoice and continue using DocuSeal or cancel your subscription. manage_subscription: Manage Subscription + submission_created_by_email_invite_html: 'Submission created by %{email} invite' + submission_created_by_email_via_source_html: 'Submission created by %{email} via %{source}' + submission_created_via_source_html: 'Submission created via %{source}' + submission_sources: + api: API + bulk: Bulk Send + embed: Embedding + invie: Invite + link: Link submission_event_names: send_email_to_html: 'Email sent to %{submitter_name}' send_reminder_email_to_html: 'Reminder email sent to %{submitter_name}' @@ -1410,6 +1419,15 @@ es: &es overdue_payment: Pago Atrasado your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Tu plan Pro ha sido suspendido debido a facturas impagas. Puedes actualizar tus datos de pago para liquidar la factura y seguir usando DocuSeal o cancelar tu suscripción. manage_subscription: Gestionar Suscripción + submission_created_by_email_invite_html: 'Envío creado por invitación de %{email}' + submission_created_by_email_via_source_html: 'Envío creado por %{email} a través de %{source}' + submission_created_via_source_html: 'Envío creado a través de %{source}' + submission_sources: + api: API + bulk: Envío masivo + embed: Integración + invite: Invitación + link: Enlace submission_event_names: send_email_to_html: 'Correo electrónico enviado a %{submitter_name}' send_reminder_email_to_html: 'Correo de recordatorio enviado a %{submitter_name}' @@ -2124,6 +2142,15 @@ it: &it overdue_payment: Pagamento Scaduto your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Il tuo piano Pro è stato sospeso a causa di fatture non pagate. Puoi aggiornare i tuoi dati di pagamento per saldare la fattura e continuare a utilizzare DocuSeal o annullare l'abbonamento. manage_subscription: Gestisci Abbonamento + submission_created_by_email_invite_html: 'Invio creato tramite invito di %{email}' + submission_created_by_email_via_source_html: 'Invio creato da %{email} tramite %{source}' + submission_created_via_source_html: 'Invio creato tramite %{source}' + submission_sources: + api: API + bulk: Invio massivo + embed: Incorporamento + invite: Invito + link: Link submission_event_names: send_email_to_html: 'E-mail inviato a %{submitter_name}' send_reminder_email_to_html: 'E-mail di promemoria inviato a %{submitter_name}' @@ -2840,6 +2867,15 @@ fr: &fr overdue_payment: Paiement En Retard your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Votre plan Pro a été suspendu en raison de factures impayées. Vous pouvez mettre à jour vos informations de paiement pour régler la facture et continuer à utiliser DocuSeal ou annuler votre abonnement. manage_subscription: Gérer l'Abonnement + submission_created_by_email_invite_html: "Soumission créée par l'invitation de %{email}" + submission_created_by_email_via_source_html: 'Soumission créée par %{email} via %{source}' + submission_created_via_source_html: 'Soumission créée via %{source}' + submission_sources: + api: API + bulk: Envoi en masse + embed: Intégration + invite: Invitation + link: Lien submission_event_names: send_email_to_html: 'E-mail envoyé à %{submitter_name}' send_reminder_email_to_html: 'E-mail de rappel envoyé à %{submitter_name}' @@ -3555,6 +3591,15 @@ pt: &pt overdue_payment: Pagamento Atrasado your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Seu plano Pro foi suspenso devido a faturas não pagas. Você pode atualizar seus dados de pagamento para quitar a fatura e continuar usando o DocuSeal ou cancelar sua assinatura. manage_subscription: Gerenciar Assinatura + submission_created_by_email_invite_html: 'Envio criado por convite de %{email}' + submission_created_by_email_via_source_html: 'Envio criado por %{email} via %{source}' + submission_created_via_source_html: 'Envio criado via %{source}' + submission_sources: + api: API + bulk: Envio em massa + embed: Incorporação + invite: Convite + link: Link submission_event_names: send_email_to_html: 'E-mail enviado para %{submitter_name}' send_reminder_email_to_html: 'E-mail de lembrete enviado para %{submitter_name}' @@ -4270,6 +4315,15 @@ de: &de overdue_payment: Überfällige Zahlung your_pro_plan_has_been_suspended_due_to_unpaid_invoices_you_can_update_your_payment_details_to_settle_the_invoice_and_continue_using_docuseal_or_cancel_your_subscription: Ihr Pro-Plan wurde aufgrund unbezahlter Rechnungen ausgesetzt. Sie können Ihre Zahlungsdaten aktualisieren, um die Rechnung zu begleichen und DocuSeal weiterhin zu nutzen, oder Ihr Abonnement kündigen. manage_subscription: Abonnement Verwalten + submission_created_by_email_invite_html: 'Übermittlung erstellt durch Einladung von %{email}' + submission_created_by_email_via_source_html: 'Übermittlung erstellt durch %{email} über %{source}' + submission_created_via_source_html: 'Übermittlung erstellt über %{source}' + submission_sources: + api: API + bulk: Massenversand + embed: Einbettung + invite: Einladung + link: Link submission_event_names: send_email_to_html: 'E-Mail gesendet an %{submitter_name}' send_reminder_email_to_html: 'Erinnerungs-E-Mail gesendet an %{submitter_name}' diff --git a/config/routes.rb b/config/routes.rb index d4d792c6..7e24097b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -72,6 +72,7 @@ Rails.application.routes.draw do resources :submissions, only: %i[index], controller: 'submissions_dashboard' resources :submissions, only: %i[show destroy] do resources :unarchive, only: %i[create], controller: 'submissions_unarchive' + resources :events, only: %i[index], controller: 'submission_events' end resources :submitters, only: %i[edit update] resources :console_redirect, only: %i[index]