Building Mortimer, day 5

"I hate Mondays" is what Garfield has been expressing for 46 years (it has an anniversary in two days from now 😄) or to put it somewhat more civic – I don't like Mondays

Suffice to say the first day of the week (at least since 1988) was never my favorite, but here we are on day 5 of Building Mortimer.

Day 5

I left Mortimer yesterday in a state of transition, from no UI framework moving towards a UI using TailwindCSS. So why not build on new strengths?

as a user I will see a dashboard with stats and a menu and my "punch in/out" button once logged in

I'll start with the button and add a test for it

  test "should show punch button when logged in" do
    sign_in users(:one)
    get root_url
    assert_response :success
    assert_select "section" # where the stats will go
    assert_select "a[href=?]", destroy_user_session_url # part of a menu
    assert_select "button"
  end

Phlex (& PhlexUI)

Seriously stabbing at the UI had me consider what component framework to go with: ViewComponent or Phlex were the "usual suspects" and I choose Phlex, among other reasons due to the speed with which Phlex renders! To complement it all I reached for the stars going with PhlexUI 🫃

bundle add phlex-rails
rails generate phlex:install
bundle add phlex_ui

I continued following the installation guide for Rails and then in the end I jumped ship and finalized it all with using the PhlexUI Rails with importmap installation guide. I must have timed my "full immersion" really bad 'cause I was not able to produce any output from the PhlexUI components - sadly! So, I reversed the entire thing (with git holding my hand that's as easy as tapping the 'discard changes' left circling arrow in the source control tab in Visual Studio Code) and then did it again but for the Phlex only.

Phlex has been a part of my toolbelt for quite some time and even though Joel Drapper and his League of Extraordinary Do-Good'ers seriously remodeled the little finca, I feverishly tagged along best I could.

So for this first use case I needed some stats and a menu and a punch button - so my first 3 components were exactly that.

First add a few helpers:

module PhlexUiHelper
  def punch_button
    render PunchButtonComponent.new
  end
  def menu
    render MenuComponent.new
  end
  def stats_section
    render StatsComponent.new
  end
end

Then on to the components definition:

# frozen_string_literal: true

class MenuComponent < ApplicationComponent
  include Phlex::Rails::Helpers::LinkTo

  def initialize
  end

  def view_template
    div do
      h1 { "Menu" }
      ul do
        li { link_to("Home", "/") }
        li { link_to("Sign out", destroy_user_session_url, data: { turbo_method: :delete }) }
      end
    end
  end
end

With that out of the way I hurried to the next use case

as a user I will be able to see whether I'm 'punched in' or 'out' – and by merely tapping the punch button punch the right thing

That required me to

rails g migration add_state_to_user state:integer

and as for persisting the punches, now I could

  # controllers/punches_controller.rb
  ...
  # POST /punches or /punches.json
  def create
    @punch = Punch.new
    @punch.user = current_user
    @punch.state = current_user.in? ? "out" : "in"
    @punch.punched_at = DateTime.now.utc
    @punch.comment = punch_params[:comment] if params_good?

    respond_to do |format|
      if @punch.save
        current_user.update state: @punch.state
        format.html { redirect_to nexturl, allow_other_host: true, notice: "Punch was successfully created." }
        format.json { render :show, status: :created, location: @punch }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @punch.errors, status: :unprocessable_entity }
      end
    end
  end

I'm feeling a bit under the weather - will call it a day, and tag it as 0.4.0_menu