diff --git a/public/css/cresta-admin.css b/public/css/cresta-admin.css new file mode 100644 index 0000000..02b34ea --- /dev/null +++ b/public/css/cresta-admin.css @@ -0,0 +1,2 @@ +@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700;800&family=Manrope:wght@500;600;700;800&display=swap'); +:root{--navy:#102b37;--navy2:#173947;--accent:#d6a96e;--text:#172e3a;--muted:#778691;--bg:#f4f6f7;--line:#e6eaed;--white:#fff}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-family:'DM Sans',sans-serif;font-size:14px}a{text-decoration:none;color:inherit}button,select,input{font:inherit}.admin-shell{display:flex;min-height:100vh}.sidebar{width:254px;background:var(--navy);color:#d4dfe2;display:flex;flex-direction:column;flex-shrink:0;position:sticky;top:0;height:100vh;padding:26px 15px}.brand{display:flex;gap:13px;align-items:center;color:white;padding:4px 13px 35px}.brand-mark{display:grid;place-items:center;width:45px;height:45px;border-radius:12px;background:var(--accent);color:var(--navy);font-family:Manrope;font-weight:800;font-size:21px}.brand strong{display:block;letter-spacing:1.6px;font-size:16px}.brand small{display:block;font-size:9px;letter-spacing:1.5px;color:#9eafb8;margin-top:4px}.nav-caption{font-size:10px;font-weight:800;letter-spacing:2px;color:#6e8996;padding:10px 16px 12px}.side-nav{display:grid;gap:5px;margin-bottom:25px}.nav-link{display:flex;align-items:center;gap:14px;padding:12px 15px;border-radius:9px;font-weight:600;color:#b7c9d0;transition:.15s}.nav-link:hover{background:#204250;color:white}.nav-link.active{background:#28505b;color:white;box-shadow:inset 3px 0 var(--accent)}.nav-icon{font-size:19px;width:21px;text-align:center;color:#aac2c8}.active .nav-icon{color:var(--accent)}.sidebar-bottom{margin-top:auto;border-top:1px solid #2a4a56;padding:19px 14px 0;font-size:12px;color:#bacbd0}.sidebar-bottom small{display:block;color:#78919b;margin:9px 0 0 15px;font-size:10px;letter-spacing:1px}.status-dot{display:inline-block;width:7px;height:7px;background:#4fcaa0;border-radius:50%;margin-right:7px}.main-area{min-width:0;flex:1;display:flex;flex-direction:column}.topbar{height:76px;background:white;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;padding:0 36px;gap:15px}.crumb{font-size:13px;color:#8996a0}.crumb span{margin:0 10px;color:#bfc9ce}.crumb strong{color:#2b4451}.topbar-right,.topbar-left{display:flex;align-items:center;gap:17px}.site-pill{background:#eef8f4;border-radius:30px;padding:9px 12px;color:#3c8b70;font-size:11px;font-weight:700}.avatar{height:34px;width:34px;background:#dce8e9;color:#2b5860;border-radius:50%;display:grid;place-items:center;font-weight:800}.account-name{font-weight:700;font-size:12px;max-width:170px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.signout{background:none;border:0;color:#7b8993;cursor:pointer;font-weight:700}.signout:hover{color:var(--navy)}.menu-toggle{display:none;border:0;background:transparent;font-size:22px;color:var(--navy);cursor:pointer}.content{width:100%;max-width:1700px;margin:0 auto;padding:39px 38px 55px;flex:1}.eyebrow{font-size:10px;font-weight:800;letter-spacing:2.2px;color:#c19a69;margin-bottom:9px}.page-heading{display:flex;justify-content:space-between;align-items:center;gap:15px;margin-bottom:27px}.page-heading h1{font:800 31px/1.25 Manrope,sans-serif;letter-spacing:-1px;margin:0 0 8px}.page-heading p{color:var(--muted);margin:0}.btn{border:1px solid var(--line);border-radius:9px;padding:12px 16px;font-weight:700;display:inline-block;white-space:nowrap;cursor:pointer}.btn.secondary{background:white;color:#36515c}.btn.primary{background:var(--navy);color:white;border-color:var(--navy)}.stats-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:18px;margin-bottom:26px}.stat-card{background:white;border:1px solid var(--line);border-radius:13px;padding:23px 24px;box-shadow:0 3px 12px #183a4505}.stat-label{display:flex;justify-content:space-between;color:#7d8d96;font-size:12px;font-weight:700}.stat-label span{font-size:20px;color:#c8a374}.stat-value{font:800 30px Manrope,sans-serif;margin:15px 0 8px;letter-spacing:-1px}.stat-foot{color:#97a4ac;font-size:11px}.panel{background:white;border:1px solid var(--line);border-radius:13px;overflow:hidden;margin-bottom:23px;box-shadow:0 3px 12px #183a4505}.panel-heading{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:23px 26px;border-bottom:1px solid var(--line)}.panel-heading h2{font:800 17px Manrope,sans-serif;margin:0 0 6px}.panel-heading p{color:var(--muted);margin:0;font-size:12px}.count-chip{background:#f1f4f5;border-radius:6px;padding:7px 11px;color:#61727b;font-size:11px;font-weight:800}.table-scroll{overflow-x:auto}.booking-table{width:100%;border-collapse:collapse;text-align:left;min-width:940px}.booking-table th{padding:16px 21px;background:#fafbfb;color:#81919a;font-size:10px;letter-spacing:1px;text-transform:uppercase}.booking-table td{padding:18px 21px;border-top:1px solid #eff1f2;vertical-align:middle;font-size:12px}.booking-table td small{display:block;color:#87969f;margin-top:5px}.reference{color:#2a6473}.date-cell{line-height:1.8}.date-to{color:#87969f}.badge{display:inline-block;border-radius:20px;padding:7px 11px;font-size:11px;font-weight:800;background:#eff1f3;color:#677783}.badge.pending{background:#fff5e5;color:#b78024}.badge.confirmed{background:#e7f7ef;color:#288b61}.badge.cancelled{background:#fcebea;color:#bd5e56}.update-form{display:flex;gap:6px}.update-form select{border:1px solid #dce4e7;border-radius:6px;padding:8px;background:white;color:#405965;min-width:100px}.update-form button{background:var(--navy);color:white;border:0;border-radius:6px;padding:8px 12px;cursor:pointer;font-weight:700}.pagination-area{padding:17px 25px;border-top:1px solid var(--line)}.pagination-area nav{max-width:100%}.empty-table{text-align:center;color:var(--muted);padding:45px!important}.quick-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px}.quick-card{background:white;border:1px solid var(--line);border-radius:12px;padding:20px 22px;display:flex;align-items:center;gap:16px}.quick-card:hover{border-color:#bdcfd3}.quick-icon{display:grid;place-items:center;width:48px;height:48px;background:#eaf1f1;border-radius:10px;color:#2a6473;font-size:22px}.quick-card strong,.quick-card small{display:block}.quick-card small{color:#82919a;margin-top:5px}.quick-arrow{margin-left:auto;font-size:19px;color:#c1a27b}.notice{padding:14px 18px;border-radius:8px;margin-bottom:20px}.notice.success{background:#e8f7ee;color:#267449}.notice.error{background:#fff0ef;color:#ad4848}.footer{display:flex;justify-content:space-between;padding:18px 38px;color:#a3adb3;font-size:11px;border-top:1px solid var(--line)}.upload-form{padding:26px;display:flex;gap:16px;align-items:center;flex-wrap:wrap}.upload-form label{font-weight:700}.upload-form input{max-width:100%}.photo-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:16px;padding:23px}.photo-card{border:1px solid var(--line);border-radius:9px;overflow:hidden}.photo-card img,.photo-placeholder{width:100%;height:170px;object-fit:cover;background:#e8eff0}.photo-placeholder{display:grid;place-items:center}.photo-caption{padding:13px;display:flex;justify-content:space-between;align-items:center}.link-danger{border:0;background:none;color:#bd5e56;cursor:pointer}.empty-panel{background:white;border:1px solid var(--line);border-radius:12px;padding:40px;color:var(--muted)}.mobile-shade{display:none}@media(max-width:1100px){.stats-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.account-name{display:none}}@media(max-width:800px){.sidebar{position:fixed;left:-270px;z-index:50;transition:left .2s;box-shadow:8px 0 25px #0002}.menu-open .sidebar{left:0}.menu-open~.mobile-shade{display:block;position:fixed;inset:0;background:#0008;z-index:40}.menu-toggle{display:block}.topbar{padding:0 20px;height:66px}.content{padding:28px 18px 40px}.site-pill{display:none}.page-heading{align-items:flex-start}.page-heading h1{font-size:26px}.quick-grid{grid-template-columns:1fr}.footer{padding:18px}}@media(max-width:520px){.stats-grid{gap:10px}.stat-card{padding:16px}.stat-value{font-size:24px}.page-heading{flex-direction:column}.topbar-right{gap:9px}.crumb{font-size:11px}.signout{font-size:11px}.panel-heading{padding:19px}.footer span{display:none}} diff --git a/resources/views/lodge/admin-layout.blade.php b/resources/views/lodge/admin-layout.blade.php new file mode 100644 index 0000000..505c3e4 --- /dev/null +++ b/resources/views/lodge/admin-layout.blade.php @@ -0,0 +1,9 @@ + +@yield('title', 'Administration') · Cresta 31 +
+
Cresta 31 / @yield('section-label','Overview')
Site online
{{ strtoupper(substr(auth()->user()->name ?? auth()->user()->email ?? 'A', 0, 1)) }}
@csrf
@if(session('success'))
{{ session('success') }}
@endif@if($errors->any())
{{ $errors->first() }}
@endif @yield('content')
diff --git a/resources/views/lodge/admin.blade.php b/resources/views/lodge/admin.blade.php index 87743d8..5ab71b5 100644 --- a/resources/views/lodge/admin.blade.php +++ b/resources/views/lodge/admin.blade.php @@ -1 +1,23 @@ -@extends('lodge.layout')@section('title','Manage bookings | Cresta 31')@section('content')

