timgremore's picture
fix: Position code select above content
96365df
raw
history blame
5.2 kB
defmodule MedicodeWeb.Components.CodeSelect do
@moduledoc """
An auto-complete select field that allows users to search for codes to add by either `code` or `description`.
"""
use MedicodeWeb, :live_component
import MedicodeWeb.Components, only: [code_display: 1]
alias Medicode.Feedback
alias Medicode.Transcriptions
@impl Phoenix.LiveComponent
def mount(socket) do
socket =
socket
|> assign(:codes, [])
|> assign(:selected_code, nil)
|> assign(:submitted_code_feedback, nil)
{:ok, socket}
end
@impl Phoenix.LiveComponent
def update(
%{id: id, text: text, current_user: current_user, chunk: chunk} = _assigns,
socket
) do
form = to_form(%{"search_term" => ""}, as: id)
socket =
socket
|> assign(:form, form)
|> assign(:text, text)
|> assign(:current_user, current_user)
|> assign(:chunk, chunk)
{:ok, socket}
end
@impl Phoenix.LiveComponent
def render(assigns) do
~H"""
<div class="w-full" phx-click-away="clear-codes" phx-target={@myself}>
<%= if is_nil(@selected_code) do %>
<.form for={@form} phx-change="suggest-code" phx-target={@myself} class="relative">
<.input
type="text"
field={@form[:search_term]}
class="w-full rounded"
style={if length(@codes) > 0, do: "border-radius: 0.25rem 0.25rem 0 0 !important;"}
placeholder="Search for another code..."
/>
<div
:if={length(@codes) > 0}
class="absolute z-10 w-full bg-white border-l border-r border-b border-zinc-400 rounded-b overflow-hidden"
>
<button
:for={code <- @codes}
type="button"
class="w-full text-left px-2 py-1 text-sm border-b border-zinc-100 last:border-b-0 hover:bg-blue-200"
phx-click="choose-code"
phx-value-code={code.code}
phx-target={@myself}
>
<%= code.code %>: <%= code.description %>
</button>
</div>
</.form>
<% else %>
<div class="px-[14px]">
<div class="flex justify-between pb-1 border-b border-zinc-300">
<p class="leading-normal font-bold text-type-black-primary uppercase">
User-selected code
</p>
<button type="button" phx-click="clear-code" phx-target={@myself}>
<.icon name="hero-x-circle" />
</button>
</div>
<.code_display code={@selected_code.code} label={@selected_code.description} />
</div>
<% end %>
</div>
"""
end
@impl Phoenix.LiveComponent
def handle_event("suggest-code", params, socket) do
form_id = socket.assigns.form.id
%{^form_id => %{"search_term" => value}} = params
suggested_codes = Medicode.Coding.search_for_code_vector(value)
{:noreply, assign(socket, :codes, suggested_codes)}
end
def handle_event("clear-codes", _params, socket) do
{:noreply, assign(socket, :codes, [])}
end
def handle_event("choose-code", %{"code" => code}, socket) do
selected_code = Enum.find(socket.assigns.codes, &(&1.code == code))
text_vector = Medicode.Coding.compute_vector_as_list(socket.assigns.text)
code_feedback =
Feedback.insert_and_return(%{
text: socket.assigns.text,
text_vector: text_vector,
response: true,
code_vector_id: selected_code.id
})
Transcriptions.upsert_code_vector_for_transcription_chunk(%{
assigned_by_user_id: socket.assigns.current_user.id,
code_vector_id: selected_code.id,
transcription_chunk_id: socket.assigns.chunk.id,
cosine_similarity:
Medicode.Coding.get_cosine_similarity(text_vector, selected_code.description_vector)
})
send_update(MedicodeWeb.Components.TranscriptionTextComponent,
id: "transcription-chunk-#{socket.assigns.chunk.id}",
chunk: socket.assigns.chunk,
chunk_id: socket.assigns.chunk.id,
current_user: socket.assigns.current_user,
on_feedback: &MedicodeWeb.TranscriptionsLive.Show.on_feedback/1,
on_remove_code: &MedicodeWeb.TranscriptionsLive.Show.on_remove_code/1
)
Phoenix.PubSub.broadcast(
:medicode_pubsub,
"transcriptions:#{socket.assigns.chunk.transcription_id}",
{:transcription_updated, socket.assigns.chunk}
)
socket =
if is_nil(code_feedback) do
put_flash(socket, :error, "Failed to record feedback")
else
socket
|> assign(:selected_code, selected_code)
|> assign(:submitted_code_feedback, code_feedback)
|> assign(:codes, [])
end
{:noreply, socket}
end
@impl Phoenix.LiveComponent
def handle_event(
"clear-code",
_params,
%{assigns: %{submitted_code_feedback: submitted_code_feedback}} = socket
) do
# Delete previous code feedback
Feedback.delete(submitted_code_feedback)
socket =
socket
|> assign(:codes, [])
|> assign(:selected_code, nil)
|> assign(:submitted_code_feedback, nil)
{:noreply, socket}
end
end