station data fetch successfully

This commit is contained in:
armiejean 2025-05-19 11:50:42 +08:00
parent 9e5a466a5b
commit 9809ef792a
5 changed files with 267 additions and 205 deletions

View File

@ -4,11 +4,75 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
class ReportsController extends Controller class ReportsController extends Controller
{ {
protected $apiBaseUrl = 'http://192.168.100.6:8081/api/'; protected $apiBaseUrl;
public function __construct()
{
$this->apiBaseUrl = env('EXTERNAL_API_URL', 'http://localhost:8081/api/');
}
private function makeApiRequest($endpoint, $params)
{
try {
$user = Session::get('user');
$accessToken = $user['access_token'] ?? null;
if (!$accessToken) {
Log::info("No access token found, redirecting to login from {$endpoint}");
return redirect()->route('login')->with('error', 'Please log in to view reports.');
}
// Ensure proper URL formation
$baseUrl = rtrim($this->apiBaseUrl, '/');
$endpoint = ltrim($endpoint, '/');
$fullUrl = "{$baseUrl}/{$endpoint}";
Log::info("Making API request to: {$fullUrl}", ['params' => $params]);
$response = Http::withHeaders([
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $accessToken,
])->timeout(30)->get($fullUrl, $params);
Log::info("API response status: {$response->status()}", [
'endpoint' => $endpoint,
'response_body' => $response->body(),
'headers' => $response->headers()
]);
if ($response->status() === 401 || $response->status() === 403) {
Log::warning("Unauthorized or Forbidden API response for {$endpoint}", ['response' => $response->json()]);
return redirect()->route('login')->with('error', 'Your session has expired. Please log in again.');
}
if (!$response->successful()) {
Log::error("API request failed for {$endpoint}", [
'status' => $response->status(),
'response' => $response->body(),
'headers' => $response->headers()
]);
return null;
}
return $response->json();
} catch (\Illuminate\Http\Client\ConnectionException $e) {
Log::error("Connection error during API request to {$endpoint}", [
'error' => $e->getMessage(),
'params' => $params
]);
return null;
} catch (\Exception $e) {
Log::error("Unexpected error during API request to {$endpoint}", [
'error' => $e->getMessage(),
'params' => $params
]);
return null;
}
}
public function mobileUsage(Request $request) public function mobileUsage(Request $request)
{ {
$params = [ $params = [
@ -17,17 +81,22 @@ class ReportsController extends Controller
'date_start' => $request->input('date_start'), 'date_start' => $request->input('date_start'),
'date_end' => $request->input('date_end'), 'date_end' => $request->input('date_end'),
'sorting' => $request->input('sort', 'date|desc'), 'sorting' => $request->input('sort', 'date|desc'),
'_search' => $request->input('_search'),
]; ];
$response = Http::get($this->apiBaseUrl . 'cms/reportMobileUsage', $params); $data = $this->makeApiRequest('cms/reportMobileUsage', $params);
$data = $response->json();
if (is_a($data, '\Illuminate\Http\RedirectResponse')) {
return $data; // Redirect to login if unauthorized
}
$mobileUsageData = []; $mobileUsageData = [];
$currentPage = $params['page']; $currentPage = $params['page'];
$lastPage = 1; $lastPage = 1;
$total = 0; $total = 0;
$errorMessage = null;
if ($response->successful() && isset($data['data'])) { if ($data && isset($data['data'])) {
$mobileUsageData = array_map(function ($item) { $mobileUsageData = array_map(function ($item) {
return [ return [
'id' => $item['id'] ?? uniqid(), 'id' => $item['id'] ?? uniqid(),
@ -40,9 +109,15 @@ class ReportsController extends Controller
$currentPage = $data['meta']['current_page'] ?? 1; $currentPage = $data['meta']['current_page'] ?? 1;
$lastPage = $data['meta']['last_page'] ?? 1; $lastPage = $data['meta']['last_page'] ?? 1;
$total = $data['meta']['total'] ?? count($mobileUsageData); $total = $data['meta']['total'] ?? count($mobileUsageData);
} elseif ($data && isset($data['message'])) {
Log::info("API returned message for mobileUsage", ['message' => $data['message']]);
$errorMessage = $data['message'];
} else {
Log::warning("No data returned or invalid response structure for mobileUsage", ['data' => $data]);
$errorMessage = 'Failed to fetch mobile usage data.';
} }
return view('pages.reports.mobile-usage-report', compact('mobileUsageData', 'currentPage', 'lastPage', 'total')); return view('pages.reports.mobile-usage-report', compact('mobileUsageData', 'currentPage', 'lastPage', 'total', 'errorMessage'));
} }
public function registration(Request $request) public function registration(Request $request)
@ -53,17 +128,22 @@ class ReportsController extends Controller
'date_start' => $request->input('date_start'), 'date_start' => $request->input('date_start'),
'date_end' => $request->input('date_end'), 'date_end' => $request->input('date_end'),
'sorting' => $request->input('sort', 'date|desc'), 'sorting' => $request->input('sort', 'date|desc'),
'_search' => $request->input('_search'),
]; ];
$response = Http::get($this->apiBaseUrl . 'cms/reportRegistration', $params); $data = $this->makeApiRequest('cms/reportRegistration', $params);
$data = $response->json();
if (is_a($data, '\Illuminate\Http\RedirectResponse')) {
return $data;
}
$registrationData = []; $registrationData = [];
$currentPage = $params['page']; $currentPage = $params['page'];
$lastPage = 1; $lastPage = 1;
$total = 0; $total = 0;
$errorMessage = null;
if ($response->successful() && isset($data['data'])) { if ($data && isset($data['data'])) {
$registrationData = array_map(function ($item) { $registrationData = array_map(function ($item) {
return [ return [
'id' => $item['id'] ?? uniqid(), 'id' => $item['id'] ?? uniqid(),
@ -75,48 +155,64 @@ class ReportsController extends Controller
$currentPage = $data['meta']['current_page'] ?? 1; $currentPage = $data['meta']['current_page'] ?? 1;
$lastPage = $data['meta']['last_page'] ?? 1; $lastPage = $data['meta']['last_page'] ?? 1;
$total = $data['meta']['total'] ?? count($registrationData); $total = $data['meta']['total'] ?? count($registrationData);
} elseif ($data && isset($data['message'])) {
Log::info("API returned message for registration", ['message' => $data['message']]);
$errorMessage = $data['message'];
} else {
Log::warning("No data returned or invalid response structure for registration", ['data' => $data]);
$errorMessage = 'Failed to fetch registration data.';
} }
return view('pages.reports.registration-report', compact('registrationData', 'currentPage', 'lastPage', 'total')); return view('pages.reports.registration-report', compact('registrationData', 'currentPage', 'lastPage', 'total', 'errorMessage'));
} }
public function stationRating(Request $request) public function stationRating(Request $request)
{ {
$params = [ $params = [
'page' => $request->input('page', 1), 'page' => $request->input('page', 1),
'page_size' => 5, 'page_size' => 5,
'date_start' => $request->input('date_start'), 'date_start' => $request->input('date_start'),
'date_end' => $request->input('date_end'), 'date_end' => $request->input('date_end'),
'sorting' => $request->input('sort', 'transaction_date_time|desc'), 'sorting' => $request->input('sort', 'date|desc'),
]; '_search' => $request->input('_search'),
];
$response = Http::get($this->apiBaseUrl . 'cms/reportStationRatings', $params); $data = $this->makeApiRequest('cms/reportStationRatings', $params);
$data = $response->json();
$stationRatingData = []; if (is_a($data, '\Illuminate\Http\RedirectResponse')) {
$currentPage = $params['page']; return $data;
$lastPage = 1;
$total = 0;
if ($response->successful() && isset($data['data'])) {
$stationRatingData = array_map(function ($item) {
return [
'id' => $item['id'] ?? uniqid(),
'transactionDateTime' => $item['transaction_date_time'],
'cardNumber' => $item['card_number'],
'salesInvoice' => $item['sales_invoice'],
'station' => $item['station'],
'ratings' => $item['ratings'],
];
}, $data['data']);
$currentPage = $data['meta']['current_page'] ?? 1;
$lastPage = $data['meta']['last_page'] ?? 1;
$total = $data['meta']['total'] ?? count($stationRatingData);
}
return view('pages.reports.station-rating-report', compact('stationRatingData', 'currentPage', 'lastPage', 'total'));
} }
$stationRatingData = [];
$currentPage = $params['page'];
$lastPage = 1;
$total = 0;
$errorMessage = null;
if ($data && isset($data['data'])) {
$stationRatingData = array_map(function ($item) {
return [
'id' => $item['id'] ?? uniqid(),
'transactionDateTime' => $item['date'],
'cardNumber' => $item['card_number'],
'salesInvoice' => $item['invoice'],
'station' => $item['station'],
'ratings' => $item['rate'],
];
}, $data['data']);
$currentPage = $data['meta']['current_page'] ?? 1;
$lastPage = $data['meta']['last_page'] ?? 1;
$total = $data['meta']['total'] ?? count($stationRatingData);
} elseif ($data && isset($data['message'])) {
Log::info("API returned message for stationRating", ['message' => $data['message']]);
$errorMessage = $data['message'];
} else {
Log::warning("No data returned or invalid response structure for stationRating", ['data' => $data]);
$errorMessage = 'Failed to fetch station rating data.';
}
return view('pages.reports.station-rating-report', compact('stationRatingData', 'currentPage', 'lastPage', 'total', 'errorMessage'));
}
public function topUp(Request $request) public function topUp(Request $request)
{ {
$params = [ $params = [
@ -125,17 +221,22 @@ class ReportsController extends Controller
'date_start' => $request->input('date_start'), 'date_start' => $request->input('date_start'),
'date_end' => $request->input('date_end'), 'date_end' => $request->input('date_end'),
'sorting' => $request->input('sort', 'transaction_date_time|desc'), 'sorting' => $request->input('sort', 'transaction_date_time|desc'),
'_search' => $request->input('_search'),
]; ];
$response = Http::get($this->apiBaseUrl . 'cms/reportTopUp', $params); $data = $this->makeApiRequest('cms/reportTopUp', $params);
$data = $response->json();
if (is_a($data, '\Illuminate\Http\RedirectResponse')) {
return $data;
}
$topUpData = []; $topUpData = [];
$currentPage = $params['page']; $currentPage = $params['page'];
$lastPage = 1; $lastPage = 1;
$total = 0; $total = 0;
$errorMessage = null;
if ($response->successful() && isset($data['data'])) { if ($data && isset($data['data'])) {
$topUpData = array_map(function ($item) { $topUpData = array_map(function ($item) {
return [ return [
'id' => $item['id'] ?? uniqid(), 'id' => $item['id'] ?? uniqid(),
@ -147,8 +248,14 @@ class ReportsController extends Controller
$currentPage = $data['meta']['current_page'] ?? 1; $currentPage = $data['meta']['current_page'] ?? 1;
$lastPage = $data['meta']['last_page'] ?? 1; $lastPage = $data['meta']['last_page'] ?? 1;
$total = $data['meta']['total'] ?? count($topUpData); $total = $data['meta']['total'] ?? count($topUpData);
} elseif ($data && isset($data['message'])) {
Log::info("API returned message for topUp", ['message' => $data['message']]);
$errorMessage = $data['message'];
} else {
Log::warning("No data returned or invalid response structure for topUp", ['data' => $data]);
$errorMessage = 'Failed to fetch top-up data.';
} }
return view('pages.reports.top-up-usage-report', compact('topUpData', 'currentPage', 'lastPage', 'total')); return view('pages.reports.top-up-usage-report', compact('topUpData', 'currentPage', 'lastPage', 'total', 'errorMessage'));
} }
} }

View File

@ -10,73 +10,71 @@ class StationController extends Controller
{ {
protected $apiBaseUrl = 'http://192.168.100.6:8081/api/'; protected $apiBaseUrl = 'http://192.168.100.6:8081/api/';
public function index(Request $request) public function index(Request $request)
{ {
$params = [ $params = [
'page' => $request->input('page', 1), 'page' => $request->input('page', 1),
'page_size' => 5, 'page_size' => 5,
'_search' => $request->input('_search'), '_search' => $request->input('_search'),
'sort' => $request->input('sort', 'code|asc'), 'sort' => $request->input('sort', 'code|asc'),
]; ];
$response = Http::get($this->apiBaseUrl . 'cms/getStations', $params); $response = Http::get($this->apiBaseUrl . 'cms/getStations', $params);
$data = $response->json(); $data = $response->json();
$stations = []; \Log::info('Stations API Response:', ['status' => $response->status(), 'data' => $data]);
$currentPage = $params['page'];
$lastPage = 1;
$total = 0;
if ($response->successful() && isset($data['data'])) { $stations = [];
$stations = array_map(function ($item) { $currentPage = $params['page'];
return [ $lastPage = 1;
'id' => $item['station_uuid'], $total = 0;
'station_code' => $item['code'],
'station_name' => $item['description'],
'branch_name' => 'N/A', // Mocked; replace with actual API field if available
'date_created' => 'N/A', // Mocked
'created_by' => 'N/A', // Mocked
'modified_by' => 'N/A', // Mocked
'date_modified' => 'N/A', // Mocked
];
}, $data['data']);
// Mock pagination since API may not support it if ($response->successful() && isset($data['data'])) {
$total = count($data['data']); $stations = array_map(function ($item) {
return [
'id' => $item['station_uuid'],
'station_code' => $item['code'],
'station_name' => $item['description'],
'branch_name' => 'N/A',
'date_created' => 'N/A',
'created_by' => 'N/A',
'modified_by' => 'N/A',
'date_modified' => 'N/A',
];
}, $data['data']);
$total = count($data['data']);
$lastPage = ceil($total / $params['page_size']);
$currentPage = min($currentPage, $lastPage);
if ($params['_search']) {
$searchTerm = strtolower($params['_search']);
$stations = array_filter($stations, function ($station) use ($searchTerm) {
return str_contains(strtolower($station['station_code']), $searchTerm) ||
str_contains(strtolower($station['station_name']), $searchTerm) ||
str_contains(strtolower($station['branch_name']), $searchTerm);
});
$stations = array_values($stations);
$total = count($stations);
$lastPage = ceil($total / $params['page_size']); $lastPage = ceil($total / $params['page_size']);
$currentPage = min($currentPage, $lastPage);
// Handle search client-side if API doesn't support _search
if ($params['_search']) {
$searchTerm = strtolower($params['_search']);
$stations = array_filter($stations, function ($station) use ($searchTerm) {
return str_contains(strtolower($station['station_code']), $searchTerm) ||
str_contains(strtolower($station['station_name']), $searchTerm) ||
str_contains(strtolower($station['branch_name']), $searchTerm);
});
$stations = array_values($stations);
$total = count($stations);
$lastPage = ceil($total / $params['page_size']);
}
// Handle sorting client-side if API doesn't support sort
if ($params['sort']) {
[$sortField, $sortDir] = explode('|', $params['sort']);
usort($stations, function ($a, $b) use ($sortField, $sortDir) {
$aValue = $a[$sortField] ?? '';
$bValue = $b[$sortField] ?? '';
return $sortDir === 'asc' ? strcmp($aValue, $bValue) : strcmp($bValue, $aValue);
});
}
// Paginate manually
$start = ($currentPage - 1) * $params['page_size'];
$stations = array_slice($stations, $start, $params['page_size']);
} }
return view('pages.station locator.stations', compact('stations', 'currentPage', 'lastPage', 'total')); if ($params['sort']) {
[$sortField, $sortDir] = explode('|', $params['sort']);
usort($stations, function ($a, $b) use ($sortField, $sortDir) {
$aValue = $a[$sortField] ?? '';
$bValue = $b[$sortField] ?? '';
return $sortDir === 'asc' ? strcmp($aValue, $bValue) : strcmp($bValue, $aValue);
});
}
$start = ($currentPage - 1) * $params['page_size'];
$stations = array_slice($stations, $start, $params['page_size']);
} }
return view('pages.station locator.stations', compact('stations', 'currentPage', 'lastPage', 'total'));
}
// public function create() // public function create()
// { // {
// return view('pages.add-station'); // return view('pages.add-station');

View File

@ -14,7 +14,6 @@
'total' => 0, 'total' => 0,
]) ])
<div class="card-body"> <div class="card-body">
<!-- Filters --> <!-- Filters -->
<div class="d-flex justify-content-between mb-3 flex-wrap gap-2"> <div class="d-flex justify-content-between mb-3 flex-wrap gap-2">
@ -26,23 +25,10 @@
<span class="input-group-text bg-light border-end-0"> <span class="input-group-text bg-light border-end-0">
<i class="fa-solid fa-magnifying-glass text-muted"></i> <i class="fa-solid fa-magnifying-glass text-muted"></i>
</span> </span>
<input type="text" class="form-control border-start-0" placeholder="Search..." id="searchInput" data-search-param="_search"> <input type="text" class="form-control border-start-0" placeholder="Search..." id="searchInput" data-search-param="_search" value="{{ request('_search') }}">
</div> </div>
</div> </div>
@endif @endif
{{-- <div class="d-flex flex-column">
<label for="startDate" class="form-label mb-1">Start Date</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-calendar-alt"></i></span>
<input type="date" class="form-control" id="startDate">
</div>
</div> --}}
{{-- <div class="d-flex flex-column">
<label for="endDate" class="form-label mb-1">End Date</label>
<div class="input-group">
<input type="date" class="form-control" id="endDate">
</div>
</div> --}}
</div> </div>
<div class="d-flex gap-2 align-items-end"> <div class="d-flex gap-2 align-items-end">
<button class="btn btn-outline-secondary btn-sm" id="clearFilters"> <button class="btn btn-outline-secondary btn-sm" id="clearFilters">
@ -51,6 +37,11 @@
</div> </div>
</div> </div>
<!-- No Data Message -->
@if (empty($data))
<div class="alert alert-info" id="no-data-message">No data available.</div>
@endif
<!-- Table --> <!-- Table -->
<div class="table-container"> <div class="table-container">
<table class="table table-hover align-middle"> <table class="table table-hover align-middle">
@ -127,6 +118,8 @@
exportEndpoint: '{{ route( Str::kebab(str_replace(" ", "-", strtolower($pageTitle)))) }}Export', exportEndpoint: '{{ route( Str::kebab(str_replace(" ", "-", strtolower($pageTitle)))) }}Export',
}; };
console.log('Table Config:', tableConfig); // Log initial config
const rowsPerPage = 5; const rowsPerPage = 5;
let currentPage = tableConfig.currentPage; let currentPage = tableConfig.currentPage;
let filteredRows = [...tableConfig.data]; let filteredRows = [...tableConfig.data];
@ -154,14 +147,23 @@
} }
function renderTable() { function renderTable() {
console.log('Rendering table with filteredRows:', filteredRows); // Log data
const tableBody = document.getElementById('tableBody'); const tableBody = document.getElementById('tableBody');
if (!tableBody) return; if (!tableBody) {
console.error('Table body not found');
return;
}
tableBody.innerHTML = ''; tableBody.innerHTML = '';
if (filteredRows.length === 0) {
tableBody.innerHTML = `<tr><td colspan="${tableConfig.columns.length}">No data to display</td></tr>`;
console.log('No data to render');
return;
}
filteredRows.forEach(row => { filteredRows.forEach(row => {
const tr = document.createElement('tr'); const tr = document.createElement('tr');
let rowHtml = ''; let rowHtml = '';
tableConfig.columns.forEach(col => { tableConfig.columns.forEach(col => {
let value = row[col.key] || ''; let value = row[col.key] || '';
if (col.format === 'date' || col.key.includes('DateTime')) { if (col.format === 'date' || col.key.includes('DateTime')) {
@ -169,17 +171,18 @@
} }
rowHtml += `<td>${value}</td>`; rowHtml += `<td>${value}</td>`;
}); });
tr.innerHTML = rowHtml; tr.innerHTML = rowHtml;
tableBody.appendChild(tr); tableBody.appendChild(tr);
}); });
updateNoDataMessage();
} }
function renderPagination() { function renderPagination() {
console.log('Rendering pagination:', { currentPage, lastPage: tableConfig.lastPage }); // Log pagination
const pagination = document.getElementById('pagination'); const pagination = document.getElementById('pagination');
if (!pagination) return; if (!pagination) {
console.error('Pagination element not found');
return;
}
pagination.innerHTML = ''; pagination.innerHTML = '';
const routeBase = tableConfig.pageTitle.toLowerCase().replace(/\s+/g, '-'); const routeBase = tableConfig.pageTitle.toLowerCase().replace(/\s+/g, '-');
@ -222,6 +225,7 @@
} }
function updateUrl(page, search, startDate, endDate) { function updateUrl(page, search, startDate, endDate) {
console.log('Updating URL:', { page, search, startDate, endDate, sortColumn, sortDirection }); // Log URL update
const url = new URL(window.location); const url = new URL(window.location);
url.searchParams.set('page', page); url.searchParams.set('page', page);
if (search) url.searchParams.set('_search', search); if (search) url.searchParams.set('_search', search);
@ -238,17 +242,11 @@
window.location.href = url.toString(); window.location.href = url.toString();
} }
function updateNoDataMessage() {
const noDataMessage = document.getElementById('no-data-message');
if (noDataMessage) {
noDataMessage.style.display = filteredRows.length === 0 ? 'block' : 'none';
}
}
function attachEventListeners() { function attachEventListeners() {
const searchInput = document.getElementById('searchInput'); const searchInput = document.getElementById('searchInput');
if (searchInput) { if (searchInput) {
searchInput.addEventListener('input', function() { searchInput.addEventListener('input', function() {
console.log('Search input changed:', this.value); // Log search
const url = new URL(window.location); const url = new URL(window.location);
const searchTerm = this.value; const searchTerm = this.value;
if (searchTerm) { if (searchTerm) {
@ -266,6 +264,7 @@
const columnKey = this.getAttribute('data-key'); const columnKey = this.getAttribute('data-key');
sortDirection = sortColumn === columnKey && sortDirection === 'asc' ? 'desc' : 'asc'; sortDirection = sortColumn === columnKey && sortDirection === 'asc' ? 'desc' : 'asc';
sortColumn = columnKey; sortColumn = columnKey;
console.log('Sorting:', { columnKey, sortDirection }); // Log sorting
document.querySelectorAll('.sortable i').forEach(icon => { document.querySelectorAll('.sortable i').forEach(icon => {
icon.classList.remove('fa-sort-up', 'fa-sort-down'); icon.classList.remove('fa-sort-up', 'fa-sort-down');
@ -286,13 +285,20 @@
const startDateInput = document.getElementById('startDate'); const startDateInput = document.getElementById('startDate');
const endDateInput = document.getElementById('endDate'); const endDateInput = document.getElementById('endDate');
if (startDateInput && endDateInput) { if (startDateInput && endDateInput) {
startDateInput.addEventListener('change', () => updateUrl(1, document.getElementById('searchInput')?.value || '', startDateInput.value, endDateInput.value)); startDateInput.addEventListener('change', () => {
endDateInput.addEventListener('change', () => updateUrl(1, document.getElementById('searchInput')?.value || '', startDateInput.value, endDateInput.value)); console.log('Start date changed:', startDateInput.value); // Log date
updateUrl(1, document.getElementById('searchInput')?.value || '', startDateInput.value, endDateInput.value);
});
endDateInput.addEventListener('change', () => {
console.log('End date changed:', endDateInput.value); // Log date
updateUrl(1, document.getElementById('searchInput')?.value || '', startDateInput.value, endDateInput.value);
});
} }
const clearFilters = document.getElementById('clearFilters'); const clearFilters = document.getElementById('clearFilters');
if (clearFilters) { if (clearFilters) {
clearFilters.addEventListener('click', function() { clearFilters.addEventListener('click', function() {
console.log('Clearing filters'); // Log filter clear
if (searchInput) searchInput.value = ''; if (searchInput) searchInput.value = '';
if (startDateInput) startDateInput.value = ''; if (startDateInput) startDateInput.value = '';
if (endDateInput) endDateInput.value = ''; if (endDateInput) endDateInput.value = '';
@ -309,6 +315,7 @@
const exportCsvBtn = document.getElementById('exportCsv'); const exportCsvBtn = document.getElementById('exportCsv');
if (exportCsvBtn) { if (exportCsvBtn) {
exportCsvBtn.addEventListener('click', () => { exportCsvBtn.addEventListener('click', () => {
console.log('Exporting CSV'); // Log export
const url = new URL(tableConfig.exportEndpoint, window.location.origin); const url = new URL(tableConfig.exportEndpoint, window.location.origin);
const searchTerm = document.getElementById('searchInput')?.value || ''; const searchTerm = document.getElementById('searchInput')?.value || '';
const startDate = document.getElementById('startDate')?.value || ''; const startDate = document.getElementById('startDate')?.value || '';
@ -319,6 +326,7 @@
if (sortColumn && sortDirection) { if (sortColumn && sortDirection) {
url.searchParams.set('sort', `${sortColumn}|${sortDirection}`); url.searchParams.set('sort', `${sortColumn}|${sortDirection}`);
} }
console.log('Export URL:', url.toString()); // Log export URL
window.location.href = url.toString(); window.location.href = url.toString();
}); });
} }

View File

@ -8,6 +8,11 @@
</div> </div>
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="card-body p-3"> <div class="card-body p-3">
<!-- Error Message -->
@if ($errorMessage)
<div class="alert alert-danger">{{ $errorMessage }}</div>
@endif
<!-- Filters --> <!-- Filters -->
<div class="d-flex justify-content-between mb-3 flex-wrap gap-2"> <div class="d-flex justify-content-between mb-3 flex-wrap gap-2">
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center gap-2">
@ -15,13 +20,13 @@
<label for="startDate" class="form-label mb-1">Start Date</label> <label for="startDate" class="form-label mb-1">Start Date</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-text"><i class="fas fa-calendar-alt"></i></span> <span class="input-group-text"><i class="fas fa-calendar-alt"></i></span>
<input type="date" class="form-control" id="startDate"> <input type="date" class="form-control" id="startDate" value="{{ request('date_start') }}">
</div> </div>
</div> </div>
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<label for="endDate" class="form-label mb-1">End Date</label> <label for="endDate" class="form-label mb-1">End Date</label>
<div class="input-group"> <div class="input-group">
<input type="date" class="form-control" id="endDate"> <input type="date" class="form-control" id="endDate" value="{{ request('date_end') }}">
</div> </div>
</div> </div>
</div> </div>
@ -46,7 +51,7 @@
'showAddButton' => false, 'showAddButton' => false,
'showCheckboxes' => false, 'showCheckboxes' => false,
'showBatchDelete' => false, 'showBatchDelete' => false,
'showSearch' => false, 'showSearch' => true,
'currentPage' => $currentPage ?? 1, 'currentPage' => $currentPage ?? 1,
'lastPage' => $lastPage ?? 1, 'lastPage' => $lastPage ?? 1,
'total' => $total ?? 0, 'total' => $total ?? 0,
@ -55,20 +60,6 @@
</div> </div>
<style> <style>
.card {
border-radius: 5px;
border: 1px solid #dee2e6;
}
.form-control {
font-size: 0.9rem;
}
.btn-outline-secondary {
border-color: #6c757d;
color: #6c757d;
}
.btn-outline-secondary:hover {
background-color: #f8f9fa;
}
.btn-export-csv { .btn-export-csv {
background-color: #ff6200; background-color: #ff6200;
color: white; color: white;
@ -77,64 +68,22 @@
.btn-export-csv:hover { .btn-export-csv:hover {
background-color: #e65a00; background-color: #e65a00;
} }
.input-group-text {
background-color: #f8f9fa;
}
</style> </style>
<script> <script>
let originalData = [...tableConfig.data];
const startDateInput = document.getElementById('startDate');
const endDateInput = document.getElementById('endDate');
const exportCsvBtn = document.getElementById('exportCsv'); const exportCsvBtn = document.getElementById('exportCsv');
function filterData() {
const startDate = startDateInput.value ? new Date(startDateInput.value) : null;
const endDate = endDateInput.value ? new Date(endDateInput.value) : null;
tableConfig.data = originalData.filter(item => {
const itemDate = new Date(item.transactionDateTime);
if (startDate && itemDate < startDate) return false;
if (endDate) {
const endDateAdjusted = new Date(endDate);
endDateAdjusted.setHours(23, 59, 59, 999);
if (itemDate > endDateAdjusted) return false;
}
return true;
});
currentPage = 1;
renderTable();
renderPagination();
}
startDateInput.addEventListener('change', filterData);
endDateInput.addEventListener('change', filterData);
exportCsvBtn.addEventListener('click', () => { exportCsvBtn.addEventListener('click', () => {
const headers = tableConfig.columns.map(col => col.name).join(','); const url = new URL(tableConfig.exportEndpoint, window.location.origin);
const rows = tableConfig.data.map(item => { const searchTerm = document.getElementById('searchInput')?.value || '';
return [ const startDate = document.getElementById('startDate')?.value || '';
item.transactionDateTime, const endDate = document.getElementById('endDate')?.value || '';
item.cardNumber, if (searchTerm) url.searchParams.set('_search', searchTerm);
item.salesInvoice, if (startDate) url.searchParams.set('date_start', startDate);
item.station, if (endDate) url.searchParams.set('date_end', endDate);
item.ratings if (sortColumn && sortDirection) {
].join(','); url.searchParams.set('sort', `${sortColumn}|${sortDirection}`);
}); }
const csvContent = [headers, ...rows].join('\n'); window.location.href = url.toString();
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', 'station-rating-report.csv');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}); });
// Initial render
renderTable();
renderPagination();
</script> </script>
@endsection @endsection

View File

@ -3,7 +3,7 @@
@section('page_title', 'Station Management') @section('page_title', 'Station Management')
@section('content') @section('content')
@include('components.station-component', [ @include('components.table-component', [
'pageTitle' => 'Station Management', 'pageTitle' => 'Station Management',
'data' => $stations ?? [], 'data' => $stations ?? [],
'columns' => [ 'columns' => [