diff --git a/lib/app/timer.ex b/lib/app/timer.ex index 30f98439..fed1cc96 100644 --- a/lib/app/timer.ex +++ b/lib/app/timer.ex @@ -21,6 +21,18 @@ defmodule App.Timer do |> validate_required([:item_id, :start]) end + @doc """ + `get_timer/1` gets a single Timer. + + Raises `Ecto.NoResultsError` if the Timer does not exist. + + ## Examples + + iex> get_timer!(123) + %Timer{} + """ + def get_timer!(id), do: Repo.get!(Timer, id) + @doc """ `start/1` starts a timer. @@ -28,10 +40,7 @@ defmodule App.Timer do ## Examples iex> start(%{item_id: 1, }) - {:ok, %Timer{}} - - iex> create_item(%{item_id: nil}) - {:error, %Ecto.Changeset{}} + {:ok, %Timer{start: ~N[2022-07-11 04:20:42]}} """ def start(attrs \\ %{}) do @@ -39,4 +48,19 @@ defmodule App.Timer do |> changeset(attrs) |> Repo.insert() end + + @doc """ + `stop/1` stops a timer. + + ## Examples + + iex> stop(%{id: 1}) + {:ok, %Timer{end: ~N[2022-07-11 05:15:31], etc.}} + + """ + def stop(attrs \\ %{}) do + get_timer!(attrs.id) + |> changeset(%{end: NaiveDateTime.utc_now}) + |> Repo.update() + end end diff --git a/lib/app_web/live/app_live.ex b/lib/app_web/live/app_live.ex index fdae17e6..42ee5349 100644 --- a/lib/app_web/live/app_live.ex +++ b/lib/app_web/live/app_live.ex @@ -1,6 +1,6 @@ defmodule AppWeb.AppLive do use AppWeb, :live_view - alias App.Item + alias App.{Item, Timer} @topic "live" @@ -8,13 +8,13 @@ defmodule AppWeb.AppLive do def mount(_params, _session, socket) do # subscribe to the channel if connected?(socket), do: AppWeb.Endpoint.subscribe(@topic) - {:ok, assign(socket, items: Item.list_items(), editing: nil)} + {:ok, assign(socket, items: Item.list_items(), editing: nil, timer: %Timer{})} end @impl true def handle_event("create", %{"text" => text}, socket) do Item.create_item(%{text: text, person_id: 1, status_code: 2}) - socket = assign(socket, items: Item.list_items(), active: %Item{}) + socket = assign(socket, items: Item.list_items(), active: %Item{}, timer: %Timer{}) AppWeb.Endpoint.broadcast_from(self(), @topic, "update", socket.assigns) {:noreply, socket} end @@ -25,7 +25,7 @@ defmodule AppWeb.AppLive do status = if Map.has_key?(data, "value"), do: 4, else: 3 item = Item.get_item!(Map.get(data, "id")) Item.update_item(item, %{id: item.id, status_code: status}) - socket = assign(socket, items: Item.list_items(), active: %Item{}) + socket = assign(socket, items: Item.list_items(), active: %Item{}, timer: %Timer{}) AppWeb.Endpoint.broadcast_from(self(), @topic, "update", socket.assigns) {:noreply, socket} end @@ -33,13 +33,50 @@ defmodule AppWeb.AppLive do @impl true def handle_event("delete", data, socket) do Item.delete_item(Map.get(data, "id")) - socket = assign(socket, items: Item.list_items(), active: %Item{}) + socket = assign(socket, items: Item.list_items(), active: %Item{}, timer: %Timer{}) AppWeb.Endpoint.broadcast_from(self(), @topic, "delete", socket.assigns) {:noreply, socket} end + @impl true + def handle_event("start", data, socket) do + # Toggle the status of the item between 3 (:active) and 4 (:done) + # status = if Map.has_key?(data, "value"), do: 4, else: 3 + item = Item.get_item!(Map.get(data, "id")) + # Item.update_item(item, %{id: item.id, status_code: status}) + {:ok, timer} = Timer.start(%{item_id: item.id, person_id: 1, start: NaiveDateTime.utc_now}) + IO.inspect(timer) + + socket = assign(socket, items: Item.list_items(), active: %Item{}, timer: timer) + AppWeb.Endpoint.broadcast_from(self(), @topic, "start", socket.assigns) + {:noreply, socket} + end + + @impl true + def handle_event("stop", data, socket) do + # Toggle the status of the item between 3 (:active) and 4 (:done) + # status = if Map.has_key?(data, "value"), do: 4, else: 3 + # item = Item.get_item!(Map.get(data, "id")) + # IO.inspect(data, label: "data") + timer_id = Map.get(data, "timerid") + # IO.inspect(timer_id, label: "timer_id") + # Item.update_item(item, %{id: item.id, status_code: status}) + {:ok, timer} = Timer.stop(%{id: timer_id}) + # IO.inspect(timer) + + socket = assign(socket, items: Item.list_items(), active: %Item{}, timer: timer) + AppWeb.Endpoint.broadcast_from(self(), @topic, "start", socket.assigns) + {:noreply, socket} + end + # helper function that checks for status 4 (:done) def done?(item) do not is_nil(item.status_code) and item.status_code == 4 end + + def started?(item, timer) do + # IO.inspect(item, label: "item") + # IO.inspect(timer, label: "timer") + item.id == timer.item_id + end end diff --git a/lib/app_web/live/app_live.html.heex b/lib/app_web/live/app_live.html.heex index 96efa171..94f4b514 100644 --- a/lib/app_web/live/app_live.html.heex +++ b/lib/app_web/live/app_live.html.heex @@ -5,6 +5,7 @@ class="w-full py-2 px-2 text-slate-800 text-3xl bg-white bg-clip-padding transition ease-in-out + border border-b border-slate-200 focus:border-none focus:outline-none" name="text" placeholder="What is on your mind?" @@ -21,25 +22,41 @@ diff --git a/mix.exs b/mix.exs index 89a00554..9a31e223 100644 --- a/mix.exs +++ b/mix.exs @@ -55,14 +55,15 @@ defmodule App.MixProject do {:jason, "~> 1.2"}, {:plug_cowboy, "~> 2.5"}, - # Easily Encrypt Senstive Data: github.com/dwyl/fields - {:fields, "~> 2.9"}, # Auth with ONE Environment Variableā„¢: github.com/dwyl/auth_plug {:auth_plug, "~> 1.4"}, + # Easily Encrypt Senstive Data: github.com/dwyl/fields + {:fields, "~> 2.9"}, # Useful functions: github.com/dwyl/useful {:useful, "~> 1.0.8"}, # Statuses: github.com/dwyl/statuses {:statuses, "~> 1.1.1"}, + # create docs on localhost by running "mix docs" {:ex_doc, "~> 0.22.6", only: :dev, runtime: false}, # Track test coverage diff --git a/test/app/timer_test.exs b/test/app/timer_test.exs index 40836409..e06a1095 100644 --- a/test/app/timer_test.exs +++ b/test/app/timer_test.exs @@ -17,7 +17,7 @@ defmodule App.TimerTest do item end - test "Timer.start!/1 returns timer that has been started" do + test "Timer.start/1 returns timer that has been started" do item = item_fixture(@valid_item_attrs) assert Item.get_item!(item.id) == item @@ -25,5 +25,20 @@ defmodule App.TimerTest do {:ok, timer} = Timer.start(%{item_id: item.id, person_id: 1, start: started}) assert NaiveDateTime.diff(timer.start, started) == 0 end + + test "Timer.stop/1 stops the timer that had been started" do + item = item_fixture(@valid_item_attrs) + assert Item.get_item!(item.id) == item + + started = NaiveDateTime.utc_now + {:ok, timer} = Timer.start(%{item_id: item.id, person_id: 1, start: started}) + assert NaiveDateTime.diff(timer.start, started) == 0 + + IO.puts "waiting 1 second ... " ; :timer.sleep(1000); IO.puts "done" + + ended = NaiveDateTime.utc_now + {:ok, timer} = Timer.stop(%{id: timer.id, end: ended}) + assert NaiveDateTime.diff(timer.end, timer.start) == 1 + end end end diff --git a/test/app_web/live/app_live_test.exs b/test/app_web/live/app_live_test.exs index 6e69e227..bdf5f04b 100644 --- a/test/app_web/live/app_live_test.exs +++ b/test/app_web/live/app_live_test.exs @@ -1,6 +1,6 @@ defmodule AppWeb.AppLiveTest do use AppWeb.ConnCase - alias App.Item + alias App.{Item, Timer} import Phoenix.LiveViewTest test "disconnected and connected render", %{conn: conn} do @@ -35,4 +35,22 @@ defmodule AppWeb.AppLiveTest do updated_item = Item.get_item!(item.id) assert updated_item.status_code == 6 end + + test "start a timer", %{conn: conn} do + {:ok, item} = Item.create_item(%{text: "Get Fancy!", person_id: 1, status_code: 2}) + assert item.status_code == 2 + + {:ok, view, _html} = live(conn, "/") + assert render_click(view, :start, %{"id" => item.id}) =~ "stop" + end + + test "stop a timer", %{conn: conn} do + {:ok, item} = Item.create_item(%{text: "Get Fancy!", person_id: 1, status_code: 2}) + assert item.status_code == 2 + started = NaiveDateTime.utc_now + {:ok, timer} = Timer.start(%{item_id: item.id, start: started}) + + {:ok, view, _html} = live(conn, "/") + assert render_click(view, :stop, %{"id" => item.id, "timerid" => timer.id}) =~ "mind" + end end