mirror of
https://codeberg.org/JasterV/spazio-solazzo.git
synced 2026-04-26 18:20:03 +00:00
This pull request makes phone numbers optional for both user registrations and bookings, and updates validation, database schema, and UI to reflect this change. The main focus is to ensure that users are no longer required to provide a phone number, and that the application gracefully handles cases where a phone number is absent. **Database & Resource Model Updates** * Made the `phone_number` attribute in the `users` table and the `customer_phone` attribute in the `bookings` table nullable, including migration and resource snapshot updates. [[1]](diffhunk://#diff-baa6aed3674c4d6cbbebeafb076662df02dc4c25231dbd9dc9c8f0534ed1a1bfR1-R29) [[2]](diffhunk://#diff-a401f66b2ae5bfb798eb1bc2221bfeeac943e258950c90d59570b0bae05d3664R1-R244) [[3]](diffhunk://#diff-0c1180d6f6abc19b5987c8703bdee9ef67905535202f950e8327c32bd5b89d8aR1-R82) * Updated Ash resource definitions in `user.ex` and `booking.ex` to allow `phone_number` and `customer_phone` to be `nil`. [[1]](diffhunk://#diff-9194b9d80dce091f6dcb56f784217272ae160e35454c4b4ccc8850ad5ee06e38L152-R152) [[2]](diffhunk://#diff-4b1ddd6d86899f2144c69d142883b8719c755e32c03dbda5da2188208a5ad503L55-R55) [[3]](diffhunk://#diff-4b1ddd6d86899f2144c69d142883b8719c755e32c03dbda5da2188208a5ad503L170-R170) **Validation & Parsing Logic** * Renamed and refactored user registration field validation to `ParseRegistrationFields`, allowing phone numbers to be omitted and trimming input values. Empty phone numbers are now treated as absent rather than as errors. [[1]](diffhunk://#diff-8ffdd76e260e3cda6f0816c8e585ae76b993a90d2519c38185a5fe22b4b49e47L1-R1) [[2]](diffhunk://#diff-8ffdd76e260e3cda6f0816c8e585ae76b993a90d2519c38185a5fe22b4b49e47R14-R60) * Updated the authentication callback logic to trim input values and omit the phone number parameter if it is blank. **User Interface Improvements** * Updated registration and booking forms to indicate that phone numbers are optional, removed the required attribute, and improved placeholder text. [[1]](diffhunk://#diff-f356eb84970d8c9ee6ff1992c297b0cae07bade37ff967c1e6e0de6f8b67081cL101-R115) [[2]](diffhunk://#diff-43c0e1f7a869ee5c43a911bc10dc80cbb265a8672340ef0fa7c1d3009c047f02L92-R92) * Updated email templates and confirmation screens to display "N/A" or "-" when phone numbers are missing. [[1]](diffhunk://#diff-48468ef2d1bb2c33b5ffb40457b77532815c7faf1830932661f665bff58b2177R6-R11) [[2]](diffhunk://#diff-3f33187b4021450b481ce53fe13166addea582c627f2cfbc99c75c7ce5c34857L10-R10) [[3]](diffhunk://#diff-43c0e1f7a869ee5c43a911bc10dc80cbb265a8672340ef0fa7c1d3009c047f02L92-R92) **Profile Management** * Improved profile update flow to ensure the form reflects the latest user data after saving changes. * Made the "Full Name" field explicitly required in the profile form UI.
192 lines
5.6 KiB
Elixir
192 lines
5.6 KiB
Elixir
defmodule SpazioSolazzo.BookingSystem.Booking do
|
|
@moduledoc """
|
|
Represents a customer booking with state management for reservation lifecycle.
|
|
"""
|
|
|
|
use Ash.Resource,
|
|
otp_app: :spazio_solazzo,
|
|
domain: SpazioSolazzo.BookingSystem,
|
|
data_layer: AshPostgres.DataLayer,
|
|
notifiers: [Ash.Notifier.PubSub],
|
|
authorizers: [Ash.Policy.Authorizer],
|
|
extensions: [AshStateMachine]
|
|
|
|
alias SpazioSolazzo.BookingSystem.Booking.EmailWorker
|
|
|
|
postgres do
|
|
table "bookings"
|
|
repo SpazioSolazzo.Repo
|
|
|
|
references do
|
|
reference :user, on_delete: :nilify, index?: true
|
|
end
|
|
end
|
|
|
|
state_machine do
|
|
initial_states([:reserved])
|
|
default_initial_state(:reserved)
|
|
|
|
transitions do
|
|
transition(:confirm_booking, from: :reserved, to: :completed)
|
|
transition(:cancel, from: :reserved, to: :cancelled)
|
|
end
|
|
end
|
|
|
|
actions do
|
|
defaults [:read]
|
|
|
|
read :list_active_asset_bookings_by_date do
|
|
argument :asset_id, :uuid, allow_nil?: false
|
|
argument :date, :date, allow_nil?: false
|
|
|
|
filter expr(
|
|
asset_id == ^arg(:asset_id) and date == ^arg(:date) and
|
|
state in [:reserved, :completed]
|
|
)
|
|
end
|
|
|
|
create :create do
|
|
argument :time_slot_template_id, :uuid, allow_nil?: false
|
|
argument :asset_id, :uuid, allow_nil?: false
|
|
argument :user_id, :uuid, allow_nil?: false
|
|
argument :date, :date, allow_nil?: false
|
|
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(:time_slot_template_id, :time_slot_template,
|
|
type: :append_and_remove
|
|
)
|
|
|
|
change manage_relationship(:asset_id, :asset, type: :append_and_remove)
|
|
|
|
change manage_relationship(:user_id, :user, type: :append_and_remove, authorize?: false)
|
|
|
|
change fn changeset, _ctx ->
|
|
template_id = Ash.Changeset.get_argument(changeset, :time_slot_template_id)
|
|
|
|
case Ash.get(SpazioSolazzo.BookingSystem.TimeSlotTemplate, template_id) do
|
|
{:ok, template} ->
|
|
changeset
|
|
|> Ash.Changeset.force_change_attribute(:start_time, template.start_time)
|
|
|> Ash.Changeset.force_change_attribute(:end_time, template.end_time)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:date,
|
|
Ash.Changeset.get_argument(changeset, :date)
|
|
)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:customer_name,
|
|
Ash.Changeset.get_argument(changeset, :customer_name)
|
|
)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:customer_email,
|
|
Ash.Changeset.get_argument(changeset, :customer_email)
|
|
)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:customer_phone,
|
|
Ash.Changeset.get_argument(changeset, :customer_phone)
|
|
)
|
|
|> Ash.Changeset.force_change_attribute(
|
|
:customer_comment,
|
|
Ash.Changeset.get_argument(changeset, :customer_comment)
|
|
)
|
|
|
|
{:error, _} ->
|
|
Ash.Changeset.add_error(changeset,
|
|
field: :time_slot_template_id,
|
|
message: "Template not found"
|
|
)
|
|
end
|
|
end
|
|
|
|
change after_action(fn _changeset, booking, _ctx ->
|
|
%{
|
|
booking_id: booking.id,
|
|
customer_name: booking.customer_name,
|
|
customer_email: booking.customer_email,
|
|
customer_phone: booking.customer_phone,
|
|
customer_comment: booking.customer_comment,
|
|
date: Calendar.strftime(booking.date, "%A, %B %d"),
|
|
start_time: booking.start_time,
|
|
end_time: booking.end_time
|
|
}
|
|
|> EmailWorker.new()
|
|
|> Oban.insert!()
|
|
|
|
{:ok, booking}
|
|
end)
|
|
end
|
|
|
|
update :confirm_booking do
|
|
accept []
|
|
change transition_state(:completed)
|
|
end
|
|
|
|
update :cancel do
|
|
accept []
|
|
change transition_state(:cancelled)
|
|
end
|
|
|
|
destroy :destroy do
|
|
description "Delete a booking record"
|
|
primary? true
|
|
end
|
|
end
|
|
|
|
policies do
|
|
policy action([:cancel, :confirm_booking]) do
|
|
authorize_if always()
|
|
end
|
|
|
|
policy action_type(:destroy) do
|
|
authorize_if expr(:user_id == ^actor(:id))
|
|
end
|
|
|
|
policy action_type(:read) do
|
|
authorize_if always()
|
|
end
|
|
|
|
policy action_type(:create) do
|
|
authorize_if always()
|
|
end
|
|
end
|
|
|
|
pub_sub do
|
|
module SpazioSolazzoWeb.Endpoint
|
|
prefix "booking"
|
|
|
|
publish :create, ["created"]
|
|
publish :cancel, ["cancelled"]
|
|
end
|
|
|
|
attributes do
|
|
uuid_primary_key :id
|
|
attribute :date, :date, allow_nil?: false
|
|
attribute :customer_name, :string, allow_nil?: false
|
|
attribute :customer_email, :string, allow_nil?: false
|
|
attribute :start_time, :time, allow_nil?: false
|
|
attribute :end_time, :time, allow_nil?: false
|
|
attribute :customer_phone, :string, allow_nil?: true
|
|
attribute :customer_comment, :string, allow_nil?: true
|
|
|
|
attribute :state, :atom do
|
|
allow_nil? false
|
|
default :reserved
|
|
public? true
|
|
constraints one_of: [:reserved, :completed, :cancelled]
|
|
end
|
|
|
|
create_timestamp :inserted_at
|
|
update_timestamp :updated_at
|
|
end
|
|
|
|
relationships do
|
|
belongs_to :asset, SpazioSolazzo.BookingSystem.Asset
|
|
belongs_to :time_slot_template, SpazioSolazzo.BookingSystem.TimeSlotTemplate
|
|
|
|
belongs_to :user, SpazioSolazzo.Accounts.User do
|
|
allow_nil? true
|
|
end
|
|
end
|
|
end
|