bilalhassankh

bilalhassankh

Need help with form fields

Create new project–>when user select a company and select it’s contact , after that if user change the company, it should shows blank contact filed for change company, and should not save the previous contact of company

I want to remove the selection from contacts and buildings when selecting other company contact. What will be the solution?

form_component.html.heex


<div class="contacts_newcom_m">
    <h1><%= page_title(@action) %></h1>

   <div class="a_asside_account_c_first_ss mt-20">
      <.form let={f} for={@changeset} phx-target={@myself} phx-change="validate" phx-submit="save" phx-update="replace">
      <span>
        <%= if entry = List.first(@uploads.image.entries) do%>
          <%= live_img_preview entry %>
        <% else %>
          <%= if @project.project_image do%>
            <img src={@project.project_image}/>
          <% else %>
            <img src={Routes.static_path(@socket, System.get_env("DEFAULT_AVATAR"))} alt="img"/>
          <% end %>
        <% end %> 
        <span class="account_add_img" phx-drop-target={@uploads.image.ref} onclick={"document.getElementById('#{@uploads.image.ref}').click()"}>
            <img src={Routes.static_path(@socket, "/images/Frame 811261 (1).svg")} alt=""/>
            <%= gettext("add image") %>
            <%= live_file_input @uploads.image, hidden: true %>
            <%= if entry = List.first(@uploads.image.entries) do%>
              <%= for err <- upload_errors(@uploads.image, entry) do %>
                <span><%= image_errors(err) %></span>
              <% end %>
            <% end %>
        </span>
      </span>

         <div class="form-control">
            <p><%= gettext("name") %></p>
            <%= text_input f, :name %>
            <%= error_tag f, :name %>
         </div>
         <div class="form-control ">
            <p><%= gettext("description") %></p>
            <%= text_input f, :description %>
            <%= error_tag f, :description %>
         </div>
         
         <div class="form-control ">
            <p><%= gettext("Estimated Time") %></p>
            <%= text_input f, :estimated_time, type: "number", min: 0, oninput: "this.value = Math.abs(this.value)" %>
            <%= error_tag f, :estimated_time %>
         </div>

         <div class="form-control ">
            <p><%= gettext("Project Start Date") %></p>
            <%= datetime_local_input f, :project_start_date %>
            <%= error_tag f, :project_start_date %>
         </div>

         <div class="form-control ">
            <p><%= gettext("Company Contact") %></p>
            <%= select f, :company_contact_id, @company_contacts_options, options(:company_contact, assigns[:parent])  %>
            <%= error_tag f, :company_contact_id %>
         </div>

         <%= inputs_for f, :project_contacts, fn a -> %>
            <%= hidden_input a, :contact_id %>
            <%= hidden_input a, :company_id %>
         <% end %>

         <%= inputs_for f, :project_buildings, fn a -> %>
            <%= hidden_input a, :building_id %>
            <%= hidden_input a, :company_id %>
         <% end %>
               
         <%= hidden_input f, :stage, value: "pending" %>
         <%= error_tag f, :stage %>

         <%= hidden_input f, :lead_column_id %>
         <%= error_tag f, :lead_column_id %>
      
         <%= hidden_input f, :company_id, value: @current_user.company_id %>
         <%= error_tag f, :company_id %>

         <div class="form-control ">
            <p><%= gettext("Contacts") %></p>
            <%= live_component AppeoWeb.TagDropdown,
            id: :project_contacts,
            ex_tags: @ex_contact_taggings,
            module: %{name: __MODULE__, id: @id, field: :contact_id}, 
            tags: @contact_options,
            disabled: options(:contact, assigns[:parent])
            %>
            <%= error_tag f, :project_contacts %>
         </div>

         <div class="form-control">
            <p><%= gettext("Buildings") %></p>
            <%= live_component AppeoWeb.TagDropdown,
            id: :project_buildings,
            ex_tags: @ex_building_taggings,
            module: %{name: __MODULE__, id: @id, field: :building_id}, 
            tags: @building_options
            %>
             <%= error_tag f, :project_buildings %>
         </div>
         
         <div class="form-control ">
            <p><%= gettext("Project Type") %></p>
            <%= select f, :project_type, ["Roofing": "roofing", "Any Name": "any name"] %>
            <%= error_tag f, :project_type %>
         </div>

         <div class="form-control ">
            <button class="btn" type="submit"><%= gettext("save") %></button>
            <div class="btn"><%= live_patch gettext("Cancel"), to: @return_to %></div>
         </div>
      </.form>
   </div>
</div>

defmodule AppeoWeb.LeadsLive.FormComponent do
  use AppeoWeb, :live_component

  alias Appeo.Leads
  alias Appeo.Leads.Project
  alias Appeo.Contacts
  alias Ecto.Changeset
  alias Appeo.ProjectPermissions

  @bucket_dir_name "projects"

  @impl true
  def update(%{current_user: _, project: project} = assigns, socket) do
    params = default_params(project.id, assigns)
    changeset = Leads.change_project(project, params)

    company_contacts = Contacts.list_company_contacts_for_project()
    company_contacts_options = Enum.map(company_contacts, &{&1.name, &1.id})

    company_contact_id =
      project.company_contact_id ||
        company_contacts
        |> Enum.at(0, %{})
        |> Map.get(:id, "")

    company_contact_id = to_string(company_contact_id)

    building_options = building_options(company_contact_id, company_contacts)
    contact_options = contacts_options(company_contact_id, company_contacts)

    {ex_contact_taggings, ex_building_taggings} =
      if project.id do
        building_tags = Map.new(building_options, &{&1.id, &1})
        contact_tags = Map.new(contact_options, &{&1.id, &1})

        {
          Enum.map(project.project_contacts, &Map.get(contact_tags, &1.contact_id)),
          Enum.map(project.project_buildings, &Map.get(building_tags, &1.building_id))
        }
      else
        {[], []}
      end

    socket =
      socket
      |> assign(assigns)
      |> assign(:changeset, changeset)
      |> assign(:project, project)
      |> assign(:contact_options, contact_options)
      |> assign(:building_options, building_options)
      |> assign(:company_contacts_options, company_contacts_options)
      |> assign(:company_contacts, company_contacts)
      |> assign(:uploaded_files, [])
      |> assign(:ex_contact_taggings, ex_contact_taggings)
      |> assign(:ex_building_taggings, ex_building_taggings)
      |> allow_upload(:image,
        accept: ~w(.jpg .jpeg .png),
        max_entries: 1,
        max_file_size: 3_145_726
      )

    {:ok, socket}
  end

  def update(assigns, socket) do
    socket =
      case assigns do
        %{field: :contact_id, taggings: taggings} ->
          changeset = build_changeset(:contact_id, taggings, socket.assigns)
          assign(socket, changeset: changeset, ex_contact_taggings: taggings)

        %{field: :building_id, taggings: taggings} ->
          changeset = build_changeset(:building_id, taggings, socket.assigns)
          assign(socket, changeset: changeset, ex_building_taggings: taggings)
      end

    {:ok, socket}
  end

  @impl true
  def handle_event("validate", %{"project" => project}, socket) do
    changeset =
      socket.assigns.project
      |> Leads.change_project(project)
      |> Map.put(:action, :validate)

    company_contacts = socket.assigns.company_contacts
    contacts_options = contacts_options(project["company_contact_id"] || "", company_contacts)
    building_options = building_options(project["company_contact_id"] || "", company_contacts)

    socket =
      socket
      |> assign(:contact_options, contacts_options)
      |> assign(:building_options, building_options)

    {:noreply, assign(socket, :changeset, changeset)}
  end

  def handle_event("save", %{"project" => project_params}, socket) do
    socket
    |> upload_image(@bucket_dir_name)
    |> save_project(socket, socket.assigns.action, project_params)
  end

  def handle_event("project_contact", %{"index" => index}, socket) do
    changeset = socket.assigns.changeset
    project_contacts = remove_field(changeset.changes.project_contacts, index)

    changeset = put_in(changeset.changes.project_contacts, project_contacts)

    {:noreply, assign(socket, :changeset, changeset)}
  end

  def build_changeset(:contact_id, taggings, assigns) do
    company_id = assigns.current_user.company_id
    project_contacts = Enum.map(taggings, &%{company_id: company_id, contact_id: &1.id})

    assigns.changeset
    |> Changeset.put_assoc(:project_contacts, project_contacts)
    |> Changeset.apply_changes()
    |> Project.changeset()
    |> Map.put(:action, :validate)
  end

  def build_changeset(:building_id, taggings, assigns) do
    company_id = assigns.current_user.company_id
    project_buildings = Enum.map(taggings, &%{company_id: company_id, building_id: &1.id})

    assigns.changeset
    |> Changeset.put_assoc(:project_buildings, project_buildings)
    |> Changeset.apply_changes()
    |> Project.changeset()
    |> Map.put(:action, :validate)
  end

  defp save_project({:error, error}, socket, _, _) do
    {:noreply, put_flash(socket, :error, error)}
  end

  defp save_project({:ok, path}, socket, :edit_project, project_params) do
    path = path || socket.assigns.project.project_image
    project_params = Map.put(project_params, "project_image", path)

    case Leads.update_project(socket.assigns.project, project_params) do
      {:ok, _contact} ->
        {:noreply,
         socket
         |> put_flash(:info, gettext("Project updated successfully"))
         |> push_patch(to: socket.assigns.return_to)}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, :changeset, changeset)}
    end
  end

  defp save_project({:ok, path}, socket, :new_project, project_params) do
    project_params =
      project_params
      |> Map.put("project_image", path)
      |> Map.put(
        "project_permission_joined_users",
        [
          %{
            "company_id" => socket.assigns.current_user.company_id,
            "user_id" => socket.assigns.current_user.id,
            "project_permission_id" => ProjectPermissions.get_permission_with_name("Owner").id
          }
        ]
      )

    case Leads.create_project(project_params) do
      {:ok, _project} ->
        {:noreply,
         socket
         |> put_flash(:info, gettext("Project created successfully"))
         |> push_redirect(to: socket.assigns.return_to)}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, changeset: changeset)}
    end
  end

  defp default_params(nil, %{current_user: current_user} = assigns) do
    %{
      lead_column_id: assigns.lead_column_id,
      company_id: current_user.company_id
    }
  end

  defp default_params(_, _assigns), do: %{}

  defp contacts_options("", _assigns), do: []

  defp contacts_options(company_contact_id, company_contacts) do
    company_contacts
    |> Enum.find(&(to_string(&1.id) == company_contact_id))
    |> Map.get(:contacts)
    |> Enum.map(&%{name: &1.first_name, id: &1.id})
  end

  defp building_options("", _assigns), do: []

  defp building_options(company_contact_id, company_contacts) do
    company_contacts
    |> Enum.find(&(to_string(&1.id) == company_contact_id))
    |> Map.get(:buildings)
    |> Enum.map(&%{name: &1.building_name, id: &1.id})
  end

  defp remove_field(changeset_list, index) do
    changeset_list
    |> Enum.with_index()
    |> Enum.reduce([], fn {value, i}, acc -> if "#{i}" == index, do: acc, else: acc ++ [value] end)
  end

  defp page_title(:new_project), do: gettext("Create New Project")
  defp page_title(:edit_project), do: gettext("Update Project")

  defp options(:company_contact, [:contact, contact]),
    do: buid_options(contact.company_contact_id)

  defp options(:company_contact, [:company_contact, %{id: id}]), do: buid_options(id)
  defp options(:contact, [:contact, _]), do: true
  defp options(:contact, _), do: false
  defp options(_, _), do: []

  defp buid_options(id), do: [disabled: true, selected: id]
end

First Post!

bilalhassankh

bilalhassankh

Anyone?

Where Next?

Popular in Questions Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New

Other popular topics Top

siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

We're in Beta

About us Mission Statement