Skip to content

Commit

Permalink
Add: campaign signup show/signup form.
Browse files Browse the repository at this point in the history
  • Loading branch information
teesloane committed Dec 11, 2023
1 parent 83815e9 commit 7717ba2
Show file tree
Hide file tree
Showing 5 changed files with 392 additions and 0 deletions.
184 changes: 184 additions & 0 deletions lib/bike_brigade_web/live/campaign_signup_live/show.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
defmodule BikeBrigadeWeb.CampaignSignupLive.Show do
use BikeBrigadeWeb, :live_view

import BikeBrigadeWeb.CampaignHelpers
alias BikeBrigade.Delivery

@impl true
def mount(_params, _session, socket) do
if connected?(socket) do
Delivery.subscribe()
end

{:ok,
socket
|> assign(:page, :campaign_signup)
|> assign(:page_title, "Signup for deliveries")
|> assign(:current_rider_id, socket.assigns.current_user.rider_id)
|> assign(:campaign, nil)
|> assign(:riders, nil)
|> assign(:tasks, nil)}
end

@impl true
def handle_params(%{"id" => id} = params, _url, socket) do
with {num, ""} <- Integer.parse(id),
campaign when not is_nil(campaign) <- Delivery.get_campaign(num) do
{:noreply,
socket
|> assign_campaign(campaign)
|> apply_action(socket.assigns.live_action, params)}
else
_ ->
{:noreply,
socket
|> put_flash(:error, "Invalid campaign id.")
|> redirect(to: ~p"/campaigns/signup/")}
end
end

defp apply_action(socket, :new, _) do
socket |> assign(:page_title, "Campaign Signup")
end

defp apply_action(socket, :rider_signup, %{"task_id" => task_id}) do
with {:parse_int, {num, ""}} <- {:parse_int, Integer.parse(task_id)},
{:get_task, task} when not is_nil(task) <- {:get_task, Delivery.get_task(num)},
{:rider_assigned, rider_id} when is_nil(rider_id) <-
{:rider_assigned, task.assigned_rider_id},
{:same_campaign, true} <-
{:same_campaign, task.campaign_id == socket.assigns.campaign.id} do
socket
|> assign(:page_title, "Signup for this delivery")
|> assign(:task, task)
else
{:rider_assigned, _} -> rider_signup_redirect(socket)
{:get_task, nil} -> rider_signup_redirect(socket, "Task does not exist.")
{:parse_int, :error} -> rider_signup_redirect(socket, "Invalid task id.")
{:same_campaign, false} -> rider_signup_redirect(socket)
_ -> rider_signup_redirect(socket, "something went wrong")
end
end

defp apply_action(socket, _, _), do: socket

defp rider_signup_redirect(socket) do
socket |> redirect(to: ~p"/campaigns/signup/#{socket.assigns.campaign}")
end

defp rider_signup_redirect(socket, flash_msg) do
socket
|> put_flash(:error, flash_msg)
|> redirect(to: ~p"/campaigns/signup/#{socket.assigns.campaign}")
end

defp split_first_name(full_name) do
case String.split(full_name, " ") do
[first_name, last_name] when is_binary(first_name) and is_binary(last_name) ->
first_name

_ ->
full_name
end
end

@impl true
def handle_event("unassign_task", %{"task_id" => task_id}, socket) do
task = get_task(socket, task_id)
rider_id = socket.assigns.current_user.rider_id

if task.assigned_rider do
{:ok, _task} =
task
|> Delivery.update_task(%{assigned_rider_id: nil})
end

# If rider is no longer assigned to any tasks, remove them from the campaign
rider_has_no_other_tasks? =
socket.assigns.tasks
# remove the task that was just clicked
|> Enum.reject(fn t -> t.id === task_id end)
# if the rider's is not found in any other of the tasks, return true.
|> Enum.filter(fn t -> t.assigned_rider_id == rider_id end)
|> Enum.empty?()

if rider_has_no_other_tasks? do
Delivery.remove_rider_from_campaign(socket.assigns.campaign, rider_id)
end

{:noreply, socket}
end

## -- Callbacks to handle Delivery broadcasts --

@broadcasted_infos [
:task_created,
:task_deleted,
:task_updated,
:campaign_rider_created,
:campaign_rider_deleted
]

@impl Phoenix.LiveView
def handle_info({event, entity}, socket) when event in @broadcasted_infos do
campaign = socket.assigns.campaign
# if a task or a campaign rider changes (ie, if any of hte broadcasted_infos)
# launches from elsewhere, check if the entity's respective campaign id matches
# the id of the campaign in the current view; if so, refetch the data.
if entity.campaign_id == campaign.id do
{:noreply, assign_campaign(socket, campaign)}
else
{:noreply, socket}
end
end

## lil helpers

defp get_task(socket, id) when is_binary(id), do: get_task(socket, String.to_integer(id))

defp get_task(socket, id) when is_integer(id),
do: Enum.find(socket.assigns.tasks, nil, fn x -> x.id == id end)

defp assign_campaign(socket, campaign) do
{riders, tasks} = Delivery.campaign_riders_and_tasks(campaign)

socket
|> assign(:campaign, campaign)
|> assign(:riders, riders)
|> assign(:tasks, tasks)
end

## Module specific components

defp get_delivery_size(assigns) do
item_list =
Enum.map(assigns.task.task_items, fn task_item ->
"#{task_item.count} #{task_item.item.category}"
end)

assigns = assign(assigns, :item_list, item_list)

~H"""
<div :for={item <- @item_list}>
<%= item %>
</div>
"""
end

defp truncated_riders_notes(assigns) do
if String.length(assigns.note) > 40 do
~H"""
<div class="w-[40ch] flex items-center">
<details>
<summary class="cursor-pointer"><%= String.slice(@note, 0..40) %>...</summary>
<%= @note %>
</details>
</div>
"""
else
~H"""
<div><%= @note %></div>
"""
end
end
end
76 changes: 76 additions & 0 deletions lib/bike_brigade_web/live/campaign_signup_live/show.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<.header>
<%= @campaign.program.name %> - <%= campaign_date(@campaign) %>
<:subtitle>
<span class="font-bold"><%= @campaign.location.address %></span>
<span :if={@campaign.program.campaign_blurb}>
- <%= @campaign.program.campaign_blurb %>
</span>
</:subtitle>
</.header>

<section>
<.table id="tasks" rows={@tasks}>
<:col :let={_task} label="Pickup time">
<%= pickup_window(@campaign) %>
</:col>
<:col :let={task} label="Delivery Size">
<.get_delivery_size task={task}/>
</:col>
<:col :let={task} label="Recipient"><%= task.dropoff_name %></:col>
<:col :let={task} label="Dropoff Location"><%= task.dropoff_location.address %></:col>
<:col :let={task} label="Notes"><%= task.delivery_status_notes %>
<.truncated_riders_notes note={task.rider_notes || "--"}/>
</:col>
<:action :let={task}>
<%= if task.assigned_rider do %>
<span
:if={task.assigned_rider.id != @current_rider_id}
class="mr-2"> <%= split_first_name(task.assigned_rider.name) %></span>

<.button
:if={task.assigned_rider.id == @current_rider_id}
id={"task-#{task.id}"}
phx-click={JS.push("unassign_task", value: %{task_id: task.id})}
color={:red}
size={:xsmall}
class="w-28">
Unassign me
</.button>

<% end %>

<%= if is_nil(task.assigned_rider) do %>
<.button
id={"task-#{task.id}"}
color={:primary}
size={:xsmall}
class="w-28"
patch={~p"/campaigns/signup/#{@campaign}/task/#{task.id}"}

>
Signup
</.button>

<% end %>
</:action>
</.table>
</section>


<.modal
:if={@live_action == :rider_signup}
id="rider-signup-modal"
show
on_cancel={JS.navigate(~p"/campaigns/signup/#{@campaign}")}
>
<.live_component
module={BikeBrigadeWeb.CampaignSignupLive.SignupRiderFormComponent}
id={@campaign.id}
title={@page_title}
action={@live_action}
campaign={@campaign}
task={@task}
rider_id={@current_user.rider_id}
navigate={~p"/campaigns/signup/#{@campaign}"}
/>
</.modal>
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
defmodule BikeBrigadeWeb.CampaignSignupLive.SignupRiderFormComponent do
use BikeBrigadeWeb, :live_component

alias BikeBrigade.Delivery
alias BikeBrigade.Delivery.CampaignRider

@impl Phoenix.LiveComponent
def mount(socket) do
changeset = Delivery.CampaignRider.changeset(%CampaignRider{})

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

@impl Phoenix.LiveComponent
def handle_event("validate", %{"campaign_rider" => cr_params}, socket) do
changeset =
%CampaignRider{}
|> CampaignRider.changeset(cr_params)
|> Map.put(:action, :validate)

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

@impl Phoenix.LiveComponent
def handle_event("rider_signup", %{"campaign_rider" => cr_params}, socket) do
%{rider_id: rider_id, task: task, campaign: campaign} = socket.assigns
attrs = Map.merge(cr_params, %{"campaign_id" => campaign.id, "rider_id" => rider_id})

case Delivery.create_campaign_rider(attrs) do
{:ok, _cr} ->
{:ok, _task} = Delivery.update_task(task, %{assigned_rider_id: rider_id})
{:noreply, socket |> push_redirect(to: ~p"/campaigns/signup/#{campaign}")}

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

def handle_event("rider_signup", _params, socket) do
{:noreply,
socket
|> put_flash(:error, "rider is required")}
end

end
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<div>
<.flash kind={:info} title="Success!" flash={@flash} />
<.flash kind={:error} title="Error!" flash={@flash} />
<.header><%= @title %></.header>
<.simple_form
:let={f}
for={@changeset}
id="rider_signup_form"
phx-target={@myself}
phx-submit="rider_signup"
phx-change="validate"
autocomplete="off"
>
<.input type="number" field={{f, :rider_capacity}} label="Capacity" />
<.input type="text" field={{f, :pickup_window}} label="Pickup Window" />
<.radio_group field={{f, :enter_building}} label="Enter buildings?">
<:radio value={true} label="Yes" />
<:radio value={false} label="No" />
</.radio_group>
<:actions>
<.button type="submit" phx-disable-with="Adding...">
Add
</.button>
</:actions>
</.simple_form>
</div>
Loading

0 comments on commit 7717ba2

Please sign in to comment.