WIP
This commit is contained in:
parent
c9791acff8
commit
8b17c987d8
4 changed files with 57 additions and 41 deletions
|
@ -1,6 +1,7 @@
|
||||||
defmodule ChoreTracker.Accounts.User do
|
defmodule ChoreTracker.Accounts.User do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
alias ChoreTracker.Chores
|
||||||
|
|
||||||
schema "users" do
|
schema "users" do
|
||||||
field :username, :string
|
field :username, :string
|
||||||
|
@ -12,6 +13,8 @@ defmodule ChoreTracker.Accounts.User do
|
||||||
field :display_name, :string
|
field :display_name, :string
|
||||||
|
|
||||||
timestamps(type: :utc_datetime)
|
timestamps(type: :utc_datetime)
|
||||||
|
|
||||||
|
has_many :assigned_chores, Chores.Chore, foreign_key: :next_assignee_id
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
|
|
@ -19,24 +19,41 @@ defmodule ChoreTracker.Chores do
|
||||||
do: Repo.get!(Chore, id) |> Repo.preload([{:logs, :user}, :assignees, :next_assignee])
|
do: Repo.get!(Chore, id) |> Repo.preload([{:logs, :user}, :assignees, :next_assignee])
|
||||||
|
|
||||||
def create_chore(attrs \\ %{}) do
|
def create_chore(attrs \\ %{}) do
|
||||||
%Chore{}
|
result =
|
||||||
|> change_chore(attrs)
|
Ecto.Multi.new()
|
||||||
|> Repo.insert()
|
|> Ecto.Multi.insert(:chore, change_chore(%Chore{}, attrs))
|
||||||
|
|> Ecto.Multi.update(:chore_with_assignee, fn %{chore: chore} ->
|
||||||
|
next_assignee = next_chore_assignee(chore)
|
||||||
|
change_chore_assignee(chore, next_assignee)
|
||||||
|
end)
|
||||||
|
|> Repo.transaction()
|
||||||
|
|
||||||
|
case result do
|
||||||
|
{:ok, %{chore_with_assignee: chore}} -> {:ok, chore}
|
||||||
|
{:error, :chore, changeset, _} -> {:error, changeset}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_chore(%Chore{} = chore, attrs) do
|
def update_chore(%Chore{} = chore, attrs) do
|
||||||
changeset = change_chore(chore, attrs)
|
changeset = change_chore(chore, attrs)
|
||||||
|
|
||||||
Ecto.Multi.new()
|
result =
|
||||||
|> Ecto.Multi.update(:chore, changeset)
|
Ecto.Multi.new()
|
||||||
|> Ecto.Multi.run(:update_next_assignee, fn _repo, %{chore: chore} ->
|
|> Ecto.Multi.update(:chore, changeset)
|
||||||
if Ecto.Changeset.changed?(changeset, :assignees) do
|
|> Ecto.Multi.update(:chore_with_assignee, fn %{chore: chore} ->
|
||||||
save_next_chore_assignee(chore)
|
if Ecto.Changeset.changed?(changeset, :assignees) do
|
||||||
else
|
next_assignee = next_chore_assignee(chore)
|
||||||
{:ok, chore}
|
change_chore_assignee(chore, next_assignee)
|
||||||
end
|
else
|
||||||
end)
|
Ecto.Changeset.change(chore)
|
||||||
|> Repo.transaction()
|
end
|
||||||
|
end)
|
||||||
|
|> Repo.transaction()
|
||||||
|
|
||||||
|
case result do
|
||||||
|
{:ok, %{chore_with_assignee: chore}} -> {:ok, chore}
|
||||||
|
{:error, :chore, changeset, _} -> {:error, changeset}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_chore(%Chore{} = chore) do
|
def delete_chore(%Chore{} = chore) do
|
||||||
|
@ -51,12 +68,14 @@ defmodule ChoreTracker.Chores do
|
||||||
|> Changeset.put_assoc(:assignees, assignees)
|
|> Changeset.put_assoc(:assignees, assignees)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_chore_assignee(%Chore{} = chore, attrs) do
|
def change_chore_assignee(%Chore{} = chore, user) do
|
||||||
change_chore_assignee(chore, attrs) |> Repo.update()
|
id =
|
||||||
end
|
case user do
|
||||||
|
nil -> nil
|
||||||
|
%User{} -> user.id
|
||||||
|
end
|
||||||
|
|
||||||
def change_chore_assignee(%Chore{} = chore, attrs \\ %{}) do
|
chore |> Ecto.Changeset.change(%{next_assignee_id: id})
|
||||||
chore |> Ecto.Changeset.cast(attrs, [:next_assignee_id])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_last_chore_log_for_assignee(%Chore{} = chore, %User{} = user) do
|
def get_last_chore_log_for_assignee(%Chore{} = chore, %User{} = user) do
|
||||||
|
@ -74,8 +93,9 @@ defmodule ChoreTracker.Chores do
|
||||||
:log,
|
:log,
|
||||||
%ChoreLog{} |> ChoreLog.changeset(%{user_id: user.id, chore_id: chore.id})
|
%ChoreLog{} |> ChoreLog.changeset(%{user_id: user.id, chore_id: chore.id})
|
||||||
)
|
)
|
||||||
|> Ecto.Multi.run(:chore, fn _repo, _change ->
|
|> Ecto.Multi.update(:chore_assignee, fn _ ->
|
||||||
save_next_chore_assignee(chore)
|
next_assignee = next_chore_assignee(chore)
|
||||||
|
change_chore_assignee(chore, next_assignee)
|
||||||
end)
|
end)
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
end
|
end
|
||||||
|
@ -113,28 +133,21 @@ defmodule ChoreTracker.Chores do
|
||||||
Returns `nil` if chore has no assignees.
|
Returns `nil` if chore has no assignees.
|
||||||
"""
|
"""
|
||||||
def next_chore_assignee(%Chore{} = chore) do
|
def next_chore_assignee(%Chore{} = chore) do
|
||||||
|
chore = chore |> Repo.preload([{:assignees, :assigned_chores}])
|
||||||
|
|
||||||
chore.assignees
|
chore.assignees
|
||||||
|> Enum.map(&{&1, get_last_chore_log_for_assignee(chore, &1)})
|
|
||||||
|> Enum.sort_by(
|
|> Enum.sort_by(
|
||||||
fn {_assignee, log} ->
|
fn assignee ->
|
||||||
case log do
|
time =
|
||||||
nil -> 0
|
case get_last_chore_log_for_assignee(chore, assignee) do
|
||||||
%ChoreLog{inserted_at: inserted_at} -> DateTime.to_unix(inserted_at)
|
nil -> 0
|
||||||
end
|
%ChoreLog{inserted_at: inserted_at} -> DateTime.to_unix(inserted_at)
|
||||||
|
end
|
||||||
|
|
||||||
|
{time, length(assignee.assigned_chores)}
|
||||||
end,
|
end,
|
||||||
:asc
|
:desc
|
||||||
)
|
)
|
||||||
|> Enum.map(fn {assignee, _log} -> assignee end)
|
|
||||||
|> List.first()
|
|> List.first()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp save_next_chore_assignee(%Chore{} = chore) do
|
|
||||||
next_assignee = next_chore_assignee(chore)
|
|
||||||
|
|
||||||
if next_assignee do
|
|
||||||
chore |> update_chore_assignee(%{next_assignee_id: next_assignee.id})
|
|
||||||
else
|
|
||||||
{:ok, nil}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,7 +21,7 @@ defmodule ChoreTrackerWeb.ChoreLive.FormComponent do
|
||||||
>
|
>
|
||||||
<div class="flex gap-2 flex-wrap">
|
<div class="flex gap-2 flex-wrap">
|
||||||
<.input field={@form[:name]} type="text" label="Name" wrapper_class="flex-1" />
|
<.input field={@form[:name]} type="text" label="Name" wrapper_class="flex-1" />
|
||||||
<.input field={@form[:emoji]} type="text" label="Emoji" />
|
<.input field={@form[:emoji]} type="text" label="Emoji" min="1" max="1" />
|
||||||
</div>
|
</div>
|
||||||
<.input field={@form[:description]} type="textarea" label="Description" />
|
<.input field={@form[:description]} type="textarea" label="Description" />
|
||||||
<div class="flex gap-6 flex-wrap">
|
<div class="flex gap-6 flex-wrap">
|
||||||
|
|
|
@ -41,7 +41,7 @@ defmodule ChoreTrackerWeb.ChoreLive.Show do
|
||||||
%{"chore" => chore_params} = params
|
%{"chore" => chore_params} = params
|
||||||
chore = socket.assigns.chore
|
chore = socket.assigns.chore
|
||||||
|
|
||||||
case Chores.update_chore_assignee(chore, chore_params) do
|
case Chores.update_chore(chore, chore_params) do
|
||||||
{:ok, chore} ->
|
{:ok, chore} ->
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|
@ -57,6 +57,6 @@ defmodule ChoreTrackerWeb.ChoreLive.Show do
|
||||||
defp update_state(socket, chore) do
|
defp update_state(socket, chore) do
|
||||||
socket
|
socket
|
||||||
|> assign(:chore, chore |> Repo.preload(:next_assignee))
|
|> assign(:chore, chore |> Repo.preload(:next_assignee))
|
||||||
|> assign(:assignee_form, to_form(Chores.change_chore_assignee(chore)))
|
|> assign(:assignee_form, to_form(Chores.change_chore(chore)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue