mirror of
https://github.com/we-promise/sure.git
synced 2026-09-06 07:11:14 +00:00
* feat: create merchant inline from transaction detail Add a searchable "create or select" merchant combobox (DS::MerchantSelect, mirroring the existing DS::TagSelect pattern) so a new FamilyMerchant can be created directly from the transaction detail and new-transaction forms, instead of requiring a trip to Settings > Merchants first. FamilyMerchantsController#create now also responds to JSON so the combobox can create-and-select a merchant without a full page reload. * fix: address PR review feedback on merchant inline creation - Handle Turbo validation failures in FamilyMerchantsController#create (missing format.turbo_stream branch raised ActionController::UnknownFormat) - Guard connect() so disabled merchant selectors (no menu target) don't throw - Select the exact match (or block form submission) on Enter when the create row is hidden - Catch network/parse failures in createMerchant and show an error - Localize the fallback "could not create merchant" error message - Move the create button/error text outside the listbox and add aria-controls for accessibility - Align create-option avatar size with the selected-value display Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: keep created merchant option inside the listbox, move logo URL logic to component - Add a dedicated listbox target and insert newly created merchant options inside it (previously landed outside role="listbox" after the create button was moved out in the prior review-fix commit) - Move selected-merchant logo URL transformation out of the template into DS::MerchantSelect#selected_merchant_logo_url Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: address maintainer review feedback on merchant inline creation - Drop the explicit format.turbo_stream branch in the merchant creation failure path: respond_to's turbo_stream matching forces the response Content-Type to text/vnd.turbo-stream.html before the block runs, so render :new, formats: [:html] only changed template lookup, not the Content-Type. Turbo's client then received a turbo-stream response with no <turbo-stream> tags and silently did nothing. Leaving turbo_stream undeclared lets Rails negotiate down to format.html, which renders :new with the correct text/html type. - Add truncate/shrink-0 classes to the merchant option partial's name and avatar spans so they match the selected-value display once updateSelectionDisplay clones them into the trigger button. - Add a regression test simulating a Turbo form submission (Accept: turbo-stream, text/html) against a duplicate merchant name. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Gerald <248542187+gfr-free@users.noreply.github.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
46 lines
1.3 KiB
Ruby
46 lines
1.3 KiB
Ruby
class DS::MerchantSelect < DesignSystemComponent
|
|
attr_reader :form, :method, :merchants, :selected_id, :disabled, :auto_submit,
|
|
:menu_placement, :label, :include_blank
|
|
|
|
MENU_PLACEMENTS = %w[auto down up].freeze
|
|
|
|
def initialize(form:, method:, merchants:, selected_id:, disabled: false, auto_submit: false,
|
|
menu_placement: :auto, label: nil, include_blank: nil)
|
|
@form = form
|
|
@method = method
|
|
@merchants = merchants
|
|
@selected_id = selected_id&.to_s
|
|
@disabled = disabled
|
|
@auto_submit = auto_submit
|
|
@menu_placement = normalize_menu_placement(menu_placement)
|
|
@label = label
|
|
@include_blank = include_blank
|
|
end
|
|
|
|
def field_name
|
|
"#{form.object_name}[#{method}]"
|
|
end
|
|
|
|
def menu_id
|
|
@menu_id ||= "merchant_select_#{field_name.gsub(/\W+/, "_")}_#{object_id}"
|
|
end
|
|
|
|
def selected_merchant
|
|
merchants.find { |merchant| merchant.id.to_s == selected_id }
|
|
end
|
|
|
|
def selected_merchant_logo_url
|
|
merchant = selected_merchant
|
|
return nil unless merchant&.respond_to?(:logo_url) && merchant.logo_url.present?
|
|
|
|
Setting.transform_brand_fetch_url(merchant.logo_url)
|
|
end
|
|
|
|
private
|
|
|
|
def normalize_menu_placement(value)
|
|
normalized = value.to_s.downcase
|
|
MENU_PLACEMENTS.include?(normalized) ? normalized : "auto"
|
|
end
|
|
end
|