-
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.
* feat: logic for handling cart items + tests * fix: remove console log * feat: Implementing GenServer, caching for cart + tests * feat: cart item live view * feat: add items to cart + tests
- Loading branch information
1 parent
c4e0cd7
commit d45d5c0
Showing
25 changed files
with
772 additions
and
62 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
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 |
---|---|---|
@@ -1,7 +1,9 @@ | ||
import LoadMoreProducts from "./hooks/loadMoreProducts" | ||
import CartSession from "./hooks/cartSession" | ||
|
||
let Hooks = { | ||
LoadMoreProducts: LoadMoreProducts | ||
LoadMoreProducts: LoadMoreProducts, | ||
CartSession: CartSession | ||
} | ||
|
||
export default Hooks |
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,10 @@ | ||
const CartSession = { | ||
mounted(){ | ||
this.handleEvent("create_cart_session_id", map => { | ||
var {cart_id: cart_id} = map; | ||
sessionStorage.setItem("cart_id", cart_id); | ||
}) | ||
} | ||
} | ||
|
||
export default CartSession; |
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
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
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,10 @@ | ||
defmodule FoodOrder.Carts do | ||
@name :cart_session | ||
|
||
def create(cart_id), do: GenServer.cast(@name, {:create, cart_id}) | ||
def add(cart_id, product), do: GenServer.cast(@name, {:add, cart_id, product}) | ||
def get(cart_id), do: GenServer.call(@name, {:get, cart_id}) | ||
def increment(cart_id, product_id), do: GenServer.call(@name, {:increment, cart_id, product_id}) | ||
def decrement(cart_id, product_id), do: GenServer.call(@name, {:decrement, cart_id, product_id}) | ||
def remove(cart_id, product_id), do: GenServer.call(@name, {:remove, cart_id, product_id}) | ||
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,156 @@ | ||
defmodule FoodOrder.Carts.Core.HandleCarts do | ||
alias FoodOrder.Carts.Data.Cart | ||
|
||
@doc """ | ||
Create a new cart session | ||
## Examples | ||
iex> FoodOrder.Carts.Core.HandleCarts.create(444_444) | ||
%Cart{ | ||
id: 444_444, | ||
items: [], | ||
total_price: %Money{amount: 0, currency: :USD}, | ||
total_qty: 0 | ||
} | ||
""" | ||
def create(cart_id) do | ||
Cart.new(cart_id) | ||
end | ||
|
||
@doc """ | ||
Add a new item to the cart | ||
## Examples | ||
iex> FoodOrder.Carts.Core.HandleCarts.add(cart, product) | ||
%Cart{ | ||
id: 444_444, | ||
items: [%{item: product, qty: 1}], | ||
total_price: product.price, | ||
total_qty: 1 | ||
} | ||
""" | ||
def add(cart, item) do | ||
new_total_price = Money.add(cart.total_price, item.price) | ||
new_items = new_item(cart.items, item) | ||
|
||
%{ | ||
cart | ||
| total_qty: cart.total_qty + 1, | ||
items: new_items, | ||
total_price: new_total_price | ||
} | ||
end | ||
|
||
defp new_item(items, item) do | ||
is_there_item_id? = Enum.find(items, &(item.id == &1.item.id)) | ||
|
||
if is_there_item_id? == nil do | ||
items ++ [%{item: item, qty: 1}] | ||
else | ||
items | ||
|> Map.new(fn item -> {item.item.id, item} end) | ||
|> Map.update!(item.id, &%{&1 | qty: &1.qty + 1}) | ||
|> Map.values() | ||
end | ||
end | ||
|
||
@doc """ | ||
Remove an item from the cart | ||
## Examples | ||
iex> FoodOrder.Carts.Core.HandleCarts.remove(cart, product.id) | ||
%Cart{ | ||
id: 444_444, | ||
items: [%{item: product, qty: 1}], | ||
total_price: product.price, | ||
total_qty: 1 | ||
} | ||
""" | ||
def remove(cart, item_id) do | ||
{items, item_removed} = Enum.reduce(cart.items, {[], nil}, &remove_item(&1, &2, item_id)) | ||
total_price_to_deduct = Money.multiply(item_removed.item.price, item_removed.qty) | ||
total_price = Money.subtract(cart.total_price, total_price_to_deduct) | ||
|
||
%{cart | items: items, total_qty: cart.total_qty - item_removed.qty, total_price: total_price} | ||
end | ||
|
||
defp remove_item(item, acc, item_id) do | ||
{list, item_acc} = acc | ||
|
||
if item.item.id == item_id do | ||
{list, item} | ||
else | ||
{[item | list], item_acc} | ||
end | ||
end | ||
|
||
@doc """ | ||
Increment an item from the cart | ||
## Examples | ||
iex> FoodOrder.Carts.Core.HandleCarts.increment(cart, product.id) | ||
%Cart{ | ||
id: 444_444, | ||
items: [%{item: product, qty: 2}], | ||
total_price: product.price, | ||
total_qty: 2 | ||
} | ||
""" | ||
def increment(%{items: items} = cart, item_id) do | ||
{items_updated, product} = | ||
Enum.reduce(items, {[], nil}, fn item_detail, acc -> | ||
{list, item} = acc | ||
|
||
if item_detail.item.id == item_id do | ||
updated_item = %{item_detail | qty: item_detail.qty + 1} | ||
item_updated = [updated_item] | ||
{list ++ item_updated, updated_item} | ||
else | ||
{[item_detail | list], item} | ||
end | ||
end) | ||
|
||
total_price = Money.add(cart.total_price, product.item.price) | ||
%{cart | items: items_updated, total_qty: cart.total_qty + 1, total_price: total_price} | ||
end | ||
|
||
@doc """ | ||
Decrement an item from the cart | ||
## Examples | ||
iex> FoodOrder.Carts.Core.HandleCarts.decrement(cart, product.id) | ||
%Cart{ | ||
id: 444_444, | ||
items: [%{item: product, qty: 1}], | ||
total_price: product.price, | ||
total_qty: 1 | ||
} | ||
""" | ||
def decrement(%{items: items} = cart, item_id) do | ||
{items_updated, product} = | ||
Enum.reduce(items, {[], nil}, fn item_detail, acc -> | ||
{list, item} = acc | ||
|
||
if item_detail.item.id == item_id do | ||
updated_item = %{item_detail | qty: item_detail.qty - 1} | ||
|
||
if updated_item.qty == 0 do | ||
{list, updated_item} | ||
else | ||
item_updated = [updated_item] | ||
{list ++ item_updated, updated_item} | ||
end | ||
else | ||
{[item_detail | list], item} | ||
end | ||
end) | ||
|
||
total_price = Money.subtract(cart.total_price, product.item.price) | ||
%{cart | items: items_updated, total_qty: cart.total_qty - 1, total_price: total_price} | ||
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,8 @@ | ||
defmodule FoodOrder.Carts.Data.Cart do | ||
defstruct id: nil, | ||
items: [], | ||
total_price: Money.new(0), | ||
total_qty: 0 | ||
|
||
def new(id), do: %__MODULE__{id: id} | ||
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,64 @@ | ||
defmodule FoodOrder.Carts.Server.CartSession do | ||
use GenServer | ||
|
||
import FoodOrder.Carts.Core.HandleCarts | ||
|
||
@name :cart_session | ||
|
||
def start_link(_), do: GenServer.start_link(__MODULE__, @name, name: @name) | ||
|
||
def init(name) do | ||
:ets.new(name, [:set, :public, :named_table]) | ||
{:ok, name} | ||
end | ||
|
||
def handle_cast({:create, cart_id}, name) do | ||
case find_cart(name, cart_id) do | ||
{:error, []} -> :ets.insert(name, {cart_id, create(cart_id)}) | ||
{:ok, _cart} -> :ok | ||
end | ||
|
||
{:noreply, name} | ||
end | ||
|
||
def handle_cast({:add, cart_id, product}, name) do | ||
{:ok, cart} = find_cart(name, cart_id) | ||
cart = add(cart, product) | ||
:ets.insert(name, {cart_id, cart}) | ||
|
||
{:noreply, name} | ||
end | ||
|
||
def handle_call({:get, cart_id}, _from, name) do | ||
{:ok, cart} = find_cart(name, cart_id) | ||
{:reply, cart, name} | ||
end | ||
|
||
def handle_call({:increment, cart_id, product_id}, _from, name) do | ||
{:ok, cart} = find_cart(name, cart_id) | ||
cart = increment(cart, product_id) | ||
:ets.insert(name, {cart_id, cart}) | ||
{:reply, cart, name} | ||
end | ||
|
||
def handle_call({:decrement, cart_id, product_id}, _from, name) do | ||
{:ok, cart} = find_cart(name, cart_id) | ||
cart = decrement(cart, product_id) | ||
:ets.insert(name, {cart_id, cart}) | ||
{:reply, cart, name} | ||
end | ||
|
||
def handle_call({:remove, cart_id, product_id}, _from, name) do | ||
{:ok, cart} = find_cart(name, cart_id) | ||
cart = remove(cart, product_id) | ||
:ets.insert(name, {cart_id, cart}) | ||
{:reply, cart, name} | ||
end | ||
|
||
defp find_cart(name, cart_id) do | ||
case :ets.lookup(name, cart_id) do | ||
[] -> {:error, []} | ||
[{_cart_id, cart}] -> {:ok, cart} | ||
end | ||
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
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
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
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 |
---|---|---|
@@ -1,7 +1,7 @@ | ||
<section class="py-16" data-role="cart"> | ||
<%= if @total_quantity == 0 do %> | ||
<%= if @cart.total_qty == 0 do %> | ||
<.empty_cart /> | ||
<% else %> | ||
<.live_component module={Details} id="cart-details" /> | ||
<.live_component module={Details} id="cart-details" cart={@cart} /> | ||
<% end %> | ||
</section> |
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
defmodule FoodOrderWeb.CartLive.Details do | ||
use FoodOrderWeb, :live_component | ||
alias __MODULE__.Item | ||
end |
Oops, something went wrong.