grace teng

See Rent-a-Pokémon Redux

Github Repo for Rent-a-Pokémon Redux

Rent-a-Pokémon

Github Repo for Rent-a-Pokémon

About Rent-a-Pokemon

At Le Wagon, every student builds an Airbnb clone in five days as part of a team. The Airbnb project is the first time during the Le Wagon bootcamp when we work in groups and collaborate on code. Although it's universally referred to as the Airbnb project, the web application does not have to involve apartment rental at all, as long as it involves the creation of a two-sided marketplace (e.g. mentors and mentees, party hosts and guests…).

Our group chose to build the Minimum Viable Product of a service that allows users to put up their Pokémon for rent, or to rent other users' Pokémon.

Naturally, this project built on many of the skills we put into practice in Mister Cocktail:

Rent-a-Pokemon schema.png

  resources :pokemons do
    resources :rentals, only: [:new, :create]
  end
  resources :rentals, only: [] do
    resources :reviews, only: [:new, :create]
  end

There was one key aspect of building Rent-a-Pokémon that was new:

Rent-a-Pokemon Redux

Post-bootcamp, I forked the Rent-A-Pokémon repository and continued working on it, with the goal of making the code cleaner and more maintainable, the layout more responsive, and fixing niggling bugs and finishing features that we did not get to in time during the week of the project itself.

The changes I made included:

The last point is worth some elaboration. My teammates and I had put in a good amount of work to make the site look good, so why did I choose to throw out the CSS and start over? A big reason I opted to do that after reviewing the code was that we did not have a unified code style or approach to our front-end development. Everyone coded in the style that we each felt most comfortable with and fell back on habits that we'd developed before the project. One person would put headers inside the container, while another would put headers outside; some views utilised the Bootstrap grid while others did not; some components received custom styling while others defaulted to the basic Bootstrap class (or worse, were not styled at all).

Normally, in a team environment, code would be carefully reviewed for both function and style before any pull requests were merged to the master branch. Being new to working collaboratively, however, we approved each other's pull requests as long as the feature was complete and there were no conflicts. Our product developed quickly, but we were accumulating a lot of unnecessary technical debt. When I returned to the project weeks later, I found myself lost and confused about where to start untangling. Stripping out the CSS and rewriting it from scratch allowed me to kill two birds with one stone: I could rebuild the design system, and at the same time make sure that the code was consistent throughout the web application.

Of course, this type of waste (as Scrum's Jeff Sutherland would term it) would be unacceptable in a professional setting. This is a lesson to be learnt once, in an educational context, and remembered in future workplaces.

A point of learning

After we finished our Airbnb project and presented the demo to the class, I went home and showed my sister the Rent-a-Pokemon website on my phone. "Play around with it," I said. "Everything should be working fine."

Within minutes, she returned my phone to me with a big red ActiveController error page: she had managed to submit the rental form with an end date before the start date.

I was baffled. Our Rental model has a custom validation that prevents the rental from being created if the start date is after the end date, and this was the error that she had triggered. But before the dates even get sent to the server, the flatpickr code I'd copied from Sonia's article was supposed to prevent the user from selecting an end date before the currently selected start date.

Here's how the date pickers are implemented:

  1. There are two text fields, one for the start date and one for the end date.
  2. The flatpickr date picker for the start date is initialised, with a predefined set of unavailable dates sent over by the Rails controller to the view, embedded as part of a HTML element's dataset and retrieved by JavaScript to be given to the flatpickr initializer.
  3. The date picker for the end date is initially disabled. (To be more precise: the text input that contains the end date is disabled.)
  4. When the user selects a start date, the text input for the end date is enabled and the flatpickr date picker for the end date is initialised, with a minimum date equal to the start date. This prevents the user from selecting an invalid end date.

However, it does not prevent the user from selecting a valid end date, and then changing the value of the start date to an invalid date after the end date. That was what my sister had done.

The fix is easy: add a validity check whenever the start date changes. If the new start date is after the end date, clear the end date input:

const startDateInput = document.getElementById('rental_start_date');
const endDateInput = document.getElementById('rental_end_date');

const checkValidity = () => {
  const startDate = startDateInput.value;
  const endDate = endDateInput.value;
  if (Date.parse(endDate) - Date.parse(startDate) < 0) {
    endDateInput.value = "";
  }
}

startDateInput.addEventListener("change", (e) => {
  // if start date is after end date, clear existing end date
  checkValidity();
});

There are some obvious lessons to be learnt from this:

  1. Your product must hold up to real-life use. User behaviour is unpredictable, but no user should be able to break your application within minutes of monkeying around. Test thoroughly and often with people who don't know how your product is "supposed to" work.
  2. Adapting tutorials to your use case is not simply a matter of copy and paste. Sonia's article is written for Le Wagon students doing exactly what we were doing, building an Airbnb clone. There are doubtless many other Le Wagon students who have implemented a date picker by following her article. I assumed that if I followed the instructions to solve the problem, I would be home free. Had I invested a little bit of my own time playing around with the result, I would probably have caught the bug myself. I can't blame the fact that the code didn't catch unexpected user behaviour on the tutorial — I copied it and I put it in the project. The bug is on me.
  3. If you're afraid to touch copy-pasted code, you might not fully understand it yet. Part of why I didn't dig deeper into the code to begin with was that I didn't want to break it. I didn't quite understand how it worked, I only knew that it did work. When I returned to the project a few weeks later to improve it and fix its issues, I had a few more weeks of JavaScript under my belt, and now the magic incantations of the code made much more sense. I didn't have the confidence to mess around with the code then, but now I do.

Takeaway

After a group project like this, I gained an appreciation for a lot of the organisational infrastructure that enables different individuals to work on a product as a single team. We had daily standup meetings and development moved at a quick clip because the team communicated freely and frequently. Everyone was always on the same page about what items in the backlog we were going to work on next. On the other hand, we didn't review code for style or establish UI/UX guidelines, resulting in code that was difficult to maintain and a disorganised user interface.

All the same, I'm proud of what we managed to achieve in five days, and we took many of the lessons we learned from this project into the development of Macrotery, which was a much more complex product to build.