spazio-solazzo/lib/spazio_solazzo_web/components/booking_components.ex
2026-01-10 19:03:02 +01:00

114 lines
3.9 KiB
Elixir

defmodule SpazioSolazzoWeb.BookingComponents do
@moduledoc """
Reusable components for the booking flow.
"""
use Phoenix.Component
alias SpazioSolazzo.CalendarExt
attr :id, :string, required: true
attr :show, :boolean, default: false
attr :on_close, :any, required: true
@doc """
Success modal displayed when a booking is completed.
"""
def booking_confirmation_modal(assigns) do
~H"""
<div
:if={@show}
id={@id}
class="relative z-50"
role="dialog"
aria-modal="true"
>
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
<div class="fixed inset-0 z-10 overflow-y-auto">
<div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<div
id={"#{@id}-container"}
class="relative transform overflow-hidden rounded-3xl bg-white dark:bg-gray-800 px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6"
>
<div>
<div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-teal-100 dark:bg-teal-900/30">
<svg
class="h-6 w-6 text-teal-600 dark:text-teal-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 13l4 4L19 7"
/>
</svg>
</div>
<div class="mt-3 text-center sm:mt-5">
<h3 class="text-lg font-semibold leading-6 text-gray-900 dark:text-white">
Booking Successful!
</h3>
<div class="mt-2">
<p class="text-sm text-gray-500 dark:text-gray-400">
Your booking has been confirmed. You will receive a confirmation email shortly.
</p>
</div>
</div>
</div>
<div class="mt-5 sm:mt-6">
<button
phx-click={@on_close}
type="button"
class="inline-flex w-full justify-center rounded-2xl bg-teal-600 px-3 py-3 text-sm font-semibold text-white shadow-lg hover:bg-teal-700 hover:shadow-xl focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600 transition-all"
>
Got it!
</button>
</div>
</div>
</div>
</div>
</div>
"""
end
attr :time_slot, :map, required: true
attr :booked, :boolean, required: true
@doc """
Renders time slot buttons in different sizes showing availability status.
"""
def time_slot(assigns) do
~H"""
<button
phx-click={unless @booked, do: "select_slot"}
phx-value-time_slot_id={@time_slot.id}
disabled={@booked}
class={[
"group w-full flex items-center justify-between p-4 rounded-xl border-2 transition-all duration-200",
if(@booked,
do:
"border-slate-300 dark:border-slate-600 bg-slate-100 dark:bg-slate-700 cursor-not-allowed opacity-75",
else:
"border-sky-500/40 hover:border-sky-500 bg-transparent hover:bg-sky-500/5 dark:hover:bg-sky-500/10 cursor-pointer"
)
]}
>
<span class={[
"text-lg font-bold transition-colors",
if(@booked,
do: "text-slate-500 dark:text-slate-400",
else: "text-slate-900 dark:text-white group-hover:text-sky-500"
)
]}>
{CalendarExt.format_time_range(@time_slot)}
</span>
<span class={[
"text-xs font-medium",
if(@booked, do: "text-slate-500", else: "text-sky-500")
]}>
{if @booked, do: "Booked", else: "Available"}
</span>
</button>
"""
end
end