feat: remove unused components

This commit is contained in:
JasterV 2026-02-02 17:45:27 +01:00
parent 7ff3adf730
commit bc0ff021e8
8 changed files with 100 additions and 239 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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")

View file

@ -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")

View file

@ -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")