diff --git a/Gemfile b/Gemfile index 422fa177..138bcd22 100644 --- a/Gemfile +++ b/Gemfile @@ -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' diff --git a/Gemfile.lock b/Gemfile.lock index af58d89c..299f4645 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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) @@ -335,6 +337,7 @@ DEPENDENCIES rspec-rails rubocop rubocop-rails + simple_calendar simplecov sprockets-rails sqlite3 (~> 1.4) diff --git a/README.md b/README.md index 8b0d734c..5946a1b0 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,8 @@

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.

+

Moradores podem fazer uma reserva de área comum, bem como cancelar essa reserva.

+

(voltar ao topo)

diff --git a/app/assets/stylesheets/application.bootstrap.scss b/app/assets/stylesheets/application.bootstrap.scss index 34f3ad0a..0fddef45 100644 --- a/app/assets/stylesheets/application.bootstrap.scss +++ b/app/assets/stylesheets/application.bootstrap.scss @@ -1,3 +1,4 @@ @import 'custom_spacers'; @import 'bootstrap/scss/bootstrap'; @import 'bootstrap-icons/font/bootstrap-icons'; +@import 'simple_calendar'; diff --git a/app/assets/stylesheets/simple_calendar.scss b/app/assets/stylesheets/simple_calendar.scss new file mode 100644 index 00000000..9d03b505 --- /dev/null +++ b/app/assets/stylesheets/simple_calendar.scss @@ -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 {} +} \ No newline at end of file diff --git a/app/controllers/reservations_controller.rb b/app/controllers/reservations_controller.rb new file mode 100644 index 00000000..9057979e --- /dev/null +++ b/app/controllers/reservations_controller.rb @@ -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 diff --git a/app/controllers/visitor_entries_controller.rb b/app/controllers/visitor_entries_controller.rb index 4573e076..19f481aa 100644 --- a/app/controllers/visitor_entries_controller.rb +++ b/app/controllers/visitor_entries_controller.rb @@ -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 diff --git a/app/models/common_area.rb b/app/models/common_area.rb index 82e18880..5b7c4582 100644 --- a/app/models/common_area.rb +++ b/app/models/common_area.rb @@ -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 diff --git a/app/models/reservation.rb b/app/models/reservation.rb new file mode 100644 index 00000000..0e999e96 --- /dev/null +++ b/app/models/reservation.rb @@ -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 diff --git a/app/models/resident.rb b/app/models/resident.rb index c7fb99e4..3cb3eec3 100644 --- a/app/models/resident.rb +++ b/app/models/resident.rb @@ -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 diff --git a/app/views/common_areas/show.html.erb b/app/views/common_areas/show.html.erb index fe1a8bd3..4b38db30 100644 --- a/app/views/common_areas/show.html.erb +++ b/app/views/common_areas/show.html.erb @@ -5,5 +5,6 @@

Capacidade Máxima: <%= @common_area.max_occupancy %> pessoas

Regras de Uso: <%= @common_area.rules %>

- <%= 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? %>
\ No newline at end of file diff --git a/app/views/reservations/new.html.erb b/app/views/reservations/new.html.erb new file mode 100644 index 00000000..a80109e3 --- /dev/null +++ b/app/views/reservations/new.html.erb @@ -0,0 +1,18 @@ +<%= render 'shared/errors', model: @reservation %> + +
+

Escolha a data da sua reserva

+ + <%= form_with model: [@common_area, @reservation] do |f| %> +
+
+ <%= f.label :date %> + <%= f.date_field :date, min: Date.current, class: 'form-control' %> +
+
+ +
+ <%= f.submit 'Reservar', class: 'btn btn-dark rounded-pill px-4 mt-3' %> +
+ <% end %> +
diff --git a/app/views/reservations/show.html.erb b/app/views/reservations/show.html.erb new file mode 100644 index 00000000..c708d28b --- /dev/null +++ b/app/views/reservations/show.html.erb @@ -0,0 +1,12 @@ +
+

