From 89022967eaacc52e70b95b42805f2b15b825679b Mon Sep 17 00:00:00 2001 From: Rubi Date: Wed, 7 May 2025 21:56:41 -0600 Subject: [PATCH] dashboard JORGE cree la vista de jorge que es el de mantenimiento --- .../Controllers/MaintenanceController.php | 82 +++++ app/Models/Maintenance.php | 32 ++ ..._07_000000_add_plate_to_tipos_veiculos.php | 27 ++ ...03_08_000000_create_maintenances_table.php | 28 ++ ...25_05_07_000000_add_rol_to_users_table.php | 22 ++ package-lock.json | 347 +++++++++++++++++- package.json | 7 +- .../components/dashboard/JorgeDashboard.jsx | 143 ++++++++ .../dashboard/NewMaintenanceForm.jsx | 151 ++++++++ resources/js/maintenance-dashboard.js | 10 + resources/views/layouts/dashboard.blade.php | 8 + .../views/maintenance/dashboard.blade.php | 9 + routes/api.php | 10 + routes/web.php | 2 + 14 files changed, 867 insertions(+), 11 deletions(-) create mode 100644 app/Http/Controllers/MaintenanceController.php create mode 100644 app/Models/Maintenance.php create mode 100644 database/migrations/2025_03_07_000000_add_plate_to_tipos_veiculos.php create mode 100644 database/migrations/2025_03_08_000000_create_maintenances_table.php create mode 100644 database/migrations/2025_05_07_000000_add_rol_to_users_table.php create mode 100644 resources/js/components/dashboard/JorgeDashboard.jsx create mode 100644 resources/js/components/dashboard/NewMaintenanceForm.jsx create mode 100644 resources/js/maintenance-dashboard.js create mode 100644 resources/views/maintenance/dashboard.blade.php diff --git a/app/Http/Controllers/MaintenanceController.php b/app/Http/Controllers/MaintenanceController.php new file mode 100644 index 0000000..7b7d3e4 --- /dev/null +++ b/app/Http/Controllers/MaintenanceController.php @@ -0,0 +1,82 @@ +orderBy('date', 'desc') + ->get(); + + return response()->json($maintenances); + } + + public function getPendingAlerts() + { + $alerts = Maintenance::with('vehicle') + ->where('status', 'Pendiente') + ->where('next_maintenance_date', '<=', now()->addDays(30)) + ->orderBy('next_maintenance_date', 'asc') + ->get(); + + return response()->json($alerts); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'vehicle_id' => 'required|exists:vehicles,id', + 'maintenance_type' => 'required|string', + 'date' => 'required|date', + 'description' => 'required|string', + 'cost' => 'required|numeric|min:0', + 'status' => 'required|in:Pendiente,En Proceso,Completado', + 'next_maintenance_date' => 'nullable|date' + ]); + + $maintenance = Maintenance::create($validated); + + return response()->json([ + 'message' => 'Mantenimiento registrado exitosamente', + 'maintenance' => $maintenance + ], 201); + } + + public function update(Request $request, Maintenance $maintenance) + { + $validated = $request->validate([ + 'vehicle_id' => 'required|exists:vehicles,id', + 'maintenance_type' => 'required|string', + 'date' => 'required|date', + 'description' => 'required|string', + 'cost' => 'required|numeric|min:0', + 'status' => 'required|in:Pendiente,En Proceso,Completado', + 'next_maintenance_date' => 'nullable|date' + ]); + + $maintenance->update($validated); + + return response()->json([ + 'message' => 'Mantenimiento actualizado exitosamente', + 'maintenance' => $maintenance + ]); + } + + public function getVehicles() + { + $vehicles = Vehicle::where('status', 'Activo')->get(); + return response()->json($vehicles); + } +} diff --git a/app/Models/Maintenance.php b/app/Models/Maintenance.php new file mode 100644 index 0000000..5393780 --- /dev/null +++ b/app/Models/Maintenance.php @@ -0,0 +1,32 @@ + 'date', + 'next_maintenance_date' => 'date', + 'cost' => 'decimal:2' + ]; + + public function vehicle() + { + return $this->belongsTo(TiposVeiculo::class, 'vehicle_id'); + } +} diff --git a/database/migrations/2025_03_07_000000_add_plate_to_tipos_veiculos.php b/database/migrations/2025_03_07_000000_add_plate_to_tipos_veiculos.php new file mode 100644 index 0000000..1f87f29 --- /dev/null +++ b/database/migrations/2025_03_07_000000_add_plate_to_tipos_veiculos.php @@ -0,0 +1,27 @@ +string('plate')->after('nombre')->nullable(); + } + if (!Schema::hasColumn('tipos_veiculos', 'model')) { + $table->string('model')->after('plate')->nullable(); + } + }); + } + + public function down() + { + Schema::table('tipos_veiculos', function (Blueprint $table) { + $table->dropColumn(['plate', 'model']); + }); + } +}; diff --git a/database/migrations/2025_03_08_000000_create_maintenances_table.php b/database/migrations/2025_03_08_000000_create_maintenances_table.php new file mode 100644 index 0000000..d6a7fdd --- /dev/null +++ b/database/migrations/2025_03_08_000000_create_maintenances_table.php @@ -0,0 +1,28 @@ +id(); + $table->foreignId('vehicle_id')->constrained('tipos_veiculos')->onDelete('cascade'); + $table->string('maintenance_type'); + $table->date('date'); + $table->text('description'); + $table->decimal('cost', 10, 2); + $table->enum('status', ['Pendiente', 'En Proceso', 'Completado'])->default('Pendiente'); + $table->date('next_maintenance_date')->nullable(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('maintenances'); + } +}; diff --git a/database/migrations/2025_05_07_000000_add_rol_to_users_table.php b/database/migrations/2025_05_07_000000_add_rol_to_users_table.php new file mode 100644 index 0000000..abb32a0 --- /dev/null +++ b/database/migrations/2025_05_07_000000_add_rol_to_users_table.php @@ -0,0 +1,22 @@ +string('rol')->default('usuario')->after('email'); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('rol'); + }); + } +}; diff --git a/package-lock.json b/package-lock.json index a8b6aef..bd442aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,15 +4,27 @@ "requires": true, "packages": { "": { + "dependencies": { + "react-bootstrap": "^2.10.9" + }, "devDependencies": { "@popperjs/core": "^2.11.6", - "axios": "^1.1.2", - "bootstrap": "^5.2.3", + "axios": "^1.9.0", + "bootstrap": "^5.3.6", "laravel-vite-plugin": "^0.7.2", "sass": "^1.56.1", "vite": "^4.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", @@ -701,13 +713,120 @@ "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "dev": true, "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, + "node_modules/@react-aria/ssr": { + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.8.tgz", + "integrity": "sha512-lQDE/c9uTfBSDOjaZUJS8xP2jCKVk4zjQeIlCH90xaLhHDgbpCdns3xvFpJJujfj3nI4Ll9K7A+ONUBDCASOuw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@restart/hooks": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.4.tgz", + "integrity": "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@popperjs/core": "^2.11.8", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.5.0", + "@types/warning": "^3.0.3", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.4", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/@restart/ui/node_modules/@restart/hooks": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.1.tgz", + "integrity": "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui/node_modules/uncontrollable": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", + "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.14.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.1.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.3.tgz", + "integrity": "sha512-dLWQ+Z0CkIvK1J8+wrDPwGxEYFA4RAyHoZPxHVGspYmFVnwGSNT24cGIhFJrtfRnWVuW8X7NO52gCXmhkVUWGQ==", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -716,9 +835,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.1.tgz", - "integrity": "sha512-NN+fvwH/kV01dYUQ3PTOZns4LWtWhOFCAhQ/pHb88WQ1hNe5V/dvFwc4VJcDL11LT9xSX0QtsR8sWUuyOuOq7g==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", "dev": true, "license": "MIT", "dependencies": { @@ -728,9 +847,9 @@ } }, "node_modules/bootstrap": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", - "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.6.tgz", + "integrity": "sha512-jX0GAcRzvdwISuvArXn3m7KZscWWFAf1MKBcnzaN02qWMb3jpMoUX4/qgeiGzqyIb4ojulRzs89UCUmGcFSzTA==", "dev": true, "funding": [ { @@ -791,6 +910,12 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -804,6 +929,12 @@ "node": ">= 0.8" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -814,6 +945,15 @@ "node": ">=0.4.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -828,6 +968,16 @@ "node": ">=0.10" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1107,6 +1257,15 @@ "dev": true, "license": "MIT" }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1143,6 +1302,12 @@ "node": ">=0.12.0" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, "node_modules/laravel-vite-plugin": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.7.8.tgz", @@ -1160,6 +1325,18 @@ "vite": "^3.0.0 || ^4.0.0" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1235,6 +1412,15 @@ "license": "MIT", "optional": true }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1284,6 +1470,30 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "license": "MIT", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -1291,6 +1501,88 @@ "dev": true, "license": "MIT" }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-bootstrap": { + "version": "2.10.9", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.9.tgz", + "integrity": "sha512-TJUCuHcxdgYpOqeWmRApM/Dy0+hVsxNRFvq2aRFQuxhNi/+ivOxC5OdWIeHS3agxvzJ4Ev4nDw2ZdBl9ymd/JQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.9.4", + "@types/prop-types": "^15.7.12", + "@types/react-transition-group": "^4.4.6", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "license": "MIT" + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -1343,6 +1635,13 @@ "@parcel/watcher": "^2.4.1" } }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT", + "peer": true + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1367,6 +1666,27 @@ "node": ">=8.0" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, "node_modules/vite": { "version": "4.5.9", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.9.tgz", @@ -1433,6 +1753,15 @@ "picocolors": "^1.0.0", "picomatch": "^2.3.1" } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } } } } diff --git a/package.json b/package.json index 84134f8..4db50f3 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,13 @@ }, "devDependencies": { "@popperjs/core": "^2.11.6", - "axios": "^1.1.2", - "bootstrap": "^5.2.3", + "axios": "^1.9.0", + "bootstrap": "^5.3.6", "laravel-vite-plugin": "^0.7.2", "sass": "^1.56.1", "vite": "^4.0.0" + }, + "dependencies": { + "react-bootstrap": "^2.10.9" } } diff --git a/resources/js/components/dashboard/JorgeDashboard.jsx b/resources/js/components/dashboard/JorgeDashboard.jsx new file mode 100644 index 0000000..786e375 --- /dev/null +++ b/resources/js/components/dashboard/JorgeDashboard.jsx @@ -0,0 +1,143 @@ +import React, { useState, useEffect } from 'react'; +import { Card, Row, Col, Button, Table, Alert } from 'react-bootstrap'; +import NewMaintenanceForm from './NewMaintenanceForm'; +import axios from 'axios'; + +const JorgeDashboard = () => { + const [maintenanceHistory, setMaintenanceHistory] = useState([]); + const [pendingAlerts, setPendingAlerts] = useState([]); + const [showNewMaintenanceForm, setShowNewMaintenanceForm] = useState(false); + const [vehicles, setVehicles] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + fetchData(); + }, []); + + const fetchData = async () => { + try { + setLoading(true); + const [historyRes, alertsRes, vehiclesRes] = await Promise.all([ + axios.get('/api/maintenance/history'), + axios.get('/api/maintenance/alerts'), + axios.get('/api/maintenance/vehicles') + ]); + + setMaintenanceHistory(historyRes.data); + setPendingAlerts(alertsRes.data); + setVehicles(vehiclesRes.data); + setError(null); + } catch (err) { + setError('Error al cargar los datos. Por favor, intente nuevamente.'); + console.error('Error fetching data:', err); + } finally { + setLoading(false); + } + }; + + const handleNewMaintenance = async (formData) => { + try { + const response = await axios.post('/api/maintenance', formData); + setMaintenanceHistory(prev => [response.data.maintenance, ...prev]); + setShowNewMaintenanceForm(false); + } catch (err) { + setError('Error al guardar el mantenimiento. Por favor, intente nuevamente.'); + console.error('Error saving maintenance:', err); + } + }; + + if (loading) { + return
Cargando...
; + } + + if (error) { + return {error}; + } + + return ( +
+

Panel de Control - Mantenimiento de Vehículos

+ + {/* Alertas Pendientes */} + + + + +

Alertas de Mantenimiento Pendiente

+
+ + {pendingAlerts.length === 0 ? ( + No hay alertas pendientes + ) : ( + pendingAlerts.map(alert => ( + + {alert.vehicle.plate} - {alert.maintenance_type} pendiente para: {new Date(alert.next_maintenance_date).toLocaleDateString()} + + )) + )} + +
+ +
+ + {/* Historial de Mantenimientos */} + + + + +

Historial de Mantenimientos

+ +
+ + + + + + + + + + + + + {maintenanceHistory.map(record => ( + + + + + + + + ))} + +
VehículoFechaTipoEstadoAcciones
{record.vehicle.plate}{new Date(record.date).toLocaleDateString()}{record.maintenance_type}{record.status} + + +
+
+
+ +
+ + {/* Modal de Nuevo Mantenimiento */} + setShowNewMaintenanceForm(false)} + onSubmit={handleNewMaintenance} + vehicles={vehicles} + /> +
+ ); +}; + +export default JorgeDashboard; diff --git a/resources/js/components/dashboard/NewMaintenanceForm.jsx b/resources/js/components/dashboard/NewMaintenanceForm.jsx new file mode 100644 index 0000000..b8d7979 --- /dev/null +++ b/resources/js/components/dashboard/NewMaintenanceForm.jsx @@ -0,0 +1,151 @@ +import React, { useState } from 'react'; +import { Modal, Form, Button } from 'react-bootstrap'; + +const NewMaintenanceForm = ({ show, handleClose, onSubmit, vehicles }) => { + const [formData, setFormData] = useState({ + vehicle_id: '', + maintenance_type: '', + date: '', + description: '', + cost: '', + status: 'Pendiente', + next_maintenance_date: '' + }); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData(prev => ({ + ...prev, + [name]: value + })); + }; + + const handleSubmit = (e) => { + e.preventDefault(); + onSubmit(formData); + // Resetear el formulario + setFormData({ + vehicle_id: '', + maintenance_type: '', + date: '', + description: '', + cost: '', + status: 'Pendiente', + next_maintenance_date: '' + }); + }; + + return ( + + + Nuevo Registro de Mantenimiento + + +
+ + Vehículo + + + {vehicles.map(vehicle => ( + + ))} + + + + + Tipo de Mantenimiento + + + + + + + + + + + Fecha + + + + + Descripción + + + + + Costo + + + + + Estado + + + + + + + + + Próxima Fecha de Mantenimiento + + + +
+ + +
+
+
+
+ ); +}; + +export default NewMaintenanceForm; diff --git a/resources/js/maintenance-dashboard.js b/resources/js/maintenance-dashboard.js new file mode 100644 index 0000000..f4be2ae --- /dev/null +++ b/resources/js/maintenance-dashboard.js @@ -0,0 +1,10 @@ +import 'bootstrap/dist/css/bootstrap.min.css'; +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import JorgeDashboard from './components/dashboard/JorgeDashboard'; + +const container = document.getElementById('maintenance-dashboard'); +if (container) { + const root = createRoot(container); + root.render(); +} diff --git a/resources/views/layouts/dashboard.blade.php b/resources/views/layouts/dashboard.blade.php index fee27d3..f7e85da 100644 --- a/resources/views/layouts/dashboard.blade.php +++ b/resources/views/layouts/dashboard.blade.php @@ -113,6 +113,14 @@ + +
  • + + + Mantenimiento + +
  • +