add template submissions filters

pull/342/head
Alex Turchyn 11 months ago committed by Pete Matsyburka
parent c2eb94b571
commit b86aac86d1

@ -115,4 +115,21 @@ class ApplicationController < ActionController::Base
redirect_to request.url.gsub('.co/', '.com/'), allow_other_host: true, status: :moved_permanently
end
def date_range(key)
p = params.permit(key => %i[from to]).fetch(key, {})
timezone = ActiveSupport::TimeZone[current_account.timezone] || Time.zone
start_date = timezone.parse(p[:from]) if p[:from].present?
end_date = timezone.parse(p[:to]) if p[:to].present?
if start_date.present? && end_date.present? && start_date < end_date
start_date..end_date
elsif start_date.present? && end_date.present? && start_date == end_date
start_date.beginning_of_day..end_date.end_of_day
elsif start_date.present?
start_date..
elsif end_date.present?
..end_date
end
end
end

@ -4,6 +4,7 @@ class TemplatesController < ApplicationController
load_and_authorize_resource :template
before_action :load_base_template, only: %i[new create]
helper_method :created_at_range, :completed_at_range
def show
submissions = @template.submissions.accessible_by(current_ability)
@ -14,12 +15,40 @@ class TemplatesController < ApplicationController
submissions = submissions.pending if params[:status] == 'pending'
submissions = submissions.completed if params[:status] == 'completed'
submissions = submissions.where(created_at: created_at_range) if created_at_range.present?
if completed_at_range.present?
submissions =
Submission.from(submissions.completed
.joins(:submitters)
.select('submissions.*, max(completed_at) AS last_completed_at')
.group('submissions.id'), :submissions)
.where(last_completed_at: completed_at_range)
end
if params[:author].present?
submissions =
submissions.joins(:created_by_user)
.where("concat_ws(' ', NULLIF(users.first_name, ''), NULLIF(last_name, '')) = ?", params[:author])
end
@pagy, @submissions = pagy(submissions.preload(submitters: :start_form_submission_events).order(id: :desc))
rescue ActiveRecord::RecordNotFound
redirect_to root_path
end
def filter
return unless params[:filter] == 'author'
submissions = @template.submissions.accessible_by(current_ability)
submissions = submissions.active if @template.archived_at.blank?
@creator_names = submissions.includes(:created_by_user)
.filter_map(&:created_by_user)
.map(&:full_name)
.uniq
.sort
end
def new
@template.name = "#{@base_template.name} (#{I18n.t('clone')})" if @base_template
end
@ -147,4 +176,12 @@ class TemplatesController < ApplicationController
@base_template = Template.accessible_by(current_ability).find_by(id: params[:base_template_id])
end
def created_at_range
@created_at_range ||= date_range(:created_at)
end
def completed_at_range
@completed_at_range ||= date_range(:completed_at)
end
end

@ -30,6 +30,7 @@ import ToggleAttribute from './elements/toggle_attribute'
import LinkedInput from './elements/linked_input'
import CheckboxGroup from './elements/checkbox_group'
import MaskedInput from './elements/masked_input'
import SetDateButton from './elements/set_date_button'
import * as TurboInstantClick from './lib/turbo_instant_click'
@ -97,6 +98,7 @@ safeRegisterElement('toggle-attribute', ToggleAttribute)
safeRegisterElement('linked-input', LinkedInput)
safeRegisterElement('checkbox-group', CheckboxGroup)
safeRegisterElement('masked-input', MaskedInput)
safeRegisterElement('set-date-button', SetDateButton)
safeRegisterElement('template-builder', class extends HTMLElement {
connectedCallback () {

@ -0,0 +1,17 @@
export default class extends HTMLElement {
connectedCallback () {
this.dateFrom = this.dataset.fromValue
this.dateTo = this.dataset.toValue
this.dateFromInput = document.getElementById(this.dataset.fromId)
this.dateToInput = document.getElementById(this.dataset.toId)
this.button.addEventListener('click', () => {
this.dateFromInput.value = this.dateFrom || ''
this.dateToInput.value = this.dateTo || ''
})
}
get button () {
return this.querySelector('button')
}
}

@ -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

@ -0,0 +1,94 @@
<%= render 'shared/turbo_modal', title: t(params[:filter], default: '') do %>
<%= form_for @template, 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? %>
<div class="space-y-2">
<% if params[:filter] == 'author' %>
<%= hidden_field_tag 'created_at[from]', params.dig(:created_at, :from) if params.dig(:created_at, :from).present? %>
<%= hidden_field_tag 'created_at[to]', params.dig(:created_at, :to) if params.dig(:created_at, :to).present? %>
<%= hidden_field_tag 'completed_at[from]', params.dig(:completed_at, :from) if params.dig(:completed_at, :from).present? %>
<%= hidden_field_tag 'completed_at[to]', params.dig(:completed_at, :to) if params.dig(:completed_at, :to).present? %>
<div class="form-control mt-6">
<%= select_tag :author, options_for_select(@creator_names), required: true, class: 'base-select' %>
</div>
<% elsif params[:filter] == 'created_at' %>
<%= hidden_field_tag 'author', params[:author] if params[:author].present? %>
<%= hidden_field_tag 'completed_at[from]', params.dig(:completed_at, :from) if params.dig(:completed_at, :from).present? %>
<%= hidden_field_tag 'completed_at[to]', params.dig(:completed_at, :to) if params.dig(:completed_at, :to).present? %>
<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.dig(:created_at, :from), id: 'date_from', class: 'base-input !select-sm !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.dig(:created_at, :to), id: 'date_to', class: 'base-input !select-sm !h-10"', autocomplete: 'off' %>
</div>
</div>
<% elsif params[:filter] == 'completed_at' %>
<%= hidden_field_tag 'author', params[:author] if params[:author].present? %>
<%= hidden_field_tag 'created_at[from]', params.dig(:created_at, :from) if params.dig(:created_at, :from).present? %>
<%= hidden_field_tag 'created_at[to]', params.dig(:created_at, :to) if params.dig(:created_at, :to).present? %>
<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.dig(:completed_at, :from), id: 'date_from', class: 'base-input !select-sm !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.dig(:completed_at, :to), id: 'date_to', class: 'base-input !select-sm !h-10"', autocomplete: 'off' %>
</div>
</div>
<% end %>
</div>
<% if %w[created_at completed_at].include?(params[:filter]) %>
<% current_time = Time.current.in_time_zone(current_account.timezone) %>
<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 normal-case" data-turbo="false" type="button">
<%= svg_icon 'calendar', class: 'w-4 h-4 shrink-0' %>
<%= t('today') %>
</button>
</set-date-button>
<set-date-button data-from-value="<%= current_time.beginning_of_week.to_date %>" data-to-value="<%= current_time.end_of_week.to_date %>" data-from-id="date_from" data-to-id="date_to">
<button class="btn btn-xs btn-primary normal-case" data-turbo="false" type="button">
<%= svg_icon 'calendar', class: 'w-4 h-4 shrink-0' %>
<%= t('this_week') %>
</button>
</set-date-button>
<set-date-button data-from-value="<%= (current_time - 1.week).beginning_of_week.to_date %>" data-to-value="<%= (current_time - 1.week).end_of_week.to_date %>" data-from-id="date_from" data-to-id="date_to">
<button class="btn btn-xs btn-primary normal-case" data-turbo="false" type="button">
<%= svg_icon 'calendar', class: 'w-4 h-4 shrink-0' %>
<%= 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 normal-case" data-turbo="false" type="button">
<%= svg_icon 'calendar', class: 'w-4 h-4 shrink-0' %>
<%= 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 normal-case" data-turbo="false" type="button">
<%= svg_icon 'calendar', class: 'w-4 h-4 shrink-0' %>
<%= 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 normal-case" data-turbo="false" type="button">
<%= svg_icon 'calendar', class: 'w-4 h-4 shrink-0' %>
<%= t('this_year') %>
</button>
</set-date-button>
</div>
<% end %>
<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[:filter].present? && params[params[:filter]].present? %>
<div class="text-center w-full mt-4">
<%= link_to t('remove_condition'), template_path(params[:id], params.to_unsafe_h.except(:id, :filter, :action, :controller, params[:filter].to_sym)), class: 'link', data: { turbo: false } %>
</div>
<% end %>
<% end %>
<% end %>

@ -1,6 +1,7 @@
<%= render 'title', template: @template %>
<% is_show_tabs = @pagy.pages > 1 || params[:status].present? %>
<% if !@pagy.count.zero? || params[:q].present? || params[:status].present? %>
<% is_filter_active = params.slice(:author, :created_at, :completed_at).to_unsafe_h.any?(&:present?) %>
<% is_show_tabs = @pagy.pages > 1 || params[:q].present? || params[:status].present? || is_filter_active %>
<% if !@pagy.count.zero? || params[:q].present? || params[:status].present? || is_filter_active %>
<div class="<%= is_show_tabs ? 'mb-4' : 'mb-6' %>">
<div class="flex justify-between items-center md:items-end">
<div>
@ -9,7 +10,7 @@
</h2>
</div>
<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? || is_filter_active || @pagy.pages > 1 %>
<%= render 'shared/search_input', title_selector: 'h2' %>
<% end %>
<%= 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,113 @@
</div>
<% end %>
<% 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">
<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 space-x-1">
<%= svg_icon('list', class: 'w-5 h-5') %>
<span class="font-normal"><%= t('all') %></span>
</div>
<div class="badge badge-neutral badge-outline font-medium">
<%= params[:status].blank? ? @pagy.count : @base_submissions.count %>
</div>
</a>
<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">
<div class="flex items-center space-x-1">
<%= svg_icon('clock', class: 'w-5 h-5') %>
<span class="font-normal"><%= t('pending') %></span>
</div>
<div class="badge badge-neutral badge-outline font-medium">
<%= params[:status] == 'pending' ? @pagy.count : @base_submissions.pending.count %>
</div>
</a>
<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">
<div class="flex items-center space-x-1">
<%= svg_icon('circle_check', class: 'w-5 h-5') %>
<span class="font-normal"><%= t('completed') %></span>
</div>
<div class="badge badge-neutral badge-outline font-medium">
<%= params[:status] == 'completed' ? @pagy.count : @base_submissions.completed.count %>
<div class="flex items-center flex-col md:flex-row md:flex-wrap gap-2 justify-between mb-4">
<div class="flex items-center md:items-end flex-col md:flex-row gap-2 w-full md:w-fit">
<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">
<div class="flex items-center space-x-1">
<%= svg_icon('list', class: 'w-5 h-5') %>
<span class="font-normal"><%= t('all') %></span>
</div>
<div class="badge badge-neutral badge-outline font-medium">
<%= params[:status].blank? ? @pagy.count : @base_submissions.count %>
</div>
</a>
<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">
<div class="flex items-center space-x-1">
<%= svg_icon('clock', class: 'w-5 h-5') %>
<span class="font-normal"><%= t('pending') %></span>
</div>
<div class="badge badge-neutral badge-outline font-medium">
<%= params[:status] == 'pending' ? @pagy.count : @base_submissions.pending.count %>
</div>
</a>
<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">
<div class="flex items-center space-x-1">
<%= svg_icon('circle_check', class: 'w-5 h-5') %>
<span class="font-normal"><%= t('completed') %></span>
</div>
<div class="badge badge-neutral badge-outline font-medium">
<%= params[:status] == 'completed' ? @pagy.count : @base_submissions.completed.count %>
</div>
</a>
</div>
<div class="flex items-end flex-col md:flex-row gap-2 w-full md:w-fit">
<% if completed_at_range.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 filter_templates_path(params.to_unsafe_h.except(:controller, :action).merge(filter: 'completed_at')), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1' 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 completed_at_range.begin&.to_date == completed_at_range.end&.to_date %>
<span><%= l(completed_at_range.begin.to_date, locale: current_account.locale) %></span>
<% else %>
<span><%= completed_at_range.begin ? l(completed_at_range.begin.to_date, locale: current_account.locale) : '∞' %></span>
<span class="px-1 md:px-0 md:hidden">-</span>
<span><%= completed_at_range.end ? l(completed_at_range.end.to_date, locale: current_account.locale) : t('today') %></span>
<% end %>
</span>
<% end %>
<%= link_to url_for(params.to_unsafe_h.except(:completed_at)), class: 'rounded-lg ml-1 hover:bg-neutral-700 hover:text-white' do %>
<%= svg_icon('x', class: 'w-5 h-5') %>
<% end %>
</div>
<% end %>
<% if @created_at_range.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 filter_templates_path(params.to_unsafe_h.except(:controller, :action).merge(filter: 'created_at')), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1' 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 created_at_range.begin&.to_date == created_at_range.end&.to_date %>
<span><%= l(created_at_range.begin.to_date, locale: current_account.locale) %></span>
<% else %>
<span><%= created_at_range.begin ? l(created_at_range.begin.to_date, locale: current_account.locale) : '∞' %></span>
<span class="px-1 md:px-0 md:hidden">-</span>
<span><%= created_at_range.end ? l(created_at_range.end.to_date, locale: current_account.locale) : t('today') %></span>
<% end %>
</span>
<% end %>
<%= link_to url_for(params.to_unsafe_h.except(:created_at)), class: 'rounded-lg ml-1 hover:bg-neutral-700 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 filter_templates_path(params.to_unsafe_h.except(:controller, :action).merge(filter: 'author')), data: { turbo_frame: 'modal' }, class: 'flex items-center space-x-1 w-full md:w-36' do %>
<%= svg_icon('user', class: 'w-5 h-5 shrink-0') %>
<span class="font-normal truncate"><%= params[:author] %></span>
<% end %>
<%= link_to url_for(params.to_unsafe_h.except(:author)), class: 'rounded-lg ml-1 hover:bg-neutral-700 hover:text-white' do %>
<%= svg_icon('x', class: 'w-5 h-5') %>
<% end %>
</div>
<% end %>
<div class="dropdown dropdown-end">
<label tabindex="0" class="flex h-10 px-2 py-1 space-x-1 text-lg items-center justify-between border text-center text-neutral font-semibold rounded-xl border-neutral-300 hover:border-neutral-700">
<%= svg_icon('filter', class: 'w-5 h-5 flex-shrink-0 stroke-2') %>
<span class="<%= is_filter_active ? '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 filter_templates_path(params.to_unsafe_h.except(:controller, :action).merge(filter: 'author')), data: { turbo_frame: 'modal' } do %>
<%= svg_icon('user', class: 'w-5 h-5 flex-shrink-0 stroke-2') %>
<span><%= t('author') %></span>
<% end %>
</li>
<li class="flex">
<%= link_to filter_templates_path(params.to_unsafe_h.except(:controller, :action).merge(filter: 'created_at')), 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 filter_templates_path(params.to_unsafe_h.except(:controller, :action).merge(filter: 'completed_at')), 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>
</ul>
</div>
</a>
</div>
</div>
<% end %>
<% if @submissions.present? %>
@ -65,31 +145,33 @@
<div class="card bg-base-200">
<div class="card-body text-center px-4 py-16">
<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') %>
</p>
<% if @template.archived_at.blank? && params[:q].blank? %>
<p><%= t('send_an_invitation_to_fill_and_complete_the_form') %></p>
<div class="space-y-2 flex flex-col">
<% if can?(:create, Submission) %>
<%= link_to new_template_submission_path(@template, with_link: true), class: 'base-button mt-6', data: { turbo_frame: 'modal' } do %>
<%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %>
<span class="mr-1"><%= t('send_to_recipients') %></span>
<% end %>
<% end %>
<% if @template.submitters.size == 1 %>
<%= 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') %>
<span class="mr-1"><%= t('sign_it_yourself') %></span>
<div class="mt-4">
<p><%= t('send_an_invitation_to_fill_and_complete_the_form') %></p>
<div class="space-y-2 flex flex-col">
<% if can?(:create, Submission) %>
<%= link_to new_template_submission_path(@template, with_link: true), class: 'base-button mt-6', data: { turbo_frame: 'modal' } do %>
<%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %>
<span class="mr-1"><%= t('send_to_recipients') %></span>
<% end %>
<% 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>
<% if @template.submitters.size == 1 %>
<%= 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') %>
<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 %>
<% end %>
</div>
</did>
</div>
<% end %>
</div>
</div>
</div>

@ -633,6 +633,18 @@ en: &en
key: Key
value: Value
webhook_secret: Webhook Secret
author: Author
to: To
created_at: Created At
remove_condition: Remove condition
apply: Apply
applying: Applying
today: Today
this_week: This Week
last_week: Last Week
this_month: This Month
last_month: Last Month
this_year: This Year
submission_event_names:
send_email_to_html: '<b>Email sent</b> to %{submitter_name}'
send_reminder_email_to_html: '<b>Reminder email sent</b> to %{submitter_name}'
@ -1284,6 +1296,18 @@ es: &es
key: Clave
value: Valor
webhook_secret: Secreto del Webhook
author: Autor
to: A
created_at: Creado el
remove_condition: Eliminar condición
apply: Aplicar
applying: Aplicando
today: Hoy
this_week: Esta Semana
last_week: La Semana Pasada
this_month: Este Mes
last_month: El Mes Pasado
this_year: Este Año
submission_event_names:
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}'
@ -1935,6 +1959,18 @@ it: &it
key: Chiave
value: Valore
webhook_secret: Segreto del Webhook
author: Autore
to: A
created_at: Creato il
remove_condition: Rimuovi condizione
apply: Applica
applying: Applicazione
today: Oggi
this_week: Questa Settimana
last_week: Settimana Scorsa
this_month: Questo Mese
last_month: Mese Scorso
this_year: "Quest'Anno"
submission_event_names:
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}'
@ -2587,6 +2623,18 @@ fr: &fr
key: Clé
value: Valeur
webhook_secret: Secret du Webhook
author: Auteur
to: À
created_at: Créé le
remove_condition: Supprimer la condition
apply: Appliquer
applying: Application en cours
today: "Aujourd'hui"
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
submission_event_names:
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}'
@ -3238,6 +3286,18 @@ pt: &pt
key: Chave
value: Valor
webhook_secret: Segredo do Webhook
author: Autor
to: Para
created_at: Criado em
remove_condition: Remover condição
apply: Aplicar
applying: Aplicando
today: Hoje
this_week: Esta Semana
last_week: Semana Passada
this_month: Este Mês
last_month: Mês Passado
this_year: Este Ano
submission_event_names:
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}'
@ -3889,6 +3949,18 @@ de: &de
key: Schlüssel
value: Wert
webhook_secret: Webhook-Geheimnis
author: Autor
to: An
created_at: Erstellt am
remove_condition: Bedingung entfernen
apply: Anwenden
applying: Anwenden
today: Heute
this_week: Diese Woche
last_week: Letzte Woche
this_month: Dieser Monat
last_month: Letzter Monat
this_year: Dieses Jahr
submission_event_names:
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}'

