Skip to content

Commit

Permalink
Merge pull request #103 from TreinaDev/registrar-reserva
Browse files Browse the repository at this point in the history
Reservar Área Comum
  • Loading branch information
ruliancruz authored Jul 18, 2024
2 parents 0f089ce + c045830 commit e7ce5f3
Show file tree
Hide file tree
Showing 27 changed files with 629 additions and 16 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ gem 'image_processing', '>= 1.2'
gem 'jbuilder'
gem 'jsbundling-rails'
gem 'puma', '~> 6.0'
gem 'simple_calendar'
gem 'sprockets-rails'
gem 'sqlite3', '~> 1.4'
gem 'stimulus-rails'
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ GEM
ruby-progressbar (1.13.0)
ruby-vips (2.2.1)
ffi (~> 1.12)
simple_calendar (3.0.4)
rails (>= 6.1)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
Expand Down Expand Up @@ -335,6 +337,7 @@ DEPENDENCIES
rspec-rails
rubocop
rubocop-rails
simple_calendar
simplecov
sprockets-rails
sqlite3 (~> 1.4)
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@

<p align="justify">Tanto administradores quanto moradores podem ver a página de listagem e detalhes de condomínio. Tendo sua exibição alterada para cada tipo de usuário.</p>

<p align="justify">Moradores podem fazer uma reserva de área comum, bem como cancelar essa reserva.</p>

<p align="right">(<a href="#readme-top">voltar ao topo</a>)</p>

<div id='instalacao-e-execucao'/>
Expand Down
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.bootstrap.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import 'custom_spacers';
@import 'bootstrap/scss/bootstrap';
@import 'bootstrap-icons/font/bootstrap-icons';
@import 'simple_calendar';
82 changes: 82 additions & 0 deletions app/assets/stylesheets/simple_calendar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
.simple-calendar {
table {
-webkit-border-horizontal-spacing: 0px;
-webkit-border-vertical-spacing: 0px;
background-color: rgba(0, 0, 0, 0);
border: 1px solid rgb(221, 221, 221);
border-collapse: collapse;
box-sizing: border-box;
max-width: 100%;
width: 100%;
}

tr {
border-collapse: collapse;
}

th {
padding: 6px;
border-bottom: 2px solid rgb(221, 221, 221);
border-collapse: collapse;
border-left: 1px solid rgb(221, 221, 221);
border-right: 1px solid rgb(221, 221, 221);
border-top: 0px none rgb(51, 51, 51);
box-sizing: border-box;
text-align: left;
}

td {
padding: 6px;
vertical-align: top;
width: 14%;

border: 1px solid #ddd;
border-top-color: rgb(221, 221, 221);
border-top-style: solid;
border-top-width: 1px;
border-right-color: rgb(221, 221, 221);
border-right-style: solid;
border-right-width: 1px;
border-bottom-color: rgb(221, 221, 221);
border-bottom-style: solid;
border-bottom-width: 1px;
border-left-color: rgb(221, 221, 221);
border-left-style: solid;
border-left-width: 1px;
}

.calendar-heading nav {
display: inline-block;
}

.day {
height: 80px;
}

.wday-0 {}
.wday-1 {}
.wday-2 {}
.wday-3 {}
.wday-4 {}
.wday-5 {}
.wday-6 {}

.today {
background: #FFFFC0
}

.past {}
.future {}

.start-date {}

.prev-month {
background: #DDD;
}
.next-month {
background: #DDD;
}
.current-month {}

.has-events {}
}
101 changes: 101 additions & 0 deletions app/controllers/reservations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
class ReservationsController < ApplicationController
before_action :set_reservation, only: %i[show canceled]
before_action :set_common_area, only: %i[new create]
before_action :set_breadcrumbs, only: [:new]
before_action :block_manager_from_resident_sign_in, only: %i[new create]
before_action :authenticate_resident!, only: %i[new create]
before_action :authenticate_for_cancelation, only: [:canceled]
before_action :authorize_user, only: [:show]

def show
@common_area = @reservation.common_area
set_breadcrumbs
end

def new
@reservation = Reservation.new common_area: @common_area
end

def create
@reservation = Reservation.new reservation_params
@reservation.resident = current_resident
@reservation.common_area = @common_area

return redirect_to @reservation, notice: t('notices.reservation.created') if @reservation.save

