Skip to content

Instantly share code, notes, and snippets.

@benjamin-thomas
Last active August 18, 2022 19:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benjamin-thomas/53354549c2e15f02a6b89faf2ed16f58 to your computer and use it in GitHub Desktop.
Save benjamin-thomas/53354549c2e15f02a6b89faf2ed16f58 to your computer and use it in GitHub Desktop.
PragmaticStudio Elixir/Phoenix/LiveView solutions
defmodule LiveViewStudioWeb.AutocompleteLive do
use LiveViewStudioWeb, :live_view
alias LiveViewStudio.Stores
alias LiveViewStudio.Cities
def mount(_params, _session, socket) do
socket =
assign(socket,
zip: "",
city: "",
cities_suggestion: [],
stores: [],
loading: false
)
{:ok, socket}
end
def render(assigns) do
~H"""
<h1>Find a Store</h1>
<div id="search">
<form phx-submit="zip-search">
<input type="text" name="zip" value={@zip}
placeholder="Zip Code"
autocomplete="off"
readonly={@loading}
>
<button type="submit">
<img src="images/search.svg">
</button>
</form>
<form phx-change="suggest-cities" phx-submit="city-search">
<input type="text" name="city" value={@city}
autofocus
list="cities"
placeholder="City"
autocomplete="off"
phx-debounce="200"
>
<datalist id="cities">
<%= for city <- @cities_suggestion do %>
<option value={city}>
<% end %>
</datalist>
<button type="submit">
<img src="images/search.svg">
</button>
</form>
<%= if @loading do %>
<div class="loader">
Loading...
</div>
<% end %>
<div class="stores">
<ul>
<%= for store <- @stores do %>
<li>
<div class="first-line">
<div class="name">
<%= store.name %>
</div>
<div class="status">
<%= if store.open do %>
<span class="open">Open</span>
<% else %>
<span class="closed">Closed</span>
<% end %>
</div>
</div>
<div class="second-line">
<div class="street">
<img src="images/location.svg">
<%= store.street %>
</div>
<div class="phone_number">
<img src="images/phone.svg">
<%= store.phone_number %>
</div>
</div>
</li>
<% end %>
</ul>
</div>
</div>
"""
end
def handle_event("zip-search", %{"zip" => zip}, socket) do
send(self(), {:run_zip_search, zip})
socket =
assign(socket,
zip: zip,
city: "",
stores: [],
loading: true
)
{:noreply, socket}
end
def handle_event("suggest-cities", %{"city" => city}, socket) do
send(self(), {:suggest_cities, city})
socket =
assign(socket,
zip: "",
city: city,
stores: [],
loading: true
)
{:noreply, socket}
end
def handle_event("city-search", %{"city" => city}, socket) do
send(self(), {:run_city_search, city})
socket =
assign(socket,
city: city,
stores: [],
loading: true
)
{:noreply, socket}
end
def handle_info({:run_zip_search, zip}, socket) do
socket =
case Stores.search_by_zip(zip) do
[] = none ->
socket
|> put_flash(:info, "No stores matching \"#{zip}\"")
|> assign(stores: none, loading: false)
stores ->
assign(socket, stores: stores, loading: false)
end
{:noreply, socket}
end
def handle_info({:suggest_cities, prefix}, socket) do
socket =
case Cities.suggest(prefix) do
[] = none ->
socket
|> assign(cities_suggestion: none, loading: false)
cities ->
assign(socket, cities_suggestion: cities, loading: false)
end
{:noreply, socket}
end
def handle_info({:run_city_search, city}, socket) do
socket =
case Stores.search_by_city(city) do
[] = none ->
socket
|> put_flash(:info, "No stores matching \"#{city}\"")
|> assign(stores: none)
stores ->
assign(socket, stores: stores) |> clear_flash
end
|> assign(cities_suggestion: [], loading: false)
{:noreply, socket}
end
end
defmodule LiveViewStudioWeb.LightLive do
use LiveViewStudioWeb, :live_view
def mount(_params, _session, socket) do
socket =
socket
|> assign(:brightness, 10)
|> assign(:inc, 5)
{:ok, socket}
end
def handle_event("on", _, socket) do
socket = assign(socket, :brightness, 100)
{:noreply, socket}
end
def handle_event("off", _, socket) do
socket = assign(socket, :brightness, 0)
{:noreply, socket}
end
def handle_event("up", _, socket) do
# brightness = socket.assigns.brightness + 10
# socket = assign(socket, :brightness, brightness)
inc = socket.assigns.inc
IO.inspect("--> inc: #{inc}")
socket = update(socket, :brightness, fn n -> min(n + inc, 100) end)
{:noreply, socket}
end
def handle_event("down", _, socket) do
inc = socket.assigns.inc
socket = update(socket, :brightness, fn n -> max(n - inc, 0) end)
{:noreply, socket}
end
def handle_event("keyup", %{"key" => "ArrowUp"}, socket) do
handle_event("up", nil, socket)
end
def handle_event("keyup", %{"key" => "PageUp"}, socket) do
handle_event("on", nil, socket)
end
def handle_event("keyup", %{"key" => "ArrowDown"}, socket) do
handle_event("down", nil, socket)
end
def handle_event("keyup", %{"key" => "PageDown"}, socket) do
handle_event("off", nil, socket)
end
def handle_event("keyup", %{"key" => key}, socket) do
IO.inspect("NOOP for key: #{key}")
{:noreply, socket}
end
def handle_event("rand", _, socket) do
# socket = update(socket, :brightness, fn _ -> Enum.random(0..100) end)
socket = assign(socket, :brightness, Enum.random(0..100))
{:noreply, socket}
end
def handle_event("submit", %{"inc" => inc}, socket) do
{inc, ""} = Integer.parse(inc)
IO.inspect("--> inc: #{inc}")
{:noreply, assign(socket, :inc, inc)}
end
def render(assigns) do
~H"""
<h1>Front Porch Light</h1>
<div id="light" phx-window-keyup="keyup">
<div class="meter">
<span style={"width: #{@brightness}%"}>
<%= @brightness %>%
</span>
</div>
<button phx-click="off"><img src="images/light-off.svg"></button>
<button phx-click="down"><img src="images/down.svg"></button>
<button phx-click="up"><img src="images/up.svg"></button>
<button phx-click="on"><img src="images/light-on.svg"></button>
<br>
<button phx-click="rand">RAND</button>
<br>
<form phx-change="submit">
<!--
<input name="inc" type="number" min="1" max="10" value={@inc}>
-->
<select name="inc">
<%= for i <- [1,5,10] do %>
<option
selected={if i==@inc do "" else nil end}
value={i}>
<%= i %>
</option>
<% end %>
</select>
</form>
<p>Increase by <%= @inc %></p>
</div>
"""
end
end
defmodule LiveViewStudioWeb.LicenseLive do
use LiveViewStudioWeb, :live_view
alias LiveViewStudio.Licenses
import Number.Currency
def mount(_params, _session, socket) do
seats = 2
socket = assign(socket, seats: seats, amount: Licenses.calculate(seats))
{:ok, socket}
end
def handle_event("change", %{"seats" => seats}, socket) do
seats = String.to_integer(seats)
socket = assign(socket, seats: seats, amount: Licenses.calculate(seats))
{:noreply, socket}
end
def render(assigns) do
~H"""
<h1>Team Licenses</h1>
<div id="license">
<div class="card">
<div class="content">
<div class="seats">
<img src="images/license.svg" alt="">
<span>
Your license is currently for <strong><%= @seats %></strong> seats.
</span>
</div>
<form phx-change="change">
<input type="range" min="1" max="10" name="seats" value={@seats}>
</form>
<div class="amount">
<%= number_to_currency @amount %>
</div>
</div>
</div>
</div>
"""
end
end
defmodule LiveViewStudioWeb.FilterLive do
use LiveViewStudioWeb, :live_view
alias LiveViewStudio.Boats
def mount(_params, _session, socket) do
socket = init(socket)
{:ok, socket, temporary_assigns: [boats: []]}
end
def render(assigns) do
~H"""
<h1>Daily Boat Rentals</h1>
<div id="filter">
<form phx-change="filter">
<div class="filters">
<select name="type" id="type">
<%= options_for_select(type_options(), @type) %>
</select>
<div class="prices">
<%= for price <- ["$", "$$", "$$$"] do %>
<%= price_checkbox(%{price: price, checked: price in @prices}) %>
<% end %>
</div>
<a phx-click="clear-all" href="javascript:void(0)">Clear All</a>
</div>
</form>
<div class="boats">
<%= for boat <- @boats do %>
<div class="card">
<img src={boat.image} alt="boat">
<div class="content">
<div class="model"><%= boat.model %></div>
<div class="details">
<span class="price"><%= boat.price %></span>
<span class="type"><%= boat.type %></span>
</div>
</div>
</div>
<% end %>
</div>
</div>
"""
end
def handle_event("filter", %{"type" => type, "prices" => prices}, socket) do
params = [type: type, prices: prices]
boats = Boats.list_boats(params)
socket = assign(socket, params ++ [boats: boats])
{:noreply, socket}
end
def handle_event("filter", %{"type" => type}, socket) do
handle_event("filter", %{"type" => type, "prices" => []}, socket)
end
def handle_event("clear-all", _, socket) do
socket = init(socket)
{:noreply, socket}
end
defp init(socket) do
assign(socket,
boats: Boats.list_boats(),
type: "",
prices: []
)
end
defp type_options do
[
"All types": "",
Fishing: "fishing",
Sporting: "sporting",
Sailing: "sailing"
]
end
defp price_checkbox(assigns) do
~H"""
<input
checked={@checked}
type="checkbox" name="prices[]" id={@price} value={@price}>
<label for={@price}><%= @price %></label>
"""
end
end
defmodule LiveViewStudioWeb.FlightsLive do
use LiveViewStudioWeb, :live_view
alias LiveViewStudio.Flights
def mount(_params, _session, socket) do
socket =
assign(socket,
loading: false,
q: "",
flights: Flights.list_flights()
)
{:ok, socket}
end
def handle_event("submit", %{"q" => q}, socket) do
send(self(), {:search_flights2, q})
socket =
assign(socket,
loading: true,
q: q,
flights: []
)
{:noreply, socket}
end
def handle_info({:search_flights, number}, socket) do
flights = Flights.search_by_number(number)
socket =
assign(socket,
loading: false,
flights: flights
)
socket =
if flights == [] do
put_flash(socket, :error, "No flights found with that number")
else
clear_flash(socket)
end
{:noreply, socket}
end
def handle_info({:search_flights2, number}, socket) do
socket =
case Flights.search_by_number(number) do
[] = empty ->
socket
|> put_flash(:info, "No flights found with number \"#{number}\"")
|> assign(flights: empty, loading: false)
flights ->
socket
|> clear_flash()
|> assign(flights: flights, loading: false)
end
{:noreply, socket}
end
def render(assigns) do
~H"""
<h1>Find a Flight</h1>
<div id="search">
<!-- NOTE: autofocus keeps working only if set before any assigns -->
<form phx-submit="submit" autocomplete="off">
<input type="text" name="q" value={@q} readonly={@loading} autofocus>
<button type="submit">
<img src="images/search.svg" alt="search">
</button>
</form>
<%= if @loading do %>
<div class="loader">Loading...</div>
<% end %>
<div class="flights">
<ul>
<%= for flight <- @flights do %>
<li>
<div class="first-line">
<div class="number">
Flight #<%= flight.number %>
</div>
<div class="origin-destination">
<img src="images/location.svg">
<%= flight.origin %> to
<%= flight.destination %>
</div>
</div>
<div class="second-line">
<div class="departs">
Departs: <%= flight.departure_time |> format_time %>
</div>
<div class="arrives">
Arrives: <%= flight.arrival_time |> format_time %>
</div>
</div>
</li>
<% end %>
</ul>
</div>
</div>
"""
end
defp format_time(time) do
Timex.format!(time, "%b %d at %H:%M", :strftime)
end
end
defmodule LiveViewStudioWeb.LightLive do
use LiveViewStudioWeb, :live_view
def mount(_params, _session, socket) do
socket =
socket
|> assign(:brightness, 10)
|> assign(:inc, 5)
|> assign(:temp, "4000")
{:ok, socket}
end
def handle_event("on", _, socket) do
socket = assign(socket, :brightness, 100)
{:noreply, socket}
end
def handle_event("off", _, socket) do
socket = assign(socket, :brightness, 0)
{:noreply, socket}
end
def handle_event("up", _, socket) do
# brightness = socket.assigns.brightness + 10
# socket = assign(socket, :brightness, brightness)
inc = socket.assigns.inc
IO.inspect("--> inc: #{inc}")
socket = update(socket, :brightness, fn n -> min(n + inc, 100) end)
{:noreply, socket}
end
def handle_event("down", _, socket) do
inc = socket.assigns.inc
socket = update(socket, :brightness, fn n -> max(n - inc, 0) end)
{:noreply, socket}
end
def handle_event("keyup", %{"key" => "ArrowUp"}, socket) do
handle_event("up", nil, socket)
end
def handle_event("keyup", %{"key" => "PageUp"}, socket) do
handle_event("on", nil, socket)
end
def handle_event("keyup", %{"key" => "ArrowDown"}, socket) do
handle_event("down", nil, socket)
end
def handle_event("keyup", %{"key" => "PageDown"}, socket) do
handle_event("off", nil, socket)
end
def handle_event("keyup", %{"key" => key}, socket) do
IO.inspect("NOOP for key: #{key}")
{:noreply, socket}
end
def handle_event("rand", _, socket) do
# socket = update(socket, :brightness, fn _ -> Enum.random(0..100) end)
socket = assign(socket, :brightness, Enum.random(0..100))
{:noreply, socket}
end
def handle_event("submit", %{"inc" => inc}, socket) do
{inc, ""} = Integer.parse(inc)
IO.inspect("--> inc: #{inc}")
{:noreply, assign(socket, :inc, inc)}
end
def handle_event("change-temp", %{"temp" => temp}, socket) do
socket = assign(socket, temp: temp)
{:noreply, socket}
end
def render(assigns) do
~H"""
<h1>Front Porch Light</h1>
<div id="light" phx-window-keyup="keyup">
<div class="meter">
<span style={"width: #{@brightness}%;background-color:#{temp_color(@temp)}"}>
<%= @brightness %>%
</span>
</div>
<button phx-click="off"><img src="images/light-off.svg"></button>
<button phx-click="down"><img src="images/down.svg"></button>
<button phx-click="up"><img src="images/up.svg"></button>
<button phx-click="on"><img src="images/light-on.svg"></button>
<br>
<button phx-click="rand">RAND</button>
<br>
<form phx-change="submit">
<!--
<input name="inc" type="number" min="1" max="10" value={@inc}>
-->
<select name="inc">
<%= for i <- [1,5,10] do %>
<option
selected={if i==@inc do "" else nil end}
value={i}>
<%= i %>
</option>
<% end %>
</select>
</form>
<p>Increase by <%= @inc %></p>
<form phx-change="change-temp">
<%= for color <- ["3000", "4000", "5000"] do %>
<%= temp_radio_button(%{color: color, checked: @temp == color}) %>
<% end %>
</form>
</div>
"""
end
# Write a function named temp_radio_button that generates a radio button and label combo.
defp temp_radio_button(assigns) do
~H"""
<input type="radio" id={@color} name="temp" value={@color} checked={@checked}>
<label for={@color}><%= @color %></label>
"""
end
defp temp_color("3000"), do: "#F1C40D"
defp temp_color("4000"), do: "#FEFF66"
defp temp_color("5000"), do: "#99CCFF"
end
defmodule LiveViewStudioWeb.SalesDashboard do
use LiveViewStudioWeb, :live_view
alias LiveViewStudio.Sales
def mount(_params, _session, socket) do
if connected?(socket) do
:timer.send_interval(2000, self(), :tick)
end
{:ok, assign_stats(socket)}
end
def handle_event("refresh", _, socket) do
{:noreply, assign_stats(socket)}
end
def handle_info(:tick, socket) do
handle_event("refresh", nil, socket)
end
def render(assigns) do
~H"""
<h1>Sales Dashboard</h1>
<div id="dashboard">
<div class="stats">
<div class="stat">
<span class="value"><%= @new_orders %></span>
<span class="name">New Orders</span>
</div>
<div class="stat">
<span class="value"><%= @sales_amount %></span>
<span class="name">Sales Amount</span>
</div>
<div class="stat">
<span class="value"><%= @satisfaction %></span>
<span class="name">Satisfaction</span>
</div>
</div>
<button phx-click="refresh">
<img src="images/refresh.svg" alt="Refresh button">
Refresh
</button>
</div>
"""
end
defp assign_stats(socket) do
assign(socket,
new_orders: Sales.new_orders(),
sales_amount: Sales.sales_amount(),
satisfaction: Sales.satisfaction()
)
end
end
defmodule LiveViewStudioWeb.SearchLive do
use LiveViewStudioWeb, :live_view
alias LiveViewStudio.Stores
def mount(_params, _session, socket) do
socket = assign(socket, loading: false, zip: "", stores: [])
{:ok, socket}
end
def handle_event("zip-search", %{"zip" => zip}, socket) do
send(self(), {:zip_search, zip})
socket = assign(socket, zip: zip, loading: true, stores: [])
{:noreply, socket}
end
def handle_info({:zip_search, zip}, socket) do
stores = Stores.search_by_zip(zip)
socket =
if stores == [] do
put_flash(
socket,
:error,
"Oops, je n'ai pas trouvé de resto avec le code postal \"#{zip}\" !"
)
else
socket |> clear_flash()
end
{:noreply, assign(socket, stores: stores, loading: false)}
end
def render(assigns) do
~H"""
<h1>Find a store</h1>
<div id="search">
<form phx-submit="zip-search" autocomplete="off">
<input type="text" name="zip" placeholder="Zip Code - e.g. 59602, 80204"
value={@zip}
readonly={@loading}
autofocus>
<button type="submit">
<img src="images/search.svg" alt="search icon">
</button>
</form>
<%= if @loading do %>
<div class="loader">
Loading...
</div>
<% end %>
<div class="stores">
<ul>
<%= for store <- @stores do %>
<li>
<div class="first-line">
<div class="name">
<%= store.name %>
</div>
</div>
<div class="status">
<%= if store.open do %>
<span class="open">Open</span>
<% else %>
<span class="closed">Closed</span>
<% end %>
</div>
<div class="second-line">
<div class="street">
<img src="images/location.svg" alt="location">
<%= store.street %>
</div>
<div class="phone_number">
<img src="images/phone.svg" alt="phone">
<%= store.phone_number %>
</div>
</div>
</li>
<% end %>
</ul>
</div>
</div>
"""
end
end
defmodule LiveViewStudioWeb.ServersLive do
use LiveViewStudioWeb, :live_view
alias LiveViewStudio.Servers
def mount(_params, _session, socket) do
servers = Servers.list_servers()
socket =
assign(socket,
servers: servers,
selected_server: hd(servers)
)
{:ok, socket}
end
def handle_event("show", %{"id" => id}, socket) do
id = String.to_integer(id)
server = Servers.get_server!(id)
socket = assign(socket, selected_server: server, page_title: "SRV: #{server.name}")
{:noreply, socket}
end
# `handle_params` is invoked after `mount` and each time `live_patch` is used
def handle_params(%{"id" => _id} = params, _url, socket) do
handle_event("show", params, socket)
end
def handle_params(_params, _url, socket) do
{:noreply, socket}
end
def render(assigns) do
~H"""
<h1>Servers</h1>
<div id="servers">
<div class="sidebar">
<nav>
<%= for server <- @servers do %>
<!--
<a href="#" phx-click="show" phx-value-id={server.id} class={if server == @selected_server, do: "active"}">
<img src="/images/server.svg">
<#%= server.name %>
</a>
-->
<div>
<%= live_patch link_body(%{name: server.name}),
to: Routes.live_path(@socket, __MODULE__, id: server.id),
class: if server == @selected_server, do: "active"
%>
</div>
<% end %>
</nav>
</div>
<div class="main">
<div class="wrapper">
<div class="card">
<div class="header">
<h2><%= @selected_server.name %></h2>
<span class={@selected_server.status}>
<%= @selected_server.status %>
</span>
</div>
<div class="body">
<div class="row">
<div class="deploys">
<img src="/images/deploy.svg">
<span>
<%= @selected_server.deploy_count %> deploys
</span>
</div>
<span>
<%= @selected_server.size %> MB
</span>
<span>
<%= @selected_server.framework %>
</span>
</div>
<h3>Git Repo</h3>
<div class="repo">
<%= @selected_server.git_repo %>
</div>
<h3>Last Commit</h3>
<div class="commit">
<%= @selected_server.last_commit_id %>
</div>
<blockquote>
<%= @selected_server.last_commit_message %>
</blockquote>
</div>
</div>
</div>
</div>
</div>
"""
end
defp link_body(assigns) do
~H"""
<img src="/images/server.svg">
<%= @name %>
"""
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment