spazio-solazzo/lib/spazio_solazzo_web/live/admin/booking_management_live.html.heex
2026-02-09 16:43:16 +01:00

196 lines
8.5 KiB
Text

<Layouts.app flash={@flash} current_user={@current_user} current_path={@current_path}>
<main class="flex-grow px-4 py-8 md:px-8">
<div class="max-w-6xl mx-auto flex flex-col gap-8">
<.back_to_link
navigate={~p"/admin/dashboard"}
value="Back to Dashboard"
/>
<%!-- Title and stats --%>
<div class="flex flex-col md:flex-row md:items-end justify-between gap-4">
<div class="flex flex-col gap-2">
<h1 class="text-slate-900 dark:text-white tracking-tight text-3xl md:text-4xl font-extrabold">
Manage Bookings
</h1>
<p class="text-slate-600 dark:text-slate-400 text-base font-normal max-w-2xl">
Review reservations and booking history. Pending requests require approval.
</p>
</div>
<div class="flex gap-4">
<div class="bg-white dark:bg-slate-800 px-5 py-3 rounded-xl border border-slate-200 dark:border-slate-700 shadow-sm flex flex-col items-start min-w-[140px]">
<span class="text-xs font-bold uppercase tracking-wider text-slate-600 dark:text-slate-400">
Pending
</span>
<span class="text-2xl font-bold text-primary">{@pending_page.count}</span>
</div>
</div>
</div>
<%!-- Filters --%>
<div class="bg-white dark:bg-slate-800 p-5 rounded-2xl shadow-sm border border-slate-200 dark:border-slate-700">
<form
phx-change="filter_bookings"
phx-submit="filter_bookings"
class="grid grid-cols-1 md:grid-cols-12 gap-4 items-end"
>
<div class="col-span-1 md:col-span-4 flex flex-col gap-1.5">
<label class="text-sm font-semibold text-slate-900 dark:text-slate-200 ml-1">
Customer Email
</label>
<div class="relative">
<span class="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500">
<.icon name="hero-magnifying-glass" class="w-5 h-5" />
</span>
<input
name="email"
value={@filter_email}
class="w-full h-12 pl-10 pr-4 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 text-slate-900 dark:text-white focus:ring-2 focus:ring-primary focus:border-transparent outline-none transition-all placeholder:text-slate-400"
placeholder="Search by email..."
type="text"
/>
</div>
</div>
<div class="col-span-1 md:col-span-3 flex flex-col gap-1.5">
<label class="text-sm font-semibold text-slate-900 dark:text-slate-200 ml-1">
Space
</label>
<div class="relative">
<span class="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500 pointer-events-none">
<.icon name="hero-map-pin" class="w-5 h-5" />
</span>
<select
name="space"
class="w-full h-12 pl-10 pr-10 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 text-slate-900 dark:text-white focus:ring-2 focus:ring-primary focus:border-transparent outline-none appearance-none cursor-pointer"
>
<option value="">All Spaces</option>
<%= for space <- @spaces do %>
<option value={space.slug} selected={@filter_space == space.slug}>
{space.name}
</option>
<% end %>
</select>
<span class="absolute right-3 top-1/2 -translate-y-1/2 text-slate-500 pointer-events-none">
<.icon name="hero-chevron-down" class="w-5 h-5" />
</span>
</div>
</div>
<div class="col-span-1 md:col-span-3 flex flex-col gap-1.5">
<label class="text-sm font-semibold text-slate-900 dark:text-slate-200 ml-1">
Date
</label>
<div class="relative">
<span class="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500 pointer-events-none">
<.icon name="hero-calendar" class="w-5 h-5" />
</span>
<input
name="date"
value={if @filter_date, do: Date.to_iso8601(@filter_date), else: ""}
class="w-full h-12 pl-10 pr-4 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 text-slate-900 dark:text-white focus:ring-2 focus:ring-primary focus:border-transparent outline-none cursor-pointer"
type="date"
/>
</div>
</div>
<div class="col-span-1 md:col-span-2">
<button
type="button"
phx-click="clear_filters"
class="w-full h-12 bg-slate-900 dark:bg-white hover:bg-slate-800 dark:hover:bg-slate-100 text-white dark:text-slate-900 font-bold rounded-xl transition-colors flex items-center justify-center gap-2 cursor-pointer"
>
<span>Clear Filters</span>
<.icon name="hero-x-mark" class="w-4 h-4" />
</button>
</div>
</form>
</div>
<%= if @pending_page.count == 0 && @history_page.count == 0 do %>
<div class="text-center py-12 bg-slate-50 dark:bg-slate-800/50 rounded-xl">
<.icon name="hero-inbox" class="w-16 h-16 text-slate-400 mx-auto mb-4" />
<p class="text-slate-500 dark:text-slate-400 text-lg">No bookings found</p>
</div>
<% end %>
<%!-- Pending Bookings Table --%>
<%= if @pending_page.count > 0 do %>
<.bookings_table
title="Pending Requests"
bookings={@pending_page.results}
page={@pending_page}
current_page={@pending_page_number}
event_prefix="pending"
expanded_booking_ids={@expanded_booking_ids}
show_actions={true}
show_cancellation_details={false}
/>
<% end %>
<%!-- Past Bookings Table --%>
<%= if @history_page.count > 0 do %>
<.bookings_table
title="Booking History"
bookings={@history_page.results}
page={@history_page}
current_page={@history_page_number}
event_prefix="history"
expanded_booking_ids={@expanded_booking_ids}
show_actions={false}
show_cancellation_details={true}
/>
<% end %>
</div>
</main>
<%!-- Reject Modal --%>
<%= if @show_reject_modal do %>
<div
class="fixed inset-0 bg-slate-900/20 backdrop-blur-sm flex items-center justify-center p-4 z-50"
phx-click="hide_reject_modal"
>
<div
class="bg-white dark:bg-slate-800 rounded-3xl border border-slate-200 dark:border-slate-700 shadow-xl shadow-slate-200/50 dark:shadow-none max-w-md w-full p-6"
phx-click="stop_propagation"
>
<h3 class="text-xl font-bold text-slate-900 dark:text-white mb-3">Reject Booking</h3>
<p class="text-slate-600 dark:text-slate-400 mb-4 text-sm">
Provide a reason for rejecting this booking. The customer will receive this in their email.
</p>
<form phx-submit="confirm_reject">
<div class="mb-4">
<label class="block text-sm font-semibold text-slate-900 dark:text-white mb-2">
Rejection Reason <span class="text-red-500">*</span>
</label>
<textarea
phx-change="update_rejection_reason"
name="reason"
rows="4"
required
placeholder="e.g., Space under maintenance, Fully booked, etc."
class="w-full px-3 py-2 border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 text-slate-900 dark:text-white rounded-xl focus:outline-none focus:ring-2 focus:ring-primary"
>{@rejection_reason}</textarea>
</div>
<div class="flex gap-2">
<button
type="button"
phx-click="hide_reject_modal"
class="flex-1 bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-200 px-4 py-2 rounded-lg font-medium hover:bg-slate-300 dark:hover:bg-slate-600 transition-colors text-sm"
>
Cancel
</button>
<button
type="submit"
class="flex-1 bg-red-500 text-white px-4 py-2 rounded-lg font-medium hover:bg-red-600 transition-colors text-sm"
>
Reject
</button>
</div>
</form>
</div>
</div>
<% end %>
</Layouts.app>