@ -91,6 +91,7 @@ Rails.application.routes.draw do
resources :template_sharings_testing, only: %i[create]
resources :templates, only: %i[index], controller: 'templates_dashboard'
resources :templates, only: %i[new create edit update show destroy] do
get :filter, on: :collection
resource :debug, only: %i[show], controller: 'templates_debug' if Rails.env.development?
resources :documents, only: %i[create], controller: 'template_documents'
resources :restore, only: %i[create], controller: 'templates_restore'

@ -17,7 +17,8 @@ FactoryBot.define do
submission.template_submitters.each do |template_submitter|
create(:submitter, submission:,
account_id: submission.account_id,
uuid: template_submitter['uuid'])
uuid: template_submitter['uuid'],
created_at: submission.created_at)
end
end
end

@ -140,4 +140,98 @@ RSpec.describe 'Template' do
end
end
end
context 'when filtering submissions' do
let(:second_user) { create(:user, account:) }
it 'displays only submissions by the selected author' do
first_user_submissions = create_list(:submission, 5, :with_submitters, template:, created_by_user: user)
second_user_submissions = create_list(:submission, 6, :with_submitters, template:, created_by_user: second_user)
visit template_path(template)
(first_user_submissions + second_user_submissions).map(&:submitters).flatten.last(10).uniq.each do |submitter|
expect(page).to have_content(submitter.name)
end
page.find('.dropdown', text: 'Filter').click
click_link 'Author'
within '#modal' do
select second_user.full_name, from: 'author'
click_button 'Apply'
end
second_user_submissions.map(&:submitters).flatten.uniq.each do |submitter|
expect(page).to have_content(submitter.name)
end
first_user_submissions.map(&:submitters).flatten.uniq.each do |submitter|
expect(page).not_to have_content(submitter.name)
end
end
it 'displays submissions created within the selected date range' do
last_week_submissions = create_list(:submission, 5, :with_submitters, template:, created_by_user: user,
created_at: 9.days.ago)
this_week_submissions = create_list(:submission, 6, :with_submitters, template:, created_by_user: user,
created_at: 5.days.ago)
visit template_path(template)
(last_week_submissions + this_week_submissions).map(&:submitters).flatten.last(10).uniq.each do |submitter|
expect(page).to have_content(submitter.name)
end
page.find('.dropdown', text: 'Filter').click
click_link 'Created At'
within '#modal' do
fill_in 'From', with: I18n.l(10.days.ago, format: '%Y-%m-%d')
fill_in 'To', with: I18n.l(6.days.ago, format: '%Y-%m-%d')
click_button 'Apply'
end
last_week_submissions.map(&:submitters).flatten.uniq.each do |submitter|
expect(page).to have_content(submitter.name)
end
this_week_submissions.map(&:submitters).flatten.uniq.each do |submitter|
expect(page).not_to have_content(submitter.name)
end
end
it 'displays submissions completed within the selected date range' do
last_week_submissions = create_list(:submission, 5, :with_submitters, template:, created_by_user: user)
this_week_submissions = create_list(:submission, 6, :with_submitters, template:, created_by_user: user)
last_week_submissions.map(&:submitters).flatten.each do |submitter|
submitter.update!(completed_at: rand(6..10).days.ago)
end
this_week_submissions.map(&:submitters).flatten.each do |submitter|
submitter.update!(completed_at: rand(2..5).days.ago)
end
visit template_path(template)
(last_week_submissions + this_week_submissions).map(&:submitters).flatten.last(10).uniq.each do |submitter|
expect(page).to have_content(submitter.name)
end
page.find('.dropdown', text: 'Filter').click
click_link 'Completed At'
within '#modal' do
fill_in 'From', with: I18n.l(5.days.ago, format: '%Y-%m-%d')
fill_in 'To', with: I18n.l(1.day.ago, format: '%Y-%m-%d')
click_button 'Apply'
end
this_week_submissions.map(&:submitters).flatten.uniq.each do |submitter|
expect(page).to have_content(submitter.name)
end
last_week_submissions.map(&:submitters).flatten.uniq.each do |submitter|
expect(page).not_to have_content(submitter.name)
end
end
end
end

Loading…
Cancel
Save