Sua Reserva

+ +

Data: <%= I18n.l @reservation.date %>

+

Local: <%= @common_area.name %>

+

Status: <%= t(@reservation.status) %>

+ + Atenção às Regras de Uso! +

<%= @common_area.rules %>

+ + <%= 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? %> +
\ No newline at end of file diff --git a/config/locales/breadcrumb.pt-BR.yml b/config/locales/breadcrumb.pt-BR.yml index ec70cded..9fc70839 100644 --- a/config/locales/breadcrumb.pt-BR.yml +++ b/config/locales/breadcrumb.pt-BR.yml @@ -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: diff --git a/config/locales/models/reservation.pt-BR.yml b/config/locales/models/reservation.pt-BR.yml new file mode 100644 index 00000000..14c0bfb5 --- /dev/null +++ b/config/locales/models/reservation.pt-BR.yml @@ -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' \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 1ed4818b..56384afb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 @@ -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 diff --git a/db/migrate/20240716143712_create_reservations.rb b/db/migrate/20240716143712_create_reservations.rb new file mode 100644 index 00000000..81a42eab --- /dev/null +++ b/db/migrate/20240716143712_create_reservations.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index 161532a3..6de7408c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -104,6 +104,17 @@ t.index ["reset_password_token"], name: "index_managers_on_reset_password_token", unique: true end + create_table "reservations", force: :cascade do |t| + t.date "date", null: false + t.integer "status", default: 0, null: false + t.integer "common_area_id", null: false + t.integer "resident_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["common_area_id"], name: "index_reservations_on_common_area_id" + t.index ["resident_id"], name: "index_reservations_on_resident_id" + end + create_table "residents", force: :cascade do |t| t.string "full_name" t.string "registration_number" @@ -184,6 +195,8 @@ add_foreign_key "condo_managers", "managers" add_foreign_key "condos", "addresses" add_foreign_key "floors", "towers" + add_foreign_key "reservations", "common_areas" + add_foreign_key "reservations", "residents" add_foreign_key "towers", "condos" add_foreign_key "unit_types", "condos" add_foreign_key "units", "floors" diff --git a/spec/factories/reservations.rb b/spec/factories/reservations.rb new file mode 100644 index 00000000..c43b7125 --- /dev/null +++ b/spec/factories/reservations.rb @@ -0,0 +1,8 @@ +FactoryBot.define do + factory :reservation do + date { Date.current + 1.week } + status { 0 } + common_area { build :common_area } + resident { build :resident } + end +end diff --git a/spec/factories/residents.rb b/spec/factories/residents.rb index a6c7b9b4..18921839 100644 --- a/spec/factories/residents.rb +++ b/spec/factories/residents.rb @@ -5,5 +5,13 @@ sequence(:email) { |n| "João#{n}@example.com" } password { '123456' } status { :mail_confirmed } + + trait :with_residence do + transient { condo { create :condo } } + + after(:create) do |resident, evaluator| + resident.residence = create(:unit, floor: create(:floor, tower: create(:tower, condo: evaluator.condo))) + end + end end end diff --git a/spec/models/reservation_spec.rb b/spec/models/reservation_spec.rb new file mode 100644 index 00000000..f9190b28 --- /dev/null +++ b/spec/models/reservation_spec.rb @@ -0,0 +1,36 @@ +require 'rails_helper' + +RSpec.describe Reservation, type: :model do + describe '#valid' do + it 'date must be present' do + reservation = build :reservation, date: nil + + expect(reservation).not_to be_valid + expect(reservation.errors).to include :date + end + + it 'date cannot have multiple reservations' do + common_area = create :common_area, rules: 'Não pode subir no escorregador.' + first_resident = build :resident + second_resident = build :resident, email: 'morador@mail.com' + + first_reservation = build :reservation, common_area:, date: Date.current + 1.week, resident: first_resident + common_area.reservations << first_reservation + + second_reservation = build :reservation, common_area:, date: Date.current + 1.week, resident: second_resident + + expect(Reservation.all.size).to eq 1 + expect(second_reservation).not_to be_valid + expect(second_reservation.errors.full_messages).to include "Data #{I18n.l Date.current + 1.week} " \ + 'já está reservada para esta área comum' + end + + it 'date must be current or future' do + reservation = build :reservation, date: Date.current - 1.day + + expect(Reservation.all.empty?).to be true + expect(reservation).not_to be_valid + expect(reservation.errors.full_messages).to include 'Data deve ser atual ou futura' + end + end +end diff --git a/spec/requests/reservation_spec.rb b/spec/requests/reservation_spec.rb new file mode 100644 index 00000000..ba1d2f66 --- /dev/null +++ b/spec/requests/reservation_spec.rb @@ -0,0 +1,79 @@ +require 'rails_helper' + +describe 'Reservation' do + context 'POST /reservations' do + it 'must be authenticated as resident to make a reservation' do + common_area = create :common_area + + post common_area_reservations_path common_area, params: { reservation: { date: I18n.l(Date.current + 1.week) } } + + expect(response).to redirect_to new_resident_session_path + expect(flash[:alert]).to eq 'Para continuar, faça login ou registre-se.' + expect(Reservation.all.empty?).to be true + end + + it 'and administrator cannot make a reservation' do + common_area = create :common_area + manager = build :manager + + login_as manager, scope: :manager + post common_area_reservations_path common_area, params: { reservation: { date: I18n.l(Date.current + 1.week) } } + + expect(response).to redirect_to root_path + expect(flash[:alert]).to eq 'Você não tem permissão para fazer isso.' + expect(Reservation.all.empty?).to be true + end + + it 'and resident must live at related condo of the common area' do + first_condo = create :condo + first_resident = create :resident, :with_residence, condo: first_condo + + second_condo = create :condo + common_area = create :common_area, condo: second_condo + + login_as first_resident, scope: :resident + post common_area_reservations_path common_area, params: { reservation: { date: I18n.l(Date.current + 1.week) } } + + expect(response).to redirect_to root_path + expect(flash[:alert]).to eq 'Você não tem permissão para fazer isso.' + expect(Reservation.all.empty?).to be true + end + end + + context 'POST /canceled_reservation' do + it 'must be authenticated as resident to cancel a reservation' do + reservation = create :reservation + + post canceled_reservation_path reservation + + expect(response).to redirect_to new_resident_session_path + expect(flash[:alert]).to eq 'Para continuar, faça login ou registre-se.' + expect(reservation.confirmed?).to be true + end + + it 'and residents can only cancel their own reservations' do + first_resident = create :resident + second_resident = create :resident, email: 'second@email.com' + reservation = create(:reservation, resident: first_resident) + + login_as second_resident, scope: :resident + post canceled_reservation_path reservation + + expect(response).to redirect_to root_path + expect(flash[:alert]).to eq 'Você não tem permissão para fazer isso.' + expect(reservation.confirmed?).to be true + end + + it 'and administrator cannot cancel a reservation' do + reservation = create :reservation + manager = build :manager + + login_as manager, scope: :manager + post canceled_reservation_path reservation + + expect(response).to redirect_to root_path + expect(flash[:alert]).to eq 'Você não tem permissão para fazer isso.' + expect(reservation.confirmed?).to be true + end + end +end diff --git a/spec/system/common_area/manager_edits_common_area_spec.rb b/spec/system/common_area/manager_edits_common_area_spec.rb index 19ada9de..bbbb2143 100644 --- a/spec/system/common_area/manager_edits_common_area_spec.rb +++ b/spec/system/common_area/manager_edits_common_area_spec.rb @@ -1,7 +1,25 @@ require 'rails_helper' describe 'Manager edits common area' do - it 'succesfully' do + it 'and must be authenticated' do + common_area = create :common_area + + visit edit_common_area_path common_area + + expect(current_path).to eq new_manager_session_path + end + + it 'and does not see edit button if is a resident' do + common_area = create :common_area + resident = create :resident + + login_as resident, scope: :resident + visit new_common_area_reservation_path common_area + + expect(page).not_to have_link 'Editar' + end + + it 'successfully' do manager = create(:manager) common_area = create(:common_area) @@ -38,12 +56,4 @@ expect(page).to have_content 'Descrição não pode ficar em branco' expect(page).to have_content 'Capacidade Máxima não pode ficar em branco' end - - it 'and must be authenticated' do - common_area = create(:common_area) - - visit edit_common_area_path(common_area) - - expect(current_path).to eq new_manager_session_path - end end diff --git a/spec/system/common_area/reservation/resident_cancel_common_area_reservation_spec.rb b/spec/system/common_area/reservation/resident_cancel_common_area_reservation_spec.rb new file mode 100644 index 00000000..e2fbabc7 --- /dev/null +++ b/spec/system/common_area/reservation/resident_cancel_common_area_reservation_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' + +describe 'Resident cancel common area reservation' do + it 'from the reservation details page' do + resident = create :resident + reservation = create :reservation, resident:, status: :confirmed + + login_as resident, scope: :resident + visit reservation_path reservation + click_on 'Cancelar' + reservation.reload + + expect(current_path).to eq reservation_path reservation + expect(page).to have_content 'Reserva cancelada com sucesso' + expect(page).to have_content 'Status: Cancelado' + expect(page).not_to have_button 'Cancelar' + expect(reservation.canceled?).to be true + end +end diff --git a/spec/system/common_area/reservation/resident_reserves_common_area_spec.rb b/spec/system/common_area/reservation/resident_reserves_common_area_spec.rb new file mode 100644 index 00000000..fab21b1a --- /dev/null +++ b/spec/system/common_area/reservation/resident_reserves_common_area_spec.rb @@ -0,0 +1,92 @@ +require 'rails_helper' + +describe 'Resident reserves common area' do + it 'only if authenticated' do + common_area = create :common_area + + visit new_common_area_reservation_path common_area + + expect(current_path).to eq new_resident_session_path + end + + it 'and does not see reserve button if is a manager' do + common_area = create :common_area + manager = create :manager + + login_as manager, scope: :manager + visit new_common_area_reservation_path common_area + + expect(page).not_to have_link 'Reservar' + end + + it "only if has a residence at common area's condo" do + first_condo = create :condo + first_resident = create :resident, :with_residence, condo: first_condo + + second_condo = create :condo + common_area = create :common_area, condo: second_condo + + login_as first_resident, scope: :resident + visit new_common_area_reservation_path common_area + + expect(current_path).to eq root_path + expect(page).to have_content 'Você não tem permissão para fazer isso' + end + + it 'successfully if there is no confirmed reservation on the same date' do + common_area = create :common_area, rules: 'Não pode subir no escorregador.' + first_resident = create :resident, :with_residence, condo: common_area.condo + second_resident = create :resident + + create :reservation, + common_area:, + resident: second_resident, + date: Date.current + 1.week, + status: :canceled + + login_as first_resident, scope: :resident + visit common_area_path common_area + click_on 'Reservar' + fill_in 'Data', with: Date.current + 1.week + click_on 'Reservar' + + expect(current_path).to eq reservation_path Reservation.last + expect(page).to have_content 'Reserva realizada com sucesso!' + expect(page).to have_content "Data: #{I18n.l Date.current + 1.week}" + expect(page).to have_content 'Status: Confirmado' + expect(page).to have_content 'Não pode subir no escorregador' + expect(Reservation.last.resident).to eq first_resident + end + + it "fail if date isn't selected" do + common_area = create :common_area + resident = create :resident, :with_residence, condo: common_area.condo + + login_as resident, scope: :resident + visit new_common_area_reservation_path common_area + fill_in 'Data', with: '' + click_on 'Reservar' + + expect(current_path).to eq new_common_area_reservation_path common_area + expect(page).to have_content 'Não foi possível realizar a reserva' + expect(page).to have_content 'Data não pode ficar em branco' + expect(Reservation.all.empty?).to be true + end + + it 'fail if the date already has a reservation confirmed' do + common_area = create :common_area, rules: 'Não pode subir no escorregador.' + first_resident = create :resident + second_resident = create :resident, :with_residence, condo: common_area.condo + create :reservation, common_area:, date: Date.current + 1.week, resident: first_resident, status: :confirmed + + login_as second_resident, scope: :resident + visit new_common_area_reservation_path common_area + fill_in 'Data', with: Date.current + 1.week + click_on 'Reservar' + + expect(current_path).to eq new_common_area_reservation_path common_area + expect(page).to have_content 'Não foi possível realizar a reserva' + expect(page).to have_content "Data #{I18n.l Date.current + 1.week} já está reservada para esta área comum" + expect(Reservation.all.size).to eq 1 + end +end diff --git a/spec/system/common_area/reservation/user_sees_reservation_details_spec.rb b/spec/system/common_area/reservation/user_sees_reservation_details_spec.rb new file mode 100644 index 00000000..6c2a0bf5 --- /dev/null +++ b/spec/system/common_area/reservation/user_sees_reservation_details_spec.rb @@ -0,0 +1,50 @@ +require 'rails_helper' + +describe 'User sees reservation details' do + it 'and must be authenticated' do + reservation = create :reservation + + visit reservation_path reservation + + expect(current_path).to eq signup_choice_path + end + + it 'and administrators can see any reservation details from their condo' do + condo = create :condo + manager = create :manager + condo.managers << manager + common_area = create(:common_area, condo:) + reservation = create(:reservation, common_area:) + + login_as manager, scope: :manager + visit reservation_path reservation + + expect(current_path).to eq reservation_path reservation + expect(page).not_to have_link 'Cancelar' + end + + it 'and administrators cannot see reservation details from another condos' do + condo = create :condo + manager = create :manager, is_super: false + common_area = create(:common_area, condo:) + reservation = create(:reservation, common_area:) + + login_as manager, scope: :manager + visit reservation_path reservation + + expect(current_path).to eq root_path + expect(page).to have_content 'Você não tem permissão para fazer isso.' + end + + it 'and residents can only see their own reservation details' do + first_resident = create :resident + second_resident = create :resident, email: 'second@email.com' + reservation = create :reservation, resident: first_resident + + login_as second_resident, scope: :resident + visit reservation_path reservation + + expect(current_path).to eq root_path + expect(page).to have_content 'Você não tem permissão para fazer isso.' + end +end diff --git a/spec/system/resident/manager_sets_resident_as_tenant_spec.rb b/spec/system/resident/manager_sets_resident_as_tenant_spec.rb index 337aa8dd..d13c7741 100644 --- a/spec/system/resident/manager_sets_resident_as_tenant_spec.rb +++ b/spec/system/resident/manager_sets_resident_as_tenant_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'managers access page to set a resident as tenant' do +describe 'managers sets resident as tenant' do it 'and is not authenticated' do resident = create :resident @@ -36,6 +36,7 @@ select '2', from: 'Unidade' click_on 'Atualizar Morador' + sleep 3 expect(current_path).to eq resident_path resident expect(mail).to have_received(:deliver).once expect(page).to have_content 'Atualizado com sucesso!' @@ -65,8 +66,9 @@ select '2', from: 'Unidade' click_on 'Não reside neste condomínio' - expect(page).to have_content 'Atualizado com sucesso!' + sleep 3 expect(current_path).to eq resident_path resident + expect(page).to have_content 'Atualizado com sucesso!' resident.reload expect(resident.residence).to eq nil end