mirror of
https://codeberg.org/JasterV/spazio-solazzo.git
synced 2026-04-26 18:20:03 +00:00
feat: remove unused components
This commit is contained in:
parent
7ff3adf730
commit
bc0ff021e8
8 changed files with 100 additions and 239 deletions
|
|
@ -94,8 +94,6 @@ defmodule SpazioSolazzoWeb do
|
|||
import Phoenix.HTML
|
||||
# Core UI components
|
||||
import SpazioSolazzoWeb.CoreComponents
|
||||
# Landing page components
|
||||
import SpazioSolazzoWeb.LandingComponents
|
||||
|
||||
# Common modules used in templates
|
||||
alias Phoenix.LiveView.JS
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
defmodule SpazioSolazzoWeb.AdminComponents do
|
||||
@moduledoc """
|
||||
Reusable components for admin pages (dashboard & tools).
|
||||
"""
|
||||
use Phoenix.Component
|
||||
|
||||
import SpazioSolazzoWeb.CoreComponents, only: [icon: 1, button: 1]
|
||||
import Phoenix.Component
|
||||
|
||||
use Phoenix.VerifiedRoutes,
|
||||
endpoint: SpazioSolazzoWeb.Endpoint,
|
||||
router: SpazioSolazzoWeb.Router,
|
||||
statics: SpazioSolazzoWeb.static_paths()
|
||||
|
||||
@doc """
|
||||
Cards displayed for each tool available to admins
|
||||
"""
|
||||
attr :id, :string, doc: "optional id for the tool"
|
||||
attr :title, :string
|
||||
attr :icon, :string, doc: "Icon used to represent the type of tool"
|
||||
attr :description, :string
|
||||
|
||||
def tool_card(assigns) do
|
||||
~H"""
|
||||
<div class="card bg-base-100 text-base-content shadow-xl border border-base-200 hover:shadow-2xl transition-shadow cursor-pointer">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title flex items-center gap-2">
|
||||
<.icon name={@icon} class="size-6 text-secondary" /> {@title}
|
||||
</h2>
|
||||
<p class="text-base-content/70 mt-2">{@description}</p>
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<.button class="btn btn-primary btn-sm">Open</.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
|
@ -3,110 +3,95 @@ defmodule SpazioSolazzoWeb.BookingComponents do
|
|||
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-base-100 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-success/10">
|
||||
<svg
|
||||
class="h-6 w-6 text-success"
|
||||
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-base-content">
|
||||
Booking Successful!
|
||||
</h3>
|
||||
<div class="mt-2">
|
||||
<p class="text-sm text-neutral">
|
||||
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="btn btn-success w-full rounded-2xl text-white shadow-lg hover:shadow-xl transition-all"
|
||||
>
|
||||
Got it!
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
import SpazioSolazzoWeb.CoreComponents, only: [icon: 1]
|
||||
|
||||
attr :time_slot, :map, required: true
|
||||
attr :booked, :boolean, required: true
|
||||
|
||||
@doc """
|
||||
Renders time slot buttons in different sizes showing availability status.
|
||||
Renders a detailed time slot card showing availability status and booking counts.
|
||||
"""
|
||||
def time_slot(assigns) do
|
||||
def time_slot_card(assigns) do
|
||||
assigns =
|
||||
assigns
|
||||
|> assign(:availability, assigns.time_slot.booking_stats.availability_status)
|
||||
|> assign(:requested_count, assigns.time_slot.booking_stats.requested_count)
|
||||
|> assign(:accepted_count, assigns.time_slot.booking_stats.accepted_count)
|
||||
|> assign(:user_has_booking, assigns.time_slot.booking_stats.user_has_booking)
|
||||
|
||||
~H"""
|
||||
<button
|
||||
phx-click={unless @booked, do: "select_slot"}
|
||||
phx-click={if @user_has_booking, do: nil, else: "select_slot"}
|
||||
phx-value-time_slot_id={@time_slot.id}
|
||||
disabled={@booked}
|
||||
disabled={@user_has_booking}
|
||||
class={[
|
||||
"group w-full flex items-center justify-between p-4 rounded-xl border-2 transition-all duration-200",
|
||||
if(@booked,
|
||||
do: "border-base-300 bg-base-200 cursor-not-allowed opacity-75",
|
||||
"w-full p-4 rounded-xl border-2 transition-all duration-200 text-left",
|
||||
if(@user_has_booking,
|
||||
do:
|
||||
"border-slate-200 bg-slate-100 cursor-not-allowed opacity-60 dark:bg-slate-700/50 dark:border-slate-600",
|
||||
else:
|
||||
"border-secondary/40 hover:border-secondary bg-transparent hover:bg-secondary/5 cursor-pointer"
|
||||
if(@availability == :available,
|
||||
do:
|
||||
"border-green-200 bg-green-50 hover:border-green-500 hover:shadow-lg cursor-pointer dark:bg-green-900/20 dark:border-green-800 dark:hover:border-green-600",
|
||||
else:
|
||||
"border-yellow-200 bg-yellow-50 hover:border-yellow-500 hover:shadow-lg cursor-pointer dark:bg-yellow-900/20 dark:border-yellow-800 dark:hover:border-yellow-600"
|
||||
)
|
||||
)
|
||||
]}
|
||||
>
|
||||
<span class={[
|
||||
"text-lg font-bold transition-colors",
|
||||
if(@booked,
|
||||
do: "text-neutral",
|
||||
else: "text-base-content group-hover:text-secondary"
|
||||
)
|
||||
]}>
|
||||
{CalendarExt.format_time_range(@time_slot)}
|
||||
</span>
|
||||
<span class={[
|
||||
"text-xs font-medium",
|
||||
if(@booked, do: "text-neutral", else: "text-secondary")
|
||||
]}>
|
||||
{if @booked, do: "Booked", else: "Available"}
|
||||
</span>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="text-lg font-semibold text-slate-900 dark:text-white">
|
||||
{Calendar.strftime(@time_slot.start_time, "%H:%M")} - {Calendar.strftime(
|
||||
@time_slot.end_time,
|
||||
"%H:%M"
|
||||
)}
|
||||
</div>
|
||||
<%= if @user_has_booking do %>
|
||||
<div class="text-sm text-slate-500 dark:text-slate-400 font-medium mt-1">
|
||||
Already Requested
|
||||
</div>
|
||||
<% else %>
|
||||
<%= if @availability == :available do %>
|
||||
<div class="text-sm text-green-600 dark:text-green-400 font-medium mt-1">
|
||||
Available - Request Booking
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="text-sm text-yellow-600 dark:text-yellow-400 font-medium mt-1">
|
||||
High Demand - Join Waitlist
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<div class="flex gap-3 mt-2 text-xs text-slate-600 dark:text-slate-400">
|
||||
<%= if @requested_count > 0 do %>
|
||||
<span class="flex items-center gap-1">
|
||||
<.icon name="hero-clock" class="w-3.5 h-3.5" />
|
||||
{@requested_count} pending
|
||||
</span>
|
||||
<% end %>
|
||||
<%= if @accepted_count > 0 do %>
|
||||
<span class="flex items-center gap-1">
|
||||
<.icon name="hero-check-circle" class="w-3.5 h-3.5" />
|
||||
{@accepted_count} booked
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<.icon
|
||||
name={if @user_has_booking, do: "hero-check", else: "hero-arrow-right"}
|
||||
class={[
|
||||
"w-5 h-5",
|
||||
if(@user_has_booking,
|
||||
do: "text-slate-400 dark:text-slate-500",
|
||||
else:
|
||||
if(@availability == :available,
|
||||
do: "text-green-500 dark:text-green-400",
|
||||
else: "text-yellow-500 dark:text-yellow-400"
|
||||
)
|
||||
)
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ defmodule SpazioSolazzoWeb.SpaceBookingLive do
|
|||
use SpazioSolazzoWeb, :live_view
|
||||
|
||||
alias SpazioSolazzo.BookingSystem
|
||||
require Ash.Query
|
||||
import SpazioSolazzoWeb.BookingComponents
|
||||
|
||||
def mount(%{"space_slug" => space_slug}, _session, socket) do
|
||||
case BookingSystem.get_space_by_slug(space_slug) do
|
||||
|
|
@ -27,8 +27,7 @@ defmodule SpazioSolazzoWeb.SpaceBookingLive do
|
|||
selected_time_slot: nil,
|
||||
show_booking_modal: false,
|
||||
show_success_modal: false,
|
||||
time_slots: time_slots,
|
||||
current_scope: nil
|
||||
time_slots: time_slots
|
||||
)}
|
||||
|
||||
{:error, _error} ->
|
||||
|
|
@ -68,12 +67,12 @@ defmodule SpazioSolazzoWeb.SpaceBookingLive do
|
|||
result =
|
||||
BookingSystem.create_booking(
|
||||
socket.assigns.space.id,
|
||||
current_user && current_user.id,
|
||||
current_user.id,
|
||||
socket.assigns.selected_date,
|
||||
socket.assigns.selected_time_slot.start_time,
|
||||
socket.assigns.selected_time_slot.end_time,
|
||||
booking_data.customer_name,
|
||||
(current_user && current_user.email) || booking_data.customer_email,
|
||||
current_user.email,
|
||||
booking_data.customer_phone,
|
||||
booking_data.customer_comment
|
||||
)
|
||||
|
|
@ -87,19 +86,6 @@ defmodule SpazioSolazzoWeb.SpaceBookingLive do
|
|||
show_success_modal: true
|
||||
)}
|
||||
|
||||
{:error, %Ash.Error.Invalid{errors: errors}} ->
|
||||
error_message =
|
||||
Enum.map_join(errors, ", ", fn
|
||||
%{field: :date, message: msg} -> msg
|
||||
%{message: msg} -> msg
|
||||
_error -> "Invalid booking request"
|
||||
end)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(show_booking_modal: false)
|
||||
|> put_flash(:error, error_message)}
|
||||
|
||||
{:error, _error} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|
|
@ -109,8 +95,8 @@ defmodule SpazioSolazzoWeb.SpaceBookingLive do
|
|||
end
|
||||
|
||||
def handle_info({:date_selected, date}, socket) do
|
||||
current_user = socket.assigns[:current_user]
|
||||
time_slots = load_time_slots_with_stats(socket.assigns.space, date, current_user)
|
||||
time_slots =
|
||||
load_time_slots_with_stats(socket.assigns.space, date, socket.assigns.current_user)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|
|
@ -124,8 +110,8 @@ defmodule SpazioSolazzoWeb.SpaceBookingLive do
|
|||
%{topic: "booking:" <> _event, payload: %{data: %{space_id: space_id, date: date}}},
|
||||
%{assigns: %{space: %{id: space_id}, selected_date: date}} = socket
|
||||
) do
|
||||
current_user = socket.assigns[:current_user]
|
||||
time_slots = load_time_slots_with_stats(socket.assigns.space, date, current_user)
|
||||
time_slots =
|
||||
load_time_slots_with_stats(socket.assigns.space, date, socket.assigns.current_user)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|
|
@ -137,15 +123,15 @@ defmodule SpazioSolazzoWeb.SpaceBookingLive do
|
|||
end
|
||||
|
||||
defp load_time_slots_with_stats(space, date, current_user) do
|
||||
{:ok, time_slots} = BookingSystem.get_space_time_slots_by_date(space.id, date)
|
||||
|
||||
Ash.load!(time_slots,
|
||||
booking_stats: %{
|
||||
date: date,
|
||||
space_id: space.id,
|
||||
capacity: space.capacity,
|
||||
user_id: current_user && current_user.id
|
||||
}
|
||||
BookingSystem.get_space_time_slots_by_date!(space.id, date,
|
||||
load: [
|
||||
booking_stats: %{
|
||||
date: date,
|
||||
space_id: space.id,
|
||||
capacity: space.capacity,
|
||||
user_id: current_user.id
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
{@space.name}
|
||||
</h1>
|
||||
<p class="text-lg text-slate-600 dark:text-slate-400 max-w-2xl mx-auto">
|
||||
{@space.description} - Flexible booking options available
|
||||
{@space.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -45,83 +45,7 @@
|
|||
</div>
|
||||
<% else %>
|
||||
<%= for time_slot <- @time_slots do %>
|
||||
<% availability = time_slot.booking_stats.availability_status %>
|
||||
<% requested_count = time_slot.booking_stats.requested_count %>
|
||||
<% accepted_count = time_slot.booking_stats.accepted_count %>
|
||||
<% user_has_booking = time_slot.booking_stats.user_has_booking %>
|
||||
<button
|
||||
phx-click={if user_has_booking, do: nil, else: "select_slot"}
|
||||
phx-value-time_slot_id={time_slot.id}
|
||||
disabled={user_has_booking}
|
||||
class={[
|
||||
"w-full p-4 rounded-xl border-2 transition-all duration-200 text-left",
|
||||
if(user_has_booking,
|
||||
do:
|
||||
"border-slate-200 bg-slate-100 cursor-not-allowed opacity-60 dark:bg-slate-700/50 dark:border-slate-600",
|
||||
else:
|
||||
if(availability == :available,
|
||||
do:
|
||||
"border-green-200 bg-green-50 hover:border-green-500 hover:shadow-lg cursor-pointer dark:bg-green-900/20 dark:border-green-800 dark:hover:border-green-600",
|
||||
else:
|
||||
"border-yellow-200 bg-yellow-50 hover:border-yellow-500 hover:shadow-lg cursor-pointer dark:bg-yellow-900/20 dark:border-yellow-800 dark:hover:border-yellow-600"
|
||||
)
|
||||
)
|
||||
]}
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="text-lg font-semibold text-slate-900 dark:text-white">
|
||||
{Calendar.strftime(time_slot.start_time, "%H:%M")} - {Calendar.strftime(
|
||||
time_slot.end_time,
|
||||
"%H:%M"
|
||||
)}
|
||||
</div>
|
||||
<%= if user_has_booking do %>
|
||||
<div class="text-sm text-slate-500 dark:text-slate-400 font-medium mt-1">
|
||||
Already Requested
|
||||
</div>
|
||||
<% else %>
|
||||
<%= if availability == :available do %>
|
||||
<div class="text-sm text-green-600 dark:text-green-400 font-medium mt-1">
|
||||
Available - Request Booking
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="text-sm text-yellow-600 dark:text-yellow-400 font-medium mt-1">
|
||||
High Demand - Join Waitlist
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<div class="flex gap-3 mt-2 text-xs text-slate-600 dark:text-slate-400">
|
||||
<%= if requested_count > 0 do %>
|
||||
<span class="flex items-center gap-1">
|
||||
<.icon name="hero-clock" class="w-3.5 h-3.5" />
|
||||
{requested_count} pending
|
||||
</span>
|
||||
<% end %>
|
||||
<%= if accepted_count > 0 do %>
|
||||
<span class="flex items-center gap-1">
|
||||
<.icon name="hero-check-circle" class="w-3.5 h-3.5" />
|
||||
{accepted_count} booked
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<.icon
|
||||
name={if user_has_booking, do: "hero-check", else: "hero-arrow-right"}
|
||||
class={[
|
||||
"w-5 h-5",
|
||||
if(user_has_booking,
|
||||
do: "text-slate-400 dark:text-slate-500",
|
||||
else:
|
||||
if(availability == :available,
|
||||
do: "text-green-500 dark:text-green-400",
|
||||
else: "text-yellow-500 dark:text-yellow-400"
|
||||
)
|
||||
)
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
<.time_slot_card time_slot={time_slot} />
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ defmodule SpazioSolazzoWeb.CoworkingLive do
|
|||
use SpazioSolazzoWeb, :live_view
|
||||
|
||||
alias SpazioSolazzo.BookingSystem
|
||||
# Landing page components
|
||||
import SpazioSolazzoWeb.LandingComponents
|
||||
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, space} = BookingSystem.get_space_by_slug("coworking")
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ defmodule SpazioSolazzoWeb.MeetingLive do
|
|||
use SpazioSolazzoWeb, :live_view
|
||||
|
||||
alias SpazioSolazzo.BookingSystem
|
||||
# Landing page components
|
||||
import SpazioSolazzoWeb.LandingComponents
|
||||
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, space} = BookingSystem.get_space_by_slug("meeting")
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ defmodule SpazioSolazzoWeb.MusicLive do
|
|||
use SpazioSolazzoWeb, :live_view
|
||||
|
||||
alias SpazioSolazzo.BookingSystem
|
||||
# Landing page components
|
||||
import SpazioSolazzoWeb.LandingComponents
|
||||
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, space} = BookingSystem.get_space_by_slug("music")
|
||||
|
|
|
|||
Loading…
Reference in a new issue