action-requests-demo.jamey..../lib/action_requests_demo/action_requests.ex
Jamey Greenwood de1b1bd484 Initial commit: Phoenix LiveView demo for interactive data tables with filtering, sorting, pagination, URL state, and progressive enhancement
Implements a fully-featured action requests table in a single LiveView module using Flop, Ecto, and SQLite. Includes:

- Fuzzy search, status/assignment filters, column sorting, 25-per-page pagination
- Real-time updates, bookmarkable URLs via `handle_params/3`
- JS-disabled fallback with GET forms (no duplicate logic)
- 1,000,000 seeded records, Tailwind + DaisyUI styling, light/dark themes
- Comprehensive README with comparisons to Django+React/Rails+React stacks
- 31 tests covering all scenarios

Tech: Phoenix 1.8+, LiveView, Flop, Ecto, SQLite, Elixir 1.15+
2025-11-16 10:24:06 +00:00

80 lines
2.5 KiB
Elixir

defmodule ActionRequestsDemo.ActionRequests do
import Ecto.Query
alias ActionRequestsDemo.{Repo, ActionRequests.ActionRequest}
def list_action_requests(params, current_user_id \\ nil) do
# Extract custom filters
patient_name = get_in(params, ["patient_name"]) |> clean_param()
status = get_in(params, ["status"]) |> clean_param()
assignment = get_in(params, ["assignment"]) |> clean_param()
# Build base query with custom filters
query =
ActionRequest
|> apply_patient_name_filter(patient_name)
|> apply_status_filter(status)
|> apply_assignment_filter(assignment, current_user_id)
# Use Flop for sorting and pagination only
flop_params = Map.drop(params, ["patient_name", "status", "assignment"])
# Set default sort if not specified
flop_params =
if is_nil(flop_params["order_by"]) || flop_params["order_by"] == "" do
flop_params
|> Map.put("order_by", ["inserted_at"])
|> Map.put("order_directions", ["desc"])
else
# Convert order_by and order_directions to arrays if they're strings
flop_params
|> maybe_listify("order_by")
|> maybe_listify("order_directions")
end
Flop.validate_and_run(query, flop_params, for: ActionRequest, repo: Repo)
end
defp maybe_listify(params, key) do
case params[key] do
nil -> params
"" -> Map.delete(params, key)
val when is_binary(val) -> Map.put(params, key, [val])
val when is_atom(val) -> Map.put(params, key, [val])
val when is_list(val) -> params
_ -> params
end
end
defp clean_param(nil), do: nil
defp clean_param(""), do: nil
defp clean_param("all"), do: nil
defp clean_param(val), do: val
defp apply_patient_name_filter(query, nil), do: query
defp apply_patient_name_filter(query, name) do
pattern = "%#{name}%"
where(query, [a], like(a.patient_name, ^pattern))
end
defp apply_status_filter(query, nil), do: query
defp apply_status_filter(query, status) do
where(query, [a], a.status == ^status)
end
defp apply_assignment_filter(query, nil, _), do: query
defp apply_assignment_filter(query, "mine", current_user_id) do
where(query, [a], a.assigned_user_id == ^current_user_id)
end
defp apply_assignment_filter(query, "assigned", _) do
where(query, [a], not is_nil(a.assigned_user_id))
end
defp apply_assignment_filter(query, "unassigned", _) do
where(query, [a], is_nil(a.assigned_user_id))
end
end