NEW: Tasks LiveComponent (#27)
This commit is contained in:
parent
a91f1924b2
commit
3d70659861
8 changed files with 364 additions and 7 deletions
235
lib/planner_web/live/tasks_components.ex
Normal file
235
lib/planner_web/live/tasks_components.ex
Normal file
|
@ -0,0 +1,235 @@
|
|||
defmodule TasksComponent do
|
||||
use PlannerWeb, :live_component
|
||||
|
||||
alias Planner.Tasks
|
||||
alias Planner.Tasks.Task
|
||||
|
||||
def update(%{:changeset => changeset, :id => _id}, socket) do
|
||||
{:ok, assign(socket, :changeset, changeset)}
|
||||
end
|
||||
|
||||
def update(assigns, socket) do
|
||||
socket =
|
||||
socket
|
||||
|> assign(assigns)
|
||||
|> assign(:changeset, Tasks.change_task(%Task{}))
|
||||
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
~L"""
|
||||
<div class="content">
|
||||
<%= f = form_for(@changeset, "#", [phx_submit: "new-task"]) %>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<%= text_input(f,
|
||||
:value,
|
||||
placeholder: "add new task",
|
||||
class: "input", autocomplete: "off"
|
||||
)%>
|
||||
</div>
|
||||
<%= error_tag(f, :value) %>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<ul class="tasks">
|
||||
<%= for task <- @tasks do %>
|
||||
<%= live_component(@socket,
|
||||
TaskComponent,
|
||||
id: "task:#{task.id}",
|
||||
task: task,
|
||||
live_action: @live_action,
|
||||
is_active: @active_task == task.id,
|
||||
route_func_2: @route_func_2,
|
||||
route_func_3: @route_func_3
|
||||
)%>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
defmodule TaskComponent do
|
||||
use Phoenix.LiveComponent
|
||||
|
||||
import PlannerWeb.Util
|
||||
|
||||
def render(assigns) do
|
||||
~L"""
|
||||
<li>
|
||||
<div>
|
||||
<div class="is-pulled-left">
|
||||
<button
|
||||
type="button"
|
||||
role="checkbox"
|
||||
class="doit"
|
||||
phx-click="finish-task"
|
||||
phx-value-task-id="<%= @task.id %>">
|
||||
</button>
|
||||
</div>
|
||||
<div class="ml-5-5">
|
||||
<%= if(@is_active) do %>
|
||||
<%= case @live_action do %>
|
||||
<% :show -> %>
|
||||
<%= live_component(@socket,
|
||||
TaskDetailsComponent,
|
||||
id: "task_details:#{@task.id}",
|
||||
task: @task,
|
||||
route_func_2: @route_func_2,
|
||||
route_func_3: @route_func_3
|
||||
)%>
|
||||
<% :edit -> %>
|
||||
<%= live_component(@socket,
|
||||
TaskEditComponent,
|
||||
id: "task_edit:#{@task.id}",
|
||||
task: @task
|
||||
)%>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= live_patch(to: @route_func_3.(@socket, :show, @task.id),
|
||||
style: "display: block;"
|
||||
) do %>
|
||||
<div class="value ">
|
||||
<%= md_to_html(@task.value) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= if(not is_nil(@task.due_at)) do %>
|
||||
<div class="tags mb-0">
|
||||
<span class="tag">
|
||||
due: <%= @task.due_at %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
defmodule TaskDetailsComponent do
|
||||
use PlannerWeb, :live_component
|
||||
|
||||
def render(assigns) do
|
||||
~L"""
|
||||
<div class="box">
|
||||
<%= live_patch("",
|
||||
to: @route_func_2.(@socket, :index),
|
||||
class: "delete is-pulled-right"
|
||||
) %>
|
||||
<%= if(not is_nil(@task.due_at) or is_nil(@task.filed_at)) do %>
|
||||
<div class="tags">
|
||||
<%= if(not is_nil(@task.due_at)) do %>
|
||||
<span class="tag is-warning">
|
||||
due: <%= @task.due_at %>
|
||||
</span><% end %>
|
||||
<%= if(is_nil(@task.filed_at)) do %>
|
||||
<span class="tag is-danger">
|
||||
unfiled
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="mb-5">
|
||||
<%= md_to_html(@task.value) %>
|
||||
</div>
|
||||
|
||||
<div class="tags">
|
||||
<span class="tag is-light">updated: <%= @task.updated_at %></span>
|
||||
<span class="tag is-light">created: <%= @task.inserted_at %></span>
|
||||
</div>
|
||||
|
||||
<div class="buttons has-addons">
|
||||
<%= live_patch("edit",
|
||||
to: @route_func_3.(@socket, :edit, @task.id),
|
||||
class: "button is-dark is-small"
|
||||
) %>
|
||||
<a
|
||||
class="button is-dark is-small"
|
||||
phx-click="delete-task"
|
||||
phx-value-task-id="<%= @task.id %>">
|
||||
delete
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
defmodule TaskEditComponent do
|
||||
use PlannerWeb, :live_component
|
||||
|
||||
alias Planner.Tasks
|
||||
|
||||
def update(%{:changeset => changeset, :id => _id}, socket) do
|
||||
{:ok, assign(socket, :changeset, changeset)}
|
||||
end
|
||||
|
||||
def update(assigns, socket) do
|
||||
socket =
|
||||
socket
|
||||
|> assign(assigns)
|
||||
|> assign(:changeset, Tasks.change_task(assigns.task))
|
||||
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
~L"""
|
||||
<div class="box">
|
||||
<%= f = form_for(@changeset, "#", [phx_submit: "save-task"]) %>
|
||||
<%= hidden_input(f, :id) %>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<%= textarea(f,
|
||||
:value,
|
||||
required: true,
|
||||
class: "textarea",
|
||||
placeholder: "task",
|
||||
autocomplete: "off"
|
||||
) %>
|
||||
</div>
|
||||
<%= error_tag(f, :value) %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= label(f, :due_at, class: "label") do %>
|
||||
due (YYYY-MM-DD HH:MM:SS)
|
||||
<% end %>
|
||||
<div class="control">
|
||||
<%= text_input(f,
|
||||
:due_at,
|
||||
class: "input",
|
||||
placeholder: "YYYY-MM-DD HH:MM:SS",
|
||||
autocomplete: "off"
|
||||
) %>
|
||||
</div>
|
||||
<%= error_tag(f, :due_at) %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= label(f, :finished_at, class: "label") do %>
|
||||
<%= if(is_nil(@task.finished_at)) do %>
|
||||
<%= checkbox(f, :finished_at) %>
|
||||
<% else %>
|
||||
<%= checkbox(f, :finished_at, checked_value: @task.finished_at) %>
|
||||
<% end %>
|
||||
finished
|
||||
<% end %>
|
||||
<%= error_tag(f, :finished_at) %>
|
||||
</div>
|
||||
|
||||
<div class="control">
|
||||
<%= submit("save", class: "button is-dark is-small") %>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
97
lib/planner_web/live/tasks_live.ex
Normal file
97
lib/planner_web/live/tasks_live.ex
Normal file
|
@ -0,0 +1,97 @@
|
|||
defmodule PlannerWeb.TasksLive do
|
||||
use PlannerWeb, :live_view
|
||||
|
||||
alias Planner.Tasks
|
||||
|
||||
def mount(_params, _session, socket) do
|
||||
socket =
|
||||
socket
|
||||
|> assign(:tasks, Tasks.list_unfinished_tasks())
|
||||
|> assign(:active_task, nil)
|
||||
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
def handle_params(%{"id" => task_id}, _, socket) do
|
||||
case Tasks.verify_task_id_from_url(task_id) do
|
||||
true -> {:noreply, assign(socket, :active_task, task_id)}
|
||||
_ -> {:noreply, push_patch(socket, to: Routes.tasks_path(socket, :index))}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_params(_, _, socket) do
|
||||
{:noreply, assign(socket, :active_task, nil)}
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
~L"""
|
||||
<div phx-window-keydown="keydown" phx-key="Escape">
|
||||
<%= live_component(@socket,
|
||||
TasksComponent,
|
||||
id: :all_unfinished_tasks,
|
||||
live_action: @live_action,
|
||||
tasks: @tasks,
|
||||
active_task: @active_task,
|
||||
route_func_2: &Routes.tasks_path/2,
|
||||
route_func_3: &Routes.tasks_path/3
|
||||
)%>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def handle_event("keydown", _params, socket) do
|
||||
case socket.assigns.live_action do
|
||||
:index -> {:noreply, socket}
|
||||
_ -> {:noreply, push_patch(socket, to: Routes.tasks_path(socket, :index))}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event("save-task", %{"task" => task_params}, socket) do
|
||||
task = Tasks.get_task!(task_params["id"])
|
||||
|
||||
case Tasks.update_task(task, task_params) do
|
||||
{:ok, task} ->
|
||||
# I suspect splicing in the updated task isn't much faster than just refreshing the whole list
|
||||
socket =
|
||||
socket
|
||||
|> refresh_tasks_and_flash_msg("task \"#{task.value}\" updated")
|
||||
|
||||
{:noreply, push_patch(socket, to: Routes.tasks_path(socket, :show, task.id))}
|
||||
|
||||
{:error, changeset} ->
|
||||
send_update(TaskEditComponent, id: "task_edit:#{task.id}", changeset: changeset)
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_event("finish-task", %{"task-id" => task_id}, socket) do
|
||||
{_, task} = Tasks.finish_task_by_id!(task_id)
|
||||
{:noreply, refresh_tasks_and_flash_msg(socket, "task \"#{task.value}\" completed")}
|
||||
end
|
||||
|
||||
def handle_event("delete-task", %{"task-id" => task_id}, socket) do
|
||||
{_, task} = Tasks.delete_task_by_id!(task_id)
|
||||
{:noreply, refresh_tasks_and_flash_msg(socket, "task \"#{task.value}\" deleted")}
|
||||
end
|
||||
|
||||
def handle_event("new-task", %{"task" => task_params}, socket) do
|
||||
case Tasks.add_task(task_params) do
|
||||
{:ok, task} ->
|
||||
socket =
|
||||
socket
|
||||
|> refresh_tasks_and_flash_msg("task \"#{task.value}\" created")
|
||||
|
||||
{:noreply, push_patch(socket, to: Routes.tasks_path(socket, :show, task.id))}
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
send_update(TasksComponent, id: :all_unfinished_tasks, changeset: changeset)
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
defp refresh_tasks_and_flash_msg(socket, msg) do
|
||||
socket
|
||||
|> assign(:tasks, Tasks.list_unfinished_tasks())
|
||||
|> put_flash(:info, msg)
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue