export csv added
This commit is contained in:
parent
2a92dc2983
commit
bc8f68a610
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Livewire\Components;
|
||||
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Livewire\Component;
|
||||
|
||||
class Table extends Component
|
||||
|
@ -20,6 +21,12 @@ class Table extends Component
|
|||
public $search = ''; // Search query for filtering rows
|
||||
public $sortField = null; // Column to sort by
|
||||
public $sortDirection = 'asc'; // Sorting direction (asc or desc)
|
||||
public bool $hasSearch = true;
|
||||
|
||||
|
||||
public $startDate;
|
||||
public $endDate;
|
||||
|
||||
|
||||
// Modal Configuration
|
||||
public $showModal = false; // Whether the modal is visible
|
||||
|
@ -114,6 +121,36 @@ class Table extends Component
|
|||
}, SORT_REGULAR, $this->sortDirection === 'desc')->values()->all(); // Use all() to return plain array again
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the data from the tables
|
||||
*/
|
||||
|
||||
public function export()
|
||||
{
|
||||
$filename = 'export.csv';
|
||||
|
||||
return response()->streamDownload(function () {
|
||||
// Open output stream
|
||||
$handle = fopen('php://output', 'w');
|
||||
|
||||
// Write the CSV header
|
||||
fputcsv($handle, collect($this->columns)->pluck('label')->toArray());
|
||||
|
||||
// Write the rows
|
||||
foreach ($this->rows as $row) {
|
||||
fputcsv($handle, collect($this->columns)->map(function ($column) use ($row) {
|
||||
return $row[$column['field']] ?? '';
|
||||
})->toArray());
|
||||
}
|
||||
|
||||
// Close the output stream
|
||||
fclose($handle);
|
||||
}, $filename, [
|
||||
'Content-Type' => 'text/csv',
|
||||
'Content-Disposition' => "attachment; filename={$filename}",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the table view
|
||||
*/
|
||||
|
|
|
@ -8,8 +8,22 @@ use Livewire\Attributes\Layout; // Required for layout declaration
|
|||
#[Layout('layouts.dashboard')] // Attribute syntax for Laravel 11
|
||||
class MobileUsageReport extends Component
|
||||
{
|
||||
public $mobileUsageReport = [];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->loadMobileUsageReport(); // Load mobileUsageReport initially
|
||||
}
|
||||
|
||||
public function loadMobileUsageReport()
|
||||
{
|
||||
$this->mobileUsageReport = collect(json_decode(file_get_contents(storage_path('app/mobile-usage.json')), true));
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.report.mobile-usage-report');
|
||||
return view('livewire.report.mobile-usage-report', [
|
||||
'mobileUsageReport' => $this->mobileUsageReport,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,22 @@ use Livewire\Attributes\Layout; // Required for layout declaration
|
|||
#[Layout('layouts.dashboard')] // Attribute syntax for Laravel 11
|
||||
class RegistrationReport extends Component
|
||||
{
|
||||
public $registrationReport = [];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->loadRegistrationReport(); // Load registrationReport initially
|
||||
}
|
||||
|
||||
public function loadRegistrationReport()
|
||||
{
|
||||
$this->registrationReport = collect(json_decode(file_get_contents(storage_path('app/registration-report.json')), true));
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.report.registration-report');
|
||||
return view('livewire.report.registration-report', [
|
||||
'registrationReport' => $this->registrationReport,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,8 +8,22 @@ use Livewire\Attributes\Layout; // Required for layout declaration
|
|||
#[Layout('layouts.dashboard')] // Attribute syntax for Laravel 11
|
||||
class StationRatingReport extends Component
|
||||
{
|
||||
public $stationRating = [];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->loadStationRating(); // Load stationRating initially
|
||||
}
|
||||
|
||||
public function loadStationRating()
|
||||
{
|
||||
$this->stationRating = collect(json_decode(file_get_contents(storage_path('app/station-rating.json')), true));
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.report.station-rating-report');
|
||||
return view('livewire.report.station-rating-report', [
|
||||
'stationRating' => $this->stationRating,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,27 @@ use Livewire\Attributes\Layout; // Required for layout declaration
|
|||
#[Layout('layouts.dashboard')] // Attribute syntax for Laravel 11
|
||||
class TopUpUsageReport extends Component
|
||||
{
|
||||
public $topUpUsage = [];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->loadTopUpUsage(); // Load topUpUsage initially
|
||||
}
|
||||
|
||||
public function loadTopUpUsage()
|
||||
{
|
||||
$this->topUpUsage = collect(json_decode(file_get_contents(storage_path('app/topup-usage-report.json')), true));
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.report.top-up-usage-report');
|
||||
return view('livewire.report.top-up-usage-report', [
|
||||
'topUpUsage' => $this->topUpUsage,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,22 +1,48 @@
|
|||
<div class="mt-10">
|
||||
<div class="p-4 bg-white shadow-md">
|
||||
|
||||
<!-- Top Bar with Search & Add Button -->
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<!-- Search Input -->
|
||||
<input type="text" wire:model.debounce.500ms="search"
|
||||
class="w-80 p-2 border border-gray-300 rounded-md"
|
||||
placeholder="Search..."
|
||||
>
|
||||
|
||||
<!-- Add Button (if enabled and route exists) -->
|
||||
@if ($hasAddButton && $addRoute)
|
||||
<a href="{{ $addRoute }}" wire:navigate
|
||||
class="ml-4 px-4 py-2 bg-orange-500 text-white rounded-md hover:bg-orange-600">
|
||||
+ Add
|
||||
</a>
|
||||
@endif
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
@if ($hasSearch ?? true)
|
||||
<!-- Search bar -->
|
||||
<input
|
||||
type="text"
|
||||
wire:model="search"
|
||||
placeholder="Search..."
|
||||
class="border rounded px-3 py-2"
|
||||
/>
|
||||
@else
|
||||
<!-- Start Date and End Date filters -->
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="date"
|
||||
wire:model="startDate"
|
||||
class="border rounded px-3 py-2"
|
||||
/>
|
||||
|
||||
<input
|
||||
type="date"
|
||||
wire:model="endDate"
|
||||
class="border rounded px-3 py-2"
|
||||
/>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($hasAddButton ?? true)
|
||||
<!-- Add button -->
|
||||
<a href="{{ $addRoute }}" class="bg-orange-600 text-white px-4 py-2 rounded">
|
||||
+ Add
|
||||
</a>
|
||||
@else
|
||||
<!-- Export button -->
|
||||
<button
|
||||
wire:click="export"
|
||||
class="bg-orange-600 text-white px-4 py-2 rounded flex items-center gap-2"
|
||||
>
|
||||
Export CSV
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Table Header -->
|
||||
<table class="table-auto w-full">
|
||||
|
@ -24,30 +50,30 @@
|
|||
<tr>
|
||||
<!-- Checkbox for selecting rows (if enabled) -->
|
||||
@if ($hasCheckbox)
|
||||
<th class="px-4 py-2 text-left">
|
||||
<input type="checkbox" wire:model="selectAll" wire:change="selectAllRows" class="cursor-pointer">
|
||||
</th>
|
||||
<th class="px-4 py-2 text-left">
|
||||
<input type="checkbox" wire:model="selectAll" wire:change="selectAllRows" class="cursor-pointer">
|
||||
</th>
|
||||
@endif
|
||||
|
||||
<!-- Dynamic Columns (sortable) -->
|
||||
@foreach ($columns as $column)
|
||||
<th class="px-4 py-2 text-left cursor-pointer " wire:click="sortBy('{{ $column['field'] }}')">
|
||||
{{ $column['label'] }}
|
||||
@if ($sortField === $column['field'])
|
||||
@if ($sortDirection === 'asc')
|
||||
<span class="ml-2">↑</span>
|
||||
@else
|
||||
<span class="ml-2">↓</span>
|
||||
@endif
|
||||
@else
|
||||
<span class="ml-2">↕</span>
|
||||
@endif
|
||||
</th>
|
||||
<th class="px-4 py-2 text-left cursor-pointer " wire:click="sortBy('{{ $column['field'] }}')">
|
||||
{{ $column['label'] }}
|
||||
@if ($sortField === $column['field'])
|
||||
@if ($sortDirection === 'asc')
|
||||
<span class="ml-2">↑</span>
|
||||
@else
|
||||
<span class="ml-2">↓</span>
|
||||
@endif
|
||||
@else
|
||||
<span class="ml-2">↕</span>
|
||||
@endif
|
||||
</th>
|
||||
@endforeach
|
||||
|
||||
<!-- Actions Column (if enabled) -->
|
||||
@if ($hasActions)
|
||||
<th class="px-4 py-2 text-left">Actions</th>
|
||||
<th class="px-4 py-2 text-left">Actions</th>
|
||||
@endif
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -55,53 +81,53 @@
|
|||
<!-- Table Body -->
|
||||
<tbody>
|
||||
@forelse ($rows as $row)
|
||||
<tr class="hover:bg-gray-50 border-b">
|
||||
<!-- Checkbox for row selection (if enabled) -->
|
||||
@if ($hasCheckbox)
|
||||
<td class="px-4 py-2">
|
||||
<input type="checkbox" wire:click="selectRow('{{ $row['id'] }}')"
|
||||
@if(in_array($row['id'], $selected)) checked @endif class="cursor-pointer">
|
||||
</td>
|
||||
@endif
|
||||
<tr class="hover:bg-gray-50 border-b">
|
||||
<!-- Checkbox for row selection (if enabled) -->
|
||||
@if ($hasCheckbox)
|
||||
<td class="px-4 py-2">
|
||||
<input type="checkbox" wire:click="selectRow('{{ $row['id'] }}')"
|
||||
@if(in_array($row['id'], $selected)) checked @endif class="cursor-pointer">
|
||||
</td>
|
||||
@endif
|
||||
|
||||
<!-- Display Data for each column -->
|
||||
@foreach ($columns as $column)
|
||||
<td class="px-4 py-2">
|
||||
{{ $row[$column['field']] ?? '' }}
|
||||
</td>
|
||||
@endforeach
|
||||
<!-- Display Data for each column -->
|
||||
@foreach ($columns as $column)
|
||||
<td class="px-4 py-2">
|
||||
{{ $row[$column['field']] ?? '' }}
|
||||
</td>
|
||||
@endforeach
|
||||
|
||||
<!-- Action Buttons (if enabled) -->
|
||||
@if ($hasActions)
|
||||
<td class="px-4 py-2 gap-2 flex">
|
||||
@if($isViewPage)
|
||||
<button wire:click="viewRow({{ $row['id'] }})" class="text-gray-500 hover:text-gray-700">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
@else
|
||||
<button wire:click="editRow({{ $row['id'] }})" class="text-blue-500 hover:text-blue-700">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button wire:click="viewRow({{ $row['id'] }})" class="text-gray-500 hover:text-gray-700">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
<button wire:click="deleteRow({{ $row['id'] }})" class="text-red-500 hover:text-red-700">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
@endif
|
||||
</td>
|
||||
<!-- Action Buttons (if enabled) -->
|
||||
@if ($hasActions)
|
||||
<td class="px-4 py-2 gap-2 flex">
|
||||
@if($isViewPage)
|
||||
<button wire:click="viewRow({{ $row['id'] }})" class="text-gray-500 hover:text-gray-700">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
@else
|
||||
<button wire:click="editRow({{ $row['id'] }})" class="text-blue-500 hover:text-blue-700">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button wire:click="viewRow({{ $row['id'] }})" class="text-gray-500 hover:text-gray-700">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
<button wire:click="deleteRow({{ $row['id'] }})" class="text-red-500 hover:text-red-700">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
@endif
|
||||
</tr>
|
||||
</td>
|
||||
@endif
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="{{ count($columns) + 1 }}" class="text-center p-4">No data available</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="{{ count($columns) + 1 }}" class="text-center p-4">No data available</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- Delete Button -->
|
||||
@if($hasDelete)
|
||||
<button wire:click="deleteSelected"
|
||||
<button wire:click="deleteSelected"
|
||||
class="mt-4 px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 cursor-pointer"
|
||||
@if (empty($selected)) disabled @endif>
|
||||
Delete
|
||||
|
@ -110,45 +136,45 @@
|
|||
|
||||
<!-- Modal for Viewing / Editing Row -->
|
||||
@if ($showModal)
|
||||
<div class="fixed inset-0 bg-gray-900 bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div class="bg-white p-6 rounded-lg shadow-lg w-1/2">
|
||||
<!-- Modal Header -->
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-lg font-semibold">
|
||||
{{ $modalMode === 'view' ? 'View Details' : 'Edit Details' }}
|
||||
</h2>
|
||||
<button wire:click="closeModal" class="text-gray-600 hover:text-gray-800">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal Body -->
|
||||
<div class="space-y-4">
|
||||
@foreach ($columns as $column)
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">
|
||||
{{ $column['label'] }}
|
||||
</label>
|
||||
@if ($modalMode === 'edit')
|
||||
<input type="text" wire:model.defer="modalData.{{ $column['field'] }}"
|
||||
class="mt-1 p-2 border border-gray-300 rounded w-full">
|
||||
@else
|
||||
<div class="mt-1 p-2 bg-gray-100 rounded">
|
||||
{{ $modalData[$column['field']] ?? '' }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer with Save Button (if in edit mode) -->
|
||||
@if ($modalMode === 'edit')
|
||||
<div class="mt-6 flex justify-end">
|
||||
<button wire:click="saveRow" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
<div class="fixed inset-0 bg-gray-900 bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div class="bg-white p-6 rounded-lg shadow-lg w-1/2">
|
||||
<!-- Modal Header -->
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-lg font-semibold">
|
||||
{{ $modalMode === 'view' ? 'View Details' : 'Edit Details' }}
|
||||
</h2>
|
||||
<button wire:click="closeModal" class="text-gray-600 hover:text-gray-800">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal Body -->
|
||||
<div class="space-y-4">
|
||||
@foreach ($columns as $column)
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">
|
||||
{{ $column['label'] }}
|
||||
</label>
|
||||
@if ($modalMode === 'edit')
|
||||
<input type="text" wire:model.defer="modalData.{{ $column['field'] }}"
|
||||
class="mt-1 p-2 border border-gray-300 rounded w-full">
|
||||
@else
|
||||
<div class="mt-1 p-2 bg-gray-100 rounded">
|
||||
{{ $modalData[$column['field']] ?? '' }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer with Save Button (if in edit mode) -->
|
||||
@if ($modalMode === 'edit')
|
||||
<div class="mt-6 flex justify-end">
|
||||
<button wire:click="saveRow" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,5 +1,19 @@
|
|||
<div>
|
||||
{{-- Top Nav --}}
|
||||
@include('livewire.report.top-nav.mobile-usage-report')
|
||||
<h1>This is card type page</h1>
|
||||
<livewire:components.table
|
||||
:columns="[
|
||||
['label' => 'Date', 'field' => 'date'],
|
||||
['label' => 'Active Registered Users', 'field' => 'active_registered_users'],
|
||||
['label' => 'Inactive Registered Users', 'field' => 'inactive_registered_users'],
|
||||
['label' => 'Locked Registered Users', 'field' => 'locked_registered_users'],
|
||||
]"
|
||||
:rows="$mobileUsageReport"
|
||||
:hasSearch="false"
|
||||
:hasCheckbox="false"
|
||||
:hasActions="false"
|
||||
:hasDelete="false"
|
||||
:hasAddButton="false"
|
||||
:isViewPage="false"
|
||||
/>
|
||||
</div>
|
|
@ -1,5 +1,18 @@
|
|||
<div>
|
||||
{{-- Top Nav --}}
|
||||
@include('livewire.report.top-nav.registration-report')
|
||||
<h1>This is card type page</h1>
|
||||
<livewire:components.table
|
||||
:columns="[
|
||||
['label' => 'Date', 'field' => 'date'],
|
||||
['label' => 'No. of Activated Cards', 'field' => 'number_activated_cards'],
|
||||
['label' => 'No. of Registered Members', 'field' => 'number_registered_members'],
|
||||
]"
|
||||
:rows="$registrationReport"
|
||||
:hasSearch="false"
|
||||
:hasCheckbox="false"
|
||||
:hasActions="false"
|
||||
:hasDelete="false"
|
||||
:hasAddButton="false"
|
||||
:isViewPage="false"
|
||||
/>
|
||||
</div>
|
|
@ -1,5 +1,20 @@
|
|||
<div>
|
||||
{{-- Top Nav --}}
|
||||
@include('livewire.report.top-nav.station-rating-report')
|
||||
<h1>This is card type page</h1>
|
||||
<livewire:components.table
|
||||
:columns="[
|
||||
['label' => 'Transaction Date & Time', 'field' => 'transaction_date_time'],
|
||||
['label' => 'Card Number', 'field' => 'card_number'],
|
||||
['label' => 'Sales Invoice', 'field' => 'sales_invoice'],
|
||||
['label' => 'Station', 'field' => 'station'],
|
||||
['label' => 'Ratings', 'field' => 'rating'],
|
||||
]"
|
||||
:rows="$stationRating"
|
||||
:hasSearch="false"
|
||||
:hasCheckbox="false"
|
||||
:hasActions="false"
|
||||
:hasDelete="false"
|
||||
:hasAddButton="false"
|
||||
:isViewPage="false"
|
||||
/>
|
||||
</div>
|
|
@ -1,5 +1,19 @@
|
|||
<div>
|
||||
{{-- Top Nav --}}
|
||||
@include('livewire.report.top-nav.top-up-usage-report')
|
||||
<h1>This is card type page</h1>
|
||||
</div>
|
||||
{{-- Top Nav --}}
|
||||
@include('livewire.report.top-nav.top-up-usage-report')
|
||||
|
||||
<livewire:components.table
|
||||
:columns="[
|
||||
['label' => 'Transaction Date & Time', 'field' => 'transaction_date_time'],
|
||||
['label' => 'Card Number', 'field' => 'card_number'],
|
||||
['label' => 'Top-up Amount', 'field' => 'top_up_amount'],
|
||||
]"
|
||||
:rows="$topUpUsage"
|
||||
:hasAddButton="false"
|
||||
:hasSearch="false"
|
||||
:hasCheckbox="false"
|
||||
:hasActions="false"
|
||||
:hasDelete="false"
|
||||
:isViewPage="false"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -17,4 +17,6 @@
|
|||
|
||||
<!-- Bottom border -->
|
||||
<div class="border-b border-gray-300 mt-5"></div>
|
||||
|
||||
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue