From b2bc92e2b9db9567a037c550f50fba4cd6be2d4f Mon Sep 17 00:00:00 2001 From: Armie Date: Tue, 13 May 2025 19:54:49 +0800 Subject: [PATCH] integration --- app/Http/Controllers/Api/AuthController.php | 56 ++ .../Controllers/Api/CardMemberController.php | 175 ++++ .../Controllers/Api/FuelPriceController.php | 201 +++++ .../Api/NotificationsController.php | 120 +++ .../Controllers/Api/PhotoSliderController.php | 137 +++ .../Controllers/Api/PromotionsController.php | 120 +++ .../Controllers/Api/ReportsController.php | 136 +++ .../Controllers/Api/StationController.php | 148 ++++ .../Api/SystemParameterController.php | 116 +++ app/Http/Controllers/Api/TopUpController.php | 122 +++ .../Api/TopUpSettingController.php | 120 +++ app/Http/Controllers/Api/UserController.php | 93 +++ app/Http/Controllers/CardMemberController.php | 164 ++++ app/Http/Controllers/ContentController.php | 207 +++++ app/Http/Controllers/FuelPriceController.php | 120 +++ app/Http/Controllers/StationController.php | 133 +++ .../Controllers/SystemParameterController.php | 65 ++ .../Controllers/TopUpSettingController.php | 65 ++ .../Controllers/UserManagementController.php | 118 +-- app/Services/Api/ApiService.php | 92 +++ app/Services/Api/BaseApiService.php | 78 ++ app/Services/Api/CardMemberService.php | 61 ++ app/Services/Api/ContentService.php | 80 ++ app/Services/Api/FuelPriceService.php | 55 ++ app/Services/Api/StationService.php | 51 ++ app/Services/Api/SystemParameterService.php | 31 + app/Services/Api/TopUpSettingService.php | 31 + app/Services/Api/UserManagementService.php | 36 + docker-compose.yml | 3 +- package.json | 38 +- public/css/custom.css | 197 ++++- resources/js/app.js | 80 ++ resources/js/services/BaseApiService.js | 1 + resources/js/services/CardMemberService.js | 47 ++ resources/js/services/ContentService.js | 84 ++ resources/js/services/StationService.js | 51 ++ resources/js/services/UserService.js | 43 + .../components/table-component.blade.php | 778 ++++++------------ resources/views/layouts/app.blade.php | 79 +- resources/views/layouts/navbar.blade.php | 94 +++ resources/views/layouts/sidebar.blade.php | 138 ++++ resources/views/pages/add-station.blade.php | 359 ++++++-- .../pages/content/promotions/form.blade.php | 151 ++++ .../pages/content/promotions/index.blade.php | 307 +++++++ .../pages/fuel-price-on-demand.blade.php | 205 +++-- .../views/pages/fuel-price-schedule.blade.php | 371 +++++---- .../pages/fuel-price-update-logs.blade.php | 326 +++----- resources/views/pages/my-profile.blade.php | 331 ++++++-- resources/views/pages/notification.blade.php | 204 ++++- resources/views/pages/promotions.blade.php | 192 +++-- .../views/pages/stations/index.blade.php | 240 ++++++ .../views/pages/system-parameters.blade.php | 263 ++---- .../views/pages/top-up-settings.blade.php | 153 ++-- .../views/pages/user-management.blade.php | 102 ++- .../pages/user-management/form.blade.php | 218 +++++ .../pages/user-management/index.blade.php | 170 ++++ routes/web.php | 280 +++---- webpack.mix.js | 27 + 58 files changed, 6719 insertions(+), 1744 deletions(-) create mode 100644 app/Http/Controllers/Api/AuthController.php create mode 100644 app/Http/Controllers/Api/CardMemberController.php create mode 100644 app/Http/Controllers/Api/FuelPriceController.php create mode 100644 app/Http/Controllers/Api/NotificationsController.php create mode 100644 app/Http/Controllers/Api/PhotoSliderController.php create mode 100644 app/Http/Controllers/Api/PromotionsController.php create mode 100644 app/Http/Controllers/Api/ReportsController.php create mode 100644 app/Http/Controllers/Api/StationController.php create mode 100644 app/Http/Controllers/Api/SystemParameterController.php create mode 100644 app/Http/Controllers/Api/TopUpController.php create mode 100644 app/Http/Controllers/Api/TopUpSettingController.php create mode 100644 app/Http/Controllers/Api/UserController.php create mode 100644 app/Http/Controllers/CardMemberController.php create mode 100644 app/Http/Controllers/ContentController.php create mode 100644 app/Http/Controllers/FuelPriceController.php create mode 100644 app/Http/Controllers/StationController.php create mode 100644 app/Http/Controllers/SystemParameterController.php create mode 100644 app/Http/Controllers/TopUpSettingController.php create mode 100644 app/Services/Api/ApiService.php create mode 100644 app/Services/Api/BaseApiService.php create mode 100644 app/Services/Api/CardMemberService.php create mode 100644 app/Services/Api/ContentService.php create mode 100644 app/Services/Api/FuelPriceService.php create mode 100644 app/Services/Api/StationService.php create mode 100644 app/Services/Api/SystemParameterService.php create mode 100644 app/Services/Api/TopUpSettingService.php create mode 100644 app/Services/Api/UserManagementService.php create mode 100644 resources/js/app.js create mode 100644 resources/js/services/BaseApiService.js create mode 100644 resources/js/services/CardMemberService.js create mode 100644 resources/js/services/ContentService.js create mode 100644 resources/js/services/StationService.js create mode 100644 resources/js/services/UserService.js create mode 100644 resources/views/layouts/navbar.blade.php create mode 100644 resources/views/layouts/sidebar.blade.php create mode 100644 resources/views/pages/content/promotions/form.blade.php create mode 100644 resources/views/pages/content/promotions/index.blade.php create mode 100644 resources/views/pages/stations/index.blade.php create mode 100644 resources/views/pages/user-management/form.blade.php create mode 100644 resources/views/pages/user-management/index.blade.php create mode 100644 webpack.mix.js diff --git a/app/Http/Controllers/Api/AuthController.php b/app/Http/Controllers/Api/AuthController.php new file mode 100644 index 0000000..d3fc234 --- /dev/null +++ b/app/Http/Controllers/Api/AuthController.php @@ -0,0 +1,56 @@ +apiService = $apiService; + } + + public function login(Request $request) + { + $credentials = $request->validate([ + 'email' => 'required|email', + 'password' => 'required', + ]); + + try { + $response = $this->apiService->post('/auth/login', $credentials); + + if ($response->successful()) { + $data = $response->json(); + session(['api_token' => $data['token']]); + return redirect()->intended('/dashboard'); + } + + return back()->withErrors([ + 'email' => 'The provided credentials do not match our records.', + ]); + } catch (\Exception $e) { + return back()->withErrors([ + 'error' => 'Unable to connect to the authentication service.', + ]); + } + } + + public function logout() + { + try { + $this->apiService->post('/auth/logout'); + } catch (\Exception $e) { + // Log the error but proceed with local logout + } + + Session::forget('api_token'); + return redirect('/login'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/CardMemberController.php b/app/Http/Controllers/Api/CardMemberController.php new file mode 100644 index 0000000..a0558ac --- /dev/null +++ b/app/Http/Controllers/Api/CardMemberController.php @@ -0,0 +1,175 @@ +apiService = $apiService; + } + + public function index() + { + try { + $response = $this->apiService->get('/card-members'); + + if ($response->successful()) { + return view('pages.member management.card-member', [ + 'members' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch card members.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'card_number' => 'required|string|unique:card_members,card_number', + 'member_type' => 'required|string', + 'first_name' => 'required|string|max:255', + 'last_name' => 'required|string|max:255', + 'email' => 'required|email|unique:card_members,email', + 'phone' => 'required|string', + 'birth_date' => 'required|date', + 'address' => 'required|string', + 'city' => 'required|string', + 'state' => 'required|string', + 'postal_code' => 'required|string', + 'status' => 'required|string|in:active,inactive,locked' + ]); + + try { + $response = $this->apiService->post('/card-members', $validated); + + if ($response->successful()) { + return redirect()->route('card-member') + ->with('success', 'Card member created successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to create card member.'); + } + } + + public function update(Request $request, $id) + { + $validated = $request->validate([ + 'member_type' => 'required|string', + 'first_name' => 'required|string|max:255', + 'last_name' => 'required|string|max:255', + 'email' => 'required|email|unique:card_members,email,'.$id, + 'phone' => 'required|string', + 'birth_date' => 'required|date', + 'address' => 'required|string', + 'city' => 'required|string', + 'state' => 'required|string', + 'postal_code' => 'required|string', + 'status' => 'required|string|in:active,inactive,locked' + ]); + + try { + $response = $this->apiService->put("/card-members/{$id}", $validated); + + if ($response->successful()) { + return redirect()->route('card-member') + ->with('success', 'Card member updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update card member.'); + } + } + + public function destroy($id) + { + try { + $response = $this->apiService->delete("/card-members/{$id}"); + + if ($response->successful()) { + return redirect()->route('card-member') + ->with('success', 'Card member deleted successfully.'); + } + + return back()->with('error', 'Unable to delete card member.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function lockAccount($id) + { + try { + $response = $this->apiService->post("/card-members/{$id}/lock"); + + if ($response->successful()) { + return redirect()->route('card-member') + ->with('success', 'Account locked successfully.'); + } + + return back()->with('error', 'Unable to lock account.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function unlockAccount($id) + { + try { + $response = $this->apiService->post("/card-members/{$id}/unlock"); + + if ($response->successful()) { + return redirect()->route('card-member') + ->with('success', 'Account unlocked successfully.'); + } + + return back()->with('error', 'Unable to unlock account.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function getLockedAccounts() + { + try { + $response = $this->apiService->get('/card-members/locked'); + + if ($response->successful()) { + return view('pages.member management.locked-accounts', [ + 'lockedAccounts' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch locked accounts.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function getTransactionHistory($id) + { + try { + $response = $this->apiService->get("/card-members/{$id}/transactions"); + + if ($response->successful()) { + return response()->json($response->json()); + } + + return response()->json(['error' => 'Unable to fetch transaction history'], 400); + } catch (\Exception $e) { + return response()->json(['error' => 'Service unavailable'], 503); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/FuelPriceController.php b/app/Http/Controllers/Api/FuelPriceController.php new file mode 100644 index 0000000..9589742 --- /dev/null +++ b/app/Http/Controllers/Api/FuelPriceController.php @@ -0,0 +1,201 @@ +apiService = $apiService; + } + + public function onDemand() + { + try { + $response = $this->apiService->get('/fuel-prices/current'); + $stationsResponse = $this->apiService->get('/stations'); + $fuelTypesResponse = $this->apiService->get('/fuel-types'); + + if ($response->successful() && $stationsResponse->successful() && $fuelTypesResponse->successful()) { + return view('pages.fuel-price-on-demand', [ + 'prices' => $response->json()['data'], + 'stations' => $stationsResponse->json()['data'], + 'fuelTypes' => $fuelTypesResponse->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch fuel prices.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function updateOnDemand(Request $request) + { + $validated = $request->validate([ + 'prices' => 'required|array', + 'prices.*.*' => 'nullable|numeric|min:0' + ]); + + try { + $response = $this->apiService->post('/fuel-prices/update', $validated); + + if ($response->successful()) { + return redirect()->route('fuel-price.on-demand') + ->with('success', 'Fuel prices updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update fuel prices.'); + } + } + + public function importPrices(Request $request) + { + $request->validate([ + 'csv_file' => 'required|file|mimes:csv,txt' + ]); + + try { + $response = $this->apiService->post('/fuel-prices/import', [ + 'file' => $request->file('csv_file') + ], true); + + if ($response->successful()) { + return redirect()->route('fuel-price.on-demand') + ->with('success', 'Fuel prices imported successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to import fuel prices.'); + } + } + + public function exportPrices() + { + try { + $response = $this->apiService->get('/fuel-prices/export'); + + if ($response->successful()) { + return response()->streamDownload( + function () use ($response) { + echo $response->body(); + }, + 'fuel-prices.csv' + ); + } + + return back()->with('error', 'Unable to export fuel prices.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function schedule() + { + try { + $response = $this->apiService->get('/fuel-prices/schedule'); + $stationsResponse = $this->apiService->get('/stations'); + $fuelTypesResponse = $this->apiService->get('/fuel-types'); + + if ($response->successful() && $stationsResponse->successful() && $fuelTypesResponse->successful()) { + return view('pages.fuel-price-schedule', [ + 'schedules' => $response->json()['data'], + 'stations' => $stationsResponse->json()['data'], + 'fuelTypes' => $fuelTypesResponse->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch scheduled updates.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function storeSchedule(Request $request) + { + $validated = $request->validate([ + 'station_id' => 'required|integer', + 'fuel_type_id' => 'required|integer', + 'new_price' => 'required|numeric|min:0', + 'scheduled_for' => 'required|date|after:now' + ]); + + try { + $response = $this->apiService->post('/fuel-prices/schedule', $validated); + + if ($response->successful()) { + return redirect()->route('fuel-price.schedule') + ->with('success', 'Price update scheduled successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to schedule price update.'); + } + } + + public function updateSchedule(Request $request, $id) + { + $validated = $request->validate([ + 'station_id' => 'required|integer', + 'fuel_type_id' => 'required|integer', + 'new_price' => 'required|numeric|min:0', + 'scheduled_for' => 'required|date|after:now' + ]); + + try { + $response = $this->apiService->put("/fuel-prices/schedule/{$id}", $validated); + + if ($response->successful()) { + return redirect()->route('fuel-price.schedule') + ->with('success', 'Scheduled update modified successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to modify scheduled update.'); + } + } + + public function deleteSchedule($id) + { + try { + $response = $this->apiService->delete("/fuel-prices/schedule/{$id}"); + + if ($response->successful()) { + return redirect()->route('fuel-price.schedule') + ->with('success', 'Scheduled update deleted successfully.'); + } + + return back()->with('error', 'Unable to delete scheduled update.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function logs() + { + try { + $response = $this->apiService->get('/fuel-prices/logs'); + + if ($response->successful()) { + return view('pages.fuel-price-update-logs', [ + 'logs' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch update logs.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/NotificationsController.php b/app/Http/Controllers/Api/NotificationsController.php new file mode 100644 index 0000000..11caeb3 --- /dev/null +++ b/app/Http/Controllers/Api/NotificationsController.php @@ -0,0 +1,120 @@ +apiService = $apiService; + } + + public function index() + { + try { + $response = $this->apiService->get('/notifications'); + + if ($response->successful()) { + return view('pages.notification', [ + 'notifications' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch notifications.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'message' => 'required|string', + 'type' => 'required|string', + 'target_users' => 'required|array', + 'schedule_date' => 'nullable|date', + 'status' => 'required|string|in:draft,scheduled,sent' + ]); + + try { + $response = $this->apiService->post('/notifications', $validated); + + if ($response->successful()) { + return redirect()->route('notification') + ->with('success', 'Notification created successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to create notification.'); + } + } + + public function update(Request $request, $id) + { + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'message' => 'required|string', + 'type' => 'required|string', + 'target_users' => 'required|array', + 'schedule_date' => 'nullable|date', + 'status' => 'required|string|in:draft,scheduled,sent' + ]); + + try { + $response = $this->apiService->put("/notifications/{$id}", $validated); + + if ($response->successful()) { + return redirect()->route('notification') + ->with('success', 'Notification updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update notification.'); + } + } + + public function destroy($id) + { + try { + $response = $this->apiService->delete("/notifications/{$id}"); + + if ($response->successful()) { + return redirect()->route('notification') + ->with('success', 'Notification deleted successfully.'); + } + + return back()->with('error', 'Unable to delete notification.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function batchDestroy(Request $request) + { + $ids = $request->validate([ + 'ids' => 'required|array', + 'ids.*' => 'required|integer' + ]); + + try { + $response = $this->apiService->post("/notifications/batch-delete", $ids); + + if ($response->successful()) { + return response()->json(['message' => 'Notifications deleted successfully']); + } + + return response()->json(['error' => 'Unable to delete notifications'], 400); + } catch (\Exception $e) { + return response()->json(['error' => 'Service unavailable'], 503); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/PhotoSliderController.php b/app/Http/Controllers/Api/PhotoSliderController.php new file mode 100644 index 0000000..641b2e7 --- /dev/null +++ b/app/Http/Controllers/Api/PhotoSliderController.php @@ -0,0 +1,137 @@ +apiService = $apiService; + } + + public function index() + { + try { + $response = $this->apiService->get('/photo-sliders'); + + if ($response->successful()) { + return view('pages.home page.photo-slider', [ + 'sliders' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch photo sliders.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'description' => 'nullable|string', + 'image' => 'required|image|mimes:jpeg,png,jpg|max:2048', + 'order' => 'required|integer|min:1', + 'status' => 'required|string|in:active,inactive', + 'link_url' => 'nullable|url', + 'start_date' => 'required|date', + 'end_date' => 'required|date|after:start_date' + ]); + + try { + // Handle file upload + if ($request->hasFile('image')) { + $path = $request->file('image')->store('photo-sliders', 'public'); + $validated['image_path'] = $path; + } + + $response = $this->apiService->post('/photo-sliders', $validated); + + if ($response->successful()) { + return redirect()->route('photo-slider') + ->with('success', 'Photo slider created successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to create photo slider.'); + } + } + + public function update(Request $request, $id) + { + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'description' => 'nullable|string', + 'image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', + 'order' => 'required|integer|min:1', + 'status' => 'required|string|in:active,inactive', + 'link_url' => 'nullable|url', + 'start_date' => 'required|date', + 'end_date' => 'required|date|after:start_date' + ]); + + try { + // Handle file upload if new image is provided + if ($request->hasFile('image')) { + $path = $request->file('image')->store('photo-sliders', 'public'); + $validated['image_path'] = $path; + } + + $response = $this->apiService->put("/photo-sliders/{$id}", $validated); + + if ($response->successful()) { + return redirect()->route('photo-slider') + ->with('success', 'Photo slider updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update photo slider.'); + } + } + + public function destroy($id) + { + try { + $response = $this->apiService->delete("/photo-sliders/{$id}"); + + if ($response->successful()) { + return redirect()->route('photo-slider') + ->with('success', 'Photo slider deleted successfully.'); + } + + return back()->with('error', 'Unable to delete photo slider.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function updateOrder(Request $request) + { + $validated = $request->validate([ + 'orders' => 'required|array', + 'orders.*.id' => 'required|integer', + 'orders.*.order' => 'required|integer|min:1' + ]); + + try { + $response = $this->apiService->post("/photo-sliders/reorder", $validated); + + if ($response->successful()) { + return response()->json(['message' => 'Order updated successfully']); + } + + return response()->json(['error' => 'Unable to update order'], 400); + } catch (\Exception $e) { + return response()->json(['error' => 'Service unavailable'], 503); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/PromotionsController.php b/app/Http/Controllers/Api/PromotionsController.php new file mode 100644 index 0000000..489e257 --- /dev/null +++ b/app/Http/Controllers/Api/PromotionsController.php @@ -0,0 +1,120 @@ +apiService = $apiService; + } + + public function index() + { + try { + $response = $this->apiService->get('/promotions'); + + if ($response->successful()) { + return view('pages.promotions', [ + 'promotions' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch promotions.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'type' => 'required|string', + 'startDate' => 'required|date', + 'endDate' => 'required|date|after:startDate', + 'description' => 'nullable|string', + 'terms_conditions' => 'nullable|string', + ]); + + try { + $response = $this->apiService->post('/promotions', $validated); + + if ($response->successful()) { + return redirect()->route('promotions') + ->with('success', 'Promotion created successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to create promotion.'); + } + } + + public function update(Request $request, $id) + { + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'type' => 'required|string', + 'startDate' => 'required|date', + 'endDate' => 'required|date|after:startDate', + 'description' => 'nullable|string', + 'terms_conditions' => 'nullable|string', + ]); + + try { + $response = $this->apiService->put("/promotions/{$id}", $validated); + + if ($response->successful()) { + return redirect()->route('promotions') + ->with('success', 'Promotion updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update promotion.'); + } + } + + public function destroy($id) + { + try { + $response = $this->apiService->delete("/promotions/{$id}"); + + if ($response->successful()) { + return redirect()->route('promotions') + ->with('success', 'Promotion deleted successfully.'); + } + + return back()->with('error', 'Unable to delete promotion.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function batchDestroy(Request $request) + { + $ids = $request->validate([ + 'ids' => 'required|array', + 'ids.*' => 'required|integer' + ]); + + try { + $response = $this->apiService->post("/promotions/batch-delete", $ids); + + if ($response->successful()) { + return response()->json(['message' => 'Promotions deleted successfully']); + } + + return response()->json(['error' => 'Unable to delete promotions'], 400); + } catch (\Exception $e) { + return response()->json(['error' => 'Service unavailable'], 503); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/ReportsController.php b/app/Http/Controllers/Api/ReportsController.php new file mode 100644 index 0000000..a4d90f6 --- /dev/null +++ b/app/Http/Controllers/Api/ReportsController.php @@ -0,0 +1,136 @@ +apiService = $apiService; + } + + public function registrationReport(Request $request) + { + $filters = $request->validate([ + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date|after_or_equal:start_date', + 'member_type' => 'nullable|string' + ]); + + try { + $response = $this->apiService->get('/reports/registrations', $filters); + + if ($response->successful()) { + return view('pages.reports.registration-report', [ + 'report' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch registration report.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function topUpUsageReport(Request $request) + { + $filters = $request->validate([ + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date|after_or_equal:start_date', + 'payment_method' => 'nullable|string' + ]); + + try { + $response = $this->apiService->get('/reports/top-up-usage', $filters); + + if ($response->successful()) { + return view('pages.reports.top-up-usage-report', [ + 'report' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch top-up usage report.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function mobileUsageReport(Request $request) + { + $filters = $request->validate([ + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date|after_or_equal:start_date', + 'platform' => 'nullable|string' + ]); + + try { + $response = $this->apiService->get('/reports/mobile-usage', $filters); + + if ($response->successful()) { + return view('pages.reports.mobile-usage-report', [ + 'report' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch mobile usage report.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function stationRatingReport(Request $request) + { + $filters = $request->validate([ + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date|after_or_equal:start_date', + 'station_id' => 'nullable|integer', + 'rating' => 'nullable|integer|min:1|max:5' + ]); + + try { + $response = $this->apiService->get('/reports/station-ratings', $filters); + + if ($response->successful()) { + return view('pages.reports.station-rating-report', [ + 'report' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch station rating report.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function exportReport(Request $request, $reportType) + { + $filters = $request->validate([ + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date|after_or_equal:start_date', + 'format' => 'required|string|in:csv,excel,pdf' + ]); + + try { + $response = $this->apiService->get("/reports/{$reportType}/export", $filters); + + if ($response->successful()) { + return response()->streamDownload( + function () use ($response) { + echo $response->body(); + }, + "report.{$filters['format']}" + ); + } + + return back()->with('error', 'Unable to export report.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/StationController.php b/app/Http/Controllers/Api/StationController.php new file mode 100644 index 0000000..071bfc0 --- /dev/null +++ b/app/Http/Controllers/Api/StationController.php @@ -0,0 +1,148 @@ +apiService = $apiService; + } + + public function index() + { + try { + $response = $this->apiService->get('/stations'); + + if ($response->successful()) { + return view('pages.station locator.stations', [ + 'stations' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch stations.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255', + 'address' => 'required|string', + 'city' => 'required|string', + 'state' => 'required|string', + 'postal_code' => 'required|string', + 'latitude' => 'required|numeric', + 'longitude' => 'required|numeric', + 'contact_number' => 'required|string', + 'operating_hours' => 'required|string', + 'services' => 'required|array', + 'status' => 'required|string|in:active,inactive,maintenance' + ]); + + try { + $response = $this->apiService->post('/stations', $validated); + + if ($response->successful()) { + return redirect()->route('stations') + ->with('success', 'Station created successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to create station.'); + } + } + + public function update(Request $request, $id) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255', + 'address' => 'required|string', + 'city' => 'required|string', + 'state' => 'required|string', + 'postal_code' => 'required|string', + 'latitude' => 'required|numeric', + 'longitude' => 'required|numeric', + 'contact_number' => 'required|string', + 'operating_hours' => 'required|string', + 'services' => 'required|array', + 'status' => 'required|string|in:active,inactive,maintenance' + ]); + + try { + $response = $this->apiService->put("/stations/{$id}", $validated); + + if ($response->successful()) { + return redirect()->route('stations') + ->with('success', 'Station updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update station.'); + } + } + + public function destroy($id) + { + try { + $response = $this->apiService->delete("/stations/{$id}"); + + if ($response->successful()) { + return redirect()->route('stations') + ->with('success', 'Station deleted successfully.'); + } + + return back()->with('error', 'Unable to delete station.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function updateFuelPrices(Request $request, $id) + { + $validated = $request->validate([ + 'fuel_prices' => 'required|array', + 'fuel_prices.*.fuel_type' => 'required|string', + 'fuel_prices.*.price' => 'required|numeric|min:0', + 'effective_date' => 'required|date' + ]); + + try { + $response = $this->apiService->post("/stations/{$id}/fuel-prices", $validated); + + if ($response->successful()) { + return redirect()->route('stations') + ->with('success', 'Fuel prices updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update fuel prices.'); + } + } + + public function getFuelPriceHistory($id) + { + try { + $response = $this->apiService->get("/stations/{$id}/fuel-price-history"); + + if ($response->successful()) { + return response()->json($response->json()); + } + + return response()->json(['error' => 'Unable to fetch fuel price history'], 400); + } catch (\Exception $e) { + return response()->json(['error' => 'Service unavailable'], 503); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/SystemParameterController.php b/app/Http/Controllers/Api/SystemParameterController.php new file mode 100644 index 0000000..bba77dc --- /dev/null +++ b/app/Http/Controllers/Api/SystemParameterController.php @@ -0,0 +1,116 @@ +apiService = $apiService; + } + + public function index() + { + try { + $response = $this->apiService->get('/system-parameters'); + + if ($response->successful()) { + return view('pages.system-parameters', [ + 'parameters' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch system parameters.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255|unique:system_parameters,name', + 'value' => 'required|string', + 'type' => 'required|string|in:String,Number,Boolean,JSON', + 'description' => 'required|string' + ]); + + try { + // Format value based on type + $validated['value'] = $this->formatValue($validated['value'], $validated['type']); + + $response = $this->apiService->post('/system-parameters', $validated); + + if ($response->successful()) { + return redirect()->route('system-parameters') + ->with('success', 'System parameter created successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to create system parameter.'); + } + } + + public function update(Request $request, $id) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255|unique:system_parameters,name,'.$id, + 'value' => 'required|string', + 'type' => 'required|string|in:String,Number,Boolean,JSON', + 'description' => 'required|string' + ]); + + try { + // Format value based on type + $validated['value'] = $this->formatValue($validated['value'], $validated['type']); + + $response = $this->apiService->put("/system-parameters/{$id}", $validated); + + if ($response->successful()) { + return redirect()->route('system-parameters') + ->with('success', 'System parameter updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update system parameter.'); + } + } + + public function destroy($id) + { + try { + $response = $this->apiService->delete("/system-parameters/{$id}"); + + if ($response->successful()) { + return redirect()->route('system-parameters') + ->with('success', 'System parameter deleted successfully.'); + } + + return back()->with('error', 'Unable to delete system parameter.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + protected function formatValue($value, $type) + { + switch ($type) { + case 'Number': + return is_numeric($value) ? (float) $value : $value; + case 'Boolean': + return filter_var($value, FILTER_VALIDATE_BOOLEAN); + case 'JSON': + return is_string($value) && json_decode($value) ? $value : json_encode($value); + default: + return (string) $value; + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/TopUpController.php b/app/Http/Controllers/Api/TopUpController.php new file mode 100644 index 0000000..404ce41 --- /dev/null +++ b/app/Http/Controllers/Api/TopUpController.php @@ -0,0 +1,122 @@ +apiService = $apiService; + } + + public function index() + { + try { + $response = $this->apiService->get('/top-ups'); + + if ($response->successful()) { + return view('pages.top-up', [ + 'topUps' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch top-up records.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'member_id' => 'required|string', + 'amount' => 'required|numeric|min:0', + 'payment_method' => 'required|string', + 'reference_number' => 'required|string|unique:top_ups,reference_number', + 'status' => 'required|string|in:pending,completed,failed', + 'notes' => 'nullable|string' + ]); + + try { + $response = $this->apiService->post('/top-ups', $validated); + + if ($response->successful()) { + return redirect()->route('top-up') + ->with('success', 'Top-up transaction created successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to create top-up transaction.'); + } + } + + public function getSettings() + { + try { + $response = $this->apiService->get('/top-up-settings'); + + if ($response->successful()) { + return view('pages.top-up-settings', [ + 'settings' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch top-up settings.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function updateSettings(Request $request) + { + $validated = $request->validate([ + 'min_amount' => 'required|numeric|min:0', + 'max_amount' => 'required|numeric|min:0|gt:min_amount', + 'allowed_payment_methods' => 'required|array', + 'processing_fee' => 'required|numeric|min:0', + 'is_enabled' => 'required|boolean' + ]); + + try { + $response = $this->apiService->put('/top-up-settings', $validated); + + if ($response->successful()) { + return redirect()->route('top-up-settings') + ->with('success', 'Top-up settings updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update top-up settings.'); + } + } + + public function getTransactionHistory(Request $request) + { + $filters = $request->validate([ + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date|after_or_equal:start_date', + 'status' => 'nullable|string|in:pending,completed,failed', + 'payment_method' => 'nullable|string' + ]); + + try { + $response = $this->apiService->get('/top-ups/history', $filters); + + if ($response->successful()) { + return response()->json($response->json()); + } + + return response()->json(['error' => 'Unable to fetch transaction history'], 400); + } catch (\Exception $e) { + return response()->json(['error' => 'Service unavailable'], 503); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/TopUpSettingController.php b/app/Http/Controllers/Api/TopUpSettingController.php new file mode 100644 index 0000000..00c0ec2 --- /dev/null +++ b/app/Http/Controllers/Api/TopUpSettingController.php @@ -0,0 +1,120 @@ +apiService = $apiService; + } + + public function index() + { + try { + $response = $this->apiService->get('/top-up-settings'); + + if ($response->successful()) { + return view('pages.top-up-settings', [ + 'settings' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch top-up settings.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255|unique:top_up_settings,name', + 'value' => 'required|numeric|min:0', + 'description' => 'required|string', + 'type' => 'required|string|in:minimum,maximum,fee,bonus', + 'status' => 'required|boolean' + ]); + + try { + $response = $this->apiService->post('/top-up-settings', $validated); + + if ($response->successful()) { + return redirect()->route('top-up-settings') + ->with('success', 'Top-up setting created successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to create top-up setting.'); + } + } + + public function update(Request $request, $id) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255|unique:top_up_settings,name,'.$id, + 'value' => 'required|numeric|min:0', + 'description' => 'required|string', + 'type' => 'required|string|in:minimum,maximum,fee,bonus', + 'status' => 'required|boolean' + ]); + + try { + $response = $this->apiService->put("/top-up-settings/{$id}", $validated); + + if ($response->successful()) { + return redirect()->route('top-up-settings') + ->with('success', 'Top-up setting updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update top-up setting.'); + } + } + + public function destroy($id) + { + try { + $response = $this->apiService->delete("/top-up-settings/{$id}"); + + if ($response->successful()) { + return redirect()->route('top-up-settings') + ->with('success', 'Top-up setting deleted successfully.'); + } + + return back()->with('error', 'Unable to delete top-up setting.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function batchUpdate(Request $request) + { + $validated = $request->validate([ + 'settings' => 'required|array', + 'settings.*.id' => 'required|integer', + 'settings.*.value' => 'required|numeric|min:0', + 'settings.*.status' => 'required|boolean' + ]); + + try { + $response = $this->apiService->post('/top-up-settings/batch-update', $validated); + + if ($response->successful()) { + return response()->json(['message' => 'Settings updated successfully']); + } + + return response()->json(['error' => 'Unable to update settings'], 400); + } catch (\Exception $e) { + return response()->json(['error' => 'Service unavailable'], 503); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/UserController.php b/app/Http/Controllers/Api/UserController.php new file mode 100644 index 0000000..6be58df --- /dev/null +++ b/app/Http/Controllers/Api/UserController.php @@ -0,0 +1,93 @@ +apiService = $apiService; + } + + public function index() + { + try { + $response = $this->apiService->get('/users'); + + if ($response->successful()) { + return view('users.index', [ + 'users' => $response->json()['data'] + ]); + } + + return back()->with('error', 'Unable to fetch users.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255', + 'email' => 'required|email|max:255', + 'password' => 'required|min:8', + ]); + + try { + $response = $this->apiService->post('/users', $validated); + + if ($response->successful()) { + return redirect()->route('users.index') + ->with('success', 'User created successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to create user.'); + } + } + + public function update(Request $request, $id) + { + $validated = $request->validate([ + 'name' => 'required|string|max:255', + 'email' => 'required|email|max:255', + ]); + + try { + $response = $this->apiService->put("/users/{$id}", $validated); + + if ($response->successful()) { + return redirect()->route('users.index') + ->with('success', 'User updated successfully.'); + } + + return back()->withErrors($response->json()['errors']); + } catch (\Exception $e) { + return back()->with('error', 'Unable to update user.'); + } + } + + public function destroy($id) + { + try { + $response = $this->apiService->delete("/users/{$id}"); + + if ($response->successful()) { + return redirect()->route('users.index') + ->with('success', 'User deleted successfully.'); + } + + return back()->with('error', 'Unable to delete user.'); + } catch (\Exception $e) { + return back()->with('error', 'Service unavailable.'); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/CardMemberController.php b/app/Http/Controllers/CardMemberController.php new file mode 100644 index 0000000..e4debc4 --- /dev/null +++ b/app/Http/Controllers/CardMemberController.php @@ -0,0 +1,164 @@ +cardMemberService = $cardMemberService; + } + + public function index() + { + $response = $this->cardMemberService->getAllMembers(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.member-management.index', [ + 'members' => $response['data'] + ]); + } + + public function create() + { + $cardTypes = $this->cardMemberService->getCardTypes(); + + return view('pages.member-management.create', [ + 'cardTypes' => $cardTypes['data'] ?? [] + ]); + } + + public function store(Request $request) + { + $response = $this->cardMemberService->createMember($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('card-members.index') + ->with('success', 'Card member created successfully'); + } + + public function edit($id) + { + $memberResponse = $this->cardMemberService->getMember($id); + $cardTypesResponse = $this->cardMemberService->getCardTypes(); + + if (!$memberResponse['success']) { + return back()->with('error', $memberResponse['message']); + } + + return view('pages.member-management.edit', [ + 'member' => $memberResponse['data'], + 'cardTypes' => $cardTypesResponse['data'] ?? [] + ]); + } + + public function update(Request $request, $id) + { + $response = $this->cardMemberService->updateMember($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('card-members.index') + ->with('success', 'Card member updated successfully'); + } + + public function destroy($id) + { + $response = $this->cardMemberService->deleteMember($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('card-members.index') + ->with('success', 'Card member deleted successfully'); + } + + public function cardTypes() + { + $response = $this->cardMemberService->getCardTypes(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.add-card-types', [ + 'cardTypes' => $response['data'] + ]); + } + + public function storeCardType(Request $request) + { + $response = $this->cardMemberService->createCardType($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('card-types.index') + ->with('success', 'Card type created successfully'); + } + + public function updateCardType(Request $request, $id) + { + $response = $this->cardMemberService->updateCardType($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('card-types.index') + ->with('success', 'Card type updated successfully'); + } + + public function deleteCardType($id) + { + $response = $this->cardMemberService->deleteCardType($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('card-types.index') + ->with('success', 'Card type deleted successfully'); + } + + public function topUpHistory(Request $request) + { + $memberId = $request->query('member_id'); + $response = $this->cardMemberService->getTopUpHistory($memberId); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.top-up', [ + 'history' => $response['data'] + ]); + } + + public function processTopUp(Request $request) + { + $response = $this->cardMemberService->topUp($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('top-up.index') + ->with('success', 'Top-up processed successfully'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/ContentController.php b/app/Http/Controllers/ContentController.php new file mode 100644 index 0000000..19eb408 --- /dev/null +++ b/app/Http/Controllers/ContentController.php @@ -0,0 +1,207 @@ +contentService = $contentService; + } + + // Promotions + public function promotionsIndex() + { + $response = $this->contentService->getAllPromotions(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.promotions', [ + 'promotions' => $response['data'] + ]); + } + + public function createPromotion() + { + return view('pages.add-promotions'); + } + + public function storePromotion(Request $request) + { + $response = $this->contentService->createPromotion($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('promotions.index') + ->with('success', 'Promotion created successfully'); + } + + public function updatePromotion(Request $request, $id) + { + $response = $this->contentService->updatePromotion($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('promotions.index') + ->with('success', 'Promotion updated successfully'); + } + + public function deletePromotion($id) + { + $response = $this->contentService->deletePromotion($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('promotions.index') + ->with('success', 'Promotion deleted successfully'); + } + + // Notifications + public function notificationsIndex() + { + $response = $this->contentService->getAllNotifications(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.notification', [ + 'notifications' => $response['data'] + ]); + } + + public function createNotification() + { + return view('pages.add-notification'); + } + + public function storeNotification(Request $request) + { + $response = $this->contentService->createNotification($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('notifications.index') + ->with('success', 'Notification created successfully'); + } + + public function updateNotification(Request $request, $id) + { + $response = $this->contentService->updateNotification($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('notifications.index') + ->with('success', 'Notification updated successfully'); + } + + public function deleteNotification($id) + { + $response = $this->contentService->deleteNotification($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('notifications.index') + ->with('success', 'Notification deleted successfully'); + } + + // Photo Slider + public function slidesIndex() + { + $response = $this->contentService->getAllSlides(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.photo-slider', [ + 'slides' => $response['data'] + ]); + } + + public function createSlide() + { + return view('pages.add-photo-slider'); + } + + public function storeSlide(Request $request) + { + $response = $this->contentService->createSlide($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('slides.index') + ->with('success', 'Slide created successfully'); + } + + public function updateSlide(Request $request, $id) + { + $response = $this->contentService->updateSlide($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('slides.index') + ->with('success', 'Slide updated successfully'); + } + + public function deleteSlide($id) + { + $response = $this->contentService->deleteSlide($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('slides.index') + ->with('success', 'Slide deleted successfully'); + } + + // Terms and Privacy + public function termsAndPrivacy() + { + $response = $this->contentService->getTermsAndPrivacy(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.add-terms-and-privacy', [ + 'content' => $response['data'] + ]); + } + + public function updateTermsAndPrivacy(Request $request) + { + $response = $this->contentService->updateTermsAndPrivacy($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('terms-and-privacy.index') + ->with('success', 'Terms and Privacy updated successfully'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/FuelPriceController.php b/app/Http/Controllers/FuelPriceController.php new file mode 100644 index 0000000..2971e5f --- /dev/null +++ b/app/Http/Controllers/FuelPriceController.php @@ -0,0 +1,120 @@ +fuelPriceService = $fuelPriceService; + } + + public function onDemand() + { + $response = $this->fuelPriceService->getCurrentPrices(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.fuel-price-on-demand', [ + 'prices' => $response['data'] + ]); + } + + public function updateOnDemand(Request $request) + { + $response = $this->fuelPriceService->updatePrices($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('fuel-price.on-demand') + ->with('success', 'Fuel prices updated successfully'); + } + + public function schedule() + { + $response = $this->fuelPriceService->getScheduledUpdates(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.fuel-price-schedule', [ + 'schedules' => $response['data'] + ]); + } + + public function storeSchedule(Request $request) + { + $response = $this->fuelPriceService->createSchedule($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('fuel-price.schedule') + ->with('success', 'Price update scheduled successfully'); + } + + public function updateSchedule(Request $request, $id) + { + $response = $this->fuelPriceService->updateSchedule($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('fuel-price.schedule') + ->with('success', 'Schedule updated successfully'); + } + + public function deleteSchedule($id) + { + $response = $this->fuelPriceService->deleteSchedule($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('fuel-price.schedule') + ->with('success', 'Schedule deleted successfully'); + } + + public function logs() + { + $response = $this->fuelPriceService->getUpdateLogs(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.fuel-price-update-logs', [ + 'logs' => $response['data'] + ]); + } + + public function importPrices(Request $request) + { + $response = $this->fuelPriceService->importPrices($request->file('csv_file')); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('fuel-price.on-demand') + ->with('success', 'Fuel prices imported successfully'); + } + + public function exportPrices() + { + return $this->fuelPriceService->exportPrices(); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/StationController.php b/app/Http/Controllers/StationController.php new file mode 100644 index 0000000..83164ff --- /dev/null +++ b/app/Http/Controllers/StationController.php @@ -0,0 +1,133 @@ +stationService = $stationService; + } + + public function index() + { + $response = $this->stationService->getAllStations(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.station-locator.index', [ + 'stations' => $response['data'] + ]); + } + + public function create() + { + return view('pages.station-locator.create'); + } + + public function store(Request $request) + { + $response = $this->stationService->createStation($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('stations.index') + ->with('success', 'Station created successfully'); + } + + public function edit($id) + { + $response = $this->stationService->getStation($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.station-locator.edit', [ + 'station' => $response['data'] + ]); + } + + public function update(Request $request, $id) + { + $response = $this->stationService->updateStation($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('stations.index') + ->with('success', 'Station updated successfully'); + } + + public function destroy($id) + { + $response = $this->stationService->deleteStation($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('stations.index') + ->with('success', 'Station deleted successfully'); + } + + public function fuelPrices() + { + $response = $this->stationService->getFuelPrices(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.fuel-price-on-demand', [ + 'fuelPrices' => $response['data'] + ]); + } + + public function updateFuelPrices(Request $request) + { + $response = $this->stationService->updateFuelPrices($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('fuel-prices.index') + ->with('success', 'Fuel prices updated successfully'); + } + + public function fuelPriceSchedule() + { + $response = $this->stationService->getFuelPriceSchedule(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.fuel-price-schedule', [ + 'schedules' => $response['data'] + ]); + } + + public function storeFuelPriceSchedule(Request $request) + { + $response = $this->stationService->createFuelPriceSchedule($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('fuel-prices.schedule') + ->with('success', 'Fuel price schedule created successfully'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/SystemParameterController.php b/app/Http/Controllers/SystemParameterController.php new file mode 100644 index 0000000..222adf6 --- /dev/null +++ b/app/Http/Controllers/SystemParameterController.php @@ -0,0 +1,65 @@ +systemParamService = $systemParamService; + } + + public function index() + { + $response = $this->systemParamService->getAllParameters(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.system-parameters', [ + 'parameters' => $response['data'] + ]); + } + + public function store(Request $request) + { + $response = $this->systemParamService->createParameter($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('system-parameters.index') + ->with('success', 'Parameter created successfully'); + } + + public function update(Request $request, $id) + { + $response = $this->systemParamService->updateParameter($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('system-parameters.index') + ->with('success', 'Parameter updated successfully'); + } + + public function destroy($id) + { + $response = $this->systemParamService->deleteParameter($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('system-parameters.index') + ->with('success', 'Parameter deleted successfully'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/TopUpSettingController.php b/app/Http/Controllers/TopUpSettingController.php new file mode 100644 index 0000000..a2f13b1 --- /dev/null +++ b/app/Http/Controllers/TopUpSettingController.php @@ -0,0 +1,65 @@ +topUpSettingService = $topUpSettingService; + } + + public function index() + { + $response = $this->topUpSettingService->getAllSettings(); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.top-up-settings', [ + 'settings' => $response['data'] + ]); + } + + public function store(Request $request) + { + $response = $this->topUpSettingService->createSetting($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('top-up-settings.index') + ->with('success', 'Setting created successfully'); + } + + public function update(Request $request, $id) + { + $response = $this->topUpSettingService->updateSetting($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('top-up-settings.index') + ->with('success', 'Setting updated successfully'); + } + + public function destroy($id) + { + $response = $this->topUpSettingService->deleteSetting($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('top-up-settings.index') + ->with('success', 'Setting deleted successfully'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/UserManagementController.php b/app/Http/Controllers/UserManagementController.php index b6e8a7d..575ef8f 100644 --- a/app/Http/Controllers/UserManagementController.php +++ b/app/Http/Controllers/UserManagementController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Services\Api\UserManagementService; use Illuminate\Http\Request; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; @@ -9,62 +10,81 @@ use Illuminate\Support\Facades\Session; class UserManagementController extends Controller { + protected $userService; protected $apiBaseUrl = 'http://192.168.100.6:8081/api'; // Same as in AuthController + public function __construct(UserManagementService $userService) + { + $this->userService = $userService; + } + /** * Display the user management page with user data */ public function index() { - try { - // Fetch the access token from the session - $user = Session::get('user'); - $accessToken = $user['access_token'] ?? null; - - if (!$accessToken) { - Log::info('No access token found, redirecting to login from user-management'); - return redirect()->route('login')->with('error', 'Please log in to view user management.'); - } - - // Make the API call to fetch admin users - $response = Http::withHeaders([ - 'Accept' => 'application/json', - 'Authorization' => 'Bearer ' . $accessToken, - ])->get("{$this->apiBaseUrl}/cms/admin"); - - $json = $response->json(); - - Log::info('User Management API Response: ', $json); - - if ($response->successful() && isset($json['data']) && is_array($json['data'])) { - // Transform the API response into the format expected by the table component - $users = array_map(function ($admin) { - return [ - - 'username' => $admin['username'], - 'firstName' => $admin['firstname'], - 'lastName' => $admin['lastname'], - 'role' => 'Admin', // Adjust if the API provides role data - 'email' => $admin['email'], - // 'status' => $admin['is_active'] ? 'Active' : 'Inactive', - ]; - }, $json['data']); - - // Pass the transformed data to the view - return view('pages.user-management', [ - 'users' => $users, - ]); - } else { - Log::warning('No user data found or invalid API response: ', $json); - return view('pages.user-management', [ - 'users' => [], // Pass an empty array if no data - ]); - } - } catch (\Exception $e) { - Log::error('Error fetching user data: ' . $e->getMessage()); - return view('pages.user-management', [ - 'users' => [], // Pass an empty array on error - ]); + $response = $this->userService->getAllUsers(); + + if (!$response['success']) { + return back()->with('error', $response['message']); } + + return view('pages.user-management.index', [ + 'users' => $response['data'] + ]); + } + + public function create() + { + return view('pages.user-management.create'); + } + + public function store(Request $request) + { + $response = $this->userService->createUser($request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('user-management.index') + ->with('success', 'User created successfully'); + } + + public function edit($id) + { + $response = $this->userService->getUser($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return view('pages.user-management.edit', [ + 'user' => $response['data'] + ]); + } + + public function update(Request $request, $id) + { + $response = $this->userService->updateUser($id, $request->all()); + + if (!$response['success']) { + return back()->withInput()->with('error', $response['message']); + } + + return redirect()->route('user-management.index') + ->with('success', 'User updated successfully'); + } + + public function destroy($id) + { + $response = $this->userService->deleteUser($id); + + if (!$response['success']) { + return back()->with('error', $response['message']); + } + + return redirect()->route('user-management.index') + ->with('success', 'User deleted successfully'); } } \ No newline at end of file diff --git a/app/Services/Api/ApiService.php b/app/Services/Api/ApiService.php new file mode 100644 index 0000000..be31dd7 --- /dev/null +++ b/app/Services/Api/ApiService.php @@ -0,0 +1,92 @@ +baseUrl = env('EXTERNAL_API_URL', 'http://localhost:8000/api'); + } + + /** + * Make a GET request to the API + */ + public function fetch($endpoint, array $params = []) + { + try { + $response = Http::withHeaders($this->getHeaders()) + ->get($this->baseUrl . $endpoint, $params); + + if ($response->successful()) { + return [ + 'success' => true, + 'data' => $response->json()['data'] ?? $response->json(), + 'message' => 'Data fetched successfully' + ]; + } + + return [ + 'success' => false, + 'message' => $response->json()['message'] ?? 'Failed to fetch data', + 'errors' => $response->json()['errors'] ?? [] + ]; + } catch (Exception $e) { + return [ + 'success' => false, + 'message' => 'API service is unavailable', + 'errors' => [$e->getMessage()] + ]; + } + } + + /** + * Make a POST request to the API + */ + public function submit($endpoint, array $data = []) + { + try { + $response = Http::withHeaders($this->getHeaders()) + ->post($this->baseUrl . $endpoint, $data); + + if ($response->successful()) { + return [ + 'success' => true, + 'data' => $response->json()['data'] ?? $response->json(), + 'message' => 'Data submitted successfully' + ]; + } + + return [ + 'success' => false, + 'message' => $response->json()['message'] ?? 'Failed to submit data', + 'errors' => $response->json()['errors'] ?? [] + ]; + } catch (Exception $e) { + return [ + 'success' => false, + 'message' => 'API service is unavailable', + 'errors' => [$e->getMessage()] + ]; + } + } + + /** + * Get the headers for API requests + */ + protected function getHeaders(): array + { + return [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + 'Authorization' => 'Bearer ' . session('api_token'), + ]; + } +} \ No newline at end of file diff --git a/app/Services/Api/BaseApiService.php b/app/Services/Api/BaseApiService.php new file mode 100644 index 0000000..1bb8a36 --- /dev/null +++ b/app/Services/Api/BaseApiService.php @@ -0,0 +1,78 @@ +baseUrl = env('EXTERNAL_API_URL', 'http://localhost:8000/api'); + } + + protected function get($endpoint, array $params = []) + { + try { + $response = Http::withHeaders($this->getHeaders()) + ->get($this->baseUrl . $endpoint, $params); + + return $this->handleResponse($response); + } catch (Exception $e) { + return $this->handleException($e); + } + } + + protected function post($endpoint, array $data = [], $hasFile = false) + { + try { + $http = Http::withHeaders($this->getHeaders()); + + if ($hasFile) { + $http = $http->asMultipart(); + } + + $response = $http->post($this->baseUrl . $endpoint, $data); + return $this->handleResponse($response); + } catch (Exception $e) { + return $this->handleException($e); + } + } + + protected function handleResponse($response) + { + if ($response->successful()) { + return [ + 'success' => true, + 'data' => $response->json()['data'] ?? $response->json(), + 'message' => 'Operation successful' + ]; + } + + return [ + 'success' => false, + 'message' => $response->json()['message'] ?? 'Operation failed', + 'errors' => $response->json()['errors'] ?? [] + ]; + } + + protected function handleException(Exception $e) + { + return [ + 'success' => false, + 'message' => 'API service is unavailable', + 'errors' => [$e->getMessage()] + ]; + } + + protected function getHeaders() + { + return [ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer ' . session('api_token') + ]; + } +} \ No newline at end of file diff --git a/app/Services/Api/CardMemberService.php b/app/Services/Api/CardMemberService.php new file mode 100644 index 0000000..1e91fb0 --- /dev/null +++ b/app/Services/Api/CardMemberService.php @@ -0,0 +1,61 @@ +get('/card-members', $params); + } + + public function getMember($id) + { + return $this->get("/card-members/{$id}"); + } + + public function createMember(array $data) + { + return $this->post('/card-members', $data); + } + + public function updateMember($id, array $data) + { + return $this->post("/card-members/{$id}", array_merge($data, ['_method' => 'PUT'])); + } + + public function deleteMember($id) + { + return $this->post("/card-members/{$id}", ['_method' => 'DELETE']); + } + + public function getCardTypes() + { + return $this->get('/card-types'); + } + + public function createCardType(array $data) + { + return $this->post('/card-types', $data); + } + + public function updateCardType($id, array $data) + { + return $this->post("/card-types/{$id}", array_merge($data, ['_method' => 'PUT'])); + } + + public function deleteCardType($id) + { + return $this->post("/card-types/{$id}", ['_method' => 'DELETE']); + } + + public function topUp(array $data) + { + return $this->post('/card-members/top-up', $data); + } + + public function getTopUpHistory($memberId, array $params = []) + { + return $this->get("/card-members/{$memberId}/top-up-history", $params); + } +} \ No newline at end of file diff --git a/app/Services/Api/ContentService.php b/app/Services/Api/ContentService.php new file mode 100644 index 0000000..4180a1f --- /dev/null +++ b/app/Services/Api/ContentService.php @@ -0,0 +1,80 @@ +get('/promotions', $params); + } + + public function createPromotion(array $data) + { + return $this->post('/promotions', $data, true); // true for image upload + } + + public function updatePromotion($id, array $data) + { + return $this->post("/promotions/{$id}", array_merge($data, ['_method' => 'PUT']), true); + } + + public function deletePromotion($id) + { + return $this->post("/promotions/{$id}", ['_method' => 'DELETE']); + } + + // Notifications + public function getAllNotifications(array $params = []) + { + return $this->get('/notifications', $params); + } + + public function createNotification(array $data) + { + return $this->post('/notifications', $data); + } + + public function updateNotification($id, array $data) + { + return $this->post("/notifications/{$id}", array_merge($data, ['_method' => 'PUT'])); + } + + public function deleteNotification($id) + { + return $this->post("/notifications/{$id}", ['_method' => 'DELETE']); + } + + // Photo Slider + public function getAllSlides(array $params = []) + { + return $this->get('/photo-slider', $params); + } + + public function createSlide(array $data) + { + return $this->post('/photo-slider', $data, true); // true for image upload + } + + public function updateSlide($id, array $data) + { + return $this->post("/photo-slider/{$id}", array_merge($data, ['_method' => 'PUT']), true); + } + + public function deleteSlide($id) + { + return $this->post("/photo-slider/{$id}", ['_method' => 'DELETE']); + } + + // Terms and Privacy + public function getTermsAndPrivacy() + { + return $this->get('/terms-and-privacy'); + } + + public function updateTermsAndPrivacy(array $data) + { + return $this->post('/terms-and-privacy', $data); + } +} \ No newline at end of file diff --git a/app/Services/Api/FuelPriceService.php b/app/Services/Api/FuelPriceService.php new file mode 100644 index 0000000..9a356cd --- /dev/null +++ b/app/Services/Api/FuelPriceService.php @@ -0,0 +1,55 @@ +get('/fuel-prices/current', $params); + } + + public function updatePrices(array $data) + { + return $this->post('/fuel-prices/update', $data); + } + + public function getScheduledUpdates(array $params = []) + { + return $this->get('/fuel-prices/schedule', $params); + } + + public function createSchedule(array $data) + { + return $this->post('/fuel-prices/schedule', $data); + } + + public function updateSchedule($id, array $data) + { + return $this->post("/fuel-prices/schedule/{$id}", array_merge($data, ['_method' => 'PUT'])); + } + + public function deleteSchedule($id) + { + return $this->post("/fuel-prices/schedule/{$id}", ['_method' => 'DELETE']); + } + + public function getUpdateLogs(array $params = []) + { + return $this->get('/fuel-prices/logs', $params); + } + + public function importPrices(UploadedFile $file) + { + return $this->post('/fuel-prices/import', [ + 'file' => $file + ], true); + } + + public function exportPrices() + { + return $this->get('/fuel-prices/export'); + } +} \ No newline at end of file diff --git a/app/Services/Api/StationService.php b/app/Services/Api/StationService.php new file mode 100644 index 0000000..89f3eb0 --- /dev/null +++ b/app/Services/Api/StationService.php @@ -0,0 +1,51 @@ +get('/stations', $params); + } + + public function getStation($id) + { + return $this->get("/stations/{$id}"); + } + + public function createStation(array $data) + { + return $this->post('/stations', $data, true); // true for file upload support + } + + public function updateStation($id, array $data) + { + return $this->post("/stations/{$id}", array_merge($data, ['_method' => 'PUT']), true); + } + + public function deleteStation($id) + { + return $this->post("/stations/{$id}", ['_method' => 'DELETE']); + } + + public function getFuelPrices(array $params = []) + { + return $this->get('/stations/fuel-prices', $params); + } + + public function updateFuelPrices(array $data) + { + return $this->post('/stations/fuel-prices', $data); + } + + public function getFuelPriceSchedule(array $params = []) + { + return $this->get('/stations/fuel-prices/schedule', $params); + } + + public function createFuelPriceSchedule(array $data) + { + return $this->post('/stations/fuel-prices/schedule', $data); + } +} \ No newline at end of file diff --git a/app/Services/Api/SystemParameterService.php b/app/Services/Api/SystemParameterService.php new file mode 100644 index 0000000..d09615d --- /dev/null +++ b/app/Services/Api/SystemParameterService.php @@ -0,0 +1,31 @@ +get('/system-parameters', $params); + } + + public function getParameter($id) + { + return $this->get("/system-parameters/{$id}"); + } + + public function createParameter(array $data) + { + return $this->post('/system-parameters', $data); + } + + public function updateParameter($id, array $data) + { + return $this->post("/system-parameters/{$id}", array_merge($data, ['_method' => 'PUT'])); + } + + public function deleteParameter($id) + { + return $this->post("/system-parameters/{$id}", ['_method' => 'DELETE']); + } +} \ No newline at end of file diff --git a/app/Services/Api/TopUpSettingService.php b/app/Services/Api/TopUpSettingService.php new file mode 100644 index 0000000..54402dc --- /dev/null +++ b/app/Services/Api/TopUpSettingService.php @@ -0,0 +1,31 @@ +get('/top-up-settings', $params); + } + + public function getSetting($id) + { + return $this->get("/top-up-settings/{$id}"); + } + + public function createSetting(array $data) + { + return $this->post('/top-up-settings', $data); + } + + public function updateSetting($id, array $data) + { + return $this->post("/top-up-settings/{$id}", array_merge($data, ['_method' => 'PUT'])); + } + + public function deleteSetting($id) + { + return $this->post("/top-up-settings/{$id}", ['_method' => 'DELETE']); + } +} \ No newline at end of file diff --git a/app/Services/Api/UserManagementService.php b/app/Services/Api/UserManagementService.php new file mode 100644 index 0000000..3bcf969 --- /dev/null +++ b/app/Services/Api/UserManagementService.php @@ -0,0 +1,36 @@ +get('/users', $params); + } + + public function getUser($id) + { + return $this->get("/users/{$id}"); + } + + public function createUser(array $data) + { + return $this->post('/users', $data); + } + + public function updateUser($id, array $data) + { + return $this->post("/users/{$id}", array_merge($data, ['_method' => 'PUT'])); + } + + public function deleteUser($id) + { + return $this->post("/users/{$id}", ['_method' => 'DELETE']); + } + + public function changePassword(array $data) + { + return $this->post('/users/change-password', $data); + } +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 2231486..9db0cc2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,8 +31,9 @@ services: - DB_DATABASE=unioil-database - DB_USERNAME=rootuser - DB_PASSWORD=password + - MYSQL_ROOT_PASSWORD=newpassword - CACHE_DRIVER=file - - API_URL=http://backend-web:8081 + - API_URL=http://nginx:8081 web-frontend: image: nginx:1.26.3-alpine diff --git a/package.json b/package.json index 2a770db..b9ebb01 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,31 @@ { "private": true, - "type": "module", "scripts": { - "build": "vite build", - "dev": "vite" + "dev": "npm run development", + "development": "mix", + "watch": "mix watch", + "watch-poll": "mix watch -- --watch-options-poll=1000", + "hot": "mix watch --hot", + "prod": "npm run production", + "production": "mix --production" }, "devDependencies": { - "@popperjs/core": "^2.11.6", - "autoprefixer": "^10.4.20", - "axios": "^1.9.0", - "bootstrap": "^5.2.3", - "concurrently": "^9.0.1", - "laravel-vite-plugin": "^1.2.0", - "postcss": "^8.4.47", - "sass": "^1.56.1", - "sass-embedded": "^1.87.0", - "tailwindcss": "^3.4.13", - "vite": "^6.3.4" + "@popperjs/core": "^2.11.8", + "axios": "^1.6.7", + "bootstrap": "^5.3.3", + "jquery": "^3.7.1", + "laravel-mix": "^6.0.49", + "lodash": "^4.17.21", + "resolve-url-loader": "^5.0.0", + "sass": "^1.71.1", + "sass-loader": "^14.1.1" }, "dependencies": { - "@popperjs/core": "^2.11.8", - "bootstrap": "^5.3.5" + "@fortawesome/fontawesome-free": "^6.5.1", + "datatables.net-bs5": "^1.13.7", + "datatables.net-responsive-bs5": "^2.5.0", + "daterangepicker": "^3.1.0", + "moment": "^2.30.1", + "toastr": "^2.1.4" } } diff --git a/public/css/custom.css b/public/css/custom.css index 9c0b4b5..fa7d0e6 100644 --- a/public/css/custom.css +++ b/public/css/custom.css @@ -776,4 +776,199 @@ footer .copyright { /* --------------------------------------------------- MEDIAQUERIES ------------------------------------------------------ */ \ No newline at end of file +----------------------------------------------------- */ + +/* Global Styles */ +body { + font-family: 'Roboto', sans-serif; + background-color: #f8f9fa; +} + +.wrapper { + display: flex; + width: 100%; + min-height: 100vh; +} + +#content { + width: 100%; + padding: 20px; + transition: all 0.3s; +} + +/* Card Styles */ +.card { + border: none; + border-radius: 10px; + box-shadow: 0 0 10px rgba(0,0,0,0.1); + margin-bottom: 20px; +} + +.card-header { + background-color: transparent; + border-bottom: 1px solid #eee; + padding: 1.25rem; +} + +.card-title { + margin-bottom: 0; + color: #333; + font-weight: 500; +} + +/* Table Styles */ +.table { + margin-bottom: 0; +} + +.table th { + border-top: none; + font-weight: 500; + color: #333; + background-color: #f8f9fa; +} + +.table td { + vertical-align: middle; +} + +/* Form Styles */ +.form-control { + border-radius: 5px; + border: 1px solid #ced4da; + padding: 0.5rem 0.75rem; +} + +.form-control:focus { + border-color: #E74610; + box-shadow: 0 0 0 0.2rem rgba(231, 70, 16, 0.25); +} + +/* Button Styles */ +.btn-primary { + background-color: #E74610; + border-color: #E74610; +} + +.btn-primary:hover { + background-color: #d63d0c; + border-color: #d63d0c; +} + +.btn-outline-primary { + color: #E74610; + border-color: #E74610; +} + +.btn-outline-primary:hover { + background-color: #E74610; + border-color: #E74610; +} + +/* Badge Styles */ +.badge { + padding: 0.5em 0.75em; + font-weight: 500; + border-radius: 5px; +} + +.badge-success { + background-color: #28a745; +} + +.badge-danger { + background-color: #dc3545; +} + +.badge-warning { + background-color: #ffc107; + color: #333; +} + +.badge-info { + background-color: #17a2b8; +} + +/* Modal Styles */ +.modal-content { + border: none; + border-radius: 10px; +} + +.modal-header { + border-bottom: 1px solid #eee; + padding: 1.25rem; +} + +.modal-footer { + border-top: 1px solid #eee; + padding: 1.25rem; +} + +/* DataTables Styles */ +.dataTables_wrapper .dataTables_paginate .paginate_button.current { + background: #E74610; + border-color: #E74610; + color: #fff !important; +} + +.dataTables_wrapper .dataTables_paginate .paginate_button:hover { + background: #d63d0c; + border-color: #d63d0c; + color: #fff !important; +} + +/* Toastr Styles */ +.toast-success { + background-color: #28a745; +} + +.toast-error { + background-color: #dc3545; +} + +.toast-info { + background-color: #17a2b8; +} + +.toast-warning { + background-color: #ffc107; +} + +/* Responsive Styles */ +@media (max-width: 768px) { + #content { + padding: 15px; + } + + .card-header { + padding: 1rem; + } + + .table th, + .table td { + padding: 0.5rem; + } + + .btn { + padding: 0.375rem 0.75rem; + font-size: 0.875rem; + } +} + +/* Utility Classes */ +.cursor-pointer { + cursor: pointer; +} + +.text-primary { + color: #E74610 !important; +} + +.bg-primary { + background-color: #E74610 !important; +} + +.border-primary { + border-color: #E74610 !important; +} \ No newline at end of file diff --git a/resources/js/app.js b/resources/js/app.js new file mode 100644 index 0000000..05f1390 --- /dev/null +++ b/resources/js/app.js @@ -0,0 +1,80 @@ +import './bootstrap'; +import UserService from './services/UserService'; +import StationService from './services/StationService'; +import CardMemberService from './services/CardMemberService'; +import ContentService from './services/ContentService'; + +// Initialize services +window.services = { + user: new UserService(), + station: new StationService(), + cardMember: new CardMemberService(), + content: new ContentService() +}; + +// Configure global AJAX settings +$.ajaxSetup({ + headers: { + 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') + } +}); + +// Configure Toastr notifications +toastr.options = { + closeButton: true, + progressBar: true, + positionClass: 'toast-top-right', + timeOut: 3000 +}; + +// Initialize Bootstrap components +$(function () { + $('[data-bs-toggle="tooltip"]').tooltip(); + $('[data-bs-toggle="popover"]').popover(); +}); + +// Sidebar toggle functionality +$(document).ready(function() { + $('#sidebarCollapse').on('click', function() { + $('#sidebar').toggleClass('active'); + $('#content').toggleClass('active'); + }); + + $('.more-button,.body-overlay').on('click', function() { + $('#sidebar,.body-overlay').toggleClass('show-nav'); + }); +}); + +// Handle file inputs +$(document).on('change', '.custom-file-input', function() { + let fileName = $(this).val().split('\\').pop(); + $(this).next('.custom-file-label').addClass("selected").html(fileName); +}); + +// Handle form validation +$(document).on('submit', 'form.needs-validation', function(event) { + if (!this.checkValidity()) { + event.preventDefault(); + event.stopPropagation(); + } + $(this).addClass('was-validated'); +}); + +// Handle DataTables initialization +$.extend(true, $.fn.dataTable.defaults, { + language: { + search: "_INPUT_", + searchPlaceholder: "Search...", + lengthMenu: "_MENU_ records per page", + info: "Showing _START_ to _END_ of _TOTAL_ records", + infoEmpty: "Showing 0 to 0 of 0 records", + infoFiltered: "(filtered from _MAX_ total records)" + }, + dom: '<"row"<"col-sm-12 col-md-6"l><"col-sm-12 col-md-6"f>>' + + '<"row"<"col-sm-12"tr>>' + + '<"row"<"col-sm-12 col-md-5"i><"col-sm-12 col-md-7"p>>', + pageLength: 10, + processing: true, + responsive: true, + stateSave: true +}); \ No newline at end of file diff --git a/resources/js/services/BaseApiService.js b/resources/js/services/BaseApiService.js new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/resources/js/services/BaseApiService.js @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/js/services/CardMemberService.js b/resources/js/services/CardMemberService.js new file mode 100644 index 0000000..fc4ca5e --- /dev/null +++ b/resources/js/services/CardMemberService.js @@ -0,0 +1,47 @@ +import BaseApiService from './BaseApiService'; + +export default class CardMemberService extends BaseApiService { + constructor() { + super('/api/card-members'); + } + + async getCardMembers(params = {}) { + return this.get('', params); + } + + async getLockedAccounts(params = {}) { + return this.get('/locked', params); + } + + async unlockAccount(id) { + return this.post(`/${id}/unlock`); + } + + async getCardTypes(params = {}) { + return this.get('/card-types', params); + } + + async createCardType(cardTypeData) { + return this.post('/card-types', cardTypeData); + } + + async updateCardType(id, cardTypeData) { + return this.put(`/card-types/${id}`, cardTypeData); + } + + async deleteCardType(id) { + return this.delete(`/card-types/${id}`); + } + + async getTermsAndPrivacy() { + return this.get('/terms-and-privacy'); + } + + async updateTermsAndPrivacy(data) { + return this.put('/terms-and-privacy', data); + } + + async batchDelete(ids) { + return this.post('/batch-delete', { ids }); + } +} \ No newline at end of file diff --git a/resources/js/services/ContentService.js b/resources/js/services/ContentService.js new file mode 100644 index 0000000..3ad642f --- /dev/null +++ b/resources/js/services/ContentService.js @@ -0,0 +1,84 @@ +import BaseApiService from './BaseApiService'; + +export default class ContentService extends BaseApiService { + constructor() { + super('/api/content'); + } + + // Photo Slider Management + async getPhotoSliders(params = {}) { + return this.get('/photo-sliders', params); + } + + async createPhotoSlider(sliderData) { + return this.upload('/photo-sliders', sliderData); + } + + async updatePhotoSlider(id, sliderData) { + return this.upload(`/photo-sliders/${id}`, sliderData); + } + + async deletePhotoSlider(id) { + return this.delete(`/photo-sliders/${id}`); + } + + // Promotions Management + async getPromotions(params = {}) { + return this.get('/promotions', params); + } + + async createPromotion(promotionData) { + return this.upload('/promotions', promotionData); + } + + async updatePromotion(id, promotionData) { + return this.upload(`/promotions/${id}`, promotionData); + } + + async deletePromotion(id) { + return this.delete(`/promotions/${id}`); + } + + // System Parameters + async getSystemParameters(params = {}) { + return this.get('/system-parameters', params); + } + + async updateSystemParameter(id, paramData) { + return this.put(`/system-parameters/${id}`, paramData); + } + + // Top-up Settings + async getTopUpSettings(params = {}) { + return this.get('/top-up-settings', params); + } + + async updateTopUpSetting(id, settingData) { + return this.put(`/top-up-settings/${id}`, settingData); + } + + // Notifications + async getNotifications(params = {}) { + return this.get('/notifications', params); + } + + async createNotification(notificationData) { + return this.post('/notifications', notificationData); + } + + async updateNotification(id, notificationData) { + return this.put(`/notifications/${id}`, notificationData); + } + + async deleteNotification(id) { + return this.delete(`/notifications/${id}`); + } + + async sendNotification(id) { + return this.post(`/notifications/${id}/send`); + } + + async batchDelete(type, ids) { + return this.post(`/${type}/batch-delete`, { ids }); + } +} \ No newline at end of file diff --git a/resources/js/services/StationService.js b/resources/js/services/StationService.js new file mode 100644 index 0000000..0a7fa41 --- /dev/null +++ b/resources/js/services/StationService.js @@ -0,0 +1,51 @@ +import BaseApiService from './BaseApiService'; + +export default class StationService extends BaseApiService { + constructor() { + super('/api/stations'); + } + + async getStations(params = {}) { + return this.get('', params); + } + + async createStation(stationData) { + return this.post('', stationData); + } + + async updateStation(id, stationData) { + return this.put(`/${id}`, stationData); + } + + async deleteStation(id) { + return this.delete(`/${id}`); + } + + async getFuelPrices(stationId) { + return this.get(`/${stationId}/fuel-prices`); + } + + async updateFuelPrices(stationId, priceData) { + return this.put(`/${stationId}/fuel-prices`, priceData); + } + + async schedulePriceUpdate(stationId, scheduleData) { + return this.post(`/${stationId}/schedule-price-update`, scheduleData); + } + + async getPriceUpdateLogs(stationId, params = {}) { + return this.get(`/${stationId}/price-update-logs`, params); + } + + async getBranches(params = {}) { + return this.get('/branches', params); + } + + async getFuelTypes(params = {}) { + return this.get('/fuel-types', params); + } + + async batchDelete(ids) { + return this.post('/batch-delete', { ids }); + } +} \ No newline at end of file diff --git a/resources/js/services/UserService.js b/resources/js/services/UserService.js new file mode 100644 index 0000000..c5f0a62 --- /dev/null +++ b/resources/js/services/UserService.js @@ -0,0 +1,43 @@ +import BaseApiService from './BaseApiService'; + +export default class UserService extends BaseApiService { + constructor() { + super('/api/users'); + } + + async getUsers(params = {}) { + return this.get('', params); + } + + async createUser(userData) { + return this.post('', userData); + } + + async updateUser(id, userData) { + return this.put(`/${id}`, userData); + } + + async deleteUser(id) { + return this.delete(`/${id}`); + } + + async getUserProfile() { + return this.get('/profile'); + } + + async updateProfile(profileData) { + return this.put('/profile', profileData); + } + + async updateAvatar(formData) { + return this.upload('/profile/avatar', formData); + } + + async changePassword(passwordData) { + return this.post('/profile/change-password', passwordData); + } + + async batchDelete(ids) { + return this.post('/batch-delete', { ids }); + } +} \ No newline at end of file diff --git a/resources/views/components/table-component.blade.php b/resources/views/components/table-component.blade.php index be82f13..e5edd46 100644 --- a/resources/views/components/table-component.blade.php +++ b/resources/views/components/table-component.blade.php @@ -2,156 +2,310 @@ 'pageTitle' => '', 'data' => [], 'columns' => [], + 'allFields' => [], 'actions' => [], 'showAddButton' => false, 'addButtonUrl' => '#', 'showCheckboxes' => false, 'showBatchDelete' => false, 'showEditModal' => false, - 'showViewModal' => false + 'showViewModal' => false, + 'baseRoute' => '' ]) - -
-
-
{{ $pageTitle }}
- @if ($showAddButton) - - Add {{ $pageTitle }} - - @endif -
+
+
+
{{ $pageTitle }}
+ @if($showAddButton) + + Add New + + @endif
- -
-
-
- - - - -
-
-
- -
-
- - -
- - +
+
+ - @if ($showCheckboxes) - @endif - @foreach ($columns as $index => $column) - + @foreach($columns as $column) + @endforeach - @if (!empty($actions)) - + @if(count($actions) > 0) + @endif -
- + @if($showCheckboxes) + + - {{ $column['name'] }} - @if ($column['sortable']) - - @endif - {{ $column['name'] }}ActionActions
- - -
- @if ($showBatchDelete) -
- -
- @endif - -
+
- +@if($showEditModal) -@if ($showEditModal) -