-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
581 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
defmodule Pento.Catalog do | ||
@moduledoc """ | ||
The Catalog context. | ||
""" | ||
|
||
import Ecto.Query, warn: false | ||
alias Pento.Repo | ||
|
||
alias Pento.Catalog.Product | ||
|
||
@doc """ | ||
Returns the list of products. | ||
## Examples | ||
iex> list_products() | ||
[%Product{}, ...] | ||
""" | ||
def list_products do | ||
Repo.all(Product) | ||
end | ||
|
||
@doc """ | ||
Gets a single product. | ||
Raises `Ecto.NoResultsError` if the Product does not exist. | ||
## Examples | ||
iex> get_product!(123) | ||
%Product{} | ||
iex> get_product!(456) | ||
** (Ecto.NoResultsError) | ||
""" | ||
def get_product!(id), do: Repo.get!(Product, id) | ||
|
||
@doc """ | ||
Creates a product. | ||
## Examples | ||
iex> create_product(%{field: value}) | ||
{:ok, %Product{}} | ||
iex> create_product(%{field: bad_value}) | ||
{:error, %Ecto.Changeset{}} | ||
""" | ||
def create_product(attrs \\ %{}) do | ||
%Product{} | ||
|> Product.changeset(attrs) | ||
|> Repo.insert() | ||
end | ||
|
||
@doc """ | ||
Updates a product. | ||
## Examples | ||
iex> update_product(product, %{field: new_value}) | ||
{:ok, %Product{}} | ||
iex> update_product(product, %{field: bad_value}) | ||
{:error, %Ecto.Changeset{}} | ||
""" | ||
def update_product(%Product{} = product, attrs) do | ||
product | ||
|> Product.changeset(attrs) | ||
|> Repo.update() | ||
end | ||
|
||
@doc """ | ||
Deletes a product. | ||
## Examples | ||
iex> delete_product(product) | ||
{:ok, %Product{}} | ||
iex> delete_product(product) | ||
{:error, %Ecto.Changeset{}} | ||
""" | ||
def delete_product(%Product{} = product) do | ||
Repo.delete(product) | ||
end | ||
|
||
@doc """ | ||
Returns an `%Ecto.Changeset{}` for tracking product changes. | ||
## Examples | ||
iex> change_product(product) | ||
%Ecto.Changeset{data: %Product{}} | ||
""" | ||
def change_product(%Product{} = product, attrs \\ %{}) do | ||
Product.changeset(product, attrs) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
defmodule Pento.Catalog.Product do | ||
use Ecto.Schema | ||
import Ecto.Changeset | ||
|
||
schema "products" do | ||
field :name, :string | ||
field :description, :string | ||
field :unit_price, :float | ||
field :sku, :integer | ||
|
||
timestamps(type: :utc_datetime) | ||
end | ||
|
||
@doc false | ||
def changeset(product, attrs) do | ||
product | ||
|> cast(attrs, [:name, :description, :unit_price, :sku]) | ||
|> validate_required([:name, :description, :unit_price, :sku]) | ||
|> unique_constraint(:sku) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
defmodule PentoWeb.ProductLive.FormComponent do | ||
use PentoWeb, :live_component | ||
|
||
alias Pento.Catalog | ||
|
||
@impl true | ||
def render(assigns) do | ||
~H""" | ||
<div> | ||
<.header> | ||
<%= @title %> | ||
<:subtitle>Use this form to manage product records in your database.</:subtitle> | ||
</.header> | ||
<.simple_form | ||
for={@form} | ||
id="product-form" | ||
phx-target={@myself} | ||
phx-change="validate" | ||
phx-submit="save" | ||
> | ||
<.input field={@form[:name]} type="text" label="Name" /> | ||
<.input field={@form[:description]} type="text" label="Description" /> | ||
<.input field={@form[:unit_price]} type="number" label="Unit price" step="any" /> | ||
<.input field={@form[:sku]} type="number" label="Sku" /> | ||
<:actions> | ||
<.button phx-disable-with="Saving...">Save Product</.button> | ||
</:actions> | ||
</.simple_form> | ||
</div> | ||
""" | ||
end | ||
|
||
@impl true | ||
def update(%{product: product} = assigns, socket) do | ||
changeset = Catalog.change_product(product) | ||
|
||
{:ok, | ||
socket | ||
|> assign(assigns) | ||
|> assign_form(changeset)} | ||
end | ||
|
||
@impl true | ||
def handle_event("validate", %{"product" => product_params}, socket) do | ||
changeset = | ||
socket.assigns.product | ||
|> Catalog.change_product(product_params) | ||
|> Map.put(:action, :validate) | ||
|
||
{:noreply, assign_form(socket, changeset)} | ||
end | ||
|
||
def handle_event("save", %{"product" => product_params}, socket) do | ||
save_product(socket, socket.assigns.action, product_params) | ||
end | ||
|
||
defp save_product(socket, :edit, product_params) do | ||
case Catalog.update_product(socket.assigns.product, product_params) do | ||
{:ok, product} -> | ||
notify_parent({:saved, product}) | ||
|
||
{:noreply, | ||
socket | ||
|> put_flash(:info, "Product updated successfully") | ||
|> push_patch(to: socket.assigns.patch)} | ||
|
||
{:error, %Ecto.Changeset{} = changeset} -> | ||
{:noreply, assign_form(socket, changeset)} | ||
end | ||
end | ||
|
||
defp save_product(socket, :new, product_params) do | ||
case Catalog.create_product(product_params) do | ||
{:ok, product} -> | ||
notify_parent({:saved, product}) | ||
|
||
{:noreply, | ||
socket | ||
|> put_flash(:info, "Product 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
defmodule PentoWeb.ProductLive.Index do | ||
use PentoWeb, :live_view | ||
|
||
alias Pento.Catalog | ||
alias Pento.Catalog.Product | ||
|
||
@impl true | ||
def mount(_params, _session, socket) do | ||
{:ok, stream(socket, :products, Catalog.list_products())} | ||
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 Product") | ||
|> assign(:product, Catalog.get_product!(id)) | ||
end | ||
|
||
defp apply_action(socket, :new, _params) do | ||
socket | ||
|> assign(:page_title, "New Product") | ||
|> assign(:product, %Product{}) | ||
end | ||
|
||
defp apply_action(socket, :index, _params) do | ||
socket | ||
|> assign(:page_title, "Listing Products") | ||
|> assign(:product, nil) | ||
end | ||
|
||
@impl true | ||
def handle_info({PentoWeb.ProductLive.FormComponent, {:saved, product}}, socket) do | ||
{:noreply, stream_insert(socket, :products, product)} | ||
end | ||
|
||
@impl true | ||
def handle_event("delete", %{"id" => id}, socket) do | ||
product = Catalog.get_product!(id) | ||
{:ok, _} = Catalog.delete_product(product) | ||
|
||
{:noreply, stream_delete(socket, :products, product)} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<.header> | ||
Listing Products | ||
<:actions> | ||
<.link patch={~p"/products/new"}> | ||
<.button>New Product</.button> | ||
</.link> | ||
</:actions> | ||
</.header> | ||
|
||
<.table | ||
id="products" | ||
rows={@streams.products} | ||
row_click={fn {_id, product} -> JS.navigate(~p"/products/#{product}") end} | ||
> | ||
<:col :let={{_id, product}} label="Name"><%= product.name %></:col> | ||
<:col :let={{_id, product}} label="Description"><%= product.description %></:col> | ||
<:col :let={{_id, product}} label="Unit price"><%= product.unit_price %></:col> | ||
<:col :let={{_id, product}} label="Sku"><%= product.sku %></:col> | ||
<:action :let={{_id, product}}> | ||
<div class="sr-only"> | ||
<.link navigate={~p"/products/#{product}"}>Show</.link> | ||
</div> | ||
<.link patch={~p"/products/#{product}/edit"}>Edit</.link> | ||
</:action> | ||
<:action :let={{id, product}}> | ||
<.link | ||
phx-click={JS.push("delete", value: %{id: product.id}) |> hide("##{id}")} | ||
data-confirm="Are you sure?" | ||
> | ||
Delete | ||
</.link> | ||
</:action> | ||
</.table> | ||
|
||
<.modal :if={@live_action in [:new, :edit]} id="product-modal" show on_cancel={JS.patch(~p"/products")}> | ||
<.live_component | ||
module={PentoWeb.ProductLive.FormComponent} | ||
id={@product.id || :new} | ||
title={@page_title} | ||
action={@live_action} | ||
product={@product} | ||
patch={~p"/products"} | ||
/> | ||
</.modal> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
defmodule PentoWeb.ProductLive.Show do | ||
use PentoWeb, :live_view | ||
|
||
alias Pento.Catalog | ||
|
||
@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(:product, Catalog.get_product!(id))} | ||
end | ||
|
||
defp page_title(:show), do: "Show Product" | ||
defp page_title(:edit), do: "Edit Product" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<.header> | ||
Product <%= @product.id %> | ||
<:subtitle>This is a product record from your database.</:subtitle> | ||
<:actions> | ||
<.link patch={~p"/products/#{@product}/show/edit"} phx-click={JS.push_focus()}> | ||
<.button>Edit product</.button> | ||
</.link> | ||
</:actions> | ||
</.header> | ||
|
||
<.list> | ||
<:item title="Name"><%= @product.name %></:item> | ||
<:item title="Description"><%= @product.description %></:item> | ||
<:item title="Unit price"><%= @product.unit_price %></:item> | ||
<:item title="Sku"><%= @product.sku %></:item> | ||
</.list> | ||
|
||
<.back navigate={~p"/products"}>Back to products</.back> | ||
|
||
<.modal :if={@live_action == :edit} id="product-modal" show on_cancel={JS.patch(~p"/products/#{@product}")}> | ||
<.live_component | ||
module={PentoWeb.ProductLive.FormComponent} | ||
id={@product.id} | ||
title={@page_title} | ||
action={@live_action} | ||
product={@product} | ||
patch={~p"/products/#{@product}"} | ||
/> | ||
</.modal> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
defmodule Pento.Repo.Migrations.CreateProducts do | ||
use Ecto.Migration | ||
|
||
def change do | ||
create table(:products) do | ||
add :name, :string | ||
add :description, :string | ||
add :unit_price, :float | ||
add :sku, :integer | ||
|
||
timestamps(type: :utc_datetime) | ||
end | ||
|
||
create unique_index(:products, [:sku]) | ||
end | ||
end |
Oops, something went wrong.