PhoenixKitCatalogue.Web.Helpers (PhoenixKitCatalogue v0.2.0)

Copy Markdown View Source

Tiny utilities shared by every catalogue LiveView. Imported into LVs via the standard import PhoenixKitCatalogue.Web.Helpers line.

Currently exports:

  • actor_opts/1 — extract the current user's UUID from socket assigns, return [actor_uuid: uuid] for the opts \\ [] keyword list every mutating context function accepts. Returns [] when no user is signed in (e.g. inside a test that mounts the LV with a bare conn). The atom is suitable to thread through Catalogue.create_* / update_* / trash_* / restore_* / permanently_delete_* etc.
  • actor_uuid/1 — the raw UUID (or nil). Use when you need the value directly rather than a keyword list, e.g. when building activity-log metadata in a LiveView.
  • log_operation_error/3 — engineer-visible Logger.error for a failed mutation plus an Activity row tagged db_pending: true so the user-visible audit feed records the attempted action even when it fails. The function's own docs describe the success-vs-failure layering in detail.

Summary

Types

Convenience alias for the keyword list shape mutating ctx fns accept.

Functions

Extracts [actor_uuid: uuid] from socket.assigns.phoenix_kit_current_user.

Returns the current user's UUID from socket assigns, or nil.

Maps an LV operation string + entity_type to the canonical activity action atom the catalogue context already uses on the success path.

HTML-escapes a string for safe interpolation into raw markup.

Human-readable byte size with B / KB / MB / GB suffixes.

Translated relative-time label for a timestamp.

Logs a failed LV mutation in two places at once

Pulls the error_message off a (possibly preloaded) Pdf row; nil if no error.

Pulls the extracted_at timestamp off a (possibly preloaded) Pdf row; nil if not extracted.

Pulls the page count off a (possibly preloaded) Pdf row; returns nil if unknown.

Pulls the extraction status off a (possibly preloaded) Pdf row; defaults to pending.

daisyUI badge class for an extraction status string.

Translated label for an extraction status.

Translates a catalogue/category/item/manufacturer/supplier status field value to a localised label via gettext.

Types

actor_opts()

@type actor_opts() :: [{:actor_uuid, Ecto.UUID.t()}] | []

Convenience alias for the keyword list shape mutating ctx fns accept.

Functions

actor_opts(socket)

@spec actor_opts(Phoenix.LiveView.Socket.t()) :: actor_opts()

Extracts [actor_uuid: uuid] from socket.assigns.phoenix_kit_current_user.

Returns [] when no user is signed in. Pass the result straight into any PhoenixKitCatalogue.Catalogue mutating function as its trailing opts argument.

actor_uuid(socket)

@spec actor_uuid(Phoenix.LiveView.Socket.t()) :: Ecto.UUID.t() | nil

Returns the current user's UUID from socket assigns, or nil.

derive_activity_action(operation, entity_type)

@spec derive_activity_action(String.t(), String.t() | nil) :: String.t() | nil

Maps an LV operation string + entity_type to the canonical activity action atom the catalogue context already uses on the success path.

Falls back to nil when the operation doesn't follow the <verb>_<entity> shape; the caller skips the audit-row write in that case (engineer log still fires).

escape_html(s)

@spec escape_html(String.t() | nil) :: String.t()

HTML-escapes a string for safe interpolation into raw markup.

format_byte_size(bytes)

@spec format_byte_size(integer() | nil) :: String.t()

Human-readable byte size with B / KB / MB / GB suffixes.

format_time_ago(datetime)

@spec format_time_ago(DateTime.t() | nil) :: String.t()

Translated relative-time label for a timestamp.

Buckets: < 1m → "just now", < 1h → "Nm ago", < 1d → "Nh ago", < 1w → "Nd ago", else Mon DD, YYYY (locale-formatted via gettext'd strftime template).

log_operation_error(socket, operation, context)

@spec log_operation_error(Phoenix.LiveView.Socket.t(), String.t(), map()) :: :ok

Logs a failed LV mutation in two places at once:

  1. Engineer logLogger.error with the operation, the LV-level entity context, and the changeset / atom reason. This is the rich-context line that production-incident triage reads.
  2. User-visible audit row — an Activity entry with the same action atom the success path would have written, plus metadata.db_pending: true. The audit feed therefore records what the user attempted, not just what succeeded — a deliberate change in the post-Apr 2026 pipeline (workspace AGENTS.md C12 agent #2 — "Activity logging coverage").

The action atom is derived from operation via derive_activity_action/2. Validation cycles (form-validate events) never reach this helper — by construction it's only called from {:error, _} handle_event branches, where the failure is a real infrastructure / consistency error worth auditing.

Expected context keys

  • :entity_type"item" / "category" / "catalogue" / "manufacturer" / "supplier" (drives both the activity resource_type and the action-atom prefix).
  • :entity_uuid — primary-key UUID; lands as resource_uuid.
  • :reason — an %Ecto.Changeset{}, an atom, or any other inspectable shape. Logged engineer-side; on the audit row it's summarised into PII-safe metadata.error_keys (changeset field names only — never values, since user-typed strings can carry PII).

Activity-log failures (missing table, ownership errors, sandbox exit) are swallowed by ActivityLog.log/1; they never bubble up to the LV.

pdf_error_message(arg1)

@spec pdf_error_message(map()) :: String.t() | nil

Pulls the error_message off a (possibly preloaded) Pdf row; nil if no error.

pdf_extracted_at(arg1)

@spec pdf_extracted_at(map()) :: DateTime.t() | NaiveDateTime.t() | nil

Pulls the extracted_at timestamp off a (possibly preloaded) Pdf row; nil if not extracted.

pdf_extraction_pages(arg1)

@spec pdf_extraction_pages(map()) :: integer() | nil

Pulls the page count off a (possibly preloaded) Pdf row; returns nil if unknown.

pdf_extraction_status(arg1)

@spec pdf_extraction_status(map()) :: String.t()

Pulls the extraction status off a (possibly preloaded) Pdf row; defaults to pending.

pdf_status_badge_class(arg1)

@spec pdf_status_badge_class(String.t()) :: String.t()

daisyUI badge class for an extraction status string.

pdf_status_label(other)

@spec pdf_status_label(String.t()) :: String.t()

Translated label for an extraction status.

status_label(other)

@spec status_label(String.t() | nil) :: String.t()

Translates a catalogue/category/item/manufacturer/supplier status field value to a localised label via gettext.

Handles every status string that any catalogue schema can emit (active / inactive / archived / deleted / discontinued) with explicit literal gettext(...) clauses so mix gettext.extract picks them up. Unknown status values pass through unchanged — never use String.capitalize/1 on translated text because the result would pin English casing on a value the extractor can't see.