add template submissions filters
This commit is contained in:
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 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>
|
||||
<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>
|
||||
</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>
|
||||
<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 %>
|
||||
<% 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>
|
||||
<% 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 %>
|
||||
<% 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 %>
|
||||
</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
|
||||
|
||||
Reference in New Issue
Block a user