diff --git a/friends/assets/js/app.js b/friends/assets/js/app.js index bf203ba..39c39e4 100644 --- a/friends/assets/js/app.js +++ b/friends/assets/js/app.js @@ -41,4 +41,25 @@ liveSocket.connect() // >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session // >> liveSocket.disableLatencySim() window.liveSocket = liveSocket +window.onload = function () { + window.address_results = document.querySelector("#address-results"); + window.addressInput = document.querySelector("input#friend_address_query"); + window.addressID = document.querySelector("input#addressID"); +} +window.hideResults = function () { + window.address_results.classList.add("hidden"); +} + +window.showResults = function () { + document.getElementById("address-results").classList.remove("hidden"); +} + +window.selectAddressSearchResult = function (result) { + const selectedResult = document.querySelector("#" + result); + const mapboxID = selectedResult.attributes.id.value; + const display = selectedResult.innerText; + + window.addressInput.value = display; + window.addressID.value = mapboxID; +} diff --git a/friends/lib/friends/friend.ex b/friends/lib/friends/friend.ex index 86840b6..40c305e 100644 --- a/friends/lib/friends/friend.ex +++ b/friends/lib/friends/friend.ex @@ -102,9 +102,9 @@ defmodule Friends.Friend do def commit(changeset) do changeset - |> generate_slug - |> @repo.insert! + |> @repo.commit! |> load_preloads + |> assign_user!() end def generate_slug(%Ecto.Changeset{} = changeset) do @@ -125,9 +125,10 @@ defmodule Friends.Friend do def create_or_update(params) do case params.id do - :new -> + "new" -> params |> create() + |> generate_slug |> commit() _number -> @@ -169,6 +170,11 @@ defmodule Friends.Friend do end end + def assign_user!(%Friend{} = friend) do + %{friend: new_friend, user: _user} = assign_user(friend) + new_friend + end + def load_user(%Friends.Friend{user: %Ecto.Association.NotLoaded{}} = model) do model |> @repo.preload(:user) diff --git a/friends/lib/friends/places/search.ex b/friends/lib/friends/places/search.ex index 1da3c88..d5412e4 100644 --- a/friends/lib/friends/places/search.ex +++ b/friends/lib/friends/places/search.ex @@ -1,5 +1,7 @@ defmodule Friends.Places.Search do - def api_key, do: "pk.7c4a6f4bf061fd4a9af9663132c58af3" + def api_key, + do: + "pk.eyJ1IjoicnlhbnBhbmR5YSIsImEiOiJja3psM2tlcDA1MXl1Mm9uZmo5bGxpNzdxIn0.TwBKpTTypcD5fWFc8XRyHg" def viewbox(region) do [lat_min, lat_max, lon_min, lon_max] = region |> Enum.map(&String.to_float/1) @@ -12,16 +14,26 @@ defmodule Friends.Places.Search do ] end - def query(str, region \\ nil) do + def autocomplete(str, region \\ nil) do viewbox = if region do - viewbox(query(region)) + viewbox(autocomplete(region)) end - url = "https://us1.locationiq.com/v1/search?key=#{api_key()}&q=#{str}&format=json#{viewbox}" + url = + "https://api.mapbox.com/geocoding/v5/mapbox.places/#{str}.json?proximity=ip&types=place%2Cpostcode%2Caddress&access_token=#{api_key}" response = HTTPoison.get!(url) results = Poison.decode!(response.body) - results + + results |> Map.get("features") + end + + def display_address(%{"place_name" => name, "id" => id} = result) do + %{ + name: name, + mapbox_id: id, + id: id |> String.replace(~r/\./, "-") + } end end diff --git a/friends/lib/friends/repo.ex b/friends/lib/friends/repo.ex index 428b72b..1b38a5f 100644 --- a/friends/lib/friends/repo.ex +++ b/friends/lib/friends/repo.ex @@ -2,4 +2,13 @@ defmodule Friends.Repo do use Ecto.Repo, otp_app: :friends, adapter: Ecto.Adapters.Postgres + + def commit!(changeset) do + IO.inspect(changeset) + + case changeset.action do + :update -> update!(changeset) + :insert -> insert!(changeset) + end + end end diff --git a/friends/lib/friends_web/controllers/user_auth.ex b/friends/lib/friends_web/controllers/user_auth.ex index 4da5ac7..4a6333a 100644 --- a/friends/lib/friends_web/controllers/user_auth.ex +++ b/friends/lib/friends_web/controllers/user_auth.ex @@ -159,7 +159,7 @@ defmodule FriendsWeb.UserAuth do nil -> conn |> put_flash(:info, "You're logged in but we still need to make you a profile!") - |> redirect(to: Routes.friends_edit_path(conn, :overview, :new)) + |> redirect(to: Routes.friends_edit_path(conn, :welcome)) |> halt() # Or make a new one diff --git a/friends/lib/friends_web/live/components/components.ex b/friends/lib/friends_web/live/components/components.ex index 6620433..892d283 100644 --- a/friends/lib/friends_web/live/components/components.ex +++ b/friends/lib/friends_web/live/components/components.ex @@ -25,17 +25,20 @@ defmodule FriendsWeb.FriendsLive.Components do """ end + @spec edit_menu(any) :: Phoenix.LiveView.Rendered.t() def edit_menu(assigns) do - ~H""" - - """ + if assigns.live_action == :welcome, + do: "", + else: ~H""" + + """ end def show_page(:main, assigns), do: show_page(:overview, %{assigns | live_action: :overview}) @@ -119,11 +122,16 @@ defmodule FriendsWeb.FriendsLive.Components do end ### + def edit_page(:welcome, assigns) do + top = ~H""" +

Welcome!

+

Before we get started, we just need some basic info about you:

+ <%= edit_page(:overview, assigns) %> + """ + end def edit_page(:overview, assigns) do ~H""" - <%= @peer_data.address |> Tuple.to_list |> Enum.join(".") %> - <.form for={@changeset} let={f} @@ -145,10 +153,19 @@ defmodule FriendsWeb.FriendsLive.Components do
<%= error_tag f, :name %>
-
- <.link patch={Routes.friends_show_path(FriendsWeb.Endpoint, :overview, @friend.slug)} class="btn btn-block btn-outline">back -
+ <%= if @live_action != :welcome do %> +
+ <.link patch={Routes.friends_show_path(FriendsWeb.Endpoint, :overview, @friend.slug)} class="btn btn-block btn-outline">back +
+ <% end %>
<%= if @changeset.valid? do %> <%= submit "Save", phx_disable_with: "Saving...", class: "btn btn-block" %> @@ -190,9 +213,9 @@ defmodule FriendsWeb.FriendsLive.Components do <%= submit "Save", class: "btn btn-block btn-disabled" %> <% end %>
- <%= if @live_action != :new do %> + <%= if @current_user.profile.id == @friend.id do %>
- + <.link href={Routes.user_settings_path(FriendsWeb.Endpoint, :edit)} class="btn btn-block btn-error">Delete
<% end %>
diff --git a/friends/lib/friends_web/live/edit.ex b/friends/lib/friends_web/live/edit.ex index 2160ab2..fa024b3 100644 --- a/friends/lib/friends_web/live/edit.ex +++ b/friends/lib/friends_web/live/edit.ex @@ -7,13 +7,22 @@ defmodule FriendsWeb.FriendsLive.Edit do alias Friends.{Friend, Places} + def mount(%{}, token, socket) do + friend = Friend.new() + + {:ok, + socket + |> assign(:live_action, socket.assigns.live_action) + |> assign_current_user(token |> Map.get("user_token")) + |> assign(:friend, friend) + |> title("Welcome") + |> assign(:changeset, %Friend{} |> Friend.changeset())} + end + def mount(%{"slug" => slug} = _attrs, token, socket) do live_action = socket.assigns.live_action || false friend = Friend.get_by_slug(slug) - editable = friend |> Friend.can_be_edited_by(socket.assigns[:current_user]) - - # address_viewbox = Places.Search.query() if(live_action) do {:ok, @@ -21,16 +30,17 @@ defmodule FriendsWeb.FriendsLive.Edit do |> assign(:live_action, live_action) |> assign_current_user(token |> Map.get("user_token")) |> assign(:friend, friend) + |> assign(:action, Routes.friends_path(socket, :update)) |> title(friend.name <> " - " <> (live_action |> titlecase)) |> assign(:changeset, %Friend{} |> Friend.changeset()) - |> assign(:action, editable) - |> assign(:address_query, nil)} + |> assign(:address_query, nil) + |> assign(:address_results, nil)} else {:ok, socket |> redirect(to: Routes.friends_show_path(socket, :overview, friend.slug))} end end - def handle_params(%{"slug" => slug} = attrs, _url, socket) do + def handle_params(%{"slug" => slug} = _attrs, _url, socket) do live_action = socket.assigns.live_action || false friend = Friend.get_by_slug(slug) @@ -39,11 +49,26 @@ defmodule FriendsWeb.FriendsLive.Edit do {:noreply, socket |> assign_friend(friend) + |> assign(:action, Routes.friends_path(socket, :update)) |> assign(:live_action, live_action) + |> assign(:address_query, nil) + |> assign(:address_results, nil) |> title(friend.name <> " - " <> (live_action |> titlecase)) |> assign(:editable, editable)} end + def handle_params(_attrs, _token, socket) do + friend = Friend.new() + + {:noreply, + socket + |> assign_friend(friend) + |> assign(:live_action, socket.assigns.live_action) + |> assign(:address_query, nil) + |> assign(:action, Routes.friends_path(socket, :update)) + |> title("Welcome")} + end + def handle_event("validate", %{"friend" => form_params}, %{assigns: %{friend: friend}} = socket) do id = form_params["id"] name = form_params["name"] @@ -81,23 +106,26 @@ defmodule FriendsWeb.FriendsLive.Edit do def handle_event( "save", %{"friend" => form_params}, - %{assigns: %{changeset: changeset}} = socket + %{assigns: %{changeset: _changeset}} = socket ) do name = form_params["name"] nickname = form_params["nickname"] born = form_params["born"] email = form_params["email"] phone = form_params["phone"] |> format_phone - id = form_params["id"] + slug = form_params["slug"] || name |> to_slug + id = form_params["id"] || :new + address_id = form_params["address_id"] new_params = %{ id: id, name: name, nickname: nickname, - slug: name |> to_slug, + slug: slug, born: born, phone: phone, - email: email + email: email, + address_id: address_id } updated_friend = Friend.create_or_update(new_params) @@ -109,17 +137,21 @@ defmodule FriendsWeb.FriendsLive.Edit do |> put_flash(:info, "Saved #{updated_friend |> first_name}!") |> assign(:new_friend, new_changeset) |> assign(:friend, updated_friend) - |> push_patch(to: "/friend/#{updated_friend.slug}") + |> push_navigate(to: "/friend/#{updated_friend.slug}") } end - # Handle deleting a friend - def handle_event("delete", %{"friend_id" => friend_id}, socket) do - friend = Friend.get_by_id(friend_id) + def handle_event("address_search", %{"friend" => %{"address_query" => query}}, socket) do + results = Places.Search.autocomplete(query) |> Enum.map(&Places.Search.display_address/1) - {:noreply, - socket - |> put_flash(:error, "Deleted '#{friend.name}'.") - |> push_navigate(to: "/")} + if query == "" do + {:noreply, socket |> assign(:address_results, nil)} + else + {:noreply, socket |> assign(:address_results, results)} + end + end + + def handle_event(event, unsigned_params, socket) do + {:noreply, socket} end end diff --git a/friends/lib/friends_web/router.ex b/friends/lib/friends_web/router.ex index 8ca52d9..515f5fa 100644 --- a/friends/lib/friends_web/router.ex +++ b/friends/lib/friends_web/router.ex @@ -73,6 +73,8 @@ defmodule FriendsWeb.Router do post "/confirm", UserConfirmationController, :create get "/confirm/:token", UserConfirmationController, :edit post "/confirm/:token", UserConfirmationController, :update + + live "/welcome", FriendsLive.Edit, :welcome end # Routes that require the user be authenticated: @@ -104,13 +106,13 @@ defmodule FriendsWeb.Router do end # Edit modes (require being logged in and having a profile) - scope "/friend/update/", FriendsWeb do + scope "/edit/", FriendsWeb do pipe_through [:browser, :require_authenticated_user, :capture_profile] + post "/", FriendsController, :update + live "/:slug/overview", FriendsLive.Edit, :overview live "/:slug/timeline", FriendsLive.Edit, :timeline live "/:slug/relationships", FriendsLive.Edit, :relationships - - post "/:slug/update", FriendsController, :update end end diff --git a/friends/test/friends_web/controllers/friends_live_test.exs b/friends/test/friends_web/controllers/friends_live_test.exs index 966a857..db04c21 100644 --- a/friends/test/friends_web/controllers/friends_live_test.exs +++ b/friends/test/friends_web/controllers/friends_live_test.exs @@ -9,9 +9,14 @@ defmodule FriendsWeb.FriendsLiveTest do } = friend_fixture(%{email: user_fixture().email}) |> Friends.Friend.assign_user() end - describe "GET '/friends/:slug'" do + describe "GET '/friend/:slug'" do + test "redirects if live_action not specified", %{conn: conn, friend: friend} do + conn = conn |> get("/friend/#{friend.slug}/") + assert redirected_to(conn) == Routes.friends_show_path(conn, :overview, friend.slug) + end + test "shows the friend overview", %{conn: conn, friend: friend} do - conn = conn |> get("/friends/#{friend.slug}") + conn = conn |> get("/friend/#{friend.slug}/overview") assert html_response(conn, 200) =~ friend.name end end