mirror of
https://codeberg.org/JasterV/spazio-solazzo.git
synced 2026-04-26 18:20:03 +00:00
refactor: walk in booking form
This commit is contained in:
parent
e0f25c1bd5
commit
cab1831fc8
12 changed files with 140 additions and 483 deletions
|
|
@ -56,8 +56,7 @@ defmodule SpazioSolazzo.BookingSystem do
|
|||
:end_datetime,
|
||||
:customer_name,
|
||||
:customer_email,
|
||||
:customer_phone,
|
||||
:customer_comment
|
||||
:customer_phone
|
||||
]
|
||||
|
||||
define :approve_booking, action: :approve, args: []
|
||||
|
|
|
|||
|
|
@ -238,7 +238,6 @@ defmodule SpazioSolazzo.BookingSystem.Booking do
|
|||
argument :customer_name, :string, allow_nil?: false
|
||||
argument :customer_email, :string, allow_nil?: false
|
||||
argument :customer_phone, :string, allow_nil?: true
|
||||
argument :customer_comment, :string, allow_nil?: true
|
||||
|
||||
change manage_relationship(:space_id, :space, type: :append_and_remove)
|
||||
|
||||
|
|
@ -302,10 +301,6 @@ defmodule SpazioSolazzo.BookingSystem.Booking do
|
|||
:customer_phone,
|
||||
Ash.Changeset.get_argument(changeset, :customer_phone)
|
||||
)
|
||||
|> Ash.Changeset.force_change_attribute(
|
||||
:customer_comment,
|
||||
Ash.Changeset.get_argument(changeset, :customer_comment)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ defmodule SpazioSolazzoWeb.CoreComponents do
|
|||
<.button phx-click="go" variant="primary">Send!</.button>
|
||||
<.button navigate={~p"/"}>Home</.button>
|
||||
"""
|
||||
attr :rest, :global, include: ~w(href navigate patch method download name value disabled)
|
||||
attr :rest, :global, include: ~w(href navigate patch method download name value disabled form)
|
||||
attr :class, :any
|
||||
attr :variant, :string, values: ~w(primary)
|
||||
slot :inner_block, required: true
|
||||
|
|
|
|||
|
|
@ -7,20 +7,17 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLive do
|
|||
alias SpazioSolazzo.BookingSystem
|
||||
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, coworking_space} = BookingSystem.get_space_by_slug("coworking")
|
||||
{:ok, space} = BookingSystem.get_space_by_slug("coworking")
|
||||
|
||||
{:ok,
|
||||
assign(socket,
|
||||
coworking_space: coworking_space,
|
||||
space: space,
|
||||
multi_day_mode: false,
|
||||
start_date: nil,
|
||||
end_date: nil,
|
||||
start_time: ~T[09:00:00],
|
||||
end_time: ~T[18:00:00],
|
||||
customer_name: "",
|
||||
customer_email: "",
|
||||
customer_phone: "",
|
||||
customer_comment: ""
|
||||
customer_details_form: customer_details_form()
|
||||
)}
|
||||
end
|
||||
|
||||
|
|
@ -44,57 +41,89 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLive do
|
|||
end
|
||||
end
|
||||
|
||||
def handle_event("update_customer_details", params, socket) do
|
||||
{:noreply,
|
||||
assign(socket,
|
||||
customer_name: Map.get(params, "customer_name", ""),
|
||||
customer_email: Map.get(params, "customer_email", ""),
|
||||
customer_phone: Map.get(params, "customer_phone", ""),
|
||||
customer_comment: Map.get(params, "customer_comment", "")
|
||||
)}
|
||||
def handle_event(
|
||||
"validate_customer_details",
|
||||
form,
|
||||
socket
|
||||
) do
|
||||
{:noreply, assign(socket, customer_details_form: to_form(form))}
|
||||
end
|
||||
|
||||
def handle_event("create_booking", _, socket) do
|
||||
with true <- socket.assigns.customer_name != "",
|
||||
true <- socket.assigns.customer_email != "",
|
||||
start_date when not is_nil(start_date) <- get_start_date(socket),
|
||||
end_date when not is_nil(end_date) <- get_end_date(socket) do
|
||||
# Create datetime objects
|
||||
start_datetime =
|
||||
DateTime.new!(start_date, socket.assigns.start_time, "Etc/UTC")
|
||||
def handle_event(
|
||||
"create_booking",
|
||||
_,
|
||||
%{assigns: %{start_date: start_date, end_date: end_date}} = socket
|
||||
)
|
||||
when is_nil(start_date) or is_nil(end_date) do
|
||||
{:noreply, put_flash(socket, :error, "Please fill in all required fields and select a date")}
|
||||
end
|
||||
|
||||
end_datetime =
|
||||
DateTime.new!(end_date, socket.assigns.end_time, "Etc/UTC")
|
||||
def handle_event("create_booking", form, socket) do
|
||||
case parse_submitted_form(form) do
|
||||
{:error, error} -> {:noreply, put_flash(socket, :error, error)}
|
||||
{:ok, form} -> create_walk_in(form, socket)
|
||||
end
|
||||
end
|
||||
|
||||
case BookingSystem.create_walk_in(
|
||||
socket.assigns.coworking_space.id,
|
||||
start_datetime,
|
||||
end_datetime,
|
||||
socket.assigns.customer_name,
|
||||
socket.assigns.customer_email,
|
||||
socket.assigns.customer_phone,
|
||||
socket.assigns.customer_comment
|
||||
) do
|
||||
{:ok, _booking} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(
|
||||
customer_name: "",
|
||||
customer_email: "",
|
||||
customer_phone: "",
|
||||
customer_comment: "",
|
||||
start_date: nil,
|
||||
end_date: nil
|
||||
)
|
||||
|> put_flash(:info, "Walk-in booking created successfully")}
|
||||
defp create_walk_in(
|
||||
form,
|
||||
%{
|
||||
assigns: %{
|
||||
start_date: start_date,
|
||||
end_date: end_date,
|
||||
start_time: start_time,
|
||||
end_time: end_time,
|
||||
space: space
|
||||
}
|
||||
} = socket
|
||||
) do
|
||||
start_datetime =
|
||||
DateTime.new!(start_date, start_time, "Etc/UTC")
|
||||
|
||||
{:error, error} ->
|
||||
{:noreply, put_flash(socket, :error, "Failed to create walk-in: #{inspect(error)}")}
|
||||
end
|
||||
else
|
||||
_ ->
|
||||
end_datetime =
|
||||
DateTime.new!(end_date, end_time, "Etc/UTC")
|
||||
|
||||
case BookingSystem.create_walk_in(
|
||||
space.id,
|
||||
start_datetime,
|
||||
end_datetime,
|
||||
form.customer_name,
|
||||
form.customer_email,
|
||||
form.customer_phone
|
||||
) do
|
||||
{:ok, _booking} ->
|
||||
{:noreply,
|
||||
put_flash(socket, :error, "Please fill in all required fields and select a date")}
|
||||
socket
|
||||
|> assign(
|
||||
customer_details_form: customer_details_form(),
|
||||
start_date: nil,
|
||||
end_date: nil
|
||||
)
|
||||
|> put_flash(:info, "Walk-in booking created successfully")}
|
||||
|
||||
{:error, error} ->
|
||||
{:noreply, put_flash(socket, :error, "Failed to create walk-in: #{inspect(error)}")}
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_submitted_form(%{
|
||||
"customer_name" => customer_name,
|
||||
"customer_email" => customer_email,
|
||||
"customer_phone" => customer_phone
|
||||
}) do
|
||||
customer_name = String.trim(customer_name)
|
||||
customer_email = String.trim(customer_email)
|
||||
customer_phone = String.trim(customer_phone)
|
||||
|
||||
if customer_name == "" || customer_email == "" do
|
||||
{:error, "Please fill in all required fields and select a date"}
|
||||
else
|
||||
{:ok,
|
||||
%{
|
||||
customer_name: customer_name,
|
||||
customer_email: customer_email,
|
||||
customer_phone: customer_phone
|
||||
}}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -110,14 +139,6 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLive do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
defp get_start_date(socket) do
|
||||
socket.assigns.start_date
|
||||
end
|
||||
|
||||
defp get_end_date(socket) do
|
||||
socket.assigns.end_date
|
||||
end
|
||||
|
||||
defp days_selected(nil, nil), do: 0
|
||||
defp days_selected(start_date, nil) when not is_nil(start_date), do: 1
|
||||
|
||||
|
|
@ -127,4 +148,8 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLive do
|
|||
end
|
||||
|
||||
defp days_selected(_, _), do: 0
|
||||
|
||||
defp customer_details_form() do
|
||||
to_form(%{"customer_name" => "", "customer_email" => "", "customer_phone" => ""})
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,15 +13,11 @@
|
|||
|
||||
<%!-- Title --%>
|
||||
<div class="mb-10 flex flex-col items-center md:items-start text-center md:text-left">
|
||||
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 text-primary dark:text-primary-hover dark:bg-primary/20 text-xs font-bold mb-4 border border-primary/20">
|
||||
<.icon name="hero-building-office-2" class="w-4 h-4" />
|
||||
<span>Coworking Space Only</span>
|
||||
</div>
|
||||
<h1 class="text-3xl md:text-4xl font-black text-slate-900 dark:text-white tracking-tight mb-3">
|
||||
New Coworking Walk-in Booking
|
||||
New Arcipelago Walk-in Booking
|
||||
</h1>
|
||||
<p class="text-slate-600 dark:text-slate-400 max-w-2xl text-lg">
|
||||
Follow the steps below to create a new guided reservation for the coworking area.
|
||||
Create a walk-in booking for the Arcipelago space.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -48,7 +44,7 @@
|
|||
<.live_component
|
||||
module={SpazioSolazzoWeb.Admin.AdminCalendarComponent}
|
||||
id="walk-in-calendar"
|
||||
space_id={@coworking_space.id}
|
||||
space_id={@space.id}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -191,17 +187,23 @@
|
|||
</div>
|
||||
</header>
|
||||
|
||||
<.form for={%{}} phx-change="update_customer_details" class="space-y-4 max-w-2xl">
|
||||
<.form
|
||||
for={@customer_details_form}
|
||||
id="customer-details-form"
|
||||
phx-change="validate_customer_details"
|
||||
phx-submit="create_booking"
|
||||
class="space-y-4 max-w-2xl"
|
||||
>
|
||||
<div class="relative">
|
||||
<span class="absolute inset-y-0 left-0 flex items-center pl-3 text-slate-400">
|
||||
<.icon name="hero-user" class="w-5 h-5" />
|
||||
</span>
|
||||
<input
|
||||
name="customer_name"
|
||||
value={@customer_name}
|
||||
<.input
|
||||
field={@customer_details_form["customer_name"]}
|
||||
class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-700 text-slate-900 dark:text-white text-sm rounded-xl pl-10 pr-4 py-3 focus:ring-2 focus:ring-primary focus:border-primary transition-all placeholder:text-slate-400"
|
||||
placeholder="Customer Name"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -209,12 +211,12 @@
|
|||
<span class="absolute inset-y-0 left-0 flex items-center pl-3 text-slate-400">
|
||||
<.icon name="hero-envelope" class="w-5 h-5" />
|
||||
</span>
|
||||
<input
|
||||
name="customer_email"
|
||||
value={@customer_email}
|
||||
<.input
|
||||
field={@customer_details_form["customer_email"]}
|
||||
class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-700 text-slate-900 dark:text-white text-sm rounded-xl pl-10 pr-4 py-3 focus:ring-2 focus:ring-primary focus:border-primary transition-all placeholder:text-slate-400"
|
||||
placeholder="customer@example.com"
|
||||
type="email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -222,36 +224,26 @@
|
|||
<span class="absolute inset-y-0 left-0 flex items-center pl-3 text-slate-400">
|
||||
<.icon name="hero-phone" class="w-5 h-5" />
|
||||
</span>
|
||||
<input
|
||||
name="customer_phone"
|
||||
value={@customer_phone}
|
||||
<.input
|
||||
field={@customer_details_form["customer_phone"]}
|
||||
class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-700 text-slate-900 dark:text-white text-sm rounded-xl pl-10 pr-4 py-3 focus:ring-2 focus:ring-primary focus:border-primary transition-all placeholder:text-slate-400"
|
||||
placeholder="Customer Phone Number (Optional)"
|
||||
type="tel"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<textarea
|
||||
name="customer_comment"
|
||||
value={@customer_comment}
|
||||
rows="3"
|
||||
class="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-700 text-slate-900 dark:text-white text-sm rounded-xl px-4 py-3 focus:ring-2 focus:ring-primary focus:border-primary transition-all placeholder:text-slate-400"
|
||||
placeholder="Additional notes or comments (Optional)"
|
||||
></textarea>
|
||||
</div>
|
||||
</.form>
|
||||
</article>
|
||||
|
||||
<%!-- Submit button --%>
|
||||
<div class="flex justify-center pt-4">
|
||||
<button
|
||||
phx-click="create_booking"
|
||||
<.button
|
||||
type="submit"
|
||||
form="customer-details-form"
|
||||
class="w-full sm:w-auto flex items-center justify-center gap-2 overflow-hidden rounded-xl h-12 px-10 bg-primary hover:bg-primary/90 transition-colors text-white text-base font-bold shadow-lg shadow-primary/30"
|
||||
>
|
||||
<span>Create Booking</span>
|
||||
<.icon name="hero-check" class="w-5 h-5" />
|
||||
</button>
|
||||
</.button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ defmodule SpazioSolazzoWeb.BookingFormLiveComponent do
|
|||
current_user = assigns.current_user
|
||||
|
||||
initial_data = %{
|
||||
"customer_name" => (current_user && current_user.name) || "",
|
||||
"customer_email" => (current_user && current_user.email) || "",
|
||||
"customer_phone" => (current_user && current_user.phone_number) || "",
|
||||
"customer_name" => current_user.name,
|
||||
"customer_email" => current_user.email,
|
||||
"customer_phone" => current_user.phone_number || "",
|
||||
"customer_comment" => ""
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,14 +82,4 @@ defmodule SpazioSolazzoWeb.Router do
|
|||
forward "/mailbox", Plug.Swoosh.MailboxPreview
|
||||
end
|
||||
end
|
||||
|
||||
if Application.compile_env(:spazio_solazzo, :dev_routes) do
|
||||
import AshAdmin.Router
|
||||
|
||||
scope "/admin" do
|
||||
pipe_through :browser
|
||||
|
||||
ash_admin "/"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
1
mix.exs
1
mix.exs
|
|
@ -50,7 +50,6 @@ defmodule SpazioSolazzo.MixProject do
|
|||
defp deps do
|
||||
[
|
||||
{:ash, "~> 3.0"},
|
||||
{:ash_admin, "~> 0.13"},
|
||||
{:ash_authentication, "~> 4.0"},
|
||||
{:ash_authentication_phoenix, "~> 2.0"},
|
||||
{:ash_phoenix, "~> 2.0"},
|
||||
|
|
|
|||
|
|
@ -1,333 +0,0 @@
|
|||
defmodule SpazioSolazzo.BookingSystem.BookingMonthCountTest do
|
||||
use SpazioSolazzo.DataCase
|
||||
|
||||
alias SpazioSolazzo.BookingSystem
|
||||
|
||||
describe "list_bookings_for_month_count/3" do
|
||||
setup do
|
||||
# Create space
|
||||
{:ok, space} = BookingSystem.create_space("Coworking", "coworking", "Desc", 10)
|
||||
|
||||
# Use dates in the future (next month, day 15)
|
||||
today = Date.utc_today()
|
||||
next_month = Date.add(today, 30)
|
||||
test_date = %{next_month | day: 15}
|
||||
|
||||
start_datetime = DateTime.new!(test_date, ~T[09:00:00], "Etc/UTC")
|
||||
end_datetime = DateTime.new!(test_date, ~T[17:00:00], "Etc/UTC")
|
||||
|
||||
# Create booking with full data
|
||||
{:ok, booking} =
|
||||
BookingSystem.create_walk_in(
|
||||
space.id,
|
||||
start_datetime,
|
||||
end_datetime,
|
||||
"John Doe",
|
||||
"john@example.com",
|
||||
"555-1234",
|
||||
"Test comment"
|
||||
)
|
||||
|
||||
# Reload booking
|
||||
{:ok, booking} = Ash.reload(booking)
|
||||
|
||||
# Calculate month boundaries
|
||||
start_of_month = Date.beginning_of_month(test_date)
|
||||
end_of_month = Date.end_of_month(test_date)
|
||||
|
||||
%{
|
||||
space: space,
|
||||
booking: booking,
|
||||
test_date: test_date,
|
||||
start_of_month: start_of_month,
|
||||
end_of_month: end_of_month
|
||||
}
|
||||
end
|
||||
|
||||
test "returns only datetime fields, not full booking data",
|
||||
%{space: space, start_of_month: start_date, end_of_month: end_date} do
|
||||
start_datetime = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC")
|
||||
end_datetime = DateTime.new!(Date.add(end_date, 1), ~T[00:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, bookings} =
|
||||
BookingSystem.search_bookings(
|
||||
space.id,
|
||||
start_datetime,
|
||||
end_datetime,
|
||||
[:accepted],
|
||||
[:start_datetime, :end_datetime]
|
||||
)
|
||||
|
||||
assert length(bookings) == 1
|
||||
booking = hd(bookings)
|
||||
|
||||
# Assert datetime fields ARE present
|
||||
assert %DateTime{} = booking.start_datetime
|
||||
assert %DateTime{} = booking.end_datetime
|
||||
|
||||
# Assert other fields are NOT loaded
|
||||
refute Ash.Resource.loaded?(booking, :customer_name)
|
||||
refute Ash.Resource.loaded?(booking, :customer_email)
|
||||
refute Ash.Resource.loaded?(booking, :customer_phone)
|
||||
refute Ash.Resource.loaded?(booking, :customer_comment)
|
||||
refute Ash.Resource.loaded?(booking, :user)
|
||||
refute Ash.Resource.loaded?(booking, :space)
|
||||
end
|
||||
|
||||
test "returns empty list for month with no bookings", %{space: space} do
|
||||
# Query a different month (two months from now)
|
||||
today = Date.utc_today()
|
||||
future_month = Date.add(today, 60)
|
||||
start_date = Date.beginning_of_month(future_month)
|
||||
end_date = Date.end_of_month(future_month)
|
||||
|
||||
start_datetime = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC")
|
||||
end_datetime = DateTime.new!(Date.add(end_date, 1), ~T[00:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, bookings} =
|
||||
BookingSystem.search_bookings(
|
||||
space.id,
|
||||
start_datetime,
|
||||
end_datetime,
|
||||
[:accepted],
|
||||
[:start_datetime, :end_datetime]
|
||||
)
|
||||
|
||||
assert bookings == []
|
||||
end
|
||||
|
||||
test "handles bookings that span multiple days",
|
||||
%{space: space, test_date: test_date, start_of_month: start_date, end_of_month: end_date} do
|
||||
# Create a 3-day booking (day 20-22)
|
||||
multi_day_start = %{test_date | day: 20}
|
||||
multi_day_end = %{test_date | day: 22}
|
||||
|
||||
start_datetime = DateTime.new!(multi_day_start, ~T[09:00:00], "Etc/UTC")
|
||||
end_datetime = DateTime.new!(multi_day_end, ~T[17:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, _booking} =
|
||||
BookingSystem.create_walk_in(
|
||||
space.id,
|
||||
start_datetime,
|
||||
end_datetime,
|
||||
"Jane Doe",
|
||||
"jane@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
month_start_datetime = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC")
|
||||
month_end_datetime = DateTime.new!(Date.add(end_date, 1), ~T[00:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, bookings} =
|
||||
BookingSystem.search_bookings(
|
||||
space.id,
|
||||
month_start_datetime,
|
||||
month_end_datetime,
|
||||
[:accepted],
|
||||
[:start_datetime, :end_datetime]
|
||||
)
|
||||
|
||||
# Should have 2 bookings (original + multi-day)
|
||||
assert length(bookings) == 2
|
||||
|
||||
# All should only have datetime fields
|
||||
Enum.each(bookings, fn booking ->
|
||||
refute Ash.Resource.loaded?(booking, :customer_name)
|
||||
refute Ash.Resource.loaded?(booking, :customer_email)
|
||||
end)
|
||||
end
|
||||
|
||||
test "handles month boundaries correctly",
|
||||
%{space: space, test_date: test_date, start_of_month: start_date, end_of_month: end_date} do
|
||||
# Booking starts before month, ends during month (last day of previous month to day 2)
|
||||
before_month = Date.add(start_date, -1)
|
||||
during_month = %{test_date | day: 2}
|
||||
|
||||
start_datetime1 = DateTime.new!(before_month, ~T[09:00:00], "Etc/UTC")
|
||||
end_datetime1 = DateTime.new!(during_month, ~T[17:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, _before} =
|
||||
BookingSystem.create_walk_in(
|
||||
space.id,
|
||||
start_datetime1,
|
||||
end_datetime1,
|
||||
"Before Month",
|
||||
"before@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
# Booking starts during month, ends after month (day 27 to first day of next month)
|
||||
during_month2 = %{test_date | day: min(27, Date.days_in_month(test_date))}
|
||||
after_month = Date.add(end_date, 1)
|
||||
|
||||
start_datetime2 = DateTime.new!(during_month2, ~T[09:00:00], "Etc/UTC")
|
||||
end_datetime2 = DateTime.new!(after_month, ~T[17:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, _after} =
|
||||
BookingSystem.create_walk_in(
|
||||
space.id,
|
||||
start_datetime2,
|
||||
end_datetime2,
|
||||
"After Month",
|
||||
"after@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
month_start_datetime = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC")
|
||||
month_end_datetime = DateTime.new!(Date.add(end_date, 1), ~T[00:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, bookings} =
|
||||
BookingSystem.search_bookings(
|
||||
space.id,
|
||||
month_start_datetime,
|
||||
month_end_datetime,
|
||||
[:accepted],
|
||||
[:start_datetime, :end_datetime]
|
||||
)
|
||||
|
||||
# Should include all 3 bookings (original + before + after)
|
||||
assert length(bookings) == 3
|
||||
end
|
||||
|
||||
test "only returns accepted bookings, not pending/rejected/cancelled",
|
||||
%{space: space, test_date: test_date, start_of_month: start_date, end_of_month: end_date} do
|
||||
# Create a regular requested booking (not walk-in) on day 10
|
||||
pending_date = %{test_date | day: 10}
|
||||
|
||||
{:ok, _pending} =
|
||||
BookingSystem.create_booking(
|
||||
space.id,
|
||||
nil,
|
||||
pending_date,
|
||||
~T[09:00:00],
|
||||
~T[17:00:00],
|
||||
"Pending",
|
||||
"pending@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
# Create and reject a booking on day 11
|
||||
rejected_date = %{test_date | day: 11}
|
||||
|
||||
{:ok, rejected} =
|
||||
BookingSystem.create_booking(
|
||||
space.id,
|
||||
nil,
|
||||
rejected_date,
|
||||
~T[09:00:00],
|
||||
~T[17:00:00],
|
||||
"Rejected",
|
||||
"rejected@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
{:ok, _} = BookingSystem.reject_booking(rejected, "Test reason")
|
||||
|
||||
month_start_datetime = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC")
|
||||
month_end_datetime = DateTime.new!(Date.add(end_date, 1), ~T[00:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, bookings} =
|
||||
BookingSystem.search_bookings(
|
||||
space.id,
|
||||
month_start_datetime,
|
||||
month_end_datetime,
|
||||
[:accepted],
|
||||
[:start_datetime, :end_datetime]
|
||||
)
|
||||
|
||||
# Should only have the original accepted booking from setup
|
||||
assert length(bookings) == 1
|
||||
end
|
||||
|
||||
test "handles bookings at exact month boundaries",
|
||||
%{space: space, start_of_month: start_date, end_of_month: end_date} do
|
||||
# Booking exactly at month start
|
||||
month_start_datetime = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC")
|
||||
month_start_end = DateTime.new!(start_date, ~T[08:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, _start} =
|
||||
BookingSystem.create_walk_in(
|
||||
space.id,
|
||||
month_start_datetime,
|
||||
month_start_end,
|
||||
"Start Boundary",
|
||||
"start@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
# Booking exactly at month end
|
||||
month_end_start = DateTime.new!(end_date, ~T[18:00:00], "Etc/UTC")
|
||||
month_end_datetime = DateTime.new!(end_date, ~T[23:59:59], "Etc/UTC")
|
||||
|
||||
{:ok, _end} =
|
||||
BookingSystem.create_walk_in(
|
||||
space.id,
|
||||
month_end_start,
|
||||
month_end_datetime,
|
||||
"End Boundary",
|
||||
"end@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
month_start_datetime = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC")
|
||||
month_end_datetime = DateTime.new!(Date.add(end_date, 1), ~T[00:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, bookings} =
|
||||
BookingSystem.search_bookings(
|
||||
space.id,
|
||||
month_start_datetime,
|
||||
month_end_datetime,
|
||||
[:accepted],
|
||||
[:start_datetime, :end_datetime]
|
||||
)
|
||||
|
||||
# Should include all bookings including boundaries
|
||||
assert length(bookings) >= 3
|
||||
end
|
||||
|
||||
test "filters by space_id correctly",
|
||||
%{space: space, test_date: test_date, start_of_month: start_date, end_of_month: end_date} do
|
||||
# Create another space
|
||||
{:ok, other_space} = BookingSystem.create_space("Other", "other", "Other space", 5)
|
||||
|
||||
# Create booking for other space on day 16
|
||||
other_date = %{test_date | day: 16}
|
||||
start_datetime = DateTime.new!(other_date, ~T[09:00:00], "Etc/UTC")
|
||||
end_datetime = DateTime.new!(other_date, ~T[17:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, _other_booking} =
|
||||
BookingSystem.create_walk_in(
|
||||
other_space.id,
|
||||
start_datetime,
|
||||
end_datetime,
|
||||
"Other Space",
|
||||
"other@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
# Query for original space
|
||||
month_start_datetime = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC")
|
||||
month_end_datetime = DateTime.new!(Date.add(end_date, 1), ~T[00:00:00], "Etc/UTC")
|
||||
|
||||
{:ok, bookings} =
|
||||
BookingSystem.search_bookings(
|
||||
space.id,
|
||||
month_start_datetime,
|
||||
month_end_datetime,
|
||||
[:accepted],
|
||||
[:start_datetime, :end_datetime]
|
||||
)
|
||||
|
||||
# Should only return bookings for the original space
|
||||
assert length(bookings) == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -749,15 +749,13 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
end_datetime,
|
||||
"Walk-in Customer",
|
||||
"walkin@example.com",
|
||||
"+39 1234567890",
|
||||
"Walk-in booking"
|
||||
"+39 1234567890"
|
||||
)
|
||||
|
||||
assert booking.space_id == space.id
|
||||
assert booking.customer_name == "Walk-in Customer"
|
||||
assert booking.customer_email == "walkin@example.com"
|
||||
assert booking.customer_phone == "+39 1234567890"
|
||||
assert booking.customer_comment == "Walk-in booking"
|
||||
assert booking.state == :accepted
|
||||
assert booking.date == DateTime.to_date(start_datetime)
|
||||
# Compare times ignoring microseconds
|
||||
|
|
@ -784,7 +782,6 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
end_datetime,
|
||||
"Walk-in Customer",
|
||||
"walkin@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
|
|
@ -804,7 +801,6 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
end_datetime,
|
||||
"Walk-in Customer",
|
||||
"walkin@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
|
|
@ -823,7 +819,6 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
end_datetime,
|
||||
"Walk-in Customer",
|
||||
"walkin@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
|
|
@ -842,7 +837,6 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
end_datetime,
|
||||
"Walk-in Customer",
|
||||
"walkin@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
|
|
@ -861,7 +855,6 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
end_datetime,
|
||||
"Walk-in Customer",
|
||||
"invalid-email",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
|
|
@ -884,7 +877,6 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
end_datetime,
|
||||
"Walk-in Customer",
|
||||
"walkin@example.com",
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveSimpleTest do
|
|||
|
||||
# Fill in customer details using the form
|
||||
view
|
||||
|> form("form[phx-change='update_customer_details']", %{
|
||||
|> form("form[phx-change='validate_customer_details']", %{
|
||||
"customer_name" => "John Doe",
|
||||
"customer_email" => "john@example.com"
|
||||
})
|
||||
|
|
@ -53,8 +53,8 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveSimpleTest do
|
|||
# Try to create the booking
|
||||
html =
|
||||
view
|
||||
|> element("button[phx-click='create_booking']")
|
||||
|> render_click()
|
||||
|> element("form[phx-submit='create_booking']")
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "Walk-in booking created successfully"
|
||||
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
conn = log_in_user(conn, user)
|
||||
{:ok, view, _html} = live(conn, "/admin/walk-in")
|
||||
|
||||
assert has_element?(view, "form[phx-change='update_customer_details']")
|
||||
assert has_element?(view, "form[phx-change='validate_customer_details']")
|
||||
assert has_element?(view, "input[name='customer_name']")
|
||||
assert has_element?(view, "input[name='customer_email']")
|
||||
assert has_element?(view, "button[phx-click='create_booking']")
|
||||
assert has_element?(view, "button[type='submit']")
|
||||
end
|
||||
|
||||
test "creates single-day walk-in booking successfully", %{
|
||||
|
|
@ -58,7 +58,7 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
|
||||
# Fill in customer details
|
||||
view
|
||||
|> form("form[phx-change='update_customer_details']", %{
|
||||
|> form("form[phx-change='validate_customer_details']", %{
|
||||
"customer_name" => "John Doe",
|
||||
"customer_email" => "john@example.com"
|
||||
})
|
||||
|
|
@ -67,8 +67,8 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
# Submit the form
|
||||
html =
|
||||
view
|
||||
|> element("button[phx-click='create_booking']")
|
||||
|> render_click()
|
||||
|> element("form[phx-submit='create_booking']")
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "Walk-in booking created successfully"
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
|
||||
# Fill in customer details without selecting a date
|
||||
view
|
||||
|> form("form[phx-change='update_customer_details']", %{
|
||||
|> form("form[phx-change='validate_customer_details']", %{
|
||||
"customer_name" => "John Doe",
|
||||
"customer_email" => "john@example.com"
|
||||
})
|
||||
|
|
@ -107,8 +107,8 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
# Try to submit
|
||||
html =
|
||||
view
|
||||
|> element("button[phx-click='create_booking']")
|
||||
|> render_click()
|
||||
|> element("form[phx-submit='create_booking']")
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "Please fill in all required fields and select a date"
|
||||
end
|
||||
|
|
@ -122,15 +122,15 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
:timer.sleep(50)
|
||||
|
||||
view
|
||||
|> form("form[phx-change='update_customer_details']", %{
|
||||
|> form("form[phx-change='validate_customer_details']", %{
|
||||
"customer_email" => "john@example.com"
|
||||
})
|
||||
|> render_change()
|
||||
|
||||
html =
|
||||
view
|
||||
|> element("button[phx-click='create_booking']")
|
||||
|> render_click()
|
||||
|> element("form[phx-submit='create_booking']")
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "Please fill in all required fields and select a date"
|
||||
end
|
||||
|
|
@ -144,15 +144,15 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
:timer.sleep(50)
|
||||
|
||||
view
|
||||
|> form("form[phx-change='update_customer_details']", %{
|
||||
|> form("form[phx-change='validate_customer_details']", %{
|
||||
"customer_name" => "John Doe"
|
||||
})
|
||||
|> render_change()
|
||||
|
||||
html =
|
||||
view
|
||||
|> element("button[phx-click='create_booking']")
|
||||
|> render_click()
|
||||
|> element("form[phx-submit='create_booking']")
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "Please fill in all required fields and select a date"
|
||||
end
|
||||
|
|
@ -170,7 +170,7 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
|
||||
# Fill in customer details
|
||||
view
|
||||
|> form("form[phx-change='update_customer_details']", %{
|
||||
|> form("form[phx-change='validate_customer_details']", %{
|
||||
"customer_name" => "Jane Smith",
|
||||
"customer_email" => "jane@example.com"
|
||||
})
|
||||
|
|
@ -179,8 +179,8 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
# Submit the form
|
||||
html =
|
||||
view
|
||||
|> element("button[phx-click='create_booking']")
|
||||
|> render_click()
|
||||
|> element("form[phx-submit='create_booking']")
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "Walk-in booking created successfully"
|
||||
|
||||
|
|
@ -219,7 +219,7 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
assert length(day3_bookings) == 1
|
||||
end
|
||||
|
||||
test "includes optional phone and comment", %{conn: conn, user: user, space: space} do
|
||||
test "includes optional phone", %{conn: conn, user: user, space: space} do
|
||||
conn = log_in_user(conn, user)
|
||||
{:ok, view, _html} = live(conn, "/admin/walk-in")
|
||||
|
||||
|
|
@ -228,18 +228,17 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
:timer.sleep(50)
|
||||
|
||||
view
|
||||
|> form("form[phx-change='update_customer_details']", %{
|
||||
|> form("form[phx-change='validate_customer_details']", %{
|
||||
"customer_name" => "John Doe",
|
||||
"customer_email" => "john@example.com",
|
||||
"customer_phone" => "+39 1234567890",
|
||||
"customer_comment" => "Special request"
|
||||
"customer_phone" => "+39 1234567890"
|
||||
})
|
||||
|> render_change()
|
||||
|
||||
html =
|
||||
view
|
||||
|> element("button[phx-click='create_booking']")
|
||||
|> render_click()
|
||||
|> element("form[phx-submit='create_booking']")
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "Walk-in booking created successfully"
|
||||
|
||||
|
|
@ -257,7 +256,6 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
|
||||
booking = hd(bookings)
|
||||
assert booking.customer_phone == "+39 1234567890"
|
||||
assert booking.customer_comment == "Special request"
|
||||
end
|
||||
|
||||
test "clears form after successful booking", %{conn: conn, user: user} do
|
||||
|
|
@ -269,7 +267,7 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
:timer.sleep(50)
|
||||
|
||||
view
|
||||
|> form("form[phx-change='update_customer_details']", %{
|
||||
|> form("form[phx-change='validate_customer_details']", %{
|
||||
"customer_name" => "John Doe",
|
||||
"customer_email" => "john@example.com"
|
||||
})
|
||||
|
|
@ -277,8 +275,8 @@ defmodule SpazioSolazzoWeb.Admin.WalkInLiveTest do
|
|||
|
||||
html =
|
||||
view
|
||||
|> element("button[phx-click='create_booking']")
|
||||
|> render_click()
|
||||
|> element("form[phx-submit='create_booking']")
|
||||
|> render_submit()
|
||||
|
||||
assert html =~ "Walk-in booking created successfully"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue