Skip to content

Commit

Permalink
#2 mix phx.gen.live - create LiveView files
Browse files Browse the repository at this point in the history
  • Loading branch information
nelsonic committed Sep 22, 2023
1 parent 6c38ddb commit 4701c18
Show file tree
Hide file tree
Showing 7 changed files with 389 additions and 0 deletions.
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,54 @@ a registration form
for our fictitious
**_Awesome_ Conference**.

# 4. Create `attendee` schema

The goal is to allow `people` attending **_Awesome_ Conf**
to submit the following data:

+ `first_name` - how we greet you. Will appear on your conference pass.
+ `last_name` - your family name. Will appear on you conference pass.
+ `email` - to confirm attendance
+ `phone_number` - to verify your access when attending the secret event.
+ `address` - so we can send the welcome pack
+ `address_line_2` - if your address has multiple lines.
+ `postcode` - for the address.
+ `gender` - for venue capacity planning.
+ `dietary_preference` - for meals and snacks provided by the conference.
+ `website` - share your awesomeness and have it as a QR code on your conference pass.
+ `description` - brief description of your awesome project.
+ `feedback` - Feedback or suggestions


## 4.1 `gen.schema`

Using the
[`mix phx.gen.live`](https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Schema.html)
command,
run:
```sh
mix phx.gen.live Accounts Attendee attendees first_name:string last_name:string email:string --no-context
```

You should expect to see output similar to the following:

```sh
* creating lib/fields_demo_web/live/attendee_live/show.ex
* creating lib/fields_demo_web/live/attendee_live/index.ex
* creating lib/fields_demo_web/live/attendee_live/form_component.ex
* creating lib/fields_demo_web/live/attendee_live/index.html.heex
* creating lib/fields_demo_web/live/attendee_live/show.html.heex
* creating test/fields_demo_web/live/attendee_live_test.exs

Add the live routes to your browser scope in lib/fields_demo_web/router.ex:

live "/attendees", AttendeeLive.Index, :index
live "/attendees/new", AttendeeLive.Index, :new
live "/attendees/:id/edit", AttendeeLive.Index, :edit

live "/attendees/:id", AttendeeLive.Show, :show
live "/attendees/:id/show/edit", AttendeeLive.Show, :edit
```


# FieldsDemo
Expand Down
92 changes: 92 additions & 0 deletions lib/fields_demo_web/live/attendee_live/form_component.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
defmodule FieldsDemoWeb.AttendeeLive.FormComponent do
use FieldsDemoWeb, :live_component

alias FieldsDemo.Accounts

@impl true
def render(assigns) do
~H"""
<div>
<.header>
<%= @title %>
<:subtitle>Use this form to manage attendee records in your database.</:subtitle>
</.header>
<.simple_form
for={@form}
id="attendee-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<.input field={@form[:first_name]} type="text" label="First name" />
<.input field={@form[:last_name]} type="text" label="Last name" />
<.input field={@form[:email]} type="text" label="Email" />
<:actions>
<.button phx-disable-with="Saving...">Save Attendee</.button>
</:actions>
</.simple_form>
</div>
"""
end

@impl true
def update(%{attendee: attendee} = assigns, socket) do
changeset = Accounts.change_attendee(attendee)

{:ok,
socket
|> assign(assigns)
|> assign_form(changeset)}
end

@impl true
def handle_event("validate", %{"attendee" => attendee_params}, socket) do
changeset =
socket.assigns.attendee
|> Accounts.change_attendee(attendee_params)
|> Map.put(:action, :validate)

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

def handle_event("save", %{"attendee" => attendee_params}, socket) do
save_attendee(socket, socket.assigns.action, attendee_params)
end

defp save_attendee(socket, :edit, attendee_params) do
case Accounts.update_attendee(socket.assigns.attendee, attendee_params) do
{:ok, attendee} ->
notify_parent({:saved, attendee})

{:noreply,
socket
|> put_flash(:info, "Attendee updated successfully")
|> push_patch(to: socket.assigns.patch)}

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

defp save_attendee(socket, :new, attendee_params) do
case Accounts.create_attendee(attendee_params) do
{:ok, attendee} ->
notify_parent({:saved, attendee})

{:noreply,
socket
|> put_flash(:info, "Attendee created successfully")
|> push_patch(to: socket.assigns.patch)}

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

defp assign_form(socket, %Ecto.Changeset{} = changeset) do
assign(socket, :form, to_form(changeset))
end

defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
end
47 changes: 47 additions & 0 deletions lib/fields_demo_web/live/attendee_live/index.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
defmodule FieldsDemoWeb.AttendeeLive.Index do
use FieldsDemoWeb, :live_view

alias FieldsDemo.Accounts
alias FieldsDemo.Accounts.Attendee

@impl true
def mount(_params, _session, socket) do
{:ok, stream(socket, :attendees, Accounts.list_attendees())}
end

@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end

defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit Attendee")
|> assign(:attendee, Accounts.get_attendee!(id))
end

defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New Attendee")
|> assign(:attendee, %Attendee{})
end

defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing Attendees")
|> assign(:attendee, nil)
end

@impl true
def handle_info({FieldsDemoWeb.AttendeeLive.FormComponent, {:saved, attendee}}, socket) do
{:noreply, stream_insert(socket, :attendees, attendee)}
end

@impl true
def handle_event("delete", %{"id" => id}, socket) do
attendee = Accounts.get_attendee!(id)
{:ok, _} = Accounts.delete_attendee(attendee)

{:noreply, stream_delete(socket, :attendees, attendee)}
end
end
43 changes: 43 additions & 0 deletions lib/fields_demo_web/live/attendee_live/index.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<.header>
Listing Attendees
<:actions>
<.link patch={~p"/attendees/new"}>
<.button>New Attendee</.button>
</.link>
</:actions>
</.header>

<.table
id="attendees"
rows={@streams.attendees}
row_click={fn {_id, attendee} -> JS.navigate(~p"/attendees/#{attendee}") end}
>
<:col :let={{_id, attendee}} label="First name"><%= attendee.first_name %></:col>
<:col :let={{_id, attendee}} label="Last name"><%= attendee.last_name %></:col>
<:col :let={{_id, attendee}} label="Email"><%= attendee.email %></:col>
<:action :let={{_id, attendee}}>
<div class="sr-only">
<.link navigate={~p"/attendees/#{attendee}"}>Show</.link>
</div>
<.link patch={~p"/attendees/#{attendee}/edit"}>Edit</.link>
</:action>
<:action :let={{id, attendee}}>
<.link
phx-click={JS.push("delete", value: %{id: attendee.id}) |> hide("##{id}")}
data-confirm="Are you sure?"
>
Delete
</.link>
</:action>
</.table>

<.modal :if={@live_action in [:new, :edit]} id="attendee-modal" show on_cancel={JS.patch(~p"/attendees")}>
<.live_component
module={FieldsDemoWeb.AttendeeLive.FormComponent}
id={@attendee.id || :new}
title={@page_title}
action={@live_action}
attendee={@attendee}
patch={~p"/attendees"}
/>
</.modal>
21 changes: 21 additions & 0 deletions lib/fields_demo_web/live/attendee_live/show.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
defmodule FieldsDemoWeb.AttendeeLive.Show do
use FieldsDemoWeb, :live_view

alias FieldsDemo.Accounts

@impl true
def mount(_params, _session, socket) do
{:ok, socket}
end

@impl true
def handle_params(%{"id" => id}, _, socket) do
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:attendee, Accounts.get_attendee!(id))}
end

defp page_title(:show), do: "Show Attendee"
defp page_title(:edit), do: "Edit Attendee"
end
28 changes: 28 additions & 0 deletions lib/fields_demo_web/live/attendee_live/show.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<.header>
Attendee <%= @attendee.id %>
<:subtitle>This is a attendee record from your database.</:subtitle>
<:actions>
<.link patch={~p"/attendees/#{@attendee}/show/edit"} phx-click={JS.push_focus()}>
<.button>Edit attendee</.button>
</.link>
</:actions>
</.header>

<.list>
<:item title="First name"><%= @attendee.first_name %></:item>
<:item title="Last name"><%= @attendee.last_name %></:item>
<:item title="Email"><%= @attendee.email %></:item>
</.list>

<.back navigate={~p"/attendees"}>Back to attendees</.back>

<.modal :if={@live_action == :edit} id="attendee-modal" show on_cancel={JS.patch(~p"/attendees/#{@attendee}")}>
<.live_component
module={FieldsDemoWeb.AttendeeLive.FormComponent}
id={@attendee.id}
title={@page_title}
action={@live_action}
attendee={@attendee}
patch={~p"/attendees/#{@attendee}"}
/>
</.modal>
Loading

0 comments on commit 4701c18

Please sign in to comment.