Skip to content
This repository has been archived by the owner on Dec 28, 2023. It is now read-only.

Commit

Permalink
New admin regional holidays index page (#489)
Browse files Browse the repository at this point in the history
* add regional_holiday_decorator.rb

* add new admin regional holidays index page

* add query object for regional holidays

* accept filter params in new_admin/regional_holidays_controller.rb

* add filters to the new admin regional holidays index page

* add translations and i18n

* add specs for NewAdmin::RegionalHolidaysController

* add message for when no regional holiday is found

* add feature specs for new admin regional holidays index page

* rename method in new admin regional holidays controller

---------

Co-authored-by: Alessandro Dias Batista <alessandro.dias@codeminer42.com>
  • Loading branch information
danielmbrasil and Alessandro Dias Batista authored Jul 25, 2023
1 parent ba2c46e commit 6125ea8
Show file tree
Hide file tree
Showing 15 changed files with 603 additions and 0 deletions.
2 changes: 2 additions & 0 deletions app/assets/images/regional_holiday.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions app/controllers/new_admin/regional_holidays_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module NewAdmin
class RegionalHolidaysController < ApplicationController
layout 'new_admin'

before_action :load_cities_with_holidays, only: :index

def index
@regional_holidays = RegionalHolidaysQuery.new(**filter_params).call.decorate
end

private

def filter_params
params.permit(
:regional_holiday_id,
:month,
city_ids: []
).to_h
end

def load_cities_with_holidays
@cities_with_holidays = City.joins(:regional_holidays).distinct.order('cities.name ASC')
end
end
end
9 changes: 9 additions & 0 deletions app/decorators/regional_holiday_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class RegionalHolidayDecorator < Draper::Decorator
delegate_all

def cities
model.cities.map(&:name).join(', ')
end
end
44 changes: 44 additions & 0 deletions app/queries/regional_holidays_query.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

class RegionalHolidaysQuery
def initialize(**options)
@regional_holiday_id = options[:regional_holiday_id]
@city_ids = options[:city_ids]
@month = options[:month]
end

def call
query = RegionalHoliday.joins(:cities)
merge_options!(query)

query.distinct
end

private

attr_reader :regional_holiday_id, :city_ids, :month

def merge_options!(query)
query.merge!(by_regional_holiday(query))
query.merge!(by_cities(query))
query.merge!(by_month(query))
end

def by_regional_holiday(query)
return query unless regional_holiday_id.present?

query.where(id: regional_holiday_id)
end

def by_cities(query)
return query unless city_ids.present? && city_ids.reject(&:blank?).present?

query.where(cities: { id: city_ids })
end

def by_month(query)
return query unless month.present?

query.where(month: month)
end
end
5 changes: 5 additions & 0 deletions app/views/application/_sidebar.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
%>
</li>
</ul>
<li class="relative px-6 py-3">
<%= link_to new_admin_regional_holidays_path, class: "inline-flex items-center w-full text-sm font-semibold transition-colors duration-150 hover:text-gray-800 dark:hover:text-gray-200" do %>
<%= inline_svg_tag 'regional_holiday.svg', class: 'h-6 w-6' %>
<span class="ml-4"><%= t('regional_holidays.title') %></span>
<% end %>
</li>
</ul>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<div class="px-4 py-3 w-fit h-fit dark:bg-gray-800">
<h3 class="text-xs py-1 font-semibold tracking-wide text-left uppercase border-b dark:border-gray-700 dark:text-gray-400 dark:bg-gray-800">
<%= t('regional_holidays.filters') %>
</h3>
<%= form_with url: new_admin_regional_holidays_url, method: :get do |form| %>
<div class="mt-2 space-y-2">
<div class="mt-2 space-y-2">
<div class="flex flex-col space-y-2">
<%= form.label :name, t('regional_holidays.name'), class: 'text-xs font-semibold tracking-wide text-left text-gray-500 uppercase' %>
<%= form.collection_select :regional_holiday_id, RegionalHoliday.order(:name), :id, :name, { prompt: t('regional_holidays.any'), selected: params[:regional_holiday_id] }, { class: 'w-full font-semibold rounded-lg text-sm dark:bg-slate-700 dark:text-gray-400' } %>
</div>
</div>
<div class="mt-2 space-y-2">
<div class="flex flex-col space-y-2">
<%= form.label :city, t('regional_holidays.city'), class: 'text-xs font-semibold tracking-wide text-left text-gray-500 uppercase' %>
<%= form.collection_select :city_ids, @cities_with_holidays, :id, :name, { selected: params[:city_ids] }, { multiple: true, class: 'w-full font-semibold rounded-lg text-sm dark:bg-slate-700 dark:text-gray-400' } %>
</div>
</div>
<div class="mt-2 space-y-2">
<div class="flex flex-col space-y-2">
<%= form.label :month, t('regional_holidays.month'), class: 'text-xs font-semibold tracking-wide text-left text-gray-500 uppercase' %>
<%= select_month(params[:month]&.to_i, { prompt: t('regional_holidays.any') }, { name: 'month', class: 'w-full font-semibold rounded-lg text-sm dark:bg-slate-700 dark:text-gray-400' }) %>
</div>
</div>
<div class="mt-4 mb-2">
<div class="flex flex-row">
<%= form.submit t('regional_holidays.filter'), formmethod: :get, class: "px-4 py-2 mr-2 cursor-pointer font-semibold text-sm text-white transition-colors duration-150 rounded-lg bg-primary-600 hover:bg-primary-700" %>
<%= link_to t('regional_holidays.clear_filters'), new_admin_regional_holidays_url, class: "px-4 py-2 cursor-pointer font-semibold text-sm text-white transition-colors duration-150 rounded-lg bg-slate-700 hover:bg-gray-600" %>
</div>
</div>
<% end %>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<table class="table-auto w-full h-fit" id="index_table_regional_holidays">
<thead>
<tr class="text-xs font-semibold tracking-wide text-left text-gray-500 uppercase border-b dark:border-gray-700 bg-gray-50 dark:text-gray-400 dark:bg-gray-800">
<th class="px-4 py-3"><%= RegionalHoliday.human_attribute_name('name') %></th>
<th class="px-4 py-3"><%= RegionalHoliday.human_attribute_name('day') %></th>
<th class="px-4 py-3"><%= RegionalHoliday.human_attribute_name('month') %></th>
<th class="px-4 py-3"><%= RegionalHoliday.human_attribute_name('cities') %></th>
<th class="px-4 py-3"></th>
</tr>
</thead>
<tbody class="bg-white divide-y dark:divide-gray-700 dark:bg-gray-800 text-sm text-start">
<% regional_holidays.each do |holiday| %>
<tr id=<%= "regional_holiday_#{holiday.id}" %> class="text-gray-700 dark:text-gray-400">
<td class="px-4 py-3">
<div>
<%= holiday.name %>
</div>
</td>
<td class="px-4 py-3">
<div>
<%= holiday.day %>
</div>
</td>
<td class="px-4 py-3">
<div>
<%= holiday.month %>
</div>
</td>
<td class="px-4 py-3">
<div>
<%= holiday.cities %>
</div>
</td>
<td class="px-4 py-3">
<div class="space-x-4">
<%= link_to t('view'),
nil,
class: 'font-semibold transition-colors duration-150 underline dark:hover:text-white hover:text-gray-900'
%>
<%= link_to t('edit'),
nil,
class: 'font-semibold transition-colors duration-150 underline dark:hover:text-white hover:text-gray-900'
%>
<%= link_to t('delete'),
nil,
class: 'font-semibold transition-colors duration-150 underline dark:hover:text-white hover:text-gray-900'
%>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
18 changes: 18 additions & 0 deletions app/views/new_admin/regional_holidays/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<% content_for :page_title do %>
<%= t('regional_holidays.title') %>
<% end %>

<div data-tab-id="regional_holidays" class="overflow-hidden rounded-lg ring-1 ring-black ring-opacity-5">
<div class="flex justify-between gap-4">
<% if @regional_holidays.any? %>
<%= render 'regional_holidays_table', regional_holidays: @regional_holidays %>
<% else %>
<h3 class="text-xs font-semibold text-left uppercase dark:text-gray-400">
<%= t('regional_holidays.empty') %>
</h3>
<% end %>
<div id="filters_sidebar_section">
<%= render 'regional_holidays_filters' %>
</div>
<div>
</div>
10 changes: 10 additions & 0 deletions config/locales/en/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,13 @@ en:
answers: "Respostas"
question: "Questão"
response: "Resposta"
regional_holidays:
title: "Regional holidays"
filters: "Filters"
name: "Name"
city: "City"
month: "Month"
any: "Any"
filter: "Filter"
clear_filters: "Clear filters"
empty: "No regional holiday found"
10 changes: 10 additions & 0 deletions config/locales/pt-BR/pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,13 @@ pt-BR:
answers: "Respostas"
question: "Questão"
response: "Resposta"
regional_holidays:
title: "Feriados regionais"
filters: "Filtros"
name: "Nome"
city: "Cidade"
month: "Mês"
any: "Qualquer"
filter: "Filtrar"
clear_filters: "Limpar filtros"
empty: "Nenhum feriado regional encontrado"
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
resources :allocations, only: %i[show update edit], as: :user_allocations
resources :users, only: %i[show update edit], as: :admin_user
resources :punches, only: :show, as: :user_punches
resources :regional_holidays, only: :index
end

resources :repositories, only: :index do
Expand Down
122 changes: 122 additions & 0 deletions spec/controllers/new_admin/regional_holidays_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe NewAdmin::RegionalHolidaysController do
describe 'GET #index' do
let!(:new_york) { create(:city, name: 'New York') }
let!(:los_angeles) { create(:city, name: 'Los Angeles') }
let!(:miami) { create(:city, name: 'Miami') }
let!(:chicago) { create(:city, name: 'Chicago') }
let!(:fresno) { create(:city, name: 'San Diego') }

let!(:new_york_holiday) do
create(:regional_holiday, cities: [new_york], day: 4, month: 7, name: 'Independence Day')
end
let!(:la_holiday) do
create(:regional_holiday, cities: [los_angeles], day: 1, month: 1, name: 'New Year')
end
let!(:miami_holiday) do
create(:regional_holiday, cities: [miami], day: 25, month: 12, name: 'Christmas')
end
let!(:chicago_holiday) do
create(:regional_holiday, cities: [chicago], month: 11, name: 'Thanksgiving Day')
end

it 'renders the index template' do
get :index

expect(response).to render_template(:index)
end

it 'assigns all cities with holidays to @cities_with_holidays' do
get :index

expect(assigns(:cities_with_holidays)).to contain_exactly(new_york, los_angeles, miami, chicago)
end

context 'when no filter options are provided' do
it 'assigns all regional holidays correctly' do
get :index

expect(assigns(:regional_holidays)).to contain_exactly(new_york_holiday, la_holiday, miami_holiday, chicago_holiday)
end
end

context 'when using regional_holiday_id option' do
it 'returns the specified regional holiday' do
get :index, params: { regional_holiday_id: new_york_holiday.id }

expect(assigns(:regional_holidays)).to contain_exactly(new_york_holiday)
end

it 'returns empty list when the provided regional holiday id does not exist' do
get :index, params: { regional_holiday_id: -1 }

expect(assigns(:regional_holidays)).to be_empty
end
end

context 'when using city_ids option' do
it 'returns regional holidays from the specified cities' do
get :index, params: { city_ids: [miami.id, los_angeles.id] }

expect(assigns(:regional_holidays)).to contain_exactly(miami_holiday, la_holiday)
end

it 'returns empty list when the provided cities do not have any regional holiday' do
get :index, params: { city_ids: [fresno.id] }

expect(assigns(:regional_holidays)).to be_empty
end
end

context 'when using month option' do
it 'returns all regional holidays from the specified month' do
get :index, params: { month: 12 }

expect(assigns(:regional_holidays)).to contain_exactly(miami_holiday)
end

it 'returns empty list when the month does not have any regional holiday' do
get :index, params: { month: 13 }

expect(assigns(:regional_holidays)).to be_empty
end
end

context 'when using multiple options' do
it 'returns regional holidays matching all options' do
get :index, params: { city_ids: [new_york.id], month: 7 }

expect(assigns(:regional_holidays)).to contain_exactly(new_york_holiday)
end

it 'returns empty list when no regional holidays match all filter options' do
get :index, params: { city_ids: [los_angeles.id], month: 7 }

expect(assigns(:regional_holidays)).to be_empty
end
end

context 'when using invalid option values' do
it 'returns empty list for invalid regional_holiday_id' do
get :index, params: { regional_holiday_id: 'invalid_id' }

expect(assigns(:regional_holidays)).to be_empty
end

it 'returns empty list for invalid month' do
get :index, params: { month: 'invalid_month' }

expect(assigns(:regional_holidays)).to be_empty
end

it 'returns empty list for invalid city_ids' do
get :index, params: { city_ids: ['invalid_city_id'] }

expect(assigns(:regional_holidays)).to be_empty
end
end
end
end
Loading

0 comments on commit 6125ea8

Please sign in to comment.