1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-20 05:39:39 +02:00

Currency Dropdown (#415)

* Initial dropdown setup and styles

* Allow form field to pass through block content and update dropdown posititon

* add currency to accounts params

* Add repositionDropdown function and carry over dropdown controller

* remove block context from form builder in favour of using form tag directly

* Hide currency input and set checks for input and label before updating

* align currency button with balance

* revert form_field_tag changes

* remove margin on currency button, looks cleaner

---------

Signed-off-by: Josh Pigford <josh@joshpigford.com>
Co-authored-by: Josh Pigford <josh@joshpigford.com>
This commit is contained in:
Cristiano Crolla 2024-02-11 19:02:27 +00:00 committed by GitHub
parent b2fdf78101
commit 96debfaeda
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 86 additions and 3 deletions

View file

@ -18,6 +18,10 @@ module ApplicationHelper
render partial: "shared/modal", locals: { content: content } render partial: "shared/modal", locals: { content: content }
end end
def currency_dropdown(f: nil, options: [])
render partial: "shared/currency_dropdown", locals: { f: f, options: options }
end
def sidebar_link_to(name, path, options = {}) def sidebar_link_to(name, path, options = {})
base_class_names = [ "block", "border", "border-transparent", "rounded-xl", "-ml-2", "p-2", "text-sm", "font-medium", "text-gray-500", "flex", "items-center" ] base_class_names = [ "block", "border", "border-transparent", "rounded-xl", "-ml-2", "p-2", "text-sm", "font-medium", "text-gray-500", "flex", "items-center" ]
hover_class_names = [ "hover:bg-white", "hover:border-[#141414]/[0.07]", "hover:text-gray-900", "hover:shadow-xs" ] hover_class_names = [ "hover:bg-white", "hover:border-[#141414]/[0.07]", "hover:text-gray-900", "hover:shadow-xs" ]

View file

@ -0,0 +1,58 @@
import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="dropdown"
export default class extends Controller {
static targets = ["menu", "input", "label", "option"]
toggleMenu(event) {
event.stopPropagation(); // Prevent event from closing the menu immediately
this.repositionDropdown();
this.menuTarget.classList.toggle("hidden");
}
hideMenu = () => {
this.menuTarget.classList.add("hidden");
}
connect() {
document.addEventListener("click", this.hideMenu);
}
disconnect() {
document.removeEventListener("click", this.hideMenu);
}
repositionDropdown () {
const button = this.menuTarget.previousElementSibling;
const menu = this.menuTarget;
// Calculate position
const buttonRect = button.getBoundingClientRect();
menu.style.top = `${buttonRect.bottom + window.scrollY}px`;
menu.style.left = `${buttonRect.left + window.scrollX}px`;
}
selectOption (e) {
const value = e.target.getAttribute('data-value');
if (value) {
// Remove active option background and tick
this.optionTargets.forEach((element) => {
element.classList.remove('bg-gray-100');
element.children[0].classList.add('hidden');
});
// Set currency value and label
if (this.hasInputTarget) {
this.inputTarget.value = value;
}
if (this.hasLabelTarget) {
this.labelTarget.innerHTML = value;
}
// Reassign active option background and tick
e.currentTarget.classList.add('bg-gray-100')
e.currentTarget.children[0].classList.remove('hidden');
}
}
}

View file

@ -76,10 +76,16 @@
<%= render "accounts/#{permitted_accountable_partial(@account.accountable_type)}", f: f %> <%= render "accounts/#{permitted_accountable_partial(@account.accountable_type)}", f: f %>
<%= f.number_field :original_balance, step: :any, placeholder: 0.00, in: 0.00..100000000.00, required: 'required', label: true %> <%= form_field_tag do %>
<%= f.label :original_balance, class: "form-field__label" %>
<%= f.collection_select :original_currency, Currency.all, :iso_code, :iso_code, { prompt: "Choose a currency", selected: Current.family.currency }, { required: 'required', label: "Base Currency" } %> <%= f.number_field :original_balance, step: :any, placeholder: number_to_currency(0), in: 0.00..100000000.00, required: 'required', class: 'form-field__input max-w-[80%]' %>
<%= currency_dropdown(f: f, options: ['USD', 'EUR', 'JPY', 'GBP', 'AUD', 'CAD', 'CNY', 'BTC', 'ETH']) %>
<% end %>
</div> </div>
<%#= f.collection_select :original_currency, Currency.all, :iso_code, :iso_code, { prompt: "Choose a currency", selected: Current.family.currency }, { required: 'required', label: "Base Currency" } %>
<%= f.submit "Add #{@account.accountable.model_name.human.downcase}" %> <%= f.submit "Add #{@account.accountable.model_name.human.downcase}" %>
<% end %> <% end %>
<% end %> <% end %>

View file

@ -0,0 +1,15 @@
<div data-controller="currency-dropdown" class="absolute right-1 bottom-[10px] flex items-end">
<button type="button" class="flex justify-between items-center hover:bg-gray-100 focus:bg-gray-100 w-20 text-sm rounded-lg py-1 px-2" data-action="click->currency-dropdown#toggleMenu">
<div data-currency-dropdown-target="label"><%= f.object.currency %></div>
<%# Example of how account currency value is updated %>
<%#= f.hidden_field :currency, data: {currency_dropdown_target: "input"} %>
<%= lucide_icon("chevron-down", class: "text-[#737373] w-5 h-5" ) %>
</button>
<ul data-currency-dropdown-target="menu" class="hidden fixed p-1 z-10 bg-white rounded-[10px] shadow min-w-[112px] z-50 translate-y-2 border border-[#141414]/8 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.1)]">
<% options.each do |option| %>
<li data-action="click->currency-dropdown#selectOption" data-currency-dropdown-target="option" data-value="<%= option %>" class="flex justify-between items-center p-2 text-sm text-gray-700 hover:bg-gray-100 cursor-pointer rounded-lg <%= "bg-gray-100" if option === f.object.currency %>"><%= option %>
<%= inline_svg_tag('icn-check.svg', class: "text-gray-500 fill-current #{'hidden'if option != f.object.currency}") %>
</li>
<% end %>
</ul>
</div>