Manage bookings

@if(session('success'))

{{ session('success') }}

@endif@if($errors->any())
{{ $errors->first() }}
@endif
@forelse($bookings as $b)@empty@endforelse
ReferenceGuestDatesGuestsTotalStatusAction
{{ $b->reference }}{{ $b->guest_name }}
{{ $b->guest_email }}
{{ $b->guest_phone }}
{{ $b->check_in->format('d M Y') }} – {{ $b->check_out->format('d M Y') }}{{ $b->guests }}£{{ number_format($b->total_pence/100,2) }}{{ ucfirst($b->status) }}
@csrf @method('PATCH')
No bookings yet.
{{ $bookings->links() }}

Lodge photographs

Upload JPEG, PNG or WebP photographs. Images are automatically resized and converted to WebP, and remain available after deployments.

@csrf
@endsection \ No newline at end of file +@extends('lodge.admin-layout') +@section('title','Bookings & overview') +@section('section-label',request('section') === 'photos' ? 'Photographs' : (request('section') === 'bookings' ? 'Bookings' : 'Overview')) +@section('content') +@php +$section = request('section', 'overview'); +$items = $bookings->getCollection(); +$allCount = $bookings->total(); +$pendingOnPage = $items->where('status','pending')->count(); +$confirmedOnPage = $items->where('status','confirmed')->count(); +$revenueOnPage = $items->where('status','confirmed')->sum('total_pence') / 100; +@endphp +@if($section === 'photos') +
PROPERTY MEDIA

