Skip to content

Commit

Permalink
feat: refactor like/dislike logic
Browse files Browse the repository at this point in the history
  • Loading branch information
zvonimirr committed Jun 16, 2024
1 parent 75c9e1b commit ce6d045
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 145 deletions.
88 changes: 88 additions & 0 deletions lib/swipex/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,92 @@ defmodule Swipex.User do
_ -> {:error, "User not found."}
end
end

def get_potential_match(id) do
conn = Bolt.Sips.conn()

with {:ok,
%Bolt.Sips.Response{
results: [
%{
"u" => %{properties: potential_match}
}
]
}} <-
Bolt.Sips.query(
conn,
"""
MATCH (u2:User {id: $id})
MATCH (u:User)
WHERE NOT (u2)-[:LIKES]->(u) AND NOT (u2)-[:DISLIKES]->(u)
AND u <> u2
RETURN u LIMIT 1
""",
%{id: id}
),
{:ok, m} <- get_user_by_id(Map.get(potential_match, "id")) do
m
else
_ -> nil
end
end

def like(id, match_id) do
conn = Bolt.Sips.conn()

with {:ok, _} <-
Bolt.Sips.query(
conn,
"""
MATCH (u1:User {id: $id})
MATCH (u2:User {id: $match_id})
CREATE (u1)-[:LIKES]->(u2)
""",
%{id: id, match_id: match_id}
),
should_notify <- has_matched(id, match_id) do
{:ok, should_notify}
else
_ -> {:error, "Failed to like user."}
end
end

def dislike(id, match_id) do
conn = Bolt.Sips.conn()

with {:ok, _} <-
Bolt.Sips.query(
conn,
"""
MATCH (u1:User {id: $id})
MATCH (u2:User {id: $match_id})
CREATE (u1)-[:DISLIKES]->(u2)
""",
%{id: id, match_id: match_id}
) do
:ok
else
_ -> :error
end
end

def has_matched(id, match_id) do
conn = Bolt.Sips.conn()

with {:ok, %Bolt.Sips.Response{results: results}} <-
Bolt.Sips.query(
conn,
"""
MATCH (u1:User {id: $id})
MATCH (u2:User {id: $match_id})
MATCH (u1)-[r:LIKES]->(u2)
RETURN u1, u2
""",
%{id: id, match_id: match_id}
) do
results != []
else
_ -> false
end
end
end
3 changes: 3 additions & 0 deletions lib/swipex_web/controllers/page.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
defmodule SwipexWeb.PageController do
alias Phoenix.PubSub
use SwipexWeb, :controller

def index(conn, _params) do
Expand All @@ -22,6 +23,8 @@ defmodule SwipexWeb.PageController do
with true <- String.length(name) > 0,
true <- String.length(password) > 0,
{:ok, _} <- Swipex.User.register(name, password) do
PubSub.broadcast(Swipex.PubSub, "swipex", {:new_user, name})

conn
|> put_flash(:info, "Registered successfully!")
|> redirect(to: "/login")
Expand Down
171 changes: 26 additions & 145 deletions lib/swipex_web/live/profile_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,145 +15,47 @@ defmodule SwipexWeb.ProfileLive do
end
end

def handle_event("import", %{"id" => id}, socket) do
id = String.to_integer(id)
conn = Bolt.Sips.conn()

case Bolt.Sips.query(conn, "MATCH (u:User {id: $id}) RETURN u", %{id: id}) do
{:ok, response} ->
user = get_user_from_response(response)

if user == %{} do
{:noreply, put_flash(socket, :error, "Invalid user ID.")}
else
PubSub.broadcast(Swipex.PubSub, "swipex", {:user_changed, user})
{:noreply, assign(socket, :user, user) |> put_flash(:info, "User imported!")}
end

{:error, _error} ->
{:noreply, put_flash(socket, :error, "Invalid user ID.")}
def handle_event("like", %{"potential-match" => match_id}, socket) do
case Swipex.User.like(socket.assigns.user["id"], match_id) do
{:ok, true} ->
PubSub.broadcast(Swipex.PubSub, "swipex", {:match, match_id})
PubSub.broadcast(Swipex.PubSub, "swipex", {:match, socket.assigns.user["id"]})
{:noreply, socket}

{:ok, false} ->
{:noreply, socket}

{:error, error} ->
{:noreply, socket |> put_flash(:error, error)}
end
end

def handle_event("save", %{"name" => name, "bio" => bio}, socket) do
conn = Bolt.Sips.conn()

Bolt.Sips.transaction(conn, fn conn ->
# Create a new user if one doesn't exist
Bolt.Sips.query(conn, "MERGE (u:User {id: $id}) RETURN u", %{id: socket.assigns.user.id})
# Update the fields
Bolt.Sips.query(conn, "MATCH (u:User {id: $id}) SET u.bio = $bio RETURN u", %{
id: socket.assigns.user.id,
bio: bio
})

Bolt.Sips.query(conn, "MATCH (u:User {id: $id}) SET u.avatar = $avatar RETURN u", %{
id: socket.assigns.user.id,
avatar: socket.assigns.user.avatar
})

Bolt.Sips.query(conn, "MATCH (u:User {id: $id}) SET u.name = $name RETURN u", %{
id: socket.assigns.user.id,
name: name
})
end)

