diff --git a/lib/banchan/offerings/offering.ex b/lib/banchan/offerings/offering.ex index 72c56e848..d739c237f 100644 --- a/lib/banchan/offerings/offering.ex +++ b/lib/banchan/offerings/offering.ex @@ -31,7 +31,8 @@ defmodule Banchan.Offerings.Offering do field :currency, Ecto.Enum, values: Studios.Common.supported_currencies() field :deleted_at, :naive_datetime - field :option_prices, {:array, Money.Ecto.Composite.Type}, virtual: true + field :base_price, Money.Ecto.Composite.Type, virtual: true + field :has_addons, :boolean, virtual: true field :used_slots, :integer, virtual: true field :user_subscribed?, :boolean, virtual: true field :gallery_uploads, {:array, Upload}, virtual: true diff --git a/lib/banchan/offerings/offerings.ex b/lib/banchan/offerings/offerings.ex index 419a5b6bb..c936f216b 100644 --- a/lib/banchan/offerings/offerings.ex +++ b/lib/banchan/offerings/offerings.ex @@ -370,13 +370,18 @@ defmodule Banchan.Offerings do Calculates the offering's base price. Assumes the offering has been loaded through `list_offerings/1`, which populates the relevant virtual field. """ - def offering_base_price(%Offering{} = offering) do - if Enum.empty?(offering.option_prices) do - nil - else - offering.option_prices - |> Enum.reduce(&Money.add/2) - end + def offering_base_price(%Offering{base_price: base_price}) do + base_price + end + + @doc """ + Does this offering have any optional addons? + """ + def offering_has_addons?(%Offering{} = offering) do + !is_nil(offering.options) && + !Enum.empty?(offering.options) && + offering.options + |> Enum.any?(&(!&1.default)) end @doc """ @@ -571,19 +576,26 @@ defmodule Banchan.Offerings do as: :used_slots, on: true, left_lateral_join: - default_prices in subquery( + price_info in subquery( from oo in OfferingOption, - where: oo.offering_id == parent_as(:offering).id and oo.default, + where: oo.offering_id == parent_as(:offering).id, group_by: [oo.offering_id], select: %{ - prices: - type(fragment("array_agg(?)", oo.price), {:array, Money.Ecto.Composite.Type}), - # NB(zkat): This is hacky to the point of uselessness if we end up - # having a ton of different currencies listed, but it's serviceable for now. - sum: fragment("sum((?).amount)", oo.price) + has_addons: + fragment("max(case when ? = true then 0 else 1 end)::boolean", oo.default), + base_price: + type( + fragment( + "(sum(case when ? then (?).amount else 0 end), min((?).currency))", + oo.default, + oo.price, + oo.price + ), + Money.Ecto.Composite.Type + ) } ), - as: :default_prices, + as: :price_info, on: true, left_lateral_join: gallery_uploads in subquery( @@ -607,11 +619,8 @@ defmodule Banchan.Offerings do ), {:array, Upload} ), - option_prices: - type( - coalesce(default_prices.prices, fragment("ARRAY[]::money_with_currency[]")), - {:array, Money.Ecto.Composite.Type} - ) + has_addons: price_info.has_addons, + base_price: type(price_info.base_price, Money.Ecto.Composite.Type) }) ) |> filter_query(opts) diff --git a/lib/banchan/payments/payments.ex b/lib/banchan/payments/payments.ex index 02b63fdf2..8d17a2fbb 100644 --- a/lib/banchan/payments/payments.ex +++ b/lib/banchan/payments/payments.ex @@ -1637,15 +1637,23 @@ defmodule Banchan.Payments do For example, differentiating between different kinds of dollars that would usually just use `$` as a symbol. """ - def print_money(%Money{} = money) do - case Money.Currency.symbol(money) do - "$" -> currency_symbol(money.currency) <> Money.to_string(money, symbol: false) - "" -> currency_symbol(money.currency) <> " " <> Money.to_string(money, symbol: false) - " " -> currency_symbol(money.currency) <> " " <> Money.to_string(money, symbol: false) - _ -> Money.to_string(money, symbol: true) + def print_money(%Money{} = money, symbol \\ true) do + if symbol do + case Money.Currency.symbol(money) do + "$" -> currency_symbol(money.currency) <> Money.to_string(money, symbol: false) + "" -> currency_symbol(money.currency) <> " " <> Money.to_string(money, symbol: false) + " " -> currency_symbol(money.currency) <> " " <> Money.to_string(money, symbol: false) + _ -> Money.to_string(money, symbol: true) + end + else + Money.to_string(money, symbol: false) end end + def currency_symbol(%Money{currency: currency}) do + currency_symbol(currency) + end + def currency_symbol(currency) when is_atom(currency) do case Money.Currency.symbol(currency) do "$" -> dollar_prefix(currency) <> "$" diff --git a/lib/banchan_web/components/offering_card.ex b/lib/banchan_web/components/offering_card.ex index d48ce9345..621795ceb 100644 --- a/lib/banchan_web/components/offering_card.ex +++ b/lib/banchan_web/components/offering_card.ex @@ -6,72 +6,74 @@ defmodule BanchanWeb.Components.OfferingCard do alias Banchan.Payments - alias BanchanWeb.Components.{Card, OfferingCardImg} + alias BanchanWeb.Components.OfferingCardImg - prop current_user, :any, from_context: :current_user prop name, :string prop image, :any prop base_price, :struct - prop show_pills?, :boolean, default: true + prop has_addons?, :boolean, default: false prop show_base_price?, :boolean, default: true prop archived?, :boolean, default: false prop mature?, :boolean, default: false + prop uncensored?, :boolean, default: false prop open?, :boolean, default: false prop hidden?, :boolean, default: false prop total_slots, :integer prop available_slots, :integer - prop hover_grow?, :boolean, default: true def render(assigns) do ~F""" - - <:header> -
{@name}
- - <:image> - - -
- {#if @open? && !is_nil(@total_slots) && !is_nil(@available_slots)} -
{@available_slots}/{@total_slots} Slots
- {#elseif !@open? && !is_nil(@total_slots)} -
0/{@total_slots} Slots
- {#elseif @open?} -
Open
- {#else} -
Closed
- {/if} - {#if @mature?} -
Mature
- {/if} - {#if @hidden?} -
Hidden
- {/if} -
- -
-
-

- Base Price: + +

+ +
+
+
+
+ {@name} + {#if @mature?} + M + {/if} + {#if @hidden?} + Hidden + {/if} +
+
+ {#if @open? && !is_nil(@total_slots) && !is_nil(@available_slots)} + {@available_slots}/{@total_slots} Slots + {#elseif !@open? && !is_nil(@total_slots)} + 0/{@total_slots} Slots + {#elseif @open?} + Open + {#else} + Closed + {/if} +
+
+
+ {#if is_nil(@base_price)} - Inquire + Inquire {#else} - {Payments.print_money(@base_price)} + {#if @has_addons?} + From + + {/if} + + {Payments.currency_symbol(@base_price)} + {Payments.print_money(@base_price, false)} + {/if} -

+
- + """ end end diff --git a/lib/banchan_web/components/offering_card_img.ex b/lib/banchan_web/components/offering_card_img.ex index 6a95f39e6..0a2acc816 100644 --- a/lib/banchan_web/components/offering_card_img.ex +++ b/lib/banchan_web/components/offering_card_img.ex @@ -6,32 +6,46 @@ defmodule BanchanWeb.Components.OfferingCardImg do alias Phoenix.LiveView.UploadEntry - prop current_user, :any, from_context: :current_user prop image, :any - prop mature?, :boolean, default: false + prop blur?, :boolean, default: false def render(assigns) do ~F""" - {#case @image} - {#match %UploadEntry{}} -
+
+ {#case @image} + {#match %UploadEntry{}} +
+ <.live_img_preview + class={ + "object-contain aspect-video w-full h-full", + "blur-lg": @blur? + } + draggable="false" + entry={@image} + /> +
<.live_img_preview - class={ - "object-contain aspect-video w-full h-full", - "blur-lg": @mature? && !@current_user.uncensored_mature - } + class="object-contain w-full h-full aspect-video blur-2xl" draggable="false" entry={@image} /> -
- <.live_img_preview class="aspect-video w-full h-full blur-lg" draggable="false" entry={@image} /> - {#match _} -
+ {#match _} +
+ +
-
- - {/case} + {/case} +
""" end end diff --git a/lib/banchan_web/live/commission_live/components/offering_box.ex b/lib/banchan_web/live/commission_live/components/offering_box.ex index 990b9b574..859146510 100644 --- a/lib/banchan_web/live/commission_live/components/offering_box.ex +++ b/lib/banchan_web/live/commission_live/components/offering_box.ex @@ -27,7 +27,6 @@ defmodule BanchanWeb.CommissionLive.Components.OfferingBox do {#else} diff --git a/lib/banchan_web/live/discover_live/components/offerings.ex b/lib/banchan_web/live/discover_live/components/offerings.ex index 64b79439e..7d1dfb684 100644 --- a/lib/banchan_web/live/discover_live/components/offerings.ex +++ b/lib/banchan_web/live/discover_live/components/offerings.ex @@ -80,7 +80,7 @@ defmodule BanchanWeb.DiscoverLive.Components.Offerings do Search Studios instead. {/if} {#else} -
+
{#for {offering, idx} <- Enum.with_index(@offerings)} {/for} diff --git a/lib/banchan_web/live/home_live/index.ex b/lib/banchan_web/live/home_live/index.ex index e9f1716a8..00b1171a7 100644 --- a/lib/banchan_web/live/home_live/index.ex +++ b/lib/banchan_web/live/home_live/index.ex @@ -136,7 +136,7 @@ defmodule BanchanWeb.HomeLive do
-
+
{#for {offering, idx} <- Enum.with_index(@offerings.entries)} {/for} diff --git a/lib/banchan_web/live/offering_live/show.ex b/lib/banchan_web/live/offering_live/show.ex index 4d6362fdc..1469c9ab1 100644 --- a/lib/banchan_web/live/offering_live/show.ex +++ b/lib/banchan_web/live/offering_live/show.ex @@ -22,6 +22,7 @@ defmodule BanchanWeb.OfferingLive.Show do Lightbox, Markdown, MasonryGallery, + OfferingCardImg, ReportModal, Tag } @@ -197,15 +198,7 @@ defmodule BanchanWeb.OfferingLive.Show do > {#if @offering.card_img && !@offering.card_img.pending} - - + {#else}
@@ -307,15 +300,7 @@ defmodule BanchanWeb.OfferingLive.Show do > {#if @offering.card_img && !@offering.card_img.pending} - - + {#else}
diff --git a/lib/banchan_web/live/studio_live/components/offering.ex b/lib/banchan_web/live/studio_live/components/offering.ex index 11fc5b251..000647620 100644 --- a/lib/banchan_web/live/studio_live/components/offering.ex +++ b/lib/banchan_web/live/studio_live/components/offering.ex @@ -502,10 +502,13 @@ defmodule BanchanWeb.StudioLive.Components.Offering do &Money.add/2 ) end} + has_addons?={!is_nil(Ecto.Changeset.get_field(@changeset, :options)) && + !Enum.empty?(Ecto.Changeset.get_field(@changeset, :options)) && + Ecto.Changeset.get_field(@changeset, :options) + |> Enum.any?(&(!&1.default && &1.price))} open?={Ecto.Changeset.get_field(@changeset, :open)} hidden?={Ecto.Changeset.get_field(@changeset, :hidden)} mature?={Ecto.Changeset.get_field(@changeset, :mature)} - hover_grow?={false} total_slots={Ecto.Changeset.get_field(@changeset, :slots)} available_slots={Ecto.Changeset.get_field(@changeset, :slots)} /> diff --git a/lib/banchan_web/live/studio_live/components/offering_card.ex b/lib/banchan_web/live/studio_live/components/offering_card.ex index b344fb5d6..bc4d9d4bd 100644 --- a/lib/banchan_web/live/studio_live/components/offering_card.ex +++ b/lib/banchan_web/live/studio_live/components/offering_card.ex @@ -15,20 +15,14 @@ defmodule BanchanWeb.StudioLive.Components.OfferingCard do prop current_user_member?, :boolean, default: false prop offering, :struct, required: true - data base_price, :list data available_slots, :integer def update(assigns, socket) do socket = assign(socket, assigns) - base_price = Offerings.offering_base_price(socket.assigns.offering) - available_slots = Offerings.offering_available_slots(socket.assigns.offering) - {:ok, - socket - |> assign(base_price: base_price) - |> assign(available_slots: available_slots)} + {:ok, socket |> assign(available_slots: available_slots)} end def render(assigns) do @@ -38,9 +32,11 @@ defmodule BanchanWeb.StudioLive.Components.OfferingCard do ` component. + """ + + use Surface.Catalogue.Playground, + subject: BanchanWeb.Components.OfferingCard, + height: "400px" + + @props [] +end