Photographs

Manage the photographs displayed on your lodge website.

← Back to overview
+@if(Route::has('lodge.photos.store'))

Upload photographs

Add new images to your lodge gallery.

@csrf
@endif +@if(isset($photos) && count($photos))

Gallery

{{ count($photos) }} photos
@foreach($photos as $photo)
@php $photoPath = $photo->url ?? $photo->path ?? $photo->filename ?? null; @endphp @if($photoPath)Lodge photograph@else
Image
@endif
Photo #{{ $photo->id }}@if(Route::has('lodge.photos.destroy'))
@csrf @method('DELETE')
@endif
@endforeach
@elseif(!Route::has('lodge.photos.store'))
Photo management is not installed in this version of Cresta 31.
@else
No uploaded photographs yet.
@endif +@else +
PROPERTY MANAGEMENT

{{ $section === 'bookings' ? 'Bookings' : 'Welcome back' }}

{{ $section === 'bookings' ? 'Review reservations and update booking statuses.' : 'Here’s what’s happening with your lodge bookings.' }}

View website ↗
+
Total bookings ▤
{{ number_format($allCount) }}
All reservations
Pending ◷
{{ $pendingOnPage }}
On this page
Confirmed ✓
{{ $confirmedOnPage }}
On this page
Confirmed value £
£{{ number_format($revenueOnPage,2) }}
On this page
+

{{ $section === 'bookings' ? 'All bookings' : 'Recent bookings' }}

Manage guest reservations and their current status.

{{ number_format($allCount) }} total
@forelse($bookings as $b)@empty@endforelse
ReferenceGuestStay datesGuestsAmountStatusUpdate
{{ $b->reference }}{{ $b->guest_name }}{{ $b->guest_email }}@if($b->guest_phone){{ $b->guest_phone }}@endif{{ $b->check_in?->format('d M Y') }}
to {{ $b->check_out?->format('d M Y') }}
{{ $b->guests }}£{{ number_format($b->total_pence/100,2) }}{{ ucfirst($b->status) }}
@csrf @method('PATCH')
No bookings yet. New reservations will appear here.
{{ $bookings->appends(request()->query())->links() }}
+@if($section !== 'bookings')
▤
Manage bookingsReview and update reservations
→
▧
Lodge galleryUpload and organise photos
→
@endif +@endif +@endsection