user =
Bolt.Sips.query!(conn, "MATCH (u:User {id: $id}) RETURN u", %{id: socket.assigns.user.id})
|> get_user_from_response()

PubSub.broadcast(Swipex.PubSub, "swipex", {:new_user, user})

{:noreply, assign(socket, :user, user) |> put_flash(:info, "User updated!")}
end

def handle_event("like", %{"potential-match" => potential_match_id}, socket) do
conn = Bolt.Sips.conn()

# Create a relationship between the current user and the potential match
Bolt.Sips.query!(
conn,
"""
MATCH (u1:User {id: $id1})
MATCH (u2:User {id: $id2})
MERGE (u1)-[:LIKES]->(u2)
""",
%{
id1: socket.assigns.user.id,
id2: String.to_integer(potential_match_id)
}
)

# Check if the other user has liked the current user.
match =
Bolt.Sips.query!(
conn,
"""
MATCH (u1:User {id: $id1})
MATCH (u2:User {id: $id2})
MATCH (u1)-[r:LIKES]->(u2)
RETURN u1, u2
""",
%{
id1: String.to_integer(potential_match_id),
id2: socket.assigns.user.id
}
)
def handle_event("dislike", %{"potential-match" => match_id}, socket) do
case Swipex.User.dislike(socket.assigns.user["id"], match_id) do
:ok ->
{:noreply, socket |> put_flash(:info, "Disliked user.")}

unless match.results == [] do
[u1] = Bolt.Sips.Response.fetch!(match, "u1")
[u2] = Bolt.Sips.Response.fetch!(match, "u2")

PubSub.broadcast(Swipex.PubSub, "swipex", {:match, u1.properties["id"]})
PubSub.broadcast(Swipex.PubSub, "swipex", {:match, u2.properties["id"]})
:error ->
{:noreply, socket |> put_flash(:error, "Failed to dislike user.")}
end

{:noreply, assign(socket, :potential_match, potential_match_id)}
end

def handle_event("dislike", %{"potential-match" => potential_match_id}, socket) do
conn = Bolt.Sips.conn()

# Create a relationship between the current user and the potential match
Bolt.Sips.query!(
conn,
"""
MATCH (u1:User {id: $id1})
MATCH (u2:User {id: $id2})
MERGE (u1)-[:DISLIKES]->(u2)
""",
%{
id1: socket.assigns.user.id,
id2: String.to_integer(potential_match_id)
}
)

{:noreply, assign(socket, :potential_match, potential_match_id)}
end

def handle_info({:new_user, user}, socket) do
# Force re-rendering of the page
{:noreply, put_flash(socket, :info, "#{user.name} has arrived!")}
end

def handle_info({:match, uid}, socket) do
if socket.assigns.user.id == uid do
{:noreply, put_flash(socket, :info, "You have a new match!")}
else
{:noreply, socket}
end
def handle_info({:new_user, name}, socket) do
{:noreply, put_flash(socket, :info, "#{name} has arrived!")}
end

def handle_info({:user_changed, user}, socket) do
if socket.assigns.user.id == user.id do
{:noreply, put_flash(socket, :info, "Welcome back #{user.name}!")}
def handle_info({:match, id}, socket) do
if id == socket.assigns.user["id"] do
{:noreply, socket |> put_flash(:info, "You have a new match!")}
else
{:noreply, socket}
end
end

def render(assigns) do
assigns = assign(assigns, :potential_match, get_potential_match(assigns.user["id"]))
assigns =
assign(assigns, :potential_match, Swipex.User.get_potential_match(assigns.user["id"]))

assigns = assign(assigns, :matches, get_matches(assigns.user["id"]))

~H"""
Expand Down Expand Up @@ -210,27 +112,6 @@ defmodule SwipexWeb.ProfileLive do
"""
end

defp get_potential_match(id) do
conn = Bolt.Sips.conn()

# Get all users that don't have any relationship with the current user
Bolt.Sips.query!(
conn,
"""
MATCH (u2:User {id: $id})
MATCH (u:User)
WHERE NOT (u2)-[:LIKES]->(u) AND NOT (u2)-[:DISLIKES]->(u)
AND u <> u2
RETURN u LIMIT 1
""",
%{id: id}
)
|> Map.get(:results)
|> Enum.map(&Map.get(&1, "u"))
|> Enum.map(&get_user_from_response/1)
|> List.first()
end

defp get_matches(id) do
conn = Bolt.Sips.conn()

Expand Down

0 comments on commit ce6d045

Please sign in to comment.