diff --git a/lib/curious_messenger/chat.ex b/lib/curious_messenger/chat.ex index b2bfef1..05568ba 100644 --- a/lib/curious_messenger/chat.ex +++ b/lib/curious_messenger/chat.ex @@ -9,8 +9,6 @@ defmodule CuriousMessenger.Chat do alias CuriousMessenger.Chat.Message - alias CuriousMessenger.Chat.Conversation.Batches - @doc """ Returns the list of chat_messages. @@ -532,11 +530,10 @@ defmodule CuriousMessenger.Chat do {:error, %Ecto.Changeset{}} """ - def create_conversation(attrs \\ %{}, member_attrs \\ []) do - case Batches.create_conversation_with_members(attrs, member_attrs) |> Repo.transaction() do - {:ok, %{create_conversation_members: conversation}} -> {:ok, conversation} - anything -> anything - end + def create_conversation(attrs \\ %{}) do + %Conversation{} + |> Conversation.changeset(attrs) + |> Repo.insert() end @doc """ diff --git a/lib/curious_messenger/chat/conversation.ex b/lib/curious_messenger/chat/conversation.ex index 18ad0c9..56c04b4 100644 --- a/lib/curious_messenger/chat/conversation.ex +++ b/lib/curious_messenger/chat/conversation.ex @@ -8,6 +8,7 @@ defmodule CuriousMessenger.Chat.Conversation do field :title, :string has_many :conversation_members, ConversationMember, on_replace: :delete + has_many :users, through: [:conversation_members, :user] has_many :messages, Message timestamps() @@ -17,6 +18,7 @@ defmodule CuriousMessenger.Chat.Conversation do def changeset(conversation, attrs) do conversation |> cast(attrs, [:title]) + |> cast_assoc(:conversation_members) |> validate_required([:title]) end end diff --git a/lib/curious_messenger/chat/conversation/batches.ex b/lib/curious_messenger/chat/conversation/batches.ex deleted file mode 100644 index 8437bef..0000000 --- a/lib/curious_messenger/chat/conversation/batches.ex +++ /dev/null @@ -1,30 +0,0 @@ -defmodule CuriousMessenger.Chat.Conversation.Batches do - alias Ecto.{Multi, Changeset} - alias CuriousMessenger.Chat.{Conversation} - - def create_conversation_with_members(attrs \\ %{}, member_attrs \\ []) do - Multi.new() - |> Multi.run(:create_conversation, create_conversation(attrs)) - |> Multi.run(:create_conversation_members, create_conversation_members(member_attrs)) - end - - defp create_conversation(attrs) do - fn repo, _ -> - %Conversation{} - |> Conversation.changeset(attrs) - |> repo.insert() - end - end - - defp create_conversation_members(member_attrs) do - fn repo, %{create_conversation: conversation} -> - member_attrs = - Enum.map(member_attrs, fn member -> %{member | conversation_id: conversation.id} end) - - %{conversation | conversation_members: []} - |> Conversation.changeset(%{}) - |> Changeset.put_assoc(:conversation_members, member_attrs) - |> repo.update - end - end -end diff --git a/lib/curious_messenger/chat/conversation_member.ex b/lib/curious_messenger/chat/conversation_member.ex index 7a47dd5..8177a94 100644 --- a/lib/curious_messenger/chat/conversation_member.ex +++ b/lib/curious_messenger/chat/conversation_member.ex @@ -17,9 +17,10 @@ defmodule CuriousMessenger.Chat.ConversationMember do @doc false def changeset(conversation_member, attrs) do conversation_member - |> cast(attrs, [:owner, :conversation_id, :user_id]) - |> validate_required([:owner, :conversation_id, :user_id]) - |> unique_constraint(:user, name: :chat_conversation_members_conversation_id_user_id_index) + |> cast(attrs, [:owner, :user_id]) + |> unique_constraint(:user, + name: :chat_conversation_members_conversation_id_user_id_index + ) |> unique_constraint(:conversation_id, name: :chat_conversation_members_owner ) diff --git a/lib/curious_messenger_web/controllers/page_controller.ex b/lib/curious_messenger_web/controllers/page_controller.ex index b331c07..0bb529c 100644 --- a/lib/curious_messenger_web/controllers/page_controller.ex +++ b/lib/curious_messenger_web/controllers/page_controller.ex @@ -1,28 +1,9 @@ defmodule CuriousMessengerWeb.PageController do use CuriousMessengerWeb, :controller - alias CuriousMessenger.Auth - alias CuriousMessenger.Chat.Conversation - plug CuriousMessengerWeb.AssignUser, preload: :conversations - plug :assign_contacts - plug :assign_new_conversation_changeset def index(conn, opts \\ []) do render(conn, "index.html") end - - defp assign_contacts(conn, _params) do - users = Auth.list_auth_users() - - conn - |> assign(:contacts, users) - end - - defp assign_new_conversation_changeset(conn, _params) do - changeset = %Conversation{} |> Conversation.changeset(%{}) - - conn - |> assign(:conversation_changeset, changeset) - end end diff --git a/lib/curious_messenger_web/live/dashboard_live.ex b/lib/curious_messenger_web/live/dashboard_live.ex new file mode 100644 index 0000000..a7e0524 --- /dev/null +++ b/lib/curious_messenger_web/live/dashboard_live.ex @@ -0,0 +1,116 @@ +defmodule CuriousMessengerWeb.DashboardLive do + use Phoenix.LiveView, container: {:div, [class: "row"]} + use Phoenix.HTML + + alias CuriousMessenger.Auth + alias CuriousMessenger.Chat.Conversation + alias CuriousMessengerWeb.DashboardView + alias CuriousMessenger.Repo + alias Ecto.Changeset + + def render(assigns) do + DashboardView.render("show.html", assigns) + end + + def mount(%{current_user: current_user}, socket) do + {:ok, + socket + |> assign(current_user: current_user) + |> assign_new_conversation_changeset() + |> assign_contacts(current_user)} + end + + def handle_event( + "create_conversation", + %{"conversation" => conversation_form}, + %{ + assigns: %{ + conversation_changeset: changeset, + current_user: current_user, + contacts: contacts + } + } = socket + ) do + conversation_form = + Map.put( + conversation_form, + "title", + if(conversation_form["title"] == "", + do: build_title(changeset, contacts), + else: conversation_form["title"] + ) + ) + + {:ok, _} = + %Conversation{} + |> Conversation.changeset(conversation_form) + |> Repo.insert() + + {:noreply, + assign( + socket, + :current_user, + Repo.preload(current_user, :conversations, force: true) + )} + end + + def handle_event( + "add_member", + %{"user-id" => new_member_id}, + %{assigns: %{conversation_changeset: changeset}} = socket + ) do + {:ok, new_member_id} = Ecto.Type.cast(:integer, new_member_id) + + old_members = socket.assigns[:conversation_changeset].changes.conversation_members + existing_ids = old_members |> Enum.map(& &1.changes.user_id) + + cond do + new_member_id not in existing_ids -> + new_members = [%{user_id: new_member_id} | old_members] + + new_changeset = Changeset.put_change(changeset, :conversation_members, new_members) + + {:noreply, assign(socket, :conversation_changeset, new_changeset)} + + true -> + {:noreply, socket} + end + end + + def handle_event( + "remove_member", + %{"user-id" => removed_member_id}, + %{assigns: %{conversation_changeset: changeset}} = socket + ) do + {:ok, removed_member_id} = Ecto.Type.cast(:integer, removed_member_id) + + old_members = socket.assigns[:conversation_changeset].changes.conversation_members + new_members = old_members |> Enum.reject(&(&1.changes[:user_id] == removed_member_id)) + + new_changeset = Changeset.put_change(changeset, :conversation_members, new_members) + + {:noreply, assign(socket, :conversation_changeset, new_changeset)} + end + + defp assign_new_conversation_changeset(socket) do + changeset = + %Conversation{} + |> Conversation.changeset(%{ + "conversation_members" => [%{owner: true, user_id: socket.assigns[:current_user].id}] + }) + + assign(socket, :conversation_changeset, changeset) + end + + defp assign_contacts(socket, current_user) do + users = Auth.list_auth_users() + + assign(socket, :contacts, users) + end + + defp build_title(changeset, contacts) do + user_ids = Enum.map(changeset.changes.conversation_members, & &1.changes.user_id) + nicknames = contacts |> Enum.filter(&(&1.id in user_ids)) |> Enum.map(& &1.nickname) + Enum.join(nicknames, ", ") + end +end diff --git a/lib/curious_messenger_web/templates/dashboard/show.html.leex b/lib/curious_messenger_web/templates/dashboard/show.html.leex new file mode 100644 index 0000000..9a88b23 --- /dev/null +++ b/lib/curious_messenger_web/templates/dashboard/show.html.leex @@ -0,0 +1,47 @@ +
+

Ongoing Conversations

+ <%= for conversation <- @current_user.conversations do %> +
+ <%= link conversation.title, to: Routes.conversation_path(@socket, CuriousMessengerWeb.ConversationLive, conversation.id, @current_user.id) %> +
+ <% end %> +
+ +
+

Create Conversation

+ + <%= form_for @conversation_changeset, + "", + [phx_submit: :create_conversation], fn f -> %> +

+ <%= inputs_for f, :conversation_members, fn cmf -> %> + <% user_id = cmf.source.changes[:user_id] %> + <% nickname = @contacts |> Enum.find(&(&1.id == user_id)) |> Map.get(:nickname) %> + + <%= link "#{nickname} #{if user_id == @current_user.id, do: "(me)", else: "✖"} ", + to: "#!", + phx_click: (unless user_id == @current_user.id, do: "remove_member"), + phx_value_user_id: user_id %> + + <%= hidden_input cmf, :user_id, value: user_id %> + <% end %> +

+ +

+ <%= text_input f, :title, placeholder: "Title (optional)" %> + <%= submit "Create", disabled: Enum.count(@conversation_changeset.changes[:conversation_members]) < 2 %> +

+ + + <% end %> + +
\ No newline at end of file diff --git a/lib/curious_messenger_web/templates/page/index.html.eex b/lib/curious_messenger_web/templates/page/index.html.eex index 62b7396..a17a822 100644 --- a/lib/curious_messenger_web/templates/page/index.html.eex +++ b/lib/curious_messenger_web/templates/page/index.html.eex @@ -3,26 +3,8 @@

An awesome instant messaging app
made with ❤️ by Curiosum.

-
- <%= if @current_user do %> -
-

Ongoing Conversations

- -
-
-

Contact List

- <%= form_for @conversation_changeset, Routes.conversation_path(@conn, :create) do %> - - <% end %> - -
- <% end%> -
+<%= if @current_user do %> + <%= live_render(@conn, + CuriousMessengerWeb.DashboardLive, + session: %{current_user: @current_user}) %> +<% end%> diff --git a/lib/curious_messenger_web/views/dashboard_view.ex b/lib/curious_messenger_web/views/dashboard_view.ex new file mode 100644 index 0000000..f1cf490 --- /dev/null +++ b/lib/curious_messenger_web/views/dashboard_view.ex @@ -0,0 +1,5 @@ +defmodule CuriousMessengerWeb.DashboardView do + use CuriousMessengerWeb, :view + + require IEx +end diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index 170847d..408be10 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -11,7 +11,7 @@ # and so on) as they will fail if something goes wrong. alias CuriousMessenger.Auth.User -alias CuriousMessenger.Chat.{Conversation, ConversationMember} +alias CuriousMessenger.Chat.Conversation alias CuriousMessenger.{Auth, Chat} @@ -35,13 +35,10 @@ rand2 = Enum.random(0..1000) }) {:ok, %Conversation{id: conv_id} = conversation} = - Chat.create_conversation(%{title: "Modern Talking"}) - -{:ok, %ConversationMember{}} = - Chat.create_conversation_member(%{conversation_id: conv_id, user_id: u1_id, owner: true}) - -{:ok, %ConversationMember{}} = - Chat.create_conversation_member(%{conversation_id: conv_id, user_id: u2_id, owner: false}) + Chat.create_conversation(%{ + title: "Modern Talking", + conversation_members: [%{user_id: u1_id, owner: true}, %{user_id: u2_id, owner: false}] + }) IO.puts("Created records:") IO.inspect(user1)