main-backend/php_code/resources/views/admin/hometwo.blade copy.php
2026-06-21 14:00:47 +00:00

187 lines
9.7 KiB
PHP

@extends('layouts.master')
@section('content')
<div class="container py-4">
<div class="d-flex align-items-center mb-3">
<h3 class="me-auto">Manage Users</h3>
<div class="text-muted">June 15, 2026</div>
</div>
<!-- same HTML UI as before but with minor Blade AJAX integration -->
<!-- ...copy the HTML from the previous snippet but remove static example rows and use empty tbody for JS to populate... -->
<!-- For brevity include only key changes shown below -->
<ul class="nav nav-tabs mb-3" id="userTabs" role="tablist">
<li class="nav-item"><button class="nav-link active" id="district-tab" data-bs-toggle="tab" data-bs-target="#district" type="button" role="tab">District <span class="badge bg-secondary ms-1" id="count-district">0</span></button></li>
<li class="nav-item"><button class="nav-link" id="regional-tab" data-bs-toggle="tab" data-bs-target="#regional" type="button" role="tab">Regional <span class="badge bg-secondary ms-1" id="count-regional">0</span></button></li>
<li class="nav-item"><button class="nav-link" id="national-tab" data-bs-toggle="tab" data-bs-target="#national" type="button" role="tab">National <span class="badge bg-secondary ms-1" id="count-national">0</span></button></li>
</ul>
<!-- toolbar (same as earlier) -->
<!-- tab content: empty bodies to be filled by JS -->
<div class="tab-content" id="userTabsContent">
<div class="tab-pane fade show active" id="district" role="tabpanel" aria-labelledby="district-tab">
<div class="card mb-4"><div class="card-body p-0"><div class="table-responsive"><table class="table table-hover mb-0"><thead class="table-light"><tr><th style="width:42px;"></th><th>Person</th><th>Email</th><th>Role</th><th>Last activity</th><th style="width:130px;">Actions</th></tr></thead><tbody id="districtBody"></tbody></table></div></div></div>
</div>
<div class="tab-pane fade" id="regional" role="tabpanel" aria-labelledby="regional-tab">
<div class="card mb-4"><div class="card-body p-0"><div class="table-responsive"><table class="table table-hover mb-0"><thead class="table-light"><tr><th style="width:42px;"></th><th>Person</th><th>Email</th><th>Role</th><th>Last activity</th><th style="width:130px;">Actions</th></tr></thead><tbody id="regionalBody"></tbody></table></div></div></div>
</div>
<div class="tab-pane fade" id="national" role="tabpanel" aria-labelledby="national-tab">
<div class="card mb-4"><div class="card-body p-0"><div class="table-responsive"><table class="table table-hover mb-0"><thead class="table-light"><tr><th style="width:42px;"></th><th>Person</th><th>Email</th><th>Role</th><th>Last activity</th><th style="width:130px;">Actions</th></tr></thead><tbody id="nationalBody"></tbody></table></div></div></div>
</div>
</div>
<!-- include modals from earlier (editModal, moveModal) unchanged -->
</div>
@endsection
@push('scripts')
<script>
const routes = {
list: "{{ route('admin.users.list') }}",
show: (id)=> "{{ url('admin/users') }}/"+id,
update: (id)=> "{{ url('admin/users') }}/"+id,
move: "{{ route('admin.users.move') }}",
deactivate: "{{ route('admin.users.deactivate') }}"
};
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } });
(function(){
let currentCategory = 'District';
function fetchCategory(category){
currentCategory = category;
const params = { category, q: $('#globalSearch').val(), status: $('.filter-status:checked').map(function(){return this.value}).get() };
$.get(routes.list, params, function(data){
// data is a Laravel paginator; use data.data for items
const items = data.data || data;
const mapToTbody = { District: '#districtBody', Regional: '#regionalBody', National: '#nationalBody' };
// clear all then populate respective bodies
$('#districtBody,#regionalBody,#nationalBody').empty();
items.forEach(renderRow);
// if API returns mixed categories (when no category filter) you can instead append based on user.category
// update counts using paginator meta if available, otherwise compute
$('#count-district').text(items.filter(u=>u.category==='District').length);
$('#count-regional').text(items.filter(u=>u.category==='Regional').length);
$('#count-national').text(items.filter(u=>u.category==='National').length);
});
}
function renderRow(u){
const badgeClass = u.category === 'District' ? 'badge-district' : (u.category === 'Regional' ? 'badge-regional' : 'badge-national');
const row = $(`
<tr class="user-row" data-category="${u.category}" data-status="${u.status}" data-name="${u.name}" data-email="${u.email}" data-id="${u.id}">
<td><input class="row-select form-check-input" type="checkbox" aria-label="Select ${u.name}"></td>
<td class="align-middle">
<div class="d-flex align-items-center">
<img src="${u.avatar_url || 'https://i.pravatar.cc/40'}" alt="avatar" class="table-avatar me-2">
<div><div class="fw-semibold">${u.name}</div><div class="text-muted small">ID: ${u.id}</div></div>
</div>
</td>
<td class="align-middle">${u.email}</td>
<td class="align-middle"><span class="category-badge ${badgeClass}">${u.category}</span> &middot; ${u.role || ''}</td>
<td class="align-middle">${u.last_activity_at || ''}</td>
<td class="align-middle">
<div class="row-actions d-flex gap-2">
<button class="btn btn-sm btn-outline-secondary viewBtn" data-id="${u.id}">View</button>
<button class="btn btn-sm btn-primary editBtn" data-id="${u.id}" data-bs-toggle="modal" data-bs-target="#editModal">Edit</button>
</div>
</td>
</tr>`);
const body = u.category === 'District' ? '#districtBody' : (u.category === 'Regional' ? '#regionalBody' : '#nationalBody');
$(body).append(row);
}
// Initial load for all categories (no filter) — call list without category to fetch many, but for simplicity fetch per category:
['District','Regional','National'].forEach(c => {
$.get(routes.list, { category: c }, function(data){
(data.data || data).forEach(renderRow);
$('#count-'+c.toLowerCase()).text((data.meta?.total) ? data.meta.total : ( (data.data || data).length ));
});
});
// Search + filter debounce
let t=null;
$('#globalSearch, .filter-status').on('input change', function(){
clearTimeout(t);
t = setTimeout(()=> { fetchCategory(currentCategory); }, 300);
});
// Edit: fetch details and populate modal
let lastTrigger = null;
$(document).on('click', '.editBtn', function(){
lastTrigger = this;
const id = $(this).data('id');
$.get(routes.show(id), function(user){
$('#editId').val(user.id);
$('#editName').val(user.name);
$('#editEmail').val(user.email);
$('#editCategory').val(user.category);
});
});
// Update via AJAX
$('#editForm').on('submit', function(e){
e.preventDefault();
const id = $('#editId').val();
const payload = { name: $('#editName').val(), email: $('#editEmail').val(), category: $('#editCategory').val() };
$.ajax({
url: routes.update(id),
method: 'PUT',
data: payload,
success: function(updated){
// update DOM row if present
const row = $(`.user-row[data-id="${updated.id}"]`);
if (row.length){
row.data('name', updated.name).data('email', updated.email).data('category', updated.category);
row.find('.fw-semibold').text(updated.name);
row.find('td').eq(2).text(updated.email);
row.find('.category-badge').removeClass('badge-district badge-regional badge-national');
if (updated.category === 'District') row.find('.category-badge').addClass('badge-district').text('District');
if (updated.category === 'Regional') row.find('.category-badge').addClass('badge-regional').text('Regional');
if (updated.category === 'National') row.find('.category-badge').addClass('badge-national').text('National');
// move row if category changed
const target = updated.category === 'District' ? '#districtBody' : (updated.category === 'Regional' ? '#regionalBody' : '#nationalBody');
if (!row.parent().is(target)) row.appendTo($(target));
} else {
// if row wasn't loaded, re-fetch current category
fetchCategory(currentCategory);
}
$('#editModal').modal('hide');
},
error: function(xhr){
if (xhr.status === 422) {
// show validation briefly (extend as needed)
alert('Validation error');
} else alert('Update failed');
}
});
});
// Bulk move
$('#moveForm').on('submit', function(e){
e.preventDefault();
const ids = $('.tab-pane.active .row-select:checked').closest('.user-row').map(function(){ return $(this).data('id'); }).get();
const target = $('#moveTarget').val();
$.post(routes.move, { ids, target }, function(res){
// refresh current category view
fetchCategory(currentCategory);
$('#moveModal').modal('hide');
}).fail(function(){ alert('Move failed'); });
});
// Bulk deactivate
$('#bulkDeactivate').on('click', function(){
const ids = $('.tab-pane.active .row-select:checked').closest('.user-row').map(function(){ return $(this).data('id'); }).get();
if (!ids.length) return;
$.post(routes.deactivate, { ids }, function(res){
fetchCategory(currentCategory);
}).fail(function(){ alert('Deactivate failed'); });
});
// Additional UX: pagination, error handling, loading states can be added.
})();
</script>
@endpush