initial: project state before operator dashboard card redesign
This commit is contained in:
commit
e0aed8eed7
113 files changed
+20074
No files matched your search
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\StoreBookingRequest;
|
||||
use App\Http\Resources\BookingResource;
|
||||
use App\Models\Booking;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
|
||||
class BookingController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*/
|
||||
public function __invoke(StoreBookingRequest $request)
|
||||
{
|
||||
$validated = $request->validated();
|
||||
|
||||
$booking = \App\Models\Booking::create($validated);
|
||||
|
||||
// Note: In production, create CarRegistry here for the booking car
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => new BookingResource($booking),
|
||||
'message' => 'Booking created successfully',
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$bookings = Booking::with('parkingLot')
|
||||
->latest()
|
||||
->paginate(10);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'data' => BookingResource::collection($bookings),
|
||||
'current_page' => $bookings->currentPage(),
|
||||
'last_page' => $bookings->lastPage(),
|
||||
'per_page' => $bookings->perPage(),
|
||||
'total' => $bookings->total(),
|
||||
],
|
||||
'message' => 'Recent bookings retrieved successfully',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\StoreOperatorCheckInRequest;
|
||||
use App\Models\CarRegistry;
|
||||
use App\Models\ParkingLot;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class CarRegistryController extends Controller
|
||||
{
|
||||
public function checkIn(StoreOperatorCheckInRequest $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validated();
|
||||
$parkingLot = ParkingLot::findOrFail($validated['parking_lot_id']);
|
||||
|
||||
// Check capacity vs active registries
|
||||
$activeCount = $parkingLot->carRegistries()->active()->count();
|
||||
if ($activeCount >= $parkingLot->total_capacity) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Parking lot is full',
|
||||
], 422);
|
||||
}
|
||||
|
||||
$registry = CarRegistry::create([
|
||||
'parking_lot_id' => $validated['parking_lot_id'],
|
||||
'plate_number' => $validated['vehicle_plate'],
|
||||
'entry_time' => now(),
|
||||
// Optional: predicted exit based on duration
|
||||
'exit_time' => isset($validated['duration_hours']) ? now()->addHours($validated['duration_hours']) : null,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Car entry registered successfully',
|
||||
'data' => $registry->load('parkingLot'),
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function checkOut(Request $request, CarRegistry $carRegistry): JsonResponse
|
||||
{
|
||||
if (! $carRegistry->exit_time) {
|
||||
$carRegistry->update([
|
||||
'exit_time' => now(),
|
||||
]);
|
||||
|
||||
$durationHours = $carRegistry->entry_time->diffInHours(now());
|
||||
$parkingLot = $carRegistry->parkingLot;
|
||||
$fee = ceil($durationHours) * $parkingLot->price_per_hour;
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Car exit registered successfully',
|
||||
'data' => [
|
||||
'duration_hours' => round($durationHours, 2),
|
||||
'fee' => $fee,
|
||||
'plate_number' => $carRegistry->plate_number,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Car already checked out',
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ParkingLot;
|
||||
use App\Http\Resources\ParkingLotResource;
|
||||
use App\Models\Booking;
|
||||
use App\Models\CarRegistry;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ParkingLotController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = ParkingLot::query()
|
||||
->withCount([
|
||||
'carRegistries as active_registries_count' => function($q) {
|
||||
$q->active();
|
||||
},
|
||||
'bookings as active_bookings_count' => function($q) {
|
||||
$q->where('status', 'active');
|
||||
}
|
||||
]);
|
||||
|
||||
$lots = $query->paginate(10);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'data' => ParkingLotResource::collection($lots),
|
||||
'current_page' => $lots->currentPage(),
|
||||
'last_page' => $lots->lastPage(),
|
||||
'per_page' => $lots->perPage(),
|
||||
'total' => $lots->total()
|
||||
],
|
||||
'message' => 'Parking lots retrieved successfully',
|
||||
]);
|
||||
}
|
||||
|
||||
public function search(Request $request)
|
||||
{
|
||||
$q = $request->get('q', '');
|
||||
|
||||
$query = ParkingLot::query()
|
||||
->withCount([
|
||||
'carRegistries as active_registries_count' => function($q) {
|
||||
$q->active();
|
||||
},
|
||||
'bookings as active_bookings_count' => function($q) {
|
||||
$q->where('status', 'active');
|
||||
}
|
||||
])
|
||||
->search($q);
|
||||
|
||||
$lots = $query->paginate(10);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'data' => ParkingLotResource::collection($lots),
|
||||
'current_page' => $lots->currentPage(),
|
||||
'last_page' => $lots->lastPage(),
|
||||
'per_page' => $lots->perPage(),
|
||||
'total' => $lots->total()
|
||||
],
|
||||
'message' => 'Parking lots search results',
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(ParkingLot $parkingLot)
|
||||
{
|
||||
$parkingLot->loadCount([
|
||||
'carRegistries as active_registries_count' => function($q) {
|
||||
$q->active();
|
||||
},
|
||||
'bookings as active_bookings_count' => function($q) {
|
||||
$q->where('status', 'active');
|
||||
}
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => new ParkingLotResource($parkingLot),
|
||||
'message' => 'Parking lot details retrieved',
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(ParkingLot $parkingLot)
|
||||
{
|
||||
$activeRegistries = $parkingLot->carRegistries()->active()->count();
|
||||
$activeBookings = $parkingLot->bookings()->where('status', 'active')->count();
|
||||
$occupied = $activeRegistries + $activeBookings;
|
||||
$available = max(0, $parkingLot->total_capacity - $occupied);
|
||||
$usagePercentage = $parkingLot->total_capacity > 0 ? round(($occupied / $parkingLot->total_capacity) * 100, 2) : 0;
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'id' => $parkingLot->id,
|
||||
'name' => $parkingLot->name,
|
||||
'total_capacity' => $parkingLot->total_capacity,
|
||||
'occupied_spaces' => $occupied,
|
||||
'available_spaces' => $available,
|
||||
'usage_percentage' => $usagePercentage,
|
||||
'active_registries_count' => $activeRegistries,
|
||||
'active_bookings_count' => $activeBookings,
|
||||
'status' => $available === 0 ? 'full' : ($available < $parkingLot->total_capacity * 0.2 ? 'limited' : 'available'),
|
||||
'active_cars' => $parkingLot->carRegistries()->active()->pluck('plate_number')->toArray(),
|
||||
'active_bookings' => $parkingLot->bookings()->where('status', 'active')->get(['id', 'customer_name', 'phone', 'start_time', 'end_time'])->toArray(),
|
||||
],
|
||||
'message' => 'Parking lot status retrieved successfully',
|
||||
]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in new issue
Block a user