# `PhoenixKitEcommerce.Web.Helpers`
[🔗](https://github.com/BeamLabEU/phoenix_kit_ecommerce/blob/0.1.15/lib/phoenix_kit_ecommerce/web/helpers.ex#L1)

Shared helper functions for Shop public LiveViews.

Centralizes utility functions that were duplicated across shop_catalog,
catalog_category, catalog_product, cart_page, checkout_page, and checkout_complete.

# `best_redirect_language`

Find the best enabled language that has a slug for this entity.

Prefers the default language, then checks other enabled languages.
Returns nil if no valid language found.

# `build_lang_url`

Build a localized URL path, adding language prefix for non-default languages.
Delegates to Routes.path which handles default vs non-default consistently.

# `first_image`

Get the first image URL for a product.

Handles Storage-based images (new format with featured_image_uuid or image_uuids)
and legacy URL-based images (Shopify imports).
Returns nil if no image is available.

# `format_price`

Format a price value with currency. Returns "-" for nil price.

Accepts the amount as a Decimal, number, or numeric string (order line
items persist their amounts as strings). The currency may be a
`Currency` struct, a bare code string (`Shop.currency_for_code/1`
falls back to the code when the record's currency no longer resolves —
showing "12.50 XYZ" is honest, borrowing today's default symbol is not),
or nil (no default currency configured at all — legacy `$`).

# `get_current_user`

Extract current user from socket assigns scope.

# `get_language_from_params_or_default`

Determine language from URL params.

Uses locale param if present, otherwise falls back to Translations.default_language/0.
Used by catalog and category pages (non-product pages).

# `get_storage_image_url`

Get signed URL for a Storage image file.

Returns nil if file or variant not found (unlike product detail page
which returns a placeholder). Falls back to original variant if
requested variant is not available.

# `humanize_key`

Convert a key string to human-readable format.

Example: "material_type" -> "Material Type"

# `order_billing_identity`

The billing identity an order was placed with.

Prefers the order's immutable `billing_snapshot` over the live billing
profile: the profile is editable, so reading it made a historical order
claim an address it was never billed to (and deleting the profile made
the true one reappear). The live profile is a fallback only for orders
placed before snapshots existed.

# `parse_int`

Parse an integer from a LiveView event payload, falling back to `default`.

`String.to_integer/1` raises on anything non-numeric, and a raise inside
`handle_event/3` takes the whole LiveView down — so any hand-crafted or
merely stale `phx-value-*` produced a crashed socket rather than an
ignored event. That is reachable unauthenticated on the storefront
(quantity fields) and by any admin elsewhere.

Returns `default` for nil, blank, partially-numeric ("3abc") and
non-binary input. Callers that need a floor should still apply one —
this only guarantees you get an integer back.

# `parse_page`

Parse page param with validation. Returns 1 for invalid/missing values.

# `profile_address`

Format address for a billing profile struct or an order's snapshot map.

# `profile_display_name`

Format display name for a billing profile.

# `profile_email`

Contact email from a billing profile STRUCT or an order's snapshot MAP.

The snapshot is a plain map, so `profile.email` raises on it — the crash
a rendered confirmation page hit after order pages started preferring
the snapshot. Same shape problem as `profile_display_name/1`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
