Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cart in socket #44

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions lib/elixir_conf_africa/cart.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
defmodule ElixirConfAfrica.Cart do
@moduledoc """
The cart module
"""

alias ElixirConfAfrica.TicketTypes

@doc """
Returns the ids of all the cart items in a list



"""
def cart_list_ids(cart) do
cart |> Enum.map(fn cart_item -> cart_item.id end)
end

@doc """
Increases the quantity of a cart item given the cart item and the quantity to increase by

"""

def increase_cart_item_quantity(cart_item, quantity) do
cart_item
|> Map.put(:quantity, quantity)
end

@doc """
Adds a cart item to the cart given the cart and the cart item id to add

"""
def add_to_cart(cart, cart_item_id) do
cart_list_ids = cart_list_ids(cart)

case Enum.member?(cart_list_ids, cart_item_id) do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Case statement is overkill here. You can just use an if

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True , since it is either true or false

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to introduce styler, it auto corrects such https://github.com/adobe/elixir-styler

true ->
ticket_type = Enum.find(cart, fn item -> item.id == cart_item_id end)
updated_cart = get_updated_cart("in-cart", ticket_type, cart)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need to have a variable here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks , I have made this change

updated_cart

false ->
ticket_type = TicketTypes.get_ticket_type!(cart_item_id)
updated_cart = get_updated_cart("out-of-cart", ticket_type, cart)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need this variable. The return value of the function is enough

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks , I have fixed this

updated_cart
end
end

@doc """
Returns the updated cart for when a cart item already in the cart or out of the cart given the cart item and the cart

"""

def get_updated_cart("in-cart", cart_item, cart) do
cart_item_with_added_quantity =
add_quantity_to_cart_item(cart, cart_item, cart_item.quantity + 1)

cart
|> Enum.filter(fn item -> item.id != cart_item.id end)
|> Enum.concat([cart_item_with_added_quantity])
end

def get_updated_cart("out-of-cart", cart_item, cart) do
cart_item_with_default_quantity_of_one =
add_quantity_to_cart_item(cart, cart_item, 1)

[cart_item_with_default_quantity_of_one | cart]
end

@doc """
Returns the cart item with an increased quantity given the cart, the cart item and the quantity to increase by.
It also checks if the cart item is already in the cart and increases the quantity if it is.

"""
def add_quantity_to_cart_item(cart, cart_item, quantity) do
case cart |> Enum.filter(fn item -> item.id == cart_item.id end) do
[] ->
increase_cart_item_quantity(cart_item, quantity)

_ ->
cart
|> Enum.filter(fn item -> item.id == cart_item.id end)
|> Enum.map(fn item -> increase_cart_item_quantity(item, item.quantity + 1) end)
|> List.first()
end
end
end
5 changes: 5 additions & 0 deletions lib/elixir_conf_africa/ticket_types.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ defmodule ElixirConfAfrica.TicketTypes do
Repo.all(TicketType)
end

def add_quantity(ticket_type, quantity) do
ticket_type
|> Map.put(:quantity, quantity)
end

