diff --git a/app/Http/Controllers/TopUpController.php b/app/Http/Controllers/TopUpController.php new file mode 100644 index 0000000..08d68eb --- /dev/null +++ b/app/Http/Controllers/TopUpController.php @@ -0,0 +1,357 @@ +route('login')->with('error', 'Please log in to view top-ups.'); + } + + // Get the requested page from the request (default to 1) + $page = $request->input('page', 1); + $perPage = 5; // Set to 5 items per page + + $response = Http::withHeaders([ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $accessToken, + ])->get("{$this->apiBaseUrl}/cms/topUp", [ + 'page' => $page, + 'per_page' => $perPage, + ]); + + if ($response->status() === 401 || $response->status() === 403) { + Log::warning('Unauthorized or Forbidden API response: ', $response->json()); + return redirect()->route('login')->with('error', 'Your session has expired. Please log in again.'); + } + + $json = $response->json(); + + Log::info("TopUp API Response (Page {$page}): ", $json); + + if ($response->successful() && isset($json['data']) && is_array($json['data'])) { + $topups = array_map(function ($topup) { + Log::info('Processing top-up record: ', $topup); + return [ + 'topup_uuid' => $topup['topup_uuid'] ?? $topup['id'] ?? null, + 'freeCode' => $topup['fee_code'] ?? 'N/A', + 'name' => $topup['name'] ?? 'Unnamed', + 'value' => $topup['amount'] ?? 0, + 'type' => $topup['type'] ?? 'Unknown', + ]; + }, $json['data']); + + // Pass pagination metadata to the view + $total = $json['meta']['total'] ?? count($topups); // Total items, adjust based on API response + $lastPage = $json['meta']['last_page'] ?? ceil($total / $perPage); // Calculate last page + + return view('pages.top-up', [ + 'topups' => $topups, + 'currentPage' => $page, + 'lastPage' => $lastPage, + 'total' => $total, + ]); + } else { + Log::warning('No top-up data found or invalid API response: ', $json); + return view('pages.top-up', [ + 'topups' => [], + 'currentPage' => 1, + 'lastPage' => 1, + 'total' => 0, + ]); + } + } catch (\Exception $e) { + Log::error('Error fetching top-up data: ' . $e->getMessage()); + return view('pages.top-up', [ + 'topups' => [], + 'currentPage' => 1, + 'lastPage' => 1, + 'total' => 0, + ]); + } +} + public function create() + { + try { + $user = Session::get('user'); + $accessToken = $user['access_token'] ?? null; + + if (!$accessToken) { + Log::info('No access token found, redirecting to login from top-up create'); + return redirect()->route('login')->with('error', 'Please log in to add a top-up.'); + } + + $response = Http::withHeaders([ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $accessToken, + ])->get("{$this->apiBaseUrl}/cms/generateFeeCode"); + + $json = $response->json(); + + if ($response->successful() && isset($json['data']['fee_code'])) { + $freeCode = $json['data']['fee_code']; + return view('pages.add-top-up', ['freeCode' => $freeCode]); + } else { + Log::warning('Failed to generate fee code: ', $json); + return view('pages.add-top-up', ['freeCode' => '']); + } + } catch (\Exception $e) { + Log::error('Error generating fee code: ' . $e->getMessage()); + return view('pages.add-top-up', ['freeCode' => '']); + } + } + + public function store(Request $request) + { + try { + $user = Session::get('user'); + $accessToken = $user['access_token'] ?? null; + + if (!$accessToken) { + return redirect()->route('login')->with('error', 'Please log in to add a top-up.'); + } + + $validated = $request->validate([ + 'freeCode' => 'required|string|max:255', + 'name' => 'required|string|max:255', + 'value' => 'required|numeric|min:0', + 'type' => 'required|in:1,2,3', + ]); + + $payload = [ + 'fee_code' => $validated['freeCode'], + 'name' => $validated['name'], + 'amount' => $validated['value'], + 'type' => $validated['type'], + ]; + + Log::info('API Payload for creating top-up: ', $payload); + + $response = Http::withHeaders([ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $accessToken, + ])->post("{$this->apiBaseUrl}/cms/topUp", $payload); + + $json = $response->json(); + + if ($response->successful()) { + Log::info('Top-up created successfully: ', $json); + return redirect()->route('top-up') + ->with('success', $json['message'] ?? 'Top-up added successfully'); + } else { + Log::error('Failed to create top-up: ', $json); + return redirect()->back()->with('error', $json['message'] ?? 'Failed to add top-up.'); + } + } catch (\Exception $e) { + Log::error('Error creating top-up: ' . $e->getMessage()); + return redirect()->back()->with('error', 'An error occurred while adding the top-up.'); + } + } + + public function show($uuid) + { + try { + $user = Session::get('user'); + $accessToken = $user['access_token'] ?? null; + + if (!$accessToken) { + Log::info('No access token found, redirecting to login from top-up show'); + return redirect()->route('login')->with('error', 'Please log in to view top-up details.'); + } + + $response = Http::withHeaders([ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $accessToken, + ])->get("{$this->apiBaseUrl}/cms/topUp/{$uuid}"); + + $json = $response->json(); + + if ($response->successful() && isset($json['data'])) { + $topup = [ + 'topup_uuid' => $json['data']['topup_uuid'], + 'freeCode' => $json['data']['fee_code'], + 'name' => $json['data']['name'], + 'value' => $json['data']['amount'], + 'type' => $json['data']['type'], + ]; + return view('pages.view-top-up', ['topup' => $topup]); + } else { + Log::warning('Top-up not found: ', $json); + return redirect()->route('top-up')->with('error', $json['message'] ?? 'Top-up not found.'); + } + } catch (\Exception $e) { + Log::error('Error fetching top-up: ' . $e->getMessage()); + return redirect()->route('top-up')->with('error', 'An error occurred while fetching the top-up.'); + } + } + + public function edit($uuid) + { + try { + $user = Session::get('user'); + $accessToken = $user['access_token'] ?? null; + + if (!$accessToken) { + Log::info('No access token found, redirecting to login from top-up edit'); + return redirect()->route('login')->with('error', 'Please log in to edit a top-up.'); + } + + $response = Http::withHeaders([ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $accessToken, + ])->get("{$this->apiBaseUrl}/cms/topUp/{$uuid}"); + + $json = $response->json(); + + if ($response->successful() && isset($json['data'])) { + $topup = [ + 'topup_uuid' => $json['data']['topup_uuid'], + 'freeCode' => $json['data']['fee_code'], + 'name' => $json['data']['name'], + 'value' => $json['data']['amount'], + 'type' => $json['data']['type'], + ]; + return view('pages.edit-top-up', ['topup' => $topup]); + } else { + Log::warning('Top-up not found: ', $json); + return redirect()->route('top-up')->with('error', $json['message'] ?? 'Top-up not found.'); + } + } catch (\Exception $e) { + Log::error('Error fetching top-up for edit: ' . $e->getMessage()); + return redirect()->route('top-up')->with('error', 'An error occurred while fetching the top-up.'); + } + } + + public function update(Request $request, $uuid) + { + try { + $user = Session::get('user'); + $accessToken = $user['access_token'] ?? null; + + if (!$accessToken) { + return redirect()->route('login')->with('error', 'Please log in to update a top-up.'); + } + + $validated = $request->validate([ + 'freeCode' => 'required|string|max:255', + 'name' => 'required|string|max:255', + 'value' => 'required|numeric|min:0', + 'type' => 'required|in:Prepaid,Postpaid,Bonus', + ]); + + $payload = [ + 'fee_code' => $validated['freeCode'], + 'name' => $validated['name'], + 'amount' => $validated['value'], + 'type' => $validated['type'], + ]; + + Log::info('API Payload for updating top-up: ', $payload); + + $response = Http::withHeaders([ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $accessToken, + ])->put("{$this->apiBaseUrl}/cms/topUp/{$uuid}", $payload); + + $json = $response->json(); + + if ($response->successful()) { + Log::info('Top-up updated successfully: ', $json); + return redirect()->route('top-up') + ->with('success', $json['message'] ?? 'Top-up updated successfully'); + } else { + Log::error('Failed to update top-up: ', $json); + return redirect()->back()->with('error', $json['message'] ?? 'Failed to update top-up.'); + } + } catch (\Exception $e) { + Log::error('Error updating top-up: ' . $e->getMessage()); + return redirect()->back()->with('error', 'An error occurred while updating the top-up.'); + } + } + + public function destroy($uuid) + { + try { + $user = Session::get('user'); + $accessToken = $user['access_token'] ?? null; + + if (!$accessToken) { + return redirect()->route('login')->with('error', 'Please log in to delete a top-up.'); + } + + $response = Http::withHeaders([ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $accessToken, + ])->delete("{$this->apiBaseUrl}/cms/topUp/{$uuid}"); + + $json = $response->json(); + + if ($response->successful()) { + Log::info('Top-up deleted successfully: ', $json); + return redirect()->route('top-up') + ->with('success', $json['message'] ?? 'Top-up deleted successfully'); + } else { + Log::error('Failed to delete top-up: ', $json); + return redirect()->back()->with('error', $json['message'] ?? 'Failed to delete top-up.'); + } + } catch (\Exception $e) { + Log::error('Error deleting top-up: ' . $e->getMessage()); + return redirect()->back()->with('error', 'An error occurred while deleting the top-up.'); + } + } + + public function batchDelete(Request $request) + { + try { + $user = Session::get('user'); + $accessToken = $user['access_token'] ?? null; + + if (!$accessToken) { + return redirect()->route('login')->with('error', 'Please log in to delete top-ups.'); + } + + $uuids = $request->input('topup_uuid', []); + + if (empty($uuids)) { + return redirect()->back()->with('error', 'No top-ups selected for deletion.'); + } + + Log::info('Batch delete UUIDs: ', $uuids); + + $response = Http::withHeaders([ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . $accessToken, + ])->delete("{$this->apiBaseUrl}/cms/topUpBatchDelete", [ + 'topup_uuid' => $uuids, + ]); + + $json = $response->json(); + + if ($response->successful()) { + Log::info('Batch delete successful for UUIDs: ', $uuids); + return redirect()->route('top-up') + ->with('success', $json['message'] ?? 'Top-ups deleted successfully'); + } else { + Log::error('Failed to batch delete top-ups: ', $json); + return redirect()->back()->with('error', $json['message'] ?? 'Failed to delete top-ups.'); + } + } catch (\Exception $e) { + Log::error('Error in batch delete: ' . $e->getMessage()); + return redirect()->back()->with('error', 'An error occurred while deleting top-ups.'); + } + } +} \ No newline at end of file diff --git a/resources/views/components/table-component.blade.php b/resources/views/components/table-component.blade.php deleted file mode 100644 index be82f13..0000000 --- a/resources/views/components/table-component.blade.php +++ /dev/null @@ -1,767 +0,0 @@ -@props([ - 'pageTitle' => '', - 'data' => [], - 'columns' => [], - 'actions' => [], - 'showAddButton' => false, - 'addButtonUrl' => '#', - 'showCheckboxes' => false, - 'showBatchDelete' => false, - 'showEditModal' => false, - 'showViewModal' => false -]) - - -
-
-
{{ $pageTitle }}
- @if ($showAddButton) - - Add {{ $pageTitle }} - - @endif -
-
-
- -
-
-
- - - - -
-
-
- -
-
- - -
- - - - @if ($showCheckboxes) - - @endif - @foreach ($columns as $index => $column) - - @endforeach - @if (!empty($actions)) - - @endif - - - -
- - - {{ $column['name'] }} - @if ($column['sortable']) - - @endif - Action
-
- - -
- @if ($showBatchDelete) -
- -
- @endif - -
-
- - - -@if ($showEditModal) - -@endif - - -@if ($showViewModal) - -@endif - - - - - - - \ No newline at end of file diff --git a/resources/views/components/top-up-component.blade.php b/resources/views/components/top-up-component.blade.php new file mode 100644 index 0000000..ee4460b --- /dev/null +++ b/resources/views/components/top-up-component.blade.php @@ -0,0 +1,488 @@ +@props([ + 'pageTitle' => '', + 'data' => [], + 'columns' => [], + 'actions' => [], + 'showAddButton' => false, + 'addButtonUrl' => '#', + 'showCheckboxes' => false, + 'showBatchDelete' => false, + 'currentPage' => 1, + 'lastPage' => 1, + 'total' => 0, +]) + +
+
+
{{ $pageTitle }}
+ @if ($showAddButton) + + Add {{ $pageTitle }} + + @endif +
+
+
+ +
+
+
+ + + + +
+
+
+ +
+
+ + +
+ + + + @if ($showCheckboxes) + + @endif + @foreach ($columns as $index => $column) + + @endforeach + @if (!empty($actions)) + + @endif + + + +
+ + + {{ $column['name'] }} + @if ($column['sortable']) + + @endif + Action
+
+ + +
+ @if ($showBatchDelete) +
+ +
+ @endif + +
+
+ + + + + \ No newline at end of file diff --git a/resources/views/components/user-management-component.blade.php b/resources/views/components/user-management-component.blade.php index ddcf3c0..eddcc41 100644 --- a/resources/views/components/user-management-component.blade.php +++ b/resources/views/components/user-management-component.blade.php @@ -232,7 +232,6 @@ .table thead .sortable i { font-size: 0.65rem; } - . personally identifiable information like names, addresses, or other sensitive data. .pagination-sm .page-link { padding: 0.2rem 0.4rem; font-size: 0.75rem; @@ -321,12 +320,12 @@ tableConfig.actions.forEach(action => { if (action === 'edit') { rowHtml += ` - + `; } else if (action === 'view') { rowHtml += ` - + `; } else if (action === 'delete') { @@ -522,7 +521,7 @@ renderTable(); renderPagination(); if (selectAll) selectAll.checked = false; - window.location.reload(); + window.location.reload(); // Reload to trigger session flash }).catch(error => { console.error('Batch delete error:', error); alert(error.response?.data?.message || 'Failed to delete users. You may have included your own account.'); @@ -536,7 +535,7 @@ document.querySelectorAll('.status-option').forEach(option => { option.addEventListener('click', function(e) { e.preventDefault(); - const newStatus = this.getAttribute('data-status'); + const newStatus = this.getAttribute('data-status'); // 'active' or 'inactive' const row = this.closest('tr'); const userId = row.getAttribute('data-id'); const statusText = row.querySelector('.status-text'); @@ -553,7 +552,7 @@ status: newStatus, _token: tableConfig.csrfToken }).then(response => { - window.location.reload(); + window.location.reload(); // Reload to trigger session flash }).catch(error => { console.error('Status update error:', error); alert(error.response?.data?.message || 'Failed to update status. You cannot update your own account.'); @@ -576,7 +575,7 @@ } }).then(response => { filteredRows = filteredRows.filter(row => row.admin_uuid !== userId); - tableConfig.data = tableConfig.data.filter(row => row.admin_uuid !== userId); + tableConfig.data = tableConfig.data.filter(row => !selectedIds.includes(row.admin_uuid)); originalRows = originalRows.filter(row => row.admin_uuid !== userId); const maxPage = Math.ceil(filteredRows.length / rowsPerPage); @@ -586,7 +585,7 @@ renderTable(); renderPagination(); - window.location.reload(); + window.location.reload(); // Reload to trigger session flash }).catch(error => { console.error('Delete error:', error); alert(error.response?.data?.message || 'Failed to delete user. You cannot delete your own account.'); @@ -595,27 +594,6 @@ }); }); - //Edit - document.querySelectorAll('.edit-btn').forEach(button => { - button.addEventListener('click', function(e) { - e.preventDefault(); - const userId = this.getAttribute('data-id'); - const href = this.getAttribute('href').replace(':id', userId); - window.location.href = href; - }); - }); - - // View - document.querySelectorAll('.view-btn').forEach(button => { - button.addEventListener('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - const href = this.getAttribute('href'); - console.log('View redirect:', href); // Debug - window.location.href = href; - }); - }); - // Row click to view document.querySelectorAll('.clickable-row').forEach(row => { row.addEventListener('click', function(e) { @@ -623,9 +601,7 @@ return; } const userId = this.getAttribute('data-id'); - const url = `{{ route('user-management.show', '') }}/${userId}`; - console.log('Row redirect:', url); // Debug - window.location.href = url; + window.location.href = `{{ route('user-management.show', '') }}/${userId}`; }); }); } diff --git a/resources/views/pages/add-top-up.blade.php b/resources/views/pages/add-top-up.blade.php index 781a58e..313b1ad 100644 --- a/resources/views/pages/add-top-up.blade.php +++ b/resources/views/pages/add-top-up.blade.php @@ -8,30 +8,52 @@
-
+ @if (session('success')) +
+ {{ session('success') }} +
+ @endif + @if (session('error')) +
+ {{ session('error') }} +
+ @endif + + @csrf
- + + @error('freeCode') +
{{ $message }}
+ @enderror
- + + @error('name') +
{{ $message }}
+ @enderror
- + + @error('value') +
{{ $message }}
+ @enderror
- + + + + @error('type') +
{{ $message }}
+ @enderror
- + Cancel
@@ -51,43 +73,8 @@ font-size: 0.9rem; width: 100%; } + .alert { + font-size: 0.9rem; + } - - @endsection \ No newline at end of file diff --git a/resources/views/pages/edit-top-up.blade.php b/resources/views/pages/edit-top-up.blade.php new file mode 100644 index 0000000..068ac3a --- /dev/null +++ b/resources/views/pages/edit-top-up.blade.php @@ -0,0 +1,81 @@ +@extends('layouts.app') + +@section('page_title', 'Edit Top-Up') + +@section('content') +
+
Edit Top-Up
+
+
+
+ @if (session('success')) +
+ {{ session('success') }} +
+ @endif + @if (session('error')) +
+ {{ session('error') }} +
+ @endif +
+ @csrf + @method('PUT') +
+ + + @error('freeCode') +
{{ $message }}
+ @enderror +
+
+ + + @error('name') +
{{ $message }}
+ @enderror +
+
+ + + @error('value') +
{{ $message }}
+ @enderror +
+
+ + + @error('type') +
{{ $message }}
+ @enderror +
+
+ Cancel + +
+
+
+
+ + +@endsection \ No newline at end of file diff --git a/resources/views/pages/top-up.blade.php b/resources/views/pages/top-up.blade.php index b29679a..0c07ea5 100644 --- a/resources/views/pages/top-up.blade.php +++ b/resources/views/pages/top-up.blade.php @@ -3,78 +3,39 @@ @section('page_title', 'Top-Up') @section('content') - @php - $topups = [ - [ - 'id' => 1, - 'freeCode' => 'CODE123', - 'name' => 'Monthly Top-Up', - 'value' => '100.00', - 'type' => 'Prepaid' +
+ @if (session('success')) + + @endif + @if (session('error')) + + @endif + @include('components.top-up-component', [ + 'pageTitle' => 'Top-Up', + 'data' => $topups, + 'columns' => [ + ['name' => 'Free Code', 'key' => 'freeCode', 'sortable' => true], + ['name' => 'Name', 'key' => 'name', 'sortable' => true], + ['name' => 'Value', 'key' => 'value', 'sortable' => true], + ['name' => 'Type', 'key' => 'type', 'sortable' => true], ], - [ - 'id' => 2, - 'freeCode' => 'CODE456', - 'name' => 'Annual Plan', - 'value' => '500.00', - 'type' => 'Postpaid' - ], - [ - 'id' => 3, - 'freeCode' => 'CODE789', - 'name' => 'Welcome Bonus', - 'value' => '50.00', - 'type' => 'Bonus' - ], - [ - 'id' => 4, - 'freeCode' => 'CODE101', - 'name' => 'Data Boost', - 'value' => '200.00', - 'type' => 'Prepaid' - ], - [ - 'id' => 5, - 'freeCode' => 'CODE202', - 'name' => 'Family Plan', - 'value' => '300.00', - 'type' => 'Postpaid' - ], - [ - 'id' => 6, - 'freeCode' => 'CODE303', - 'name' => 'Loyalty Credit', - 'value' => '75.00', - 'type' => 'Bonus' - ] - ]; - @endphp - - @include('components.table-component', [ - 'pageTitle' => 'Top-Up', - 'data' => $topups, - 'columns' => [ - ['name' => 'Free Code', 'key' => 'freeCode', 'sortable' => true], - ['name' => 'Name', 'key' => 'name', 'sortable' => true], - ['name' => 'Value', 'key' => 'value', 'sortable' => true], - ['name' => 'Type', 'key' => 'type', 'sortable' => true] - ], - 'actions' => ['edit', 'view', 'delete'], - 'showAddButton' => true, - 'addButtonUrl' => '/add-top-up', - 'showCheckboxes' => true, - 'showBatchDelete' => true, - 'showEditModal' => true, - 'showViewModal' => true - ]) - - + 'actions' => ['view', 'edit', 'delete'], + 'showAddButton' => true, + 'addButtonUrl' => route('top-up.create'), + 'showCheckboxes' => true, + 'showBatchDelete' => true, + 'currentPage' => $currentPage ?? 1, + 'lastPage' => $lastPage ?? 1, + 'total' => $total ?? 0, + ]) +
+

No top-ups found.

+
+
@endsection \ No newline at end of file diff --git a/resources/views/pages/view-top-up.blade.php b/resources/views/pages/view-top-up.blade.php new file mode 100644 index 0000000..d706f72 --- /dev/null +++ b/resources/views/pages/view-top-up.blade.php @@ -0,0 +1,47 @@ +@extends('layouts.app') + +@section('page_title', 'View Top-Up') + +@section('content') +
+
View Top-Up
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ Back +
+
+
+ + +@endsection \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index f4452c2..c140fb0 100644 --- a/routes/web.php +++ b/routes/web.php @@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Http; use App\Http\Controllers\AuthController; use App\Http\Controllers\UserManagementController; use App\Http\Controllers\PhotoSliderViewController; +use App\Http\Controllers\TopUpController; @@ -165,4 +166,14 @@ Route::get('user-management/{uuid}/edit', [UserManagementController::class, 'edi Route::put('user-management/{uuid}', [UserManagementController::class, 'update'])->name('user-management.update'); Route::delete('user-management/{uuid}', [UserManagementController::class, 'destroy'])->name('user-management.destroy'); Route::delete('user-management/batch', [UserManagementController::class, 'batchDelete'])->name('user-management.batchDelete'); -Route::post('user-management/{uuid}/status', [UserManagementController::class, 'changeStatus'])->name('user-management.changeStatus'); \ No newline at end of file +Route::post('user-management/{uuid}/status', [UserManagementController::class, 'changeStatus'])->name('user-management.changeStatus'); + +//TopUp +Route::get('/top-up', [TopUpController::class, 'index'])->name('top-up'); +Route::get('/top-up/create', [TopUpController::class, 'create'])->name('top-up.create'); +Route::post('/top-up', [TopUpController::class, 'store'])->name('top-up.store'); +Route::get('/top-up/{uuid}', [TopUpController::class, 'show'])->name('top-up.show'); +Route::get('/top-up/{uuid}/edit', [TopUpController::class, 'edit'])->name('top-up.edit'); +Route::put('/top-up/{uuid}', [TopUpController::class, 'update'])->name('top-up.update'); +Route::delete('/top-up/{uuid}', [TopUpController::class, 'destroy'])->name('top-up.destroy'); +Route::delete('/top-up/batch', [TopUpController::class, 'batchDelete'])->name('top-up.batchDelete');