React Date Picker/Freeze already booked dates with Rails
Tags: rails, javascript
Published: 2021-10-26 05:38:04

Hi There, working on my phase/4 Rails project, one of the challenges I faced building a booking system was to freeze the start and end dates and all the dates in between those dates once the bookings is confirmed. 
I started with a DatePicker React component, storing the Start and End date as states using useState hook as follows: 

  const [dateRange, setDateRange] = useState([null, null]);
  const [startDate, endDate] = dateRange;
      <DatePicker
        selectsRange={true}
        startDate={startDate}
        endDate={endDate}
        onChange={(update) => {
          setDateRange(update);
          changeDate(update);
        }}
        withPortal
        placeholderText="click to select dates"
      />

Note: withPortal prop will add a styling to the Calendar to be viewed as a modal with the background blurred. I have attached a photo of what it looks like. 

Then I made a fetch post request to my backend,  after I created a 

route'/booking' with a create action, including the room_id as follows:


class BookingsController < ApplicationController
rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid

def create
 books = Room.find(params[:room_id]).bookings
 dates_arr_range = books.pluck(:start_date, :end_date)

  dates_arr_range.each do |range|
    first = Date.parse(range[0])
    last= Date.parse(range[1])
    range_between = (first..last).to_a
    requested_range = ((Date.parse(params[:start_date]))..(Date.parse(params[:end_date]))).to_a

    requested_range.each do |date|
      if range_between.include?(date)
           return render json: {error: "These dates are already booked, Please try other dates"},status: :unprocessable_entity
      end
    end

  end
      booking = Booking.create!(booking_params)
         render json: booking, status: :created
end


  private
  def booking_params
    params.permit(:start_date, :end_date, :user_id, :room_id, :duration)
  end 


end

Let me explain my code step by step: 

first, I made sure the room exists using the 'Strong params' 
looking for the room with the id matching params[:room_id] and stored the room bookings in a variable called books.

Then, I used the pluck method to pluck the start and end date from each booking of the specific room which returns an array of arrays, each array in the array includes a start and end date.

Then, I iterated over every array in the array and got the range between the two dates using .to_a method and stored that range in a variable, but first, I converted the start and end date into dates that are readable rails Date.

tip: use .class to double check if the class = Date

Using strong params, I managed to again find the range between the requested dates from my fetch request, again I converted them into Dates and into an array as follows: 

((Date.parse(params[:start_date]))..(Date.parse(params[:end_date]))).to_a

then I iterated over all the ranges of the array of arrays to make sure the dates have not been booked yet, if the dates were already booked, then it should throw an error.

Finally, I displayed the result on my front end whether the dates were already booked or were available.

I'm sure there are other much more simple ways to achieve the same results but that is what I came up with.

Thank you for reading :) .
Nancy.