latest
This commit is contained in:
1 parent
b03c1d4619
commit
b07423aef3
42 files changed
+1431
-394
No files matched your search
@@ -396,10 +396,12 @@
|
||||
{{-- ── STEP 2A : receipt + payment ────────────────────────── --}}
|
||||
<div id="endStep2Pay" style="display:none;" class="p-4">
|
||||
|
||||
<button class="btn btn-sm mb-3 fw-600" onclick="endBack()"
|
||||
style="background:#f1f5f9;color:#475569;border:none;border-radius:.5rem;font-family:'Cairo',sans-serif;">
|
||||
<i class="bi bi-arrow-right me-1"></i>رجوع
|
||||
</button>
|
||||
<div class="d-flex justify-content-end mb-3">
|
||||
<button class="btn btn-sm fw-600" onclick="endBack()"
|
||||
style="background:#f1f5f9;color:#475569;border:none;border-radius:.5rem;font-family:'Cairo',sans-serif;">
|
||||
<i class="bi bi-arrow-left me-1"></i>رجوع
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{-- Times --}}
|
||||
<div class="row g-2 mb-3">
|
||||
@@ -469,10 +471,12 @@
|
||||
{{-- ── STEP 2B : force close ───────────────────────────────── --}}
|
||||
<div id="endStep2Force" style="display:none;" class="p-4">
|
||||
|
||||
<button class="btn btn-sm mb-3 fw-600" onclick="endBack()"
|
||||
style="background:#f1f5f9;color:#475569;border:none;border-radius:.5rem;font-family:'Cairo',sans-serif;">
|
||||
<i class="bi bi-arrow-right me-1"></i>رجوع
|
||||
</button>
|
||||
<div class="d-flex justify-content-end mb-3">
|
||||
<button class="btn btn-sm fw-600" onclick="endBack()"
|
||||
style="background:#f1f5f9;color:#475569;border:none;border-radius:.5rem;font-family:'Cairo',sans-serif;">
|
||||
<i class="bi bi-arrow-left me-1"></i>رجوع
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="text-center py-2 mb-3">
|
||||
<div style="font-size:2.8rem;margin-bottom:.75rem;">⚠️</div>
|
||||
@@ -609,12 +613,12 @@ async function endChoose(type) {
|
||||
const d = data.data;
|
||||
document.getElementById('payRcptEntry').textContent = d.entry_time;
|
||||
document.getElementById('payRcptExit').textContent = d.exit_time;
|
||||
document.getElementById('payRcptTotal').textContent = Number(d.total_fee).toLocaleString('ar-SA') + ' ل.س';
|
||||
document.getElementById('payRcptTotal').textContent = Number(d.total_fee).toLocaleString('ar-SA') + ' ليرة سورية';
|
||||
const rows = d.fee_details.map(r => `
|
||||
<div style="display:flex;justify-content:space-between;padding:.3rem 0;border-bottom:1px dashed #f1f5f9;font-size:.82rem;">
|
||||
<span>${r.day} <small style="color:#94a3b8;">${r.date}</small></span>
|
||||
<span style="color:#64748b;">${r.hours}س × ${Number(r.rate).toLocaleString('ar-SA')}</span>
|
||||
<span class="fw-600" style="color:#0f172a;">${Number(r.subtotal).toLocaleString('ar-SA')} ل.س</span>
|
||||
<span class="fw-600" style="color:#0f172a;">${Number(r.subtotal).toLocaleString('ar-SA')} ليرة سورية</span>
|
||||
</div>`).join('');
|
||||
document.getElementById('payRcptBreakdown').innerHTML =
|
||||
rows || '<p class="text-xs text-center" style="color:#94a3b8;">لا تفاصيل</p>';
|
||||
|
||||
@@ -274,7 +274,7 @@ async function loadStats() {
|
||||
document.getElementById('total-bookings').textContent = data.total_bookings ?? 0;
|
||||
document.getElementById('active-bookings').textContent = data.active_bookings ?? 0;
|
||||
document.getElementById('occupancy-rate').textContent = (data.occupancy_rate ?? 0) + '%';
|
||||
document.getElementById('estimated-revenue').textContent = (data.estimated_revenue ?? 0).toLocaleString('ar-SA') + ' ر.س';
|
||||
document.getElementById('estimated-revenue').textContent = (data.estimated_revenue ?? 0).toLocaleString('ar-SA') + ' ليرة سورية';
|
||||
document.getElementById('available-spots').textContent = data.available_spots ?? 0;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,15 @@
|
||||
padding:.25em .75em; border-radius:20px; font-size:.75rem; font-weight:600;
|
||||
background:#f1f5f9; color:#94a3b8;
|
||||
}
|
||||
.lot-checkbox-list {
|
||||
border:1px solid #e2e8f0; border-radius:.625rem; max-height:180px; overflow-y:auto; padding:.5rem;
|
||||
}
|
||||
.lot-checkbox-item {
|
||||
display:flex; align-items:center; gap:.6rem; padding:.375rem .5rem; border-radius:.4rem; cursor:pointer;
|
||||
font-size:.875rem; color:#374151; transition:background .15s;
|
||||
}
|
||||
.lot-checkbox-item:hover { background:#f8fafc; }
|
||||
.lot-checkbox-item input[type=checkbox] { width:1rem; height:1rem; cursor:pointer; flex-shrink:0; }
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@@ -61,11 +70,15 @@
|
||||
<td class="py-3" style="color:#475569;">{{ $op->email }}</td>
|
||||
<td class="py-3" style="color:#475569;">{{ $op->phone ?? '—' }}</td>
|
||||
<td class="py-3">
|
||||
@if($op->assignedLot)
|
||||
<span class="lot-pill">
|
||||
<i class="bi bi-buildings"></i>
|
||||
{{ $op->assignedLot->name }}
|
||||
</span>
|
||||
@if($op->assignedLots->isNotEmpty())
|
||||
<div class="d-flex flex-wrap gap-1">
|
||||
@foreach($op->assignedLots as $assignedLot)
|
||||
<span class="lot-pill">
|
||||
<i class="bi bi-buildings"></i>
|
||||
{{ $assignedLot->name }}
|
||||
</span>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<span class="no-lot-pill">
|
||||
<i class="bi bi-dash-circle"></i>
|
||||
@@ -81,7 +94,7 @@
|
||||
data-name="{{ $op->name }}"
|
||||
data-email="{{ $op->email }}"
|
||||
data-phone="{{ $op->phone ?? '' }}"
|
||||
data-lot="{{ $op->parking_lot_id ?? '' }}">
|
||||
data-lots="{{ json_encode($op->assignedLots->pluck('id')) }}">
|
||||
<i class="bi bi-pencil me-1"></i>تعديل
|
||||
</button>
|
||||
<button class="btn btn-sm fw-600 btn-delete-op"
|
||||
@@ -134,13 +147,17 @@
|
||||
<input type="password" id="createPassword" class="form-control" placeholder="8 أحرف على الأقل" dir="ltr">
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label class="form-label fw-600" style="font-size:.875rem;color:#374151;">الموقف المخصص <span style="color:#94a3b8;font-weight:400;">(اختياري)</span></label>
|
||||
<select id="createLot" class="form-select">
|
||||
<option value="">— بدون تخصيص —</option>
|
||||
@foreach($lots as $lot)
|
||||
<option value="{{ $lot->id }}">{{ $lot->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<label class="form-label fw-600" style="font-size:.875rem;color:#374151;">المواقف المخصصة <span style="color:#94a3b8;font-weight:400;">(اختياري)</span></label>
|
||||
<div class="lot-checkbox-list" id="createLotList">
|
||||
@forelse($lots as $lot)
|
||||
<label class="lot-checkbox-item">
|
||||
<input type="checkbox" class="create-lot-cb" value="{{ $lot->id }}">
|
||||
<span>{{ $lot->name }}</span>
|
||||
</label>
|
||||
@empty
|
||||
<p class="text-center mb-0 py-2" style="color:#94a3b8;font-size:.8rem;">لا توجد مواقف</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-0 pt-1">
|
||||
@@ -186,13 +203,17 @@
|
||||
<input type="password" id="editPassword" class="form-control" placeholder="8 أحرف على الأقل" dir="ltr">
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label class="form-label fw-600" style="font-size:.875rem;color:#374151;">الموقف المخصص</label>
|
||||
<select id="editLot" class="form-select">
|
||||
<option value="">— بدون تخصيص —</option>
|
||||
@foreach($lots as $lot)
|
||||
<option value="{{ $lot->id }}">{{ $lot->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<label class="form-label fw-600" style="font-size:.875rem;color:#374151;">المواقف المخصصة</label>
|
||||
<div class="lot-checkbox-list" id="editLotList">
|
||||
@forelse($lots as $lot)
|
||||
<label class="lot-checkbox-item">
|
||||
<input type="checkbox" class="edit-lot-cb" value="{{ $lot->id }}">
|
||||
<span>{{ $lot->name }}</span>
|
||||
</label>
|
||||
@empty
|
||||
<p class="text-center mb-0 py-2" style="color:#94a3b8;font-size:.8rem;">لا توجد مواقف</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-0 pt-1">
|
||||
@@ -271,7 +292,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
// ── Open create ───────────────────────────────────────────────────────────
|
||||
document.getElementById('btnOpenCreate').addEventListener('click', function () {
|
||||
['createName','createEmail','createPhone','createPassword'].forEach(id => document.getElementById(id).value = '');
|
||||
document.getElementById('createLot').value = '';
|
||||
document.querySelectorAll('.create-lot-cb').forEach(cb => cb.checked = false);
|
||||
document.getElementById('createError').classList.add('d-none');
|
||||
modal('createModal').show();
|
||||
});
|
||||
@@ -284,7 +305,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
document.getElementById('editEmail').value = this.dataset.email;
|
||||
document.getElementById('editPhone').value = this.dataset.phone || '';
|
||||
document.getElementById('editPassword').value = '';
|
||||
document.getElementById('editLot').value = this.dataset.lot || '';
|
||||
const assignedIds = JSON.parse(this.dataset.lots || '[]');
|
||||
document.querySelectorAll('.edit-lot-cb').forEach(cb => {
|
||||
cb.checked = assignedIds.includes(parseInt(cb.value));
|
||||
});
|
||||
document.getElementById('editError').classList.add('d-none');
|
||||
modal('editModal').show();
|
||||
});
|
||||
@@ -309,15 +333,16 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
spinner.classList.remove('d-none');
|
||||
errEl.classList.add('d-none');
|
||||
try {
|
||||
const createLotIds = [...document.querySelectorAll('.create-lot-cb:checked')].map(cb => parseInt(cb.value));
|
||||
const res = await fetch('{{ route("admin.operators.store") }}', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrf },
|
||||
body: JSON.stringify({
|
||||
name: document.getElementById('createName').value.trim(),
|
||||
email: document.getElementById('createEmail').value.trim(),
|
||||
phone: document.getElementById('createPhone').value.trim() || null,
|
||||
password: document.getElementById('createPassword').value,
|
||||
parking_lot_id: document.getElementById('createLot').value || null,
|
||||
name: document.getElementById('createName').value.trim(),
|
||||
email: document.getElementById('createEmail').value.trim(),
|
||||
phone: document.getElementById('createPhone').value.trim() || null,
|
||||
password: document.getElementById('createPassword').value,
|
||||
lot_ids: createLotIds,
|
||||
}),
|
||||
});
|
||||
const json = await res.json();
|
||||
@@ -343,15 +368,16 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
spinner.classList.remove('d-none');
|
||||
errEl.classList.add('d-none');
|
||||
try {
|
||||
const editLotIds = [...document.querySelectorAll('.edit-lot-cb:checked')].map(cb => parseInt(cb.value));
|
||||
const res = await fetch(`/admin/operators/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrf },
|
||||
body: JSON.stringify({
|
||||
name: document.getElementById('editName').value.trim(),
|
||||
email: document.getElementById('editEmail').value.trim(),
|
||||
phone: document.getElementById('editPhone').value.trim() || null,
|
||||
password: document.getElementById('editPassword').value || null,
|
||||
parking_lot_id: document.getElementById('editLot').value || null,
|
||||
name: document.getElementById('editName').value.trim(),
|
||||
email: document.getElementById('editEmail').value.trim(),
|
||||
phone: document.getElementById('editPhone').value.trim() || null,
|
||||
password: document.getElementById('editPassword').value || null,
|
||||
lot_ids: editLotIds,
|
||||
}),
|
||||
});
|
||||
const json = await res.json();
|
||||
|
||||
@@ -209,7 +209,7 @@ $gradients = [
|
||||
</span>
|
||||
<span class="lot-card-stat" style="{{ !empty($lot->pricing_rules) ? 'border-color:#fbbf24;color:#92400e;' : '' }}">
|
||||
<i class="bi bi-{{ !empty($lot->pricing_rules) ? 'tags' : 'tag' }}" style="color:{{ !empty($lot->pricing_rules) ? '#f59e0b' : '#10b981' }};"></i>
|
||||
<strong>{{ number_format($lot->price_per_hour, 0) }}</strong> ر.س/س
|
||||
<strong>{{ number_format($lot->price_per_hour, 0) }}</strong> ليرة سورية/س
|
||||
@if(!empty($lot->pricing_rules))
|
||||
<span style="font-size:.6rem;color:#f59e0b;"> (مخصص)</span>
|
||||
@endif
|
||||
@@ -385,7 +385,7 @@ $gradients = [
|
||||
<input type="number" id="p_base" class="form-control"
|
||||
step="0.01" min="0" placeholder="0.00"
|
||||
oninput="syncBaseHints()">
|
||||
<span class="input-group-text" style="font-family:'Cairo',sans-serif;background:#f8fafc;color:#64748b;border-color:#e2e8f0;">ر.س / ساعة</span>
|
||||
<span class="input-group-text" style="font-family:'Cairo',sans-serif;background:#f8fafc;color:#64748b;border-color:#e2e8f0;">ليرة سورية / ساعة</span>
|
||||
</div>
|
||||
<p class="text-xs mt-1 mb-0" style="color:#94a3b8;">
|
||||
الأيام التي لا تحمل سعراً مخصصاً ستستخدم هذا السعر تلقائياً.
|
||||
@@ -425,7 +425,7 @@ $gradients = [
|
||||
step="0.01" min="0"
|
||||
placeholder="مثل السعر الأساسي"
|
||||
style="font-family:'Cairo',sans-serif;">
|
||||
<span class="input-group-text" style="background:#f8fafc;color:#94a3b8;border-color:#e2e8f0;font-size:.75rem;">ر.س</span>
|
||||
<span class="input-group-text" style="background:#f8fafc;color:#94a3b8;border-color:#e2e8f0;font-size:.75rem;">ليرة سورية</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width:70px;text-align:center;">
|
||||
|
||||
Reference in new issue
Block a user