rubyforgood / pet-rescue

Pet Rescue is an application making it easy to link adopters/fosters with pets. We work with grassroots pet rescue organizations to understand how we can make the most impact.
MIT License
57 stars 95 forks source link

832 view components #842

Closed mononoken closed 1 month ago

mononoken commented 2 months ago

🔗 Issue

832

✍️ Description

This PR adds the ViewComponent gem and removes nice_partials. ViewComponent gives us all the utility we were getting from nice_partials, namely being able to yield blocks from an html to a template file, but it gives us much more as well and is more widely used.

One other addition from ViewComponent is that it allows us to test our views. This is especially useful for more complex views such as those with conditionals.

This PR does not apply VC to our whole project. I only aimed to replace the content from views/components/ and views/shared.

Some of the content from those previous directories I thought did not warrant being a partial or a component, so I moved them to their local files. I also refactored a few things along the way too. That said, there are two main types of components in here:

Some like LikeButtonComponent I simply copied completely from the partial. On the other spectrum, CardComponent is what I think is a more ideal component. It is fairly abstract but provides structure to help unify snippets of reused code throughout our view layer. I was tempted to abstract things like LikeButtonComponent into something more abstract like a ToggleButtonComponent, but I am not sure how necessary/useful that would be. Instead, I think we can have these more specific components like LikeButtonComponent and let abstract ones emerge as more similar button components emerge.

I think a good next step would be to apply the CardComponent throughout the views layer to get all our cards using it and see how much more customization it may require.

Additional Notes

I wrote this filter_attribute method for AvatarComponent, but I could see it potentially being useful for other components or even other parts of the app. I left it in this component for now, but I think it could potentially be nice in a BaseComponent or somewhere shared in the future.

# app/components/avatar_component.rb:13
  def filter_attribute(value, allowed_values, default: nil)
    return default unless value
    return value if allowed_values.include?(value)

    default
  end

📷 Screenshots/Demos

This video gives a brief intro to ViewComponent, specifically for this project. Note, I think I said at one point that the avatar is wrapped in a link, but that is actually in a different component. In this case, the template is rendering either an image or initials if no image url is provided. https://vimeo.com/967458618?share=copy

ViewComponent docs

mononoken commented 1 month ago

@cflipse it sounded like you were familiar with ViewComponent, so if you have the time, it would be great to get your input. If anyone else also has VC experience, would love feedback. Thank you!