diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..dd525d6 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,38 @@ +/* assets/css/custom.css */ +body { + background-color: #f8f9fa; +} + +.navbar-brand { + font-weight: bold; +} + +.card-header { + font-weight: 500; +} + +.empty-state { + text-align: center; + padding: 4rem 2rem; + background-color: #fff; + border-radius: 0.5rem; + border: 1px dashed #ced4da; +} + +.empty-state i { + font-size: 3rem; + color: #adb5bd; +} + +.empty-state h5 { + margin-top: 1.5rem; + font-weight: 500; +} + +.empty-state p { + color: #6c757d; +} + +.toast-container { + z-index: 1090; +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..683d225 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,9 @@ +// assets/js/main.js +document.addEventListener('DOMContentLoaded', function () { + // Activate toasts + var toastElList = [].slice.call(document.querySelectorAll('.toast')); + var toastList = toastElList.map(function (toastEl) { + return new bootstrap.Toast(toastEl); + }); + toastList.forEach(toast => toast.show()); +}); diff --git a/db/config.php b/db/config.php index cc9229f..aabffc1 100644 --- a/db/config.php +++ b/db/config.php @@ -1,17 +1,63 @@ PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - ]); - } - return $pdo; +function db_connect() { + static $pdo; + if ($pdo) { + return $pdo; + } + + // Database credentials - DO NOT MODIFY + $host = '127.0.0.1'; + $dbname = 'app'; + $user = 'app'; + $pass = 'app'; + $port = 3306; + $charset = 'utf8mb4'; + + $dsn = "mysql:host=$host;port=$port;dbname=$dbname;charset=$charset"; + $options = [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ]; + + try { + $pdo = new PDO($dsn, $user, $pass, $options); + return $pdo; + } catch ([31m[4mPDOException[0m $e) { + // In a real app, log this error and show a generic message + throw new [31m[4mPDOException[0m($e->getMessage(), (int)$e->getCode()); + } } + +function run_migrations() { + $pdo = db_connect(); + $migrationsDir = __DIR__ . '/migrations'; + if (!is_dir($migrationsDir)) { + mkdir($migrationsDir, 0775, true); + } + + $migrationFiles = glob($migrationsDir . '/*.sql'); + sort($migrationFiles); + + foreach ($migrationFiles as $file) { + try { + $sql = file_get_contents($file); + if (!empty(trim($sql))) { + $pdo->exec($sql); + } + } catch ([31m[4mPDOException[0m $e) { + // Log error, handle failure + error_log("Migration failed for file $file: " . $e->getMessage()); + } + } +} + +// Run migrations automatically on include +run_migrations(); + +// Helper function for easy access +function db() { + return db_connect(); +} \ No newline at end of file diff --git a/db/migrations/001_create_vehicles_table.sql b/db/migrations/001_create_vehicles_table.sql new file mode 100644 index 0000000..6373b18 --- /dev/null +++ b/db/migrations/001_create_vehicles_table.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS `vehicles` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `license_plate` VARCHAR(255) NOT NULL, + `model` VARCHAR(255) NOT NULL, + `current_mileage` INT, + `assigned_driver` VARCHAR(255), + `next_service_due` DATE, + `photo` VARCHAR(255) NULL, + `last_maintenance_date` DATE NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/includes/footer.php b/includes/footer.php new file mode 100644 index 0000000..847b87f --- /dev/null +++ b/includes/footer.php @@ -0,0 +1,10 @@ + + + + + + +