Created
June 11, 2025 11:57
-
-
Save nileshtrivedi/02de3a7f697b14765a3fa04a4f74875d to your computer and use it in GitHub Desktop.
Revisions
-
nileshtrivedi created this gist
Jun 11, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,223 @@ Mix.install([ {:ash, "~> 3.0"}, {:phoenix_playground, "== 0.1.6"}, ], consolidate_protocols: false) defmodule Helpdesk do end defmodule Helpdesk.Support do use Ash.Domain, validate_config_inclusion?: false resources do resource Helpdesk.Support.Todo end end defmodule Helpdesk.Support.Todo do # This turns this module into a resource use Ash.Resource, domain: Helpdesk.Support, data_layer: Ash.DataLayer.Ets actions do defaults [:read, :destroy] create :add do accept [:task, :user_id] change set_attribute(:status, "pending") end update :toggle do accept [] change atomic_update(:status, expr(if status == :pending, do: :done, else: :pending)) end end attributes do uuid_primary_key :id attribute :user_id, :string do allow_nil? false public? true end attribute :task, :string do allow_nil? false public? true end attribute :status, :string do default "pending" allow_nil? false public? true end validations do validate attribute_in(:status, ["pending", "done"]) end end end defmodule TodoLive do use Phoenix.LiveView require Ash.Query def get_user_todos(user_id) do Helpdesk.Support.Todo |> Ash.Query.filter(user_id == ^user_id) |> Ash.read!() end def mount(_params, _session, socket) do user_id = "foobar" todos = get_user_todos(user_id) {:ok, assign(socket, todos: todos, user_id: user_id, new_todo_name: "drink water")} end def handle_event("create_todo", %{"name" => name}, socket) do if name == "" do {:noreply, socket} else # Create new todo with current user's ID Helpdesk.Support.Todo |> Ash.Changeset.for_create(:add, %{task: String.trim(name), user_id: "foobar"}) |> Ash.create!() # Update socket with new list of todos socket = socket |> assign(:todos, get_user_todos(socket.assigns.user_id)) |> assign(:new_todo_name, "") {:noreply, socket} end end def handle_event("toggle_todo", %{"id" => id}, socket) do # Find the todo and ensure it belongs to current user todo = Helpdesk.Support.Todo |> Ash.Query.filter(user_id == ^socket.assigns.user_id) |> Ash.Query.filter(id == ^id) |> Ash.read_one!() # Update todo {:ok, _todo} = todo |> Ash.Changeset.for_update(:toggle) |> Ash.update!() # Refresh todos {:noreply, assign(socket, :todos, get_user_todos(socket.assigns.user_id))} end def handle_event("delete_todo", %{"id" => id}, socket) do # Delete todo, ensuring it belongs to current user todo = Helpdesk.Support.Todo |> Ash.Query.filter(user_id == ^socket.assigns.user_id) |> Ash.Query.filter(id == ^id) |> Ash.read_one!() todo |> Ash.Changeset.for_destroy(:destroy) |> Ash.destroy!() # Refresh todos {:noreply, assign(socket, :todos, get_user_todos(socket.assigns.user_id))} end def render(assigns) do ~H""" <script src="https://cdn.tailwindcss.com?plugins=forms"></script> <div class="max-w-md mx-auto mt-10 p-6 bg-gray-200 rounded-lg shadow-md"> <h1 class="text-2xl font-bold mb-4">Todo List for <%= @user_id %></h1> <form phx-submit="create_todo" class="mb-4 flex"> <input type="text" name="name" value={@new_todo_name} placeholder="Enter a new todo" class="flex-grow mr-2 px-2 py-1 border rounded" /> <button type="submit" class="bg-blue-500 text-white px-4 py-1 rounded hover:bg-blue-600" > Add Todo </button> </form> <ul> <%= for todo <- @todos do %> <li class="flex items-center justify-between py-2 border-b"> <label class="flex items-center gap-2"> <input type="checkbox" phx-click="toggle_todo" phx-value-id={todo.id} checked={todo.status == "done"} class="mr-2" /> <span class={if todo.status == "done", do: "line-through text-gray-500", else: ""}> <%= todo.task %> </span> <span>by <%= todo.user_id %></span> </label> <button phx-click="delete_todo" phx-value-id={todo.id} class="text-red-500 hover:text-red-700" > ✕ </button> </li> <% end %> </ul> </div> """ end end defmodule Demo.Router do use Phoenix.Router import Phoenix.LiveView.Router pipeline :browser do plug :accepts, ["html"] plug :put_secret_key_base plug :fetch_session plug :put_root_layout, html: {PhoenixPlayground.Layout, :root} plug :put_secure_browser_headers end scope "/" do pipe_through :browser live "/", TodoLive end def put_secret_key_base(conn, _) do put_in conn.secret_key_base, System.get_env("SECRET_KEY_BASE") end end defmodule Demo.Endpoint do use Phoenix.Endpoint, otp_app: :phoenix_playground plug Plug.Logger socket "/live", Phoenix.LiveView.Socket plug Plug.Static, from: {:phoenix, "priv/static"}, at: "/assets/phoenix" plug Plug.Static, from: {:phoenix_live_view, "priv/static"}, at: "/assets/phoenix_live_view" socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket plug Phoenix.LiveReloader plug Phoenix.CodeReloader, reloader: &PhoenixPlayground.CodeReloader.reload/2 plug Demo.Router end PhoenixPlayground.start( open_browser: false, live_reload: true, child_specs: [], # endpoint: Demo.Endpoint, # endpoint_options: [debug_errors: true] plug: Demo.Router )