File: //home/workzeni/agency-erp-05.workzenix.com/resources/views/admin/hotel/create.blade.php
@extends('layouts.master')
@section('title', 'Hotel Booking')
@section('content')
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Create Hotel Booking</h5>
<a href="{{ route('hotel.list') }}" class="btn btn-danger btn-sm">Manage Bookings</a>
</div>
<div class="card-body">
<form action="{{ route('hotel.store') }}" method="POST" class="form">
@csrf
{{-- ========== Agency / User Selection ========== --}}
@if (in_array(auth()->user()->role, [1, 2, 3]))
<div class="row row-cols-md-2 mt-3">
<div class="form-group">
<label for="agency_id">Select Agency <span class="text-danger">*</span></label>
<select name="agency_id" id="agency_id" class="form-control" required>
<option value="" disabled selected>Select Agency</option>
@foreach ($agencies as $agency)
<option value="{{ $agency->id }}">{{ $agency->name }}</option>
@endforeach
</select>
</div>
<div class="form-group">
<label for="user_id">Select User <span class="text-danger">*</span></label>
<select name="user_id" id="user_id" class="form-control" required>
<option value="" disabled selected>Select User</option>
</select>
</div>
</div>
@else
<input type="hidden" name="agency_id" id="agency_id" value="{{ auth()->user()->company_id }}">
@endif
{{-- ========== City Selection ========== --}}
<div class="d-flex gap-3 align-items-center mt-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="city" id="cityMakkah" value="makkah">
<label class="form-check-label" for="cityMakkah">🕋 Makkah</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="city" id="cityMadinah" value="madinah">
<label class="form-check-label" for="cityMadinah">🕌 Madinah</label>
</div>
</div>
{{-- ========== Season Selection ========== --}}
<div class="form-group mt-4">
<label for="season_id">Select Season <span class="text-danger">*</span></label>
@if ($activeSeasons->count() > 1)
<select name="season_id" id="season_id" class="form-control" required>
<option value="" disabled selected>Select Season</option>
@foreach ($activeSeasons as $season)
<option value="{{ $season->id }}">{{ $season->name }}</option>
@endforeach
</select>
@elseif($activeSeasons->count() === 1)
@php $season = $activeSeasons->first(); @endphp
<input type="hidden" name="season_id" id="season_id" value="{{ $season->id }}">
<input type="text" class="form-control" value="{{ $season->name }}" readonly>
@else
<input type="text" class="form-control" value="No active season" readonly>
@endif
</div>
{{-- ========== Hotel Details ========== --}}
<div class="row row-cols-md-2 mt-3">
<div class="form-group">
<label for="hotel_name">Hotel Name <span class="text-danger">*</span></label>
<input type="text" name="hotel_name" id="hotel_name" class="form-control" required>
</div>
<div class="form-group">
<label for="owner_name">Owner Name <span class="text-danger">*</span></label>
<input type="text" name="owner_name" id="owner_name" class="form-control" required>
</div>
<div class="form-group">
<label for="representative_name">Representative Name</label>
<input type="text" name="representative_name" id="representative_name" class="form-control">
</div>
<div class="form-group">
<label for="phone_number">Phone Number</label>
<input type="text" name="phone_number" id="phone_number" class="form-control">
</div>
<div class="form-group">
<label for="tasria_owner">Tasria Name</label>
<input type="text" name="tasria_owner" id="tasria_owner" class="form-control">
</div>
<div class="form-group">
<label for="tasria_number">Tasria Number</label>
<input type="text" name="tasria_number" id="tasria_number" class="form-control">
</div>
</div>
{{-- ========== Quota Info ========== --}}
<div class="row row-cols-md-3 mt-3">
<div class="form-group">
<label for="total_seat">Total Seat <span class="text-danger">*</span></label>
<input type="number" name="total_seat" id="total_seat" class="form-control" required
min="0">
</div>
<div class="form-group">
<label for="city_quota">Quota Balance (<strong class="city_label">--</strong>)</label>
<input type="number" id="city_quota" class="form-control" readonly>
</div>
<div class="form-group">
<label for="used_city_quota">Used Quota (<strong class="city_label">--</strong>)</label>
<input type="number" id="used_city_quota" class="form-control" readonly>
</div>
</div>
{{-- ========== Room Allotment ========== --}}
<h5 class="mt-4">Room Allotment</h5>
<div class="row row-cols-md-4 mt-2">
@php $roomTypes = ['double'=>2, 'triple'=>3, 'quad'=>4, 'quintuple'=>5]; @endphp
@foreach ($roomTypes as $type => $multiplier)
<div class="form-group">
<label for="{{ $type }}_qty">{{ ucfirst($type) }} Rooms</label>
<input type="number" min="0" name="{{ $type }}_qty"
id="{{ $type }}_qty" class="form-control room-input"
data-multiplier="{{ $multiplier }}">
<small>Total: <span id="{{ $type }}_total">0</span> seats</small>
</div>
@endforeach
</div>
{{-- Allocated Seats and Quota Validation --}}
<div class="row row-cols-md-2 mt-3">
<div class="form-group mt-3">
<label>Total Allocated Seats</label>
<input type="number" class="form-control" id="allocated_seats" name="allocated_seats" readonly>
<div class="alert alert-warning d-none mt-2" id="seat_alert">
⚠️ Total allocated seats exceed Total Seat!
</div>
</div>
<div class="form-group mt-3">
<label>Overall Quota Check</label>
<input type="number" class="form-control" id="quota_check" readonly>
<div class="alert alert-warning d-none mt-2" id="quota_alert">
⚠️ <span id="city_name_alert"></span>
</div>
</div>
</div>
<hr>
{{-- ========== Payable Information ========== --}}
<h5 class="mt-4">Payable Information</h5>
<div class="row row-cols-md-2">
{{-- <div class="form-group">
<label for="subtotal_amount">Total Amount (without tax & VAT) <span class="text-danger">*</span>
<span class="sar_balance_display text-muted">(Balance: -- SAR)</span></label>
<input type="number" name="subtotal" id="subtotal_amount" class="form-control" step="0.01">
</div>
<div class="form-group">
<label for="total_amount">
Total Amount (with tax & VAT) <span class="text-danger">*</span>
<span class="sar_balance_display text-muted">(Balance: -- SAR)</span>
</label>
<input type="number" name="total_amount" id="total_amount" class="form-control" step="0.01">
<div id="sar_error" class="invalid-feedback d-none"></div>
</div> --}}
<div class="form-group">
<label for="subtotal_amount">Total Amount (without tax & VAT) <span class="text-danger">*</span>
<span class="sar_balance_display text-muted">(Balance: -- SAR)</span></label>
<input type="number" name="subtotal" id="subtotal_amount" class="form-control" step="0.01">
</div>
<div class="form-group">
<label for="total_amount">
Total Amount (with tax & VAT) <span class="text-danger">*</span>
<span class="sar_balance_display text-muted">(Balance: -- SAR)</span>
</label>
<input type="number" name="total_amount" id="total_amount" class="form-control"
step="0.01">
<div id="sar_error" class="invalid-feedback d-none"></div>
</div>
</div>
<button type="submit" class="btn btn-primary mt-4">Submit Booking</button>
</form>
</div>
</div>
<!-- Preview Modal -->
<!-- Hotel Booking – Preview Modal -->
<div class="modal fade" id="bookingPreviewModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content border-0 shadow-lg rounded-3">
<div class="modal-header bg-primary text-white rounded-top-3">
<h5 class="modal-title fw-semibold">
<i class="bi bi-building-check me-2"></i>Booking Summary
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body bg-light">
<p class="text-muted mb-4">
Please review the details below before submitting your booking.
</p>
<!-- dynamic preview table -->
<div id="bookingPreviewContent" class="table-responsive">
<!-- Filled by JavaScript -->
</div>
</div>
<div class="modal-footer bg-light rounded-bottom-4">
<button type="button" class="btn btn-outline-secondary px-4" data-bs-dismiss="modal">
<i class="bi bi-pencil-square me-1"></i> Edit
</button>
<button type="button" class="btn btn-primary px-4" id="confirmSubmit">
<i class="bi bi-check-circle me-1"></i> Confirm & Submit
</button>
</div>
</div>
</div>
</div>
{{-- <script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.querySelector('form.form');
const previewContent = document.getElementById('bookingPreviewContent');
const confirmBtn = document.getElementById('confirmSubmit');
form.addEventListener('submit', function(e) {
e.preventDefault(); // stop normal submission
const fd = new FormData(form);
let html = `
<table class="table table-striped table-hover align-middle bg-white rounded">
<tbody>
`;
fd.forEach((value, key) => {
const label = key.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
html += `
<tr>
<th class="w-25 text-primary fw-semibold">${label}</th>
<td class="text-dark">${value || '<span class="text-muted">—</span>'}</td>
</tr>
`;
});
html += '</tbody></table>';
previewContent.innerHTML = html;
const modal = new bootstrap.Modal(document.getElementById('bookingPreviewModal'));
modal.show();
confirmBtn.onclick = () => {
modal.hide();
form.submit();
};
});
});
</script> --}}
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.querySelector('form.form');
const previewContent = document.getElementById('bookingPreviewContent');
const confirmBtn = document.getElementById('confirmSubmit');
const bookingModalEl = document.getElementById('bookingPreviewModal');
const bookingModal = new bootstrap.Modal(bookingModalEl);
form.addEventListener('submit', function(e) {
e.preventDefault(); // stop normal submit for preview
const fd = new FormData(form);
let html =
`<table class="table table-striped table-hover align-middle bg-white rounded"><tbody>`;
fd.forEach((value, key) => {
// Skip fields we never want to preview
if (['_token', 'user_id'].includes(key)) return;
let label = '';
let displayValue = value || '<span class="text-muted">—</span>';
// Custom labels / lookups
switch (key) {
case 'agency_id':
label = 'Agency';
const agencySelect = document.getElementById('agency_id');
if (agencySelect) {
// works for both select or hidden input
if (agencySelect.tagName === 'SELECT') {
const opt = agencySelect.querySelector(
`option[value="${value}"]`);
if (opt) displayValue = opt.textContent.trim();
} else {
// hidden input – get agency name from the single option text if present
const singleOpt = document.querySelector(
'#agency_id option[value="' + value + '"]');
if (singleOpt) displayValue = singleOpt.textContent.trim();
}
}
break;
case 'season_id':
label = 'Season';
const seasonEl = document.getElementById('season_id');
if (seasonEl) {
if (seasonEl.tagName === 'SELECT') {
// multi-season: take selected option text
const opt = seasonEl.querySelector(`option[value="${value}"]`);
if (opt) displayValue = opt.textContent.trim();
} else {
// single-season: look for the readonly text input that shows name
const readOnlyText = seasonEl
.closest('.form-group')
?.querySelector('input[readonly]');
if (readOnlyText) displayValue = readOnlyText.value.trim();
}
}
break;
default:
label = key.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
}
html += `
<tr>
<th class="w-25 text-primary fw-semibold">${label}</th>
<td class="text-dark">${displayValue}</td>
</tr>
`;
});
html += '</tbody></table>';
previewContent.innerHTML = html;
bookingModal.show();
});
confirmBtn.addEventListener('click', function() {
bookingModal.hide();
// small delay to let modal close animation finish
setTimeout(() => form.submit(), 200);
});
});
</script>
{{-- ========== JavaScript ========== --}}
<script>
document.addEventListener('DOMContentLoaded', function() {
/* ---------- Seat calculation ---------- */
const roomInputs = document.querySelectorAll('.room-input');
const allocated = document.getElementById('allocated_seats');
const totalSeat = document.getElementById('total_seat');
const seatAlert = document.getElementById('seat_alert');
function calcSeats() {
let total = 0;
roomInputs.forEach(i => {
const qty = parseInt(i.value) || 0;
const mult = parseInt(i.dataset.multiplier);
const subtotal = qty * mult;
document.getElementById(i.id.replace('_qty', '') + '_total').textContent = subtotal;
total += subtotal;
});
allocated.value = total;
seatAlert.classList.toggle('d-none', total <= (parseInt(totalSeat.value) || 0));
calcQuota();
}
roomInputs.forEach(i => i.addEventListener('input', calcSeats));
totalSeat.addEventListener('input', calcSeats);
/* ---------- Agency / User fetch ---------- */
const agencySelect = document.getElementById('agency_id');
const userSelect = document.getElementById('user_id');
agencySelect?.addEventListener('change', () => {
if (!userSelect) return;
userSelect.innerHTML = '<option>Loading...</option>';
fetch(`/admin/payment/get-users/${agencySelect.value}`)
.then(r => r.json())
.then(d => {
userSelect.innerHTML = d.length ?
'<option value="">Select User</option>' :
'<option>No users found</option>';
d.forEach(u =>
userSelect.innerHTML +=
`<option value="${u.id}">${u.name} (${u.phone ?? ''})</option>`
);
loadCityQuota();
})
.catch(() => userSelect.innerHTML = '<option>Error loading users</option>');
});
/* ---------- Quota info ---------- */
const seasonSelect = document.getElementById('season_id');
const cityRadios = document.querySelectorAll('input[name="city"]');
const quotaInput = document.getElementById('city_quota');
const usedQuotaInput = document.getElementById('used_city_quota');
const cityLabels = document.querySelectorAll('.city_label');
let extraQuota = 0;
function selectedCity() {
const checked = document.querySelector('input[name="city"]:checked');
return checked ? checked.value : null;
}
function setCityLabel(label) {
cityLabels.forEach(l => l.textContent = label || '--');
}
function loadCityQuota() {
const agencyId = agencySelect?.value;
const seasonId = seasonSelect?.value;
const city = selectedCity();
if (!agencyId || !seasonId || !city) {
setCityLabel('--');
quotaInput.value = usedQuotaInput.value = '';
return;
}
fetch(`/get-quota-by-agency?agency_id=${agencyId}&season_id=${seasonId}`)
.then(r => r.json())
.then(d => {
let quota = 0,
used = 0,
label = '';
if (city === 'makkah') {
quota = d.makka_qouta ?? 0;
used = d.makka_used_qouta ?? 0;
label = 'Makkah';
extraQuota = d.makka_extra_qouta ?? 0;
} else {
quota = d.modina_qouta ?? 0;
used = d.modina_used_qouta ?? 0;
label = 'Madinah';
extraQuota = d.modina_extra_qouta ?? 0;
}
setCityLabel(label);
quotaInput.value = quota;
usedQuotaInput.value = used;
calcQuota();
});
}
agencySelect?.addEventListener('change', loadCityQuota);
seasonSelect?.addEventListener('change', loadCityQuota);
cityRadios.forEach(r => r.addEventListener('change', loadCityQuota));
/* ---------- Quota check with detailed alert ---------- */
const quotaCheck = document.getElementById('quota_check');
const quotaAlert = document.getElementById('quota_alert');
const cityNameAlert = document.getElementById('city_name_alert');
function calcQuota() {
const allocatedSeats = parseInt(allocated.value) || 0;
const used = parseInt(usedQuotaInput.value) || 0;
const quota = parseInt(quotaInput.value) || 0;
const totalAllowed = quota + (parseInt(extraQuota) || 0);
const cityName = selectedCity() === 'madinah' ? 'Madinah' :
selectedCity() === 'makkah' ? 'Makkah' : '';
quotaCheck.value = allocatedSeats + used;
if ((allocatedSeats + used) > totalAllowed) {
const diff = (allocatedSeats + used - quota) + (parseInt(extraQuota) || 0);
cityNameAlert.textContent =
`${cityName}: Over Extra Quota ${diff}`;
quotaAlert.classList.remove('d-none');
} else {
quotaAlert.classList.add('d-none');
}
}
calcSeats();
validatePayable();
});
</script>
{{-- <script>
document.addEventListener('DOMContentLoaded', function() {
/* ---------- existing variables ---------- */
const subtotalInput = document.getElementById('subtotal_amount');
const totalInput = document.getElementById('total_amount');
const sarDisplay = document.getElementByClass('sar_balance_display');
const sarError = document.getElementById('sar_error');
const agencySelect = document.getElementById('agency_id');
let agencySarBalance = 0; // 💡 will be filled from server
/* ---------- fetch SAR balance when agency changes ---------- */
function loadAgencySarBalance() {
const agencyId = agencySelect?.value;
if (!agencyId) return;
fetch(`/get-agency-sar-balance/${agencyId}`)
.then(r => r.json())
.then(d => {
agencySarBalance = parseFloat(d.sar_balance ?? 0);
sarDisplay.textContent = `(Balance: ${agencySarBalance.toFixed(2)} SAR)`;
validatePayable(); // re-check current input
})
.catch(() => {
agencySarBalance = 0;
sarDisplay.textContent = '(Balance: -- SAR)';
});
}
agencySelect?.addEventListener('change', loadAgencySarBalance);
subtotalInput.addEventListener('input', validatePayable);
totalInput.addEventListener('input', validatePayable);
// Initial call (if agency already pre-selected)
loadAgencySarBalance();
// validatePayable();
});
</script>
<script>
let sarBalance = 0;
function fetchAgencyBalance(agencyId) {
if (!agencyId) return;
fetch(`/get-agency-balance/${agencyId}`)
.then(response => response.json())
.then(data => {
sarBalance = parseFloat(data.sar_acct || 0);
document.getElementByClass('sar_balance_display').textContent =
`(Balance: ${sarBalance.toFixed(2)} SAR)`;
const totalAmountInput = document.getElementById('total_amount');
const currentSAR = parseFloat(totalAmountInput.value) || 0;
if (currentSAR > sarBalance) {
showSarError(`SAR amount cannot exceed ${sarBalance}`);
disableSubmit();
} else {
hideSarError();
enableSubmit();
}
})
.catch(() => {
sarBalance = 0;
document.getElementByClass('sar_balance_display').textContent = `(Balance: --.-- SAR)`;
showSarError('Could not load SAR balance.');
disableSubmit();
});
}
function showSarError(message) {
const errorDiv = document.getElementById('sar_error');
errorDiv.textContent = message;
errorDiv.classList.remove('d-none');
document.getElementById('total_amount').classList.add('is-invalid');
}
function hideSarError() {
const errorDiv = document.getElementById('sar_error');
errorDiv.classList.add('d-none');
errorDiv.textContent = '';
document.getElementById('total_amount').classList.remove('is-invalid');
}
function disableSubmit() {
document.querySelector('button[type="submit"]').disabled = true;
}
function enableSubmit() {
document.querySelector('button[type="submit"]').disabled = false;
}
document.addEventListener('DOMContentLoaded', function() {
const agencyInput = document.getElementById('agency_id');
if (agencyInput && agencyInput.value) {
fetchAgencyBalance(agencyInput.value);
}
agencyInput?.addEventListener('change', function() {
fetchAgencyBalance(this.value);
});
document.getElementById('total_amount').addEventListener('input', function() {
const entered = parseFloat(this.value) || 0;
if (entered > sarBalance) {
showSarError(`SAR amount cannot exceed ${sarBalance}`);
disableSubmit();
} else {
hideSarError();
enableSubmit();
}
});
});
</script> --}}
<script>
document.addEventListener('DOMContentLoaded', function() {
const subtotalInput = document.getElementById('subtotal_amount');
const totalInput = document.getElementById('total_amount');
const sarDisplays = document.querySelectorAll('.sar_balance_display'); // multiple elements
const sarError = document.getElementById('sar_error');
const agencySelect = document.getElementById('agency_id');
let sarBalance = 0;
// Update all balance display spans
function updateSarDisplay(balance) {
sarDisplays.forEach(el => {
el.textContent = `(Balance: ${balance ? balance.toFixed(2) : '--'} SAR)`;
});
}
function showSarError(message) {
sarError.textContent = message;
sarError.classList.remove('d-none');
totalInput.classList.add('is-invalid');
disableSubmit();
}
function hideSarError() {
sarError.textContent = '';
sarError.classList.add('d-none');
totalInput.classList.remove('is-invalid');
enableSubmit();
}
function disableSubmit() {
const btn = document.querySelector('button[type="submit"]');
if (btn) btn.disabled = true;
}
function enableSubmit() {
const btn = document.querySelector('button[type="submit"]');
if (btn) btn.disabled = false;
}
function validatePayable() {
const entered = parseFloat(totalInput.value) || 0;
if (entered > sarBalance) {
showSarError(`SAR amount cannot exceed ${sarBalance.toFixed(2)}`);
} else {
hideSarError();
}
}
function fetchAgencyBalance(agencyId) {
if (!agencyId) return;
fetch(`/get-agency-balance/${agencyId}`)
.then(res => res.json())
.then(data => {
sarBalance = parseFloat(data.sar_acct ?? 0);
updateSarDisplay(sarBalance);
validatePayable();
})
.catch(() => {
sarBalance = 0;
updateSarDisplay(null);
showSarError('Could not load SAR balance.');
});
}
// Events
agencySelect?.addEventListener('change', () => fetchAgencyBalance(agencySelect.value));
totalInput.addEventListener('input', validatePayable);
subtotalInput.addEventListener('input', validatePayable);
// Initial load
if (agencySelect && agencySelect.value) {
fetchAgencyBalance(agencySelect.value);
}
});
</script>
@endsection