flash.now[:alert] = I18n.t 'alerts.reservation.not_created'
render 'new', status: :unprocessable_entity
end

def canceled
@reservation.canceled!
redirect_to @reservation, notice: t('notices.reservation.canceled')
end

private

def reservation_params
params.require(:reservation).permit :date
end

def set_common_area
@common_area = CommonArea.find params[:common_area_id]
end

def authenticate_resident!
@residents = @common_area.condo.residents

if manager_signed_in? || (resident_signed_in? && !@common_area.access_allowed?(current_resident))
return redirect_to root_path,
alert: t('alerts.reservation.not_authorized')
end

super
end

def authenticate_for_cancelation
unless resident_signed_in? || manager_signed_in?
return redirect_to new_resident_session_path,
alert: t('alerts.reservation.access_denied')
end

return unless manager_signed_in? || (resident_signed_in? && @reservation.resident != current_resident)

redirect_to root_path, alert: t('alerts.reservation.not_authorized')
end

def authorize_user
return if !authenticate_user || super_manager? || can_access_condo? || reservation_owner?

redirect_to root_path, alert: t('alerts.reservation.not_authorized')
end

def authenticate_user
return true if manager_signed_in? || resident_signed_in?

redirect_to signup_choice_path
false
end

def super_manager?
manager_signed_in? && current_manager.is_super
end

def can_access_condo?
manager_signed_in? && current_manager.condos.include?(@reservation.common_area.condo)
end

def reservation_owner?
resident_signed_in? && @reservation.resident == current_resident
end

def set_reservation
@reservation = Reservation.find params[:id]
end

def set_breadcrumbs
add_breadcrumb @common_area.condo.name, @common_area.condo
add_breadcrumb @common_area.name, @common_area
add_breadcrumb I18n.t "breadcrumb.reservation.#{action_name}"
end
end
2 changes: 1 addition & 1 deletion app/controllers/visitor_entries_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def set_breadcrumbs_for_index
end

def authenticate_manager!
return redirect_to root_path, notice: I18n.t('alerts.visitor_entry.access_denied') if resident_signed_in?
return redirect_to root_path, alert: I18n.t('alerts.visitor_entry.access_denied') if resident_signed_in?

super
end
Expand Down
5 changes: 5 additions & 0 deletions app/models/common_area.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
class CommonArea < ApplicationRecord
belongs_to :condo
has_many :reservations, dependent: :destroy

validates :name, :description, :max_occupancy, presence: true
validates :max_occupancy, numericality: { greater_than: 0 }

def access_allowed?(resident)
condo.residents.include?(resident)
end
end
19 changes: 19 additions & 0 deletions app/models/reservation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class Reservation < ApplicationRecord
belongs_to :common_area
belongs_to :resident

enum status: { confirmed: 0, canceled: 3 }

validates :date, presence: true
validate :check_availability, :date_must_be_actual_or_future, on: :create

def check_availability
common_area.reservations.confirmed.each do |reservation|
errors.add(:date, "#{I18n.l date} já está reservada para esta área comum") if reservation[:date] == date
end
end

def date_must_be_actual_or_future
errors.add(:date, 'deve ser atual ou futura') if date&.past?
end
end
5 changes: 3 additions & 2 deletions app/models/resident.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Resident < ApplicationRecord
has_one :residence, class_name: 'Unit', foreign_key: 'tenant_id', dependent: :destroy, inverse_of: :tenant
has_many :properties, class_name: 'Unit', foreign_key: 'owner_id', dependent: :destroy, inverse_of: :owner
has_one :residence, class_name: 'Unit', foreign_key: 'tenant_id', dependent: :nullify, inverse_of: :tenant
has_many :properties, class_name: 'Unit', foreign_key: 'owner_id', dependent: :nullify, inverse_of: :owner
has_many :reservations, dependent: :destroy
has_many :visitors, dependent: :destroy

devise :database_authenticatable, :recoverable, :rememberable, :validatable
Expand Down
3 changes: 2 additions & 1 deletion app/views/common_areas/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
<p><strong>Capacidade Máxima:</strong> <%= @common_area.max_occupancy %> pessoas</p>
<p><strong>Regras de Uso:</strong> <%= @common_area.rules %></p>

