adjust filters
This commit is contained in:
@@ -115,21 +115,4 @@ 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
|
||||
|
||||
@@ -9,7 +9,14 @@ class SubmissionsArchivedController < ApplicationController
|
||||
.or(@submissions.where.not(templates: { archived_at: nil }))
|
||||
.preload(:created_by_user, template: :author)
|
||||
@submissions = Submissions.search(@submissions, params[:q], search_template: 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))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,10 +11,17 @@ class SubmissionsDashboardController < ApplicationController
|
||||
.preload(:created_by_user, template: :author)
|
||||
|
||||
@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.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
|
||||
|
||||
@@ -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
|
||||
@@ -7,8 +7,15 @@ class TemplatesArchivedSubmissionsController < ApplicationController
|
||||
def index
|
||||
@submissions = @submissions.where.not(archived_at: nil)
|
||||
@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
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
@@ -4,51 +4,29 @@ 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)
|
||||
submissions = submissions.active if @template.archived_at.blank?
|
||||
submissions = Submissions.search(submissions, params[:q], search_values: true)
|
||||
submissions = Submissions::Filter.call(submissions, current_user, params)
|
||||
|
||||
@base_submissions = submissions
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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))
|
||||
@pagy, @submissions = pagy(submissions.preload(submitters: :start_form_submission_events))
|
||||
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
|
||||
@@ -176,12 +154,4 @@ 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
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
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 || ''
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,11 @@ class Submission < ApplicationRecord
|
||||
through: :template, source: :documents_attachments
|
||||
|
||||
scope :active, -> { where(archived_at: nil) }
|
||||
scope :pending, -> { joins(:submitters).where(submitters: { completed_at: nil }).distinct }
|
||||
scope :completed, -> { where.not(id: pending.select(:submission_id)) }
|
||||
scope :pending, -> { joins(:submitters).where(submitters: { completed_at: nil }).group(: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, {
|
||||
invite: 'invite',
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
<% if params[:status].present? %>
|
||||
<input name="status" value="<%= params[:status] %>" class="hidden">
|
||||
<% 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? %>
|
||||
<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">
|
||||
|
||||
@@ -1,22 +1,31 @@
|
||||
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
|
||||
<div>
|
||||
<%= link_to root_path do %>
|
||||
←
|
||||
<span><%= t('back_to_active') %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="flex justify-between mb-4 items-center">
|
||||
<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 class="flex flex-col md:flex-row md:items-center mb-4 gap-3">
|
||||
<div class="flex w-full justify-between">
|
||||
<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>
|
||||
<% if params[:q].present? || @pagy.pages > 1 %>
|
||||
<%= render 'shared/search_input', placeholder: "#{t('search')}..." %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if @pagy.count > 0 %>
|
||||
<div class="space-y-4">
|
||||
<%= render partial: 'templates/submission', collection: @submissions, locals: { with_template: true, archived: true } %>
|
||||
</div>
|
||||
<% elsif params[:q].present? %>
|
||||
<% elsif params[:q].present? || filter_params.present? %>
|
||||
<div class="text-center">
|
||||
<div class="mt-16 text-3xl font-semibold">
|
||||
<%= 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 %>
|
||||
<div class="flex justify-between items-center w-full mb-4">
|
||||
<div class="flex items-center flex-grow min-w-0">
|
||||
@@ -10,7 +11,7 @@
|
||||
</h1>
|
||||
</div>
|
||||
<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' %>
|
||||
<% end %>
|
||||
<% if can?(:create, ::Template) %>
|
||||
@@ -32,25 +33,31 @@
|
||||
<% end %>
|
||||
<% 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>
|
||||
</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>
|
||||
</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>
|
||||
</a>
|
||||
<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-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>
|
||||
</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>
|
||||
</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>
|
||||
</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>
|
||||
<% end %>
|
||||
<% if @pagy.count > 0 %>
|
||||
@@ -58,10 +65,10 @@
|
||||
<%= render partial: 'templates/submission', collection: @submissions, locals: { with_template: true } %>
|
||||
</div>
|
||||
<% 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' %>
|
||||
<% end %>
|
||||
<% if @submissions.present? || params[:q].blank? %>
|
||||
<% if @submissions.present? || (params[:q].blank? && filter_params.blank?) %>
|
||||
<% if @pagy.pages > 1 %>
|
||||
<%= render 'shared/pagination', pagy: @pagy, items_name: 'submissions', left_additional_html: view_archived_html %>
|
||||
<% else %>
|
||||
@@ -69,7 +76,7 @@
|
||||
<%= view_archived_html %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% elsif params[:q].present? %>
|
||||
<% elsif params[:q].present? || filter_params.present? %>
|
||||
<div class="text-center">
|
||||
<div class="mt-16 text-3xl font-semibold">
|
||||
<%= 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">
|
||||
<button class="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>
|
||||
</button>
|
||||
<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).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,94 +0,0 @@
|
||||
<%= 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,7 +1,7 @@
|
||||
<%= render 'title', template: @template %>
|
||||
<% 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 %>
|
||||
<% filter_params = params.permit(Submissions::Filter::ALLOWED_PARAMS).compact_blank %>
|
||||
<% 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="flex justify-between items-center md:items-end">
|
||||
<div>
|
||||
@@ -10,7 +10,7 @@
|
||||
</h2>
|
||||
</div>
|
||||
<div class="flex justify-end space-x-2">
|
||||
<% if params[:q].present? || params[:status].present? || is_filter_active || @pagy.pages > 1 %>
|
||||
<% if params[:q].present? || params[:status].present? || filter_params.present? || @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 %>
|
||||
@@ -36,7 +36,7 @@
|
||||
<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 %>
|
||||
<%= params[:status].blank? && filter_params.blank? ? @pagy.count : @base_submissions.unscope(:group, :order).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">
|
||||
@@ -45,7 +45,7 @@
|
||||
<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 %>
|
||||
<%= params[:status] == 'pending' && filter_params.blank? ? @pagy.count : @base_submissions.pending.unscope(:group, :order).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">
|
||||
@@ -54,86 +54,13 @@
|
||||
<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 %>
|
||||
<%= params[:status] == 'completed' && filter_params.blank? ? @pagy.count : @base_submissions.completed.unscope(:group, :order).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>
|
||||
<%= render 'submissions_filters/applied_filters', filter_params: %>
|
||||
<%= render 'submissions_filters/filter_button', filter_params: %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -148,7 +75,7 @@
|
||||
<p class="text-3xl font-bold text-base-content">
|
||||
<%= t('there_are_no_submissions') %>
|
||||
</p>
|
||||
<% if @template.archived_at.blank? && params[:q].blank? %>
|
||||
<% if @template.archived_at.blank? && params[:q].blank? && filter_params.blank? %>
|
||||
<div class="mt-4">
|
||||
<p><%= t('send_an_invitation_to_fill_and_complete_the_form') %></p>
|
||||
<div class="space-y-2 flex flex-col">
|
||||
@@ -169,7 +96,7 @@
|
||||
<span class="mr-1"><%= t('sign_it_yourself') %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</did>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</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 %>
|
||||
<div>
|
||||
<%= link_to template_path(@template) do %>
|
||||
@@ -5,23 +7,33 @@
|
||||
<span><%= t('back_to_active') %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="flex justify-between mb-6 md:items-end flex-col md:flex-row">
|
||||
<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>
|
||||
<div class="flex space-x-2 mt-3 md:mt-0 justify-end">
|
||||
<%= render 'shared/search_input' %>
|
||||
<%= link_to new_template_submissions_export_path(@template), class: 'order-3 md:order-1 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 class="flex flex-col md:flex-row md:items-center mb-6 gap-3">
|
||||
<div class="flex w-full justify-between md:items-end items-center">
|
||||
<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>
|
||||
<div class="flex space-x-2 justify-end">
|
||||
<% if with_filters %>
|
||||
<%= render 'shared/search_input' %>
|
||||
<% 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>
|
||||
<% 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>
|
||||
<% if @pagy.count > 0 %>
|
||||
<div class="space-y-4">
|
||||
<%= render partial: 'templates/submission', collection: @submissions, locals: { template: @template, archived: true } %>
|
||||
</div>
|
||||
<% elsif params[:q].present? %>
|
||||
<% elsif params[:q].present? || filter_params.present? %>
|
||||
<div class="text-center">
|
||||
<div class="mt-16 text-3xl font-semibold">
|
||||
<%= t('submissions_not_found') %>
|
||||
|
||||
+19
-13
@@ -22,6 +22,7 @@ en: &en
|
||||
thanks: Thanks
|
||||
unarchive: Unarchive
|
||||
first_party: 'First Party'
|
||||
remove_filter: Remove filter
|
||||
document_download_filename_format: Document download filename format
|
||||
document_name: Document Name
|
||||
docuseal_trusted_signature: DocuSeal Trusted Signature
|
||||
@@ -621,7 +622,7 @@ en: &en
|
||||
verified: Verified
|
||||
unverified: Unverified
|
||||
document: Document
|
||||
completed_at: Completed At
|
||||
completed_at: Completed at
|
||||
edit_recipient: Edit Recipient
|
||||
update_recipient: Update Recipient
|
||||
use_international_format_1xxx_: 'Use internatioanl format: +1xxx...'
|
||||
@@ -635,16 +636,16 @@ en: &en
|
||||
webhook_secret: Webhook Secret
|
||||
author: Author
|
||||
to: To
|
||||
created_at: Created At
|
||||
remove_condition: Remove condition
|
||||
created_at: Created at
|
||||
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
|
||||
yesterday: Yesterday
|
||||
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}'
|
||||
@@ -681,6 +682,7 @@ en: &en
|
||||
read: Read your data
|
||||
|
||||
es: &es
|
||||
remove_filter: Eliminar filtro
|
||||
document_download_filename_format: Formato del nombre del archivo de descarga del documento
|
||||
document_name: Nombre del documento
|
||||
unarchive: Desarchivar
|
||||
@@ -1299,10 +1301,10 @@ es: &es
|
||||
author: Autor
|
||||
to: A
|
||||
created_at: Creado el
|
||||
remove_condition: Eliminar condición
|
||||
apply: Aplicar
|
||||
applying: Aplicando
|
||||
today: Hoy
|
||||
yesterday: Ayer
|
||||
this_week: Esta Semana
|
||||
last_week: La Semana Pasada
|
||||
this_month: Este Mes
|
||||
@@ -1344,6 +1346,7 @@ es: &es
|
||||
read: Leer tus datos
|
||||
|
||||
it: &it
|
||||
remove_filter: Rimuovi filtro
|
||||
document_download_filename_format: Formato del nome file scaricato
|
||||
document_name: Nome del Documento
|
||||
unarchive: Ripristina
|
||||
@@ -1962,10 +1965,10 @@ it: &it
|
||||
author: Autore
|
||||
to: A
|
||||
created_at: Creato il
|
||||
remove_condition: Rimuovi condizione
|
||||
apply: Applica
|
||||
applying: Applicazione
|
||||
today: Oggi
|
||||
yesterday: Ieri
|
||||
this_week: Questa Settimana
|
||||
last_week: Settimana Scorsa
|
||||
this_month: Questo Mese
|
||||
@@ -2007,6 +2010,7 @@ it: &it
|
||||
read: Leggi i tuoi dati
|
||||
|
||||
fr: &fr
|
||||
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
|
||||
@@ -2626,10 +2630,10 @@ fr: &fr
|
||||
author: Auteur
|
||||
to: À
|
||||
created_at: Créé le
|
||||
remove_condition: Supprimer la condition
|
||||
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
|
||||
@@ -2671,6 +2675,7 @@ fr: &fr
|
||||
read: Lire vos données
|
||||
|
||||
pt: &pt
|
||||
remove_filter: Remover filtro
|
||||
document_download_filename_format: Formato do nome do arquivo de download do documento
|
||||
document_name: Nome do documento
|
||||
unarchive: Desarquivar
|
||||
@@ -3289,10 +3294,10 @@ pt: &pt
|
||||
author: Autor
|
||||
to: Para
|
||||
created_at: Criado em
|
||||
remove_condition: Remover condição
|
||||
apply: Aplicar
|
||||
applying: Aplicando
|
||||
today: Hoje
|
||||
yesterday: Ontem
|
||||
this_week: Esta Semana
|
||||
last_week: Semana Passada
|
||||
this_month: Este Mês
|
||||
@@ -3334,6 +3339,7 @@ pt: &pt
|
||||
read: Ler seus dados
|
||||
|
||||
de: &de
|
||||
remove_filter: Filter entfernen
|
||||
document_download_filename_format: Format des Dateinamens beim Herunterladen von Dokumenten
|
||||
document_name: Dokumentname
|
||||
unarchive: Wiederherstellen
|
||||
@@ -3952,10 +3958,10 @@ de: &de
|
||||
author: Autor
|
||||
to: An
|
||||
created_at: Erstellt am
|
||||
remove_condition: Bedingung entfernen
|
||||
apply: Anwenden
|
||||
applying: Anwenden
|
||||
today: Heute
|
||||
yesterday: Gestern
|
||||
this_week: Diese Woche
|
||||
last_week: Letzte Woche
|
||||
this_month: Dieser Monat
|
||||
|
||||
+1
-1
@@ -90,8 +90,8 @@ Rails.application.routes.draw do
|
||||
resources :folders, only: %i[show edit update destroy], controller: 'template_folders'
|
||||
resources :template_sharings_testing, only: %i[create]
|
||||
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
|
||||
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'
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ module Submissions
|
||||
arel = arel.or(Template.arel_table[:name].lower.matches("%#{keyword.downcase}%"))
|
||||
end
|
||||
|
||||
submissions.joins(:submitters).where(arel).distinct
|
||||
submissions.joins(:submitters).where(arel).group(:id)
|
||||
end
|
||||
|
||||
def update_template_fields!(submission)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Submissions
|
||||
module Filter
|
||||
ALLOWED_PARAMS = %w[
|
||||
author
|
||||
completed_at_from
|
||||
completed_at_to
|
||||
created_at_from
|
||||
created_at_to
|
||||
].freeze
|
||||
|
||||
DATE_PARAMS = %w[
|
||||
completed_at_from
|
||||
completed_at_to
|
||||
created_at_from
|
||||
created_at_to
|
||||
].freeze
|
||||
|
||||
module_function
|
||||
|
||||
def call(submissions, current_user, params)
|
||||
filters = normalize_filter_params(params, current_user)
|
||||
|
||||
if filters[:author].present?
|
||||
user = current_user.account.users.find_by(email: filters[:author])
|
||||
submissions = submissions.where(created_by_user_id: user&.id || -1)
|
||||
end
|
||||
|
||||
submissions = submissions.where(created_at: filters[:created_at_from]..) if filters[:created_at_from].present?
|
||||
|
||||
if filters[:created_at_to].present?
|
||||
submissions = submissions.where(created_at: ..filters[:created_at_to].end_of_day)
|
||||
end
|
||||
|
||||
if filters[:completed_at_from].present? || filters[:completed_at_to].present?
|
||||
completed_arel = Submitter.arel_table[:completed_at].maximum
|
||||
submissions = submissions.completed.joins(:submitters).group(:id)
|
||||
|
||||
if filters[:completed_at_from].present?
|
||||
submissions = submissions.having(completed_arel.gteq(filters[:completed_at_from]))
|
||||
end
|
||||
|
||||
if filters[:completed_at_to].present?
|
||||
submissions = submissions.having(completed_arel.lteq(filters[:completed_at_to].end_of_day))
|
||||
end
|
||||
end
|
||||
|
||||
submissions
|
||||
end
|
||||
|
||||
def normalize_filter_params(params, current_user)
|
||||
tz = ActiveSupport::TimeZone[current_user.account.timezone] || Time.zone
|
||||
|
||||
ALLOWED_PARAMS.each_with_object({}) do |key, acc|
|
||||
next if params[key].blank?
|
||||
|
||||
value = DATE_PARAMS.include?(key) ? tz.parse(params[key]) : params[key]
|
||||
|
||||
acc[key.to_sym] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -23,7 +23,7 @@ module Submissions
|
||||
RTL_REGEXP = TextUtils::RTL_REGEXP
|
||||
MAX_IMAGE_HEIGHT = 100
|
||||
|
||||
US_TIMEZONES = %w[EST CST MST PST HST AKDT].freeze
|
||||
US_TIMEZONES = TimeUtils::US_TIMEZONES
|
||||
|
||||
module_function
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ module TimeUtils
|
||||
DEFAULT_DATE_FORMAT_US = 'MM/DD/YYYY'
|
||||
DEFAULT_DATE_FORMAT = 'DD/MM/YYYY'
|
||||
|
||||
US_TIMEZONES = %w[EST CST MST PST HST AKDT].freeze
|
||||
|
||||
module_function
|
||||
|
||||
def timezone_abbr(timezone, time = Time.current)
|
||||
|
||||
@@ -183,7 +183,7 @@ RSpec.describe 'Template' do
|
||||
end
|
||||
|
||||
page.find('.dropdown', text: 'Filter').click
|
||||
click_link 'Created At'
|
||||
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')
|
||||
@@ -218,7 +218,7 @@ RSpec.describe 'Template' do
|
||||
end
|
||||
|
||||
page.find('.dropdown', text: 'Filter').click
|
||||
click_link 'Completed At'
|
||||
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')
|
||||
|
||||
Reference in New Issue
Block a user