@doc """
Gets a single ticket_type.

Expand Down
36 changes: 29 additions & 7 deletions lib/elixir_conf_africa_web/live/home_live/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,45 @@ defmodule ElixirConfAfricaWeb.HomeLive.Index do
use ElixirConfAfricaWeb, :live_view
alias ElixirConfAfrica.Events

alias ElixirConfAfrica.Cart

def mount(_params, _session, socket) do
# these value are more static and we should find away of display this data to home page
event_name = "ElixirConf Africa #{get_current_year()}"
event_name = "ElixirConf Africa #{get_upcoming_year()}"

event =
Events.get_event_with_ticket_types_by_event_name(event_name)

available_ticket = Events.get_total_number_of_available_tickets(event_name)
available_tickets = Events.get_total_number_of_available_tickets(event_name)

{:ok,
socket
|> assign(:event, event)}
|> assign(available_ticket: available_ticket)
|> assign(:event, event)
|> assign(:cart, [])
|> assign(available_tickets: available_tickets)}
end

defp get_current_year do
defp get_upcoming_year do
%{year: year} = DateTime.utc_now()
year
year + 1
end

def handle_event("add_to_cart", %{"id" => id}, socket) do
cart_item_ids = Cart.cart_list_ids(socket.assigns.cart)

if Enum.member?(cart_item_ids, String.to_integer(id)) do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whats happening here? It seems whether this is true or false the item is still added to the cart and only the flash message is different

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How @okothkongo suggested we handle this is such that , if there is an item in the cart , and someone adds the same item to the cart , it updates the quantity of that item in the cart and updates the user that the quantity has been added as opposed to disabling the add to cart for an item already in the cart

updated_cart = Cart.add_to_cart(socket.assigns.cart, String.to_integer(id))

{:noreply,
socket
|> assign(:cart, updated_cart)
|> put_flash(:info, "Ticket already in cart , quantity increased by 1")}
else
updated_cart = Cart.add_to_cart(socket.assigns.cart, String.to_integer(id))

{:noreply,
socket
|> put_flash(:info, "Ticket added to cart")
|> assign(:cart, updated_cart)}
end
end
end
9 changes: 6 additions & 3 deletions lib/elixir_conf_africa_web/live/home_live/index.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@
</div>
</div>

<%!-- navbar --%>

<div class=" bg-[#F2F2F2]/50 py-12 pt-5">
<div class="w-[90%] flex mx-auto">
<div class="w-[100%] flex md:flex-row gap-8 flex-col justify-between items-start">
Expand Down Expand Up @@ -124,7 +122,12 @@
<div class="flex items-center justify-between w-[100%]">
<p class="poppins-bold text-xl">KSH <%= ticket_type.price %></p>
<div class="flex gap-3 poppins-regular items-center">
<button class="p-4 border-[1px] w-[73px] text-sm h-[34px] border-[#AD3989] text-[#AD3989] flex gap-2 items-center justify-center rounded-[4px]">
<button
phx-value-id={ticket_type.id}
id={"ticket_type-#{ticket_type.id}"}
phx-click="add_to_cart"
class="p-4 border-[1px] w-[73px] text-sm h-[34px] border-[#AD3989] text-[#AD3989] flex gap-2 items-center justify-center rounded-[4px]"
>
<p>+</p>
<p>Cart</p>
</button>
Expand Down
51 changes: 51 additions & 0 deletions test/elixir_conf_africa/cart_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
defmodule ElixirConfAfrica.CartTest do
use ElixirConfAfrica.DataCase
alias ElixirConfAfrica.Cart

describe "Cart Functionaity" do
import ElixirConfAfrica.Factory

setup do
event = insert!(:elixir_conf_event)
ticket_type = insert!(:elixir_conf_ticket_type, event_id: event.id)

[ticket_type: ticket_type]
end

test "cart_list_ids/1 returns all ids from the carts in a list" do
assert Cart.cart_list_ids([%{id: 1}, %{id: 2}]) == [1, 2]
end

test "increase_cart_item_quantity/2 increases the quantity of a cart item" do
assert Cart.increase_cart_item_quantity(%{quantity: 1}, 2) == %{quantity: 2}
end

test "add quantity to cart_item/3 returns the cart item with an increased quantity " do
assert Cart.add_quantity_to_cart_item([%{id: 1, quantity: 1}], %{id: 1, quantity: 1}, 2) ==
%{id: 1, quantity: 2}

assert Cart.add_quantity_to_cart_item([%{id: 1, quantity: 1}], %{id: 2}, 1) ==
%{id: 2, quantity: 1}
end

test "get_updated_cart/3 returns the updated cart" do
assert Cart.get_updated_cart("in-cart", %{id: 1, quantity: 1}, [%{id: 1, quantity: 1}]) ==
[%{id: 1, quantity: 2}]

assert Cart.get_updated_cart("out-of-cart", %{id: 2}, [%{id: 1, quantity: 1}]) ==
[%{id: 2, quantity: 1}, %{id: 1, quantity: 1}]
end

test "add_to_cart/2 adds an item to the cart", %{ticket_type: ticket_type} do
assert Cart.add_to_cart([%{id: 1, quantity: 1}, %{id: 2, quantity: 1}], 1) ==
[%{id: 2, quantity: 1}, %{id: 1, quantity: 2}]

assert Cart.add_to_cart([%{id: 1, quantity: 1}, %{id: 2, quantity: 1}], ticket_type.id) ==
[
ticket_type |> Map.put(:quantity, 1),
%{id: 1, quantity: 1},
%{id: 2, quantity: 1}
]
end
end
end
59 changes: 59 additions & 0 deletions test/elixir_conf_africa_web/live/home_live_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
defmodule ElixirConfAfricaWeb.HomeLiveTest do
use ElixirConfAfricaWeb.ConnCase

import Phoenix.LiveViewTest
import ElixirConfAfrica.Factory

setup do
event = insert!(:elixir_conf_event)
ticket_type = insert!(:elixir_conf_ticket_type, event_id: event.id)
%{ticket_type: ticket_type, event: event}
end

describe "Home Index" do
test "Displays the elixir conf website details", %{conn: conn, event: event} do
{:ok, _index_live, html} = live(conn, ~p"/home")

assert html =~ "Event Information"
assert html =~ event.name
assert html =~ event.description
assert html =~ event.location
end

test "Displays the tickets available", %{conn: conn, ticket_type: ticket_type} do
{:ok, _index_live, html} = live(conn, ~p"/home")

assert html =~ "Available Tickets"
assert html =~ ticket_type.name
assert html =~ ticket_type.description
end

test "There is an add to cart button", %{conn: conn} do
{:ok, _index_live, html} = live(conn, ~p"/home")

assert html =~ "Cart"
end

test "Clicking the add to cart button on a ticket type that is not in the cart adds it to the cart",
%{conn: conn, ticket_type: ticket_type} do
{:ok, index_live, _html} = live(conn, ~p"/home")

assert index_live
|> element("#ticket_type-#{ticket_type.id}")
|> render_click() =~ "Ticket added to cart"
end

test "Clicking the add to cart button on a ticket type that is not in the cart adds a quantity of 1 to the ticket type",
%{conn: conn, ticket_type: ticket_type} do
{:ok, index_live, _html} = live(conn, ~p"/home")

assert index_live
|> element("#ticket_type-#{ticket_type.id}")
|> render_click()

assert index_live
|> element("#ticket_type-#{ticket_type.id}")
|> render_click() =~ "Ticket already in cart , quantity increased by 1"
end
end
end
Loading