<%= link_to 'Editar', edit_common_area_path(@common_area), class: 'btn btn-dark rounded-pill px-4' %>
<%= link_to 'Editar', edit_common_area_path(@common_area), class: 'btn btn-dark rounded-pill px-4' if manager_signed_in? %>
<%= link_to 'Reservar', new_common_area_reservation_path(@common_area), class: 'btn btn-dark rounded-pill px-4' if resident_signed_in? %>
</div>
18 changes: 18 additions & 0 deletions app/views/reservations/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<%= render 'shared/errors', model: @reservation %>

<div class='bg-white rounded-5 py-3 px-5 shadow'>
<h1>Escolha a data da sua reserva</h1>

<%= form_with model: [@common_area, @reservation] do |f| %>
<div class="form-row row p-2">
<div class="form-group col-md-12 pe-3 mb-2">
<%= f.label :date %>
<%= f.date_field :date, min: Date.current, class: 'form-control' %>
</div>
</div>

<div class="d-flex justify-content-center">
<%= f.submit 'Reservar', class: 'btn btn-dark rounded-pill px-4 mt-3' %>
</div>
<% end %>
</div>
12 changes: 12 additions & 0 deletions app/views/reservations/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div class='bg-white rounded-5 py-3 px-5 shadow py-4'>
<h1 class="mb-3">Sua Reserva</h1>

<p><strong>Data:</strong> <%= I18n.l @reservation.date %></p>
<p><strong>Local:</strong> <%= @common_area.name %></p>
<p><strong>Status:</strong> <%= t(@reservation.status) %></p>

<strong>Atenção às Regras de Uso!</strong>
<p><%= @common_area.rules %></p>

<%= button_to 'Cancelar', canceled_reservation_path(@reservation), data: { turbo_confirm: 'Você tem certeza que deseja cancelar a reserva?' }, class: 'btn btn-dark rounded-pill px-4' if resident_signed_in? && @reservation.confirmed? %>
</div>
4 changes: 4 additions & 0 deletions config/locales/breadcrumb.pt-BR.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
pt-BR:
breadcrumb:
edit: 'Editar'
reservation:
index: 'Reservas'
new: 'Nova Reserva'
show: 'Detalhes da Reserva'
common_area:
new: 'Cadastrar Área Comum'
condo:
Expand Down
25 changes: 25 additions & 0 deletions config/locales/models/reservation.pt-BR.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pt-BR:
confirmed: 'Confirmado'
canceled: 'Cancelado'
notices:
reservation:
created: 'Reserva realizada com sucesso!'
canceled: 'Reserva cancelada com sucesso!'
alerts:
reservation:
not_created: 'Não foi possível realizar a reserva'
unavailable: 'Essa data já está reservada para outro morador'
access_denied: 'Para continuar, faça login ou registre-se.'
not_authorized: 'Você não tem permissão para fazer isso.'
activerecord:
models:
reservation:
one: 'Reserva'
other: 'Reservas'
attributes:
reservation:
date: 'Data'
common_area: 'Área comum'
common_area_id: 'Área comum'
resident: 'Morador'
resident_id: 'Morador'
11 changes: 10 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

devise_for :managers
devise_for :residents

resources :managers, only: [:new, :create] do
get 'edit_photo', on: :member
patch 'update_photo', on: :member
end

resources :residents, only: [:new, :create, :show, :update] do
resources :visitors, only: [:new, :create, :index]
resources :tenants, only: [:new, :create], on: :collection
Expand All @@ -22,7 +24,14 @@
get 'find_units', on: :collection
end

resources :common_areas, only: [:show, :edit, :update]
resources :common_areas, only: [:show, :edit, :update] do
resources :reservations, only: [:new, :create, :update]
end

resources :reservations, only: [:show] do
post 'canceled', on: :member
end

resources :unit_types, only: [:show, :edit, :update]

resources :condos, only: [:new, :create, :show, :edit, :update] do
Expand Down
12 changes: 12 additions & 0 deletions db/migrate/20240716143712_create_reservations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateReservations < ActiveRecord::Migration[7.1]
def change
create_table :reservations do |t|
t.date :date, null: false
t.integer :status, default: 0, null: false
t.references :common_area, null: false, foreign_key: true
t.references :resident, null: false, foreign_key: true

t.timestamps
end
end
end
Loading

0 comments on commit e7ce5f3

Please sign in to comment.