| defmodule PlausibleWeb.Live.PropsSettings.Form do |
| @moduledoc """ |
| Live view for the custom props creation form |
| """ |
| use PlausibleWeb, :live_view |
| import PlausibleWeb.Live.Components.Form |
| alias PlausibleWeb.Live.Components.ComboBox |
|
|
| def mount( |
| _params, |
| %{ |
| "site_id" => _site_id, |
| "domain" => domain, |
| "rendered_by" => pid |
| }, |
| socket |
| ) do |
| socket = |
| socket |
| |> assign_new(:site, fn %{current_user: current_user} -> |
| Plausible.Sites.get_for_user!(current_user, domain, |
| roles: [ |
| :owner, |
| :admin, |
| :editor, |
| :super_admin |
| ], |
| include_consolidated?: true |
| ) |
| end) |
| |> assign_new(:form, fn %{site: site} -> |
| new_form(site) |
| end) |
|
|
| {:ok, |
| assign(socket, |
| domain: domain, |
| rendered_by: pid, |
| prop_key_options_count: 0 |
| )} |
| end |
|
|
| def render(assigns) do |
| ~H""" |
| <div |
| class="fixed inset-0 bg-gray-500/75 transition-opacity z-50" |
| phx-window-keydown="cancel-allow-prop" |
| phx-key="Escape" |
| > |
| </div> |
| <div class="fixed inset-0 flex items-center justify-center mt-16 z-50 overflow-y-auto overflow-x-hidden"> |
| <div class="w-1/2 h-full"> |
| <.form |
| :let={f} |
| for={@form} |
| class="max-w-md w-full mx-auto bg-white dark:bg-gray-900 shadow-md rounded-sm px-8 pt-6 pb-8 mb-4 mt-8" |
| phx-submit="allow-prop" |
| phx-click-away="cancel-allow-prop" |
| > |
| <.title> |
| Add property for {Plausible.Sites.display_name(@site)} |
| </.title> |
| |
| <div class="mt-6"> |
| <.label for="prop_input"> |
| Property |
| </.label> |
| |
| <.live_component |
| id="prop_input" |
| submit_name="prop" |
| class={[ |
| "py-2" |
| ]} |
| module={ComboBox} |
| suggest_fun={ |
| pid = self() |
| |
| fn |
| "", [] -> |
| options = |
| @site |
| |> Plausible.Props.suggest_keys_to_allow() |
| |> Enum.map(&{&1, &1}) |
| |
| send(pid, {:update_prop_key_options_count, Enum.count(options)}) |
| |
| options |
| |
| input, options -> |
| ComboBox.StaticSearch.suggest(input, options) |
| end |
| } |
| creatable |
| /> |
| |
| <.error :for={{msg, opts} <- f[:allowed_event_props].errors}> |
| {Enum.reduce(opts, msg, fn {key, value}, acc -> |
| String.replace(acc, "%{ |
| end)} |
| </.error> |
| </div> |
|
|
| <.button type="submit" class="w-full"> |
| Add property |
| </.button> |
|
|
| <button |
| :if={@prop_key_options_count > 0} |
| title="Use this to add any existing properties from your past events into your settings. This allows you to set up properties without having to manually enter each item." |
| class="mt-4 text-sm hover:underline text-indigo-600 dark:text-indigo-400 text-left" |
| phx-click="allow-existing-props" |
| > |
| Already sending custom properties? Click to add {@prop_key_options_count} existing properties we found. |
| </button> |
| </.form> |
| </div> |
| </div> |
| """ |
| end |
| |
| def handle_info({:update_prop_key_options_count, count}, socket) do |
| {:noreply, assign(socket, prop_key_options_count: count)} |
| end |
| |
| def handle_event("allow-prop", %{"prop" => prop}, socket) do |
| case Plausible.Props.allow(socket.assigns.site, prop) do |
| {:ok, site} -> |
| send(socket.assigns.rendered_by, {:prop_allowed, prop}) |
| |
| {:noreply, |
| assign(socket, |
| site: site, |
| form: new_form(site) |
| )} |
| |
| {:error, changeset} -> |
| {:noreply, |
| assign(socket, |
| form: to_form(Map.put(changeset, :action, :validate)) |
| )} |
| end |
| end |
| |
| def handle_event("allow-existing-props", _params, socket) do |
| {:ok, site} = Plausible.Props.allow_existing_props(socket.assigns.site) |
| send(socket.assigns.rendered_by, {:props_allowed, site.allowed_event_props}) |
| |
| {:noreply, |
| assign(socket, |
| site: site, |
| form: new_form(site), |
| prop_key_options_count: 0 |
| )} |
| end |
| |
| def handle_event("cancel-allow-prop", _value, socket) do |
| send(socket.assigns.rendered_by, :cancel_add_prop) |
| {:noreply, socket} |
| end |
| |
| defp new_form(site) do |
| to_form(Plausible.Props.allow_changeset(site, [])) |
| end |
| end |
| |