Skip to content

Commit

Permalink
feat: add basic match mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
zvonimirr committed May 11, 2023
1 parent fe102b3 commit a16967a
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 21 deletions.
2 changes: 1 addition & 1 deletion lib/swipex_web/components/layouts/app.html.heex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<main class="px-4 py-20 sm:px-6 lg:px-8">
<div class="mx-auto max-w-2xl">
<div class="max-w-2xl">
<.flash_group flash={@flash} />
<%= @inner_content %>
</div>
Expand Down
2 changes: 0 additions & 2 deletions lib/swipex_web/controllers/profile.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
defmodule SwipexWeb.Profile do
use SwipexWeb, :verified_routes
import Plug.Conn
import Phoenix.Controller

def on_mount(:current_user, _params, session, socket) do
# Generate user info if not present in the session
Expand Down
167 changes: 149 additions & 18 deletions lib/swipex_web/live/profile_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,31 +51,163 @@ defmodule SwipexWeb.ProfileLive do
{:noreply, assign(socket, :user, user) |> put_flash(:info, "User updated!")}
end

def render(assigns) do
~H"""
<div class="py-12 flex flex-col gap-3">
<h1 class="text-4xl"><%= @user.name %></h1>
<img src={@user.avatar} class="w-32 h-32 rounded-full" />
<p>Hey there, <%= @user.name %>, this is your profile page.</p>
<p>Why don't you tell us something about yourself?</p>
def handle_event("like", %{"potential-match" => potential_match_id}, socket) do
conn = Bolt.Sips.conn()

<div class="flex flex-col gap-3">
<.live_component id="edit_form" module={EditForm} user={@user} />
</div>
# 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)
}
)

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

<hr />
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, nil)}
end

def render(assigns) do
assigns = assign(assigns, :potential_match, get_potential_match(assigns.user.id))
assigns = assign(assigns, :matches, get_matches(assigns.user.id))

~H"""
<div class="flex gap-4 justify-between w-full mb-3">
<div class="flex flex-col gap-3">
<p>Already have an account?</p>
<form phx-submit="import" class="flex flex-col gap-4">
<input type="number" name="id" placeholder="User ID" />
<button type="submit" class="bg-blue-300 text-white rounded-md p-3">Import</button>
</form>
<h1 class="text-4xl"><%= @user.name %></h1>
<img src={@user.avatar} class="w-32 h-32 rounded-full" />
<p>Hey there, <%= @user.name %>, this is your profile page.</p>
<p>Why don't you tell us something about yourself?</p>
<div class="flex flex-col gap-3">
<.live_component id="edit_form" module={EditForm} user={@user} />
</div>
<hr />
<div class="flex flex-col gap-3">
<p>Already have an account?</p>
<form phx-submit="import" class="flex flex-col gap-4">
<input type="number" name="id" placeholder="User ID" />
<button type="submit" class="bg-blue-300 text-white rounded-md p-3">Import</button>
</form>
</div>
</div>
<%= if @potential_match do %>
<div class="flex flex-col gap-3">
<p class="text-2xl">Let's swipe!</p>
<div class="flex flex-col gap-3">
<img src={@potential_match.avatar} class="w-32 h-32 rounded-full" />
<p><%= @potential_match.name %></p>
<p><%= @potential_match.bio %></p>
<div class="flex gap-3">
<button
phx-click="like"
phx-value-potential-match={@potential_match.id}
class="bg-green-300 text-white rounded-md p-3"
>
Like
</button>
<button
phx-click="dislike"
phx-value-potential-match={@potential_match.id}
class="bg-red-300 text-white rounded-md p-3"
>
Dislike
</button>
</div>
</div>
</div>
<% else %>
<p class="text-2xl">No more potential matches!</p>
<% end %>
</div>
<hr />
<div class="mt-3 flex flex-col gap-4">
<h1 class="text-5xl">Your matches</h1>
<div class="flex gap-3">
<%= for match <- @matches do %>
<div class="flex flex-col gap-3">
<img src={match.avatar} class="w-32 h-32 rounded-full" />
<p class="text-center"><%= match.name %></p>
</div>
<% end %>
</div>
</div>
"""
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()

# Get all users that like the current user
Bolt.Sips.query!(
conn,
"""
MATCH (u2:User {id: $id})
MATCH (u:User)
WHERE (u2)-[:LIKES]->(u) AND (u)-[:LIKES]->(u2)
AND u <> u2
RETURN u
""",
%{id: id}
)
|> Map.get(:results)
|> Enum.map(&Map.get(&1, "u"))
|> Enum.map(&get_user_from_response/1)
end

defp get_user_from_response(%Bolt.Sips.Types.Node{} = node) do
node
|> Map.get(:properties)
|> Map.new(fn {k, v} -> {String.to_atom(k), v} end)
end

defp get_user_from_response(response) do
case response
|> Bolt.Sips.Response.first() do
Expand All @@ -85,8 +217,7 @@ defmodule SwipexWeb.ProfileLive do
user ->
user
|> Map.get("u")
|> Map.get(:properties)
|> Map.new(fn {k, v} -> {String.to_atom(k), v} end)
|> get_user_from_response()
end
end
end
Empty file.

0 comments on commit a16967a

Please sign in to comment.