From 76d7d99142bd3308994b836fe72829d29aeaa364 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Mon, 15 Dec 2025 01:31:18 +0000 Subject: [PATCH] PMS 1 --- add_payment.php | 113 +++++++++ add_property.php | 105 ++++++++ add_request.php | 85 +++++++ add_tenant.php | 144 +++++++++++ add_user.php | 59 +++++ assets/css/custom.css | 70 ++++++ db/setup.php | 97 ++++++++ delete_file.php | 46 ++++ delete_payment.php | 26 ++ delete_property.php | 23 ++ delete_request.php | 26 ++ delete_tenant.php | 33 +++ delete_user.php | 44 ++++ edit_payment.php | 148 +++++++++++ edit_property.php | 163 ++++++++++++ edit_request.php | 108 ++++++++ edit_tenant.php | 189 ++++++++++++++ edit_user.php | 78 ++++++ index.php | 558 +++++++++++++++++++++++++++++++----------- login.php | 71 ++++++ logout.php | 6 + properties.php | 45 ++++ session.php | 21 ++ templates/footer.php | 11 + templates/header.php | 43 ++++ users.php | 43 ++++ 26 files changed, 2209 insertions(+), 146 deletions(-) create mode 100644 add_payment.php create mode 100644 add_property.php create mode 100644 add_request.php create mode 100644 add_tenant.php create mode 100644 add_user.php create mode 100644 assets/css/custom.css create mode 100644 db/setup.php create mode 100644 delete_file.php create mode 100644 delete_payment.php create mode 100644 delete_property.php create mode 100644 delete_request.php create mode 100644 delete_tenant.php create mode 100644 delete_user.php create mode 100644 edit_payment.php create mode 100644 edit_property.php create mode 100644 edit_request.php create mode 100644 edit_tenant.php create mode 100644 edit_user.php create mode 100644 login.php create mode 100644 logout.php create mode 100644 properties.php create mode 100644 session.php create mode 100644 templates/footer.php create mode 100644 templates/header.php create mode 100644 users.php diff --git a/add_payment.php b/add_payment.php new file mode 100644 index 0000000..1bcb9b2 --- /dev/null +++ b/add_payment.php @@ -0,0 +1,113 @@ +query("SELECT id, name FROM properties ORDER BY name")->fetchAll(); +$tenants = $db->query("SELECT id, name FROM tenants ORDER BY name")->fetchAll(); + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $property_id = $_POST['property_id']; + $tenant_id = $_POST['tenant_id']; + $amount = $_POST['amount']; + $payment_date = $_POST['payment_date']; + $notes = $_POST['notes']; + + $stmt = $db->prepare("INSERT INTO payments (property_id, tenant_id, amount, payment_date, notes) VALUES (?, ?, ?, ?, ?)"); + try { + $db->beginTransaction(); + $stmt->execute([$property_id, $tenant_id, $amount, $payment_date, $notes]); + $payment_id = $db->lastInsertId(); + + if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { + $upload_dir = 'uploads/'; + $file_name = uniqid() . '_' . basename($_FILES['file']['name']); + $target_file = $upload_dir . $file_name; + + if (move_uploaded_file($_FILES['file']['tmp_name'], $target_file)) { + $stmt = $db->prepare("INSERT INTO files (file_name, file_path, payment_id) VALUES (?, ?, ?)"); + $stmt->execute([$_FILES['file']['name'], $target_file, $payment_id]); + } else { + throw new Exception("Failed to upload file."); + } + } + $db->commit(); + header("Location: index.php?page=payments&success=1"); + exit; + } catch (Exception $e) { + $db->rollBack(); + $error = "Error adding payment: " . $e->getMessage(); + } +} +?> + + + + + + Add Payment - Property Management System + + + + + + +
+

Record New Payment

+ + +
+ + +
+
+
+
+ + +
+
+ + +
+
+ +
+ $ + +
+
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+
+
+
+ + + + diff --git a/add_property.php b/add_property.php new file mode 100644 index 0000000..afb3381 --- /dev/null +++ b/add_property.php @@ -0,0 +1,105 @@ +prepare($sql); + $stmt->bindParam(':name', $name, PDO::PARAM_STR); + $stmt->bindParam(':address', $address, PDO::PARAM_STR); + $stmt->bindParam(':rent_amount', $rent_amount, PDO::PARAM_STR); + $stmt->execute(); + $property_id = $db->lastInsertId(); // Get the ID of the new property + + // Handle file upload + if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { + $target_dir = "uploads/"; + if (!is_dir($target_dir)) { + mkdir($target_dir, 0755, true); + } + + $file_name = uniqid() . '-' . basename($_FILES["file"]["name"]); + $target_file = $target_dir . $file_name; + + if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) { + // Insert file info into database + $file_sql = "INSERT INTO files (file_name, file_path, property_id) VALUES (:file_name, :file_path, :property_id)"; + $file_stmt = $db->prepare($file_sql); + $file_stmt->bindParam(':file_name', $file_name, PDO::PARAM_STR); + $file_stmt->bindParam(':file_path', $target_file, PDO::PARAM_STR); + $file_stmt->bindParam(':property_id', $property_id, PDO::PARAM_INT); + $file_stmt->execute(); + } else { + $errors[] = "Sorry, there was an error uploading your file."; + // Note: The property has been added, but the file upload failed. + // You might want to handle this case, e.g., by showing a specific error message. + } + } + + header('Location: properties.php?message=Property added successfully.'); + exit; + } catch (Exception $e) { + $errors[] = "DB ERROR: " . $e->getMessage(); + } + } +} + +include 'templates/header.php'; +?> + +
+

Add New Property

+ + +
+ +

+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+
+ + diff --git a/add_request.php b/add_request.php new file mode 100644 index 0000000..4a45e7b --- /dev/null +++ b/add_request.php @@ -0,0 +1,85 @@ +query("SELECT id, name FROM properties ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC); + $tenants = $db->query("SELECT id, name FROM tenants ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + $error = "Error fetching data: " . $e->getMessage(); +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $property_id = $_POST['property_id'] ?? null; + $tenant_id = $_POST['tenant_id'] ?? null; + $description = $_POST['description'] ?? ''; + $reported_date = $_POST['reported_date'] ?? ''; + $status = $_POST['status'] ?? 'Open'; + + if ($property_id && $description && $reported_date) { + try { + $stmt = $db->prepare("INSERT INTO maintenance_requests (property_id, tenant_id, description, reported_date, status) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$property_id, $tenant_id, $description, $reported_date, $status]); + header("Location: index.php?page=maintenance&success=Request added"); + exit; + } catch (PDOException $e) { + $error = "Error: " . $e->getMessage(); + } + } else { + $error = "Please fill all required fields."; + } +} +include 'templates/header.php'; +?> + +
+

Add Maintenance Request

+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+
+ + diff --git a/add_tenant.php b/add_tenant.php new file mode 100644 index 0000000..8fb75cd --- /dev/null +++ b/add_tenant.php @@ -0,0 +1,144 @@ +query('SELECT id, name FROM properties ORDER BY name'); + $properties = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + // Don't block the page, just log error or show a message + error_log("Failed to fetch properties: " . $e->getMessage()); +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $name = $_POST['name'] ?? ''; + $email = $_POST['email'] ?? ''; + $phone = $_POST['phone'] ?? ''; + $property_id = !empty($_POST['property_id']) ? (int)$_POST['property_id'] : null; + $lease_start = !empty($_POST['lease_start']) ? $_POST['lease_start'] : null; + $lease_end = !empty($_POST['lease_end']) ? $_POST['lease_end'] : null; + $rent_due = !empty($_POST['rent_due']) ? (float)$_POST['rent_due'] : null; + $security_deposit = !empty($_POST['security_deposit']) ? (float)$_POST['security_deposit'] : null; + $status = $_POST['status'] ?? 'active'; + + try { + $db = db(); + $db->beginTransaction(); + $sql = "INSERT INTO tenants (name, email, phone, property_id, lease_start, lease_end, rent_due, security_deposit, status) VALUES (:name, :email, :phone, :property_id, :lease_start, :lease_end, :rent_due, :security_deposit, :status)"; + $stmt = $db->prepare($sql); + $stmt->bindParam(':name', $name); + $stmt->bindParam(':email', $email); + $stmt->bindParam(':phone', $phone); + $stmt->bindParam(':property_id', $property_id); + $stmt->bindParam(':lease_start', $lease_start); + $stmt->bindParam(':lease_end', $lease_end); + $stmt->bindParam(':rent_due', $rent_due); + $stmt->bindParam(':security_deposit', $security_deposit); + $stmt->bindParam(':status', $status); + $stmt->execute(); + $tenant_id = $db->lastInsertId(); + + if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { + $upload_dir = 'uploads/'; + $file_name = uniqid() . '_' . basename($_FILES['file']['name']); + $target_file = $upload_dir . $file_name; + + if (move_uploaded_file($_FILES['file']['tmp_name'], $target_file)) { + $stmt = $db->prepare("INSERT INTO files (file_name, file_path, tenant_id) VALUES (?, ?, ?)"); + $stmt->execute([$_FILES['file']['name'], $target_file, $tenant_id]); + } else { + throw new Exception("Failed to upload file."); + } + } + $db->commit(); + header('Location: index.php?tab=tenants&message=Tenant added successfully.'); + exit; + } catch (Exception $e) { + $db->rollBack(); + $error = "Error adding tenant: " . $e->getMessage(); + } +} +?> + + + + + + Add Tenant + + + + +
+

Add New Tenant

+ +
+ +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+ + Cancel +
+
+ + \ No newline at end of file diff --git a/add_user.php b/add_user.php new file mode 100644 index 0000000..7f9d623 --- /dev/null +++ b/add_user.php @@ -0,0 +1,59 @@ +prepare("INSERT INTO users (username, password, role) VALUES (?, ?, ?)"); + $stmt->execute([$username, $hashed_password, $role]); + header("Location: users.php?success=User added"); + exit; + } catch (PDOException $e) { + $error = "Error: " . $e->getMessage(); + } + } else { + $error = "Please fill all required fields."; + } +} + +include 'templates/header.php'; +?> + +
+

Add New User

+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+
+ + diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..1e42ff6 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,70 @@ +/* assets/css/custom.css */ +:root { + --primary-color: #4A90E2; /* A modern, vibrant blue */ + --secondary-color: #F5A623; /* A warm, contrasting orange for accents */ + --background-color: #FFFFFF; /* Clean white background */ + --surface-color: #F8F9FA; /* A very light grey for cards, tables etc. */ + --text-color: #333333; /* Dark grey for readability */ + --text-color-secondary: #555555; + --border-color: #E0E0E0; /* Light grey for borders */ +} + +body { + background-color: var(--background-color); + color: var(--text-color); + font-family: 'Inter', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.bg-surface { + background-color: var(--surface-color) !important; +} + +.navbar-light { + background-color: var(--background-color) !important; + border-bottom: 1px solid var(--border-color); + box-shadow: 0 2px 4px rgba(0,0,0,0.05); +} + +.btn-primary { + background-color: var(--primary-color); + border-color: var(--primary-color); + font-weight: 600; + transition: all 0.2s ease-in-out; +} + +.btn-primary:hover { + opacity: 0.9; + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0,0,0,0.1); +} + +.btn-secondary { + background-color: var(--secondary-color); + border-color: var(--secondary-color); +} + +.card { + border: none; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0,0,0,0.08); + background-color: var(--surface-color); +} + +.table { + --bs-table-bg: var(--surface-color); + --bs-table-border-color: var(--border-color); + --bs-table-striped-bg: #FDFDFD; +} + +.footer { + background-color: var(--surface-color) !important; + border-top: 1px solid var(--border-color); + color: var(--text-color-secondary); +} + +h1, h2, h3, h4, h5, h6 { + font-weight: 700; + color: var(--text-color); +} \ No newline at end of file diff --git a/db/setup.php b/db/setup.php new file mode 100644 index 0000000..8fa0daf --- /dev/null +++ b/db/setup.php @@ -0,0 +1,97 @@ +exec($sql_properties); + + $sql_tenants = " + CREATE TABLE IF NOT EXISTS tenants ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL UNIQUE, + phone VARCHAR(20), + property_id INT, + lease_start DATE, + lease_end DATE, + rent_due DECIMAL(10, 2), + security_deposit DECIMAL(10, 2), + status VARCHAR(50) DEFAULT 'active', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (property_id) REFERENCES properties(id) ON DELETE SET NULL + );"; + $db->exec($sql_tenants); + + $sql_payments = " + CREATE TABLE IF NOT EXISTS payments ( + id INT AUTO_INCREMENT PRIMARY KEY, + tenant_id INT, + property_id INT, + amount DECIMAL(10, 2) NOT NULL, + payment_date DATE NOT NULL, + notes TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE SET NULL, + FOREIGN KEY (property_id) REFERENCES properties(id) ON DELETE SET NULL + );"; + $db->exec($sql_payments); + + $sql_maintenance = " + CREATE TABLE IF NOT EXISTS maintenance_requests ( + id INT AUTO_INCREMENT PRIMARY KEY, + property_id INT, + tenant_id INT, + description TEXT NOT NULL, + status VARCHAR(50) DEFAULT 'Open', + reported_date DATE NOT NULL, + completed_date DATE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (property_id) REFERENCES properties(id) ON DELETE SET NULL, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE SET NULL + );"; + $db->exec($sql_maintenance); + + $sql_files = " + CREATE TABLE IF NOT EXISTS files ( + id INT AUTO_INCREMENT PRIMARY KEY, + file_name VARCHAR(255) NOT NULL, + file_path VARCHAR(255) NOT NULL, + property_id INT, + tenant_id INT, + payment_id INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (property_id) REFERENCES properties(id) ON DELETE CASCADE, + FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE, + FOREIGN KEY (payment_id) REFERENCES payments(id) ON DELETE CASCADE + );"; + $db->exec($sql_files); + + $sql_users = " + CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(255) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + role VARCHAR(50) NOT NULL DEFAULT 'user', -- 'user', 'admin' + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + );"; + $db->exec($sql_users); + + // Seed the database with a default admin user + $admin_user = 'admin'; + $admin_pass = password_hash('password', PASSWORD_DEFAULT); + $stmt = $db->prepare('INSERT IGNORE INTO users (username, password, role) VALUES (?, ?, ?)'); + $stmt->execute([$admin_user, $admin_pass, 'admin']); + + echo "Tables 'properties', 'tenants', 'payments', 'maintenance_requests', 'files', and 'users' created successfully."; +} catch (PDOException $e) { + die("DB ERROR: ". $e->getMessage()); +} +?> \ No newline at end of file diff --git a/delete_file.php b/delete_file.php new file mode 100644 index 0000000..f228a03 --- /dev/null +++ b/delete_file.php @@ -0,0 +1,46 @@ +prepare("SELECT * FROM files WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + $file = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($file) { + // Delete file from server + if (file_exists($file['file_path'])) { + unlink($file['file_path']); + } + + // Delete record from database + $stmt = $db->prepare("DELETE FROM files WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + } + + if ($property_id) { + header('Location: edit_property.php?id=' . $property_id . '&message=File deleted successfully'); + } elseif ($tenant_id = $_GET['tenant_id'] ?? null) { + header('Location: edit_tenant.php?id=' . $tenant_id . '&message=File deleted successfully'); + } elseif ($payment_id = $_GET['payment_id'] ?? null) { + header('Location: edit_payment.php?id=' . $payment_id . '&message=File deleted successfully'); + } else { + header('Location: index.php?page=properties&message=File deleted successfully'); + } + exit; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/delete_payment.php b/delete_payment.php new file mode 100644 index 0000000..bc120fd --- /dev/null +++ b/delete_payment.php @@ -0,0 +1,26 @@ +prepare("DELETE FROM payments WHERE id = ?"); + +if ($stmt->execute([$id])) { + header("Location: index.php?page=payments&success=3"); +} else { + header("Location: index.php?page=payments&error=2"); +} +exit; +?> diff --git a/delete_property.php b/delete_property.php new file mode 100644 index 0000000..7aec2e0 --- /dev/null +++ b/delete_property.php @@ -0,0 +1,23 @@ +prepare("DELETE FROM properties WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} + +header('Location: properties.php'); +exit; +?> \ No newline at end of file diff --git a/delete_request.php b/delete_request.php new file mode 100644 index 0000000..0045176 --- /dev/null +++ b/delete_request.php @@ -0,0 +1,26 @@ +prepare("DELETE FROM maintenance_requests WHERE id = ?"); + $stmt->execute([$id]); + header("Location: index.php?page=maintenance&success=Request deleted"); + exit; + } catch (PDOException $e) { + header("Location: index.php?page=maintenance&error=Error deleting request"); + exit; + } + } +} else { + // Redirect if not a POST request + header("Location: index.php?page=maintenance"); + exit; +} +?> diff --git a/delete_tenant.php b/delete_tenant.php new file mode 100644 index 0000000..144b6e4 --- /dev/null +++ b/delete_tenant.php @@ -0,0 +1,33 @@ +prepare("DELETE FROM tenants WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + + if ($stmt->rowCount() > 0) { + header('Location: index.php?tab=tenants&status=deleted'); + } else { + header('Location: index.php?tab=tenants&error=NotFound'); + } + exit; +} catch (PDOException $e) { + header('Location: index.php?tab=tenants&error=' . urlencode($e->getMessage())); + exit; +} +?> \ No newline at end of file diff --git a/delete_user.php b/delete_user.php new file mode 100644 index 0000000..8c6d60a --- /dev/null +++ b/delete_user.php @@ -0,0 +1,44 @@ +prepare("SELECT role FROM users WHERE id = ?"); + $stmt->execute([$id]); + $user = $stmt->fetch(); + + if ($user && $user['role'] === 'admin') { + $stmt = $db->query("SELECT COUNT(*) FROM users WHERE role = 'admin'"); + $admin_count = $stmt->fetchColumn(); + if ($admin_count <= 1) { + header("Location: users.php?error=Cannot delete the last admin"); + exit; + } + } + + try { + $stmt = $db->prepare("DELETE FROM users WHERE id = ?"); + $stmt->execute([$id]); + header("Location: users.php?success=User deleted"); + exit; + } catch (PDOException $e) { + header("Location: users.php?error=Error deleting user"); + exit; + } + } +} else { + header("Location: users.php"); + exit; +} +?> \ No newline at end of file diff --git a/edit_payment.php b/edit_payment.php new file mode 100644 index 0000000..5a1ff64 --- /dev/null +++ b/edit_payment.php @@ -0,0 +1,148 @@ +prepare("SELECT * FROM payments WHERE id = ?"); +$stmt->execute([$id]); +$payment = $stmt->fetch(); + +if (!$payment) { + header("Location: index.php?page=payments"); + exit; +} + +$properties = $db->query("SELECT id, name FROM properties ORDER BY name")->fetchAll(); +$tenants = $db->query("SELECT id, name FROM tenants ORDER BY name")->fetchAll(); + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $property_id = $_POST['property_id']; + $tenant_id = $_POST['tenant_id']; + $amount = $_POST['amount']; + $payment_date = $_POST['payment_date']; + $notes = $_POST['notes']; + + $stmt = $db->prepare("UPDATE payments SET property_id = ?, tenant_id = ?, amount = ?, payment_date = ?, notes = ? WHERE id = ?"); + try { + $db->beginTransaction(); + $stmt->execute([$property_id, $tenant_id, $amount, $payment_date, $notes, $id]); + + if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { + $upload_dir = 'uploads/'; + $file_name = uniqid() . '_' . basename($_FILES['file']['name']); + $target_file = $upload_dir . $file_name; + + if (move_uploaded_file($_FILES['file']['tmp_name'], $target_file)) { + $stmt = $db->prepare("INSERT INTO files (file_name, file_path, payment_id) VALUES (?, ?, ?)"); + $stmt->execute([$_FILES['file']['name'], $target_file, $id]); + } else { + throw new Exception("Failed to upload file."); + } + } + $db->commit(); + header("Location: index.php?page=payments&success=2"); + exit; + } catch (Exception $e) { + $db->rollBack(); + $error = "Error updating payment: " . $e->getMessage(); + } +} + +?> + + + + + + Edit Payment - Property Management System + + + + + + +
+

Edit Payment

+ + +
+ + +
+
+
+
+ + +
+
+ + +
+
+ +
+ $ + +
+
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+ +
+ +
Uploaded Files
+ prepare("SELECT * FROM files WHERE payment_id = :payment_id"); + $stmt->bindParam(':payment_id', $id, PDO::PARAM_INT); + $stmt->execute(); + $files = $stmt->fetchAll(PDO::FETCH_ASSOC); + ?> + +

No files uploaded for this payment.

+ + + +
+
+
+ + + + diff --git a/edit_property.php b/edit_property.php new file mode 100644 index 0000000..9246720 --- /dev/null +++ b/edit_property.php @@ -0,0 +1,163 @@ +prepare("SELECT * FROM properties WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + $property = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$property) { + header('Location: properties.php'); + exit; + } + + $name = $property['name']; + $address = $property['address']; + $rent_amount = $property['rent_amount']; + +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $name = $_POST['name'] ?? ''; + $address = $_POST['address'] ?? ''; + $rent_amount = $_POST['rent_amount'] ?? ''; + + if (empty($name)) { + $errors[] = 'Name is required'; + } + if (empty($address)) { + $errors[] = 'Address is required'; + } + if (empty($rent_amount) || !is_numeric($rent_amount)) { + $errors[] = 'Valid rent amount is required'; + } + + if (empty($errors)) { + $db = db(); + try { + $sql = "UPDATE properties SET name = :name, address = :address, rent_amount = :rent_amount WHERE id = :id"; + $stmt = $db->prepare($sql); + $stmt->bindParam(':name', $name, PDO::PARAM_STR); + $stmt->bindParam(':address', $address, PDO::PARAM_STR); + $stmt->bindParam(':rent_amount', $rent_amount, PDO::PARAM_STR); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + + // Handle file upload + if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { + $target_dir = "uploads/"; + if (!is_dir($target_dir)) { + mkdir($target_dir, 0755, true); + } + + $file_name = uniqid() . '-' . basename($_FILES["file"]["name"]); + $target_file = $target_dir . $file_name; + + if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) { + // Insert file info into database + $file_sql = "INSERT INTO files (file_name, file_path, property_id) VALUES (:file_name, :file_path, :property_id)"; + $file_stmt = $db->prepare($file_sql); + $file_stmt->bindParam(':file_name', $file_name, PDO::PARAM_STR); + $file_stmt->bindParam(':file_path', $target_file, PDO::PARAM_STR); + $file_stmt->bindParam(':property_id', $id, PDO::PARAM_INT); + $file_stmt->execute(); + } else { + $errors[] = "Sorry, there was an error uploading your file."; + } + } + + header('Location: edit_property.php?id=' . $id . '&message=Property updated successfully.'); + exit; + } catch (Exception $e) { + $errors[] = "DB ERROR: " . $e->getMessage(); + } + } +} + +include 'templates/header.php'; +?> + +
+

Edit Property

+ + +

+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ + + Cancel +
+ +
+ +

Uploaded Files

+ prepare("SELECT * FROM files WHERE property_id = :property_id"); + $file_stmt->bindParam(':property_id', $id, PDO::PARAM_INT); + $file_stmt->execute(); + $files = $file_stmt->fetchAll(PDO::FETCH_ASSOC); + } catch (PDOException $e) { + $files = []; + echo "

Could not load files: " . $e->getMessage() . "

"; + } + + if (count($files) > 0) { + echo ''; + } else { + echo '

No files uploaded for this property yet.

'; + } + ?> + + + diff --git a/edit_request.php b/edit_request.php new file mode 100644 index 0000000..8b6b67f --- /dev/null +++ b/edit_request.php @@ -0,0 +1,108 @@ +query("SELECT id, name FROM properties ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC); + $tenants = $db->query("SELECT id, name FROM tenants ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC); + + $stmt = $db->prepare("SELECT * FROM maintenance_requests WHERE id = ?"); + $stmt->execute([$id]); + $request = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$request) { + header("Location: index.php?page=maintenance&error=Request not found"); + exit; + } +} catch (PDOException $e) { + $error = "Error fetching data: " . $e->getMessage(); +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $property_id = $_POST['property_id'] ?? null; + $tenant_id = $_POST['tenant_id'] ?? null; + $description = $_POST['description'] ?? ''; + $reported_date = $_POST['reported_date'] ?? ''; + $completed_date = !empty($_POST['completed_date']) ? $_POST['completed_date'] : null; + $status = $_POST['status'] ?? 'Open'; + + if ($property_id && $description && $reported_date) { + try { + $stmt = $db->prepare("UPDATE maintenance_requests SET property_id = ?, tenant_id = ?, description = ?, reported_date = ?, completed_date = ?, status = ? WHERE id = ?"); + $stmt->execute([$property_id, $tenant_id, $description, $reported_date, $completed_date, $status, $id]); + header("Location: index.php?page=maintenance&success=Request updated"); + exit; + } catch (PDOException $e) { + $error = "Error: " . $e->getMessage(); + } + } else { + $error = "Please fill all required fields."; + } +} + +include 'templates/header.php'; +?> + +
+

Edit Maintenance Request

+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+
+ + diff --git a/edit_tenant.php b/edit_tenant.php new file mode 100644 index 0000000..2682cba --- /dev/null +++ b/edit_tenant.php @@ -0,0 +1,189 @@ +prepare("SELECT * FROM tenants WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + $tenant = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$tenant) { + header('Location: index.php?tab=tenants'); + exit; + } + + // Fetch properties for dropdown + $stmt = $db->query('SELECT id, name FROM properties ORDER BY name'); + $properties = $stmt->fetchAll(PDO::FETCH_ASSOC); + +} catch (PDOException $e) { + $error = "DB Error: " . $e->getMessage(); +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $name = $_POST['name'] ?? ''; + $email = $_POST['email'] ?? ''; + $phone = $_POST['phone'] ?? ''; + $property_id = !empty($_POST['property_id']) ? (int)$_POST['property_id'] : null; + $lease_start = !empty($_POST['lease_start']) ? $_POST['lease_start'] : null; + $lease_end = !empty($_POST['lease_end']) ? $_POST['lease_end'] : null; + $rent_due = !empty($_POST['rent_due']) ? (float)$_POST['rent_due'] : null; + $security_deposit = !empty($_POST['security_deposit']) ? (float)$_POST['security_deposit'] : null; + $status = $_POST['status'] ?? 'active'; + + try { + $db->beginTransaction(); + $sql = "UPDATE tenants SET name = :name, email = :email, phone = :phone, property_id = :property_id, lease_start = :lease_start, lease_end = :lease_end, rent_due = :rent_due, security_deposit = :security_deposit, status = :status WHERE id = :id"; + $stmt = $db->prepare($sql); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->bindParam(':name', $name); + $stmt->bindParam(':email', $email); + $stmt->bindParam(':phone', $phone); + $stmt->bindParam(':property_id', $property_id); + $stmt->bindParam(':lease_start', $lease_start); + $stmt->bindParam(':lease_end', $lease_end); + $stmt->bindParam(':rent_due', $rent_due); + $stmt->bindParam(':security_deposit', $security_deposit); + $stmt->bindParam(':status', $status); + $stmt->execute(); + + if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { + $upload_dir = 'uploads/'; + $file_name = uniqid() . '_' . basename($_FILES['file']['name']); + $target_file = $upload_dir . $file_name; + + if (move_uploaded_file($_FILES['file']['tmp_name'], $target_file)) { + $stmt = $db->prepare("INSERT INTO files (file_name, file_path, tenant_id) VALUES (?, ?, ?)"); + $stmt->execute([$_FILES['file']['name'], $target_file, $id]); + } else { + throw new Exception("Failed to upload file."); + } + } + $db->commit(); + header('Location: index.php?tab=tenants&message=Tenant updated successfully.'); + exit; + } catch (Exception $e) { + $db->rollBack(); + $error = "Error updating tenant: " . $e->getMessage(); + } +} +?> + + + + + + Edit Tenant + + + + +
+

Edit Tenant

+ +
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+ + Cancel +
+ +
+ +
Uploaded Files
+ prepare("SELECT * FROM files WHERE tenant_id = :tenant_id"); + $stmt->bindParam(':tenant_id', $id, PDO::PARAM_INT); + $stmt->execute(); + $files = $stmt->fetchAll(PDO::FETCH_ASSOC); + ?> + +

No files uploaded for this tenant.

+ + + + +
Tenant not found.
+ +
+ + \ No newline at end of file diff --git a/edit_user.php b/edit_user.php new file mode 100644 index 0000000..2c895f0 --- /dev/null +++ b/edit_user.php @@ -0,0 +1,78 @@ +prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$id]); +$user = $stmt->fetch(); + +if (!$user) { + header("Location: users.php?error=User not found"); + exit; +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $username = $_POST['username']; + $role = $_POST['role']; + $password = $_POST['password']; + + if ($username && $role) { + try { + if ($password) { + $hashed_password = password_hash($password, PASSWORD_DEFAULT); + $stmt = $db->prepare("UPDATE users SET username = ?, password = ?, role = ? WHERE id = ?"); + $stmt->execute([$username, $hashed_password, $role, $id]); + } else { + $stmt = $db->prepare("UPDATE users SET username = ?, role = ? WHERE id = ?"); + $stmt->execute([$username, $role, $id]); + } + header("Location: users.php?success=User updated"); + exit; + } catch (PDOException $e) { + $error = "Error: " . $e->getMessage(); + } + } else { + $error = "Please fill all required fields."; + } +} + +include 'templates/header.php'; +?> + +
+

Edit User

+ + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+
+ + diff --git a/index.php b/index.php index 7205f3d..fa1ecff 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,416 @@ query('SELECT * FROM properties ORDER BY created_at DESC'); + $properties = $stmt->fetchAll(PDO::FETCH_ASSOC); + } elseif ($page === 'dashboard') { + $stmt = $db->query('SELECT COUNT(*) FROM properties'); + $total_properties = $stmt->fetchColumn(); + $stmt = $db->query('SELECT COUNT(*) FROM tenants'); + $total_tenants = $stmt->fetchColumn(); + $stmt = $db->query('SELECT COUNT(*) FROM maintenance_requests'); + $total_requests = $stmt->fetchColumn(); + $stmt = $db->query('SELECT SUM(amount) FROM payments'); + $total_payments = $stmt->fetchColumn(); + + // Data for Payments Chart + $stmt = $db->query("SELECT MONTH(payment_date) as month, SUM(amount) as total FROM payments WHERE YEAR(payment_date) = YEAR(CURDATE()) GROUP BY MONTH(payment_date)"); + $payment_chart_data = $stmt->fetchAll(PDO::FETCH_ASSOC); + $payment_labels = []; + $payment_values = []; + foreach ($payment_chart_data as $data) { + $payment_labels[] = date('F', mktime(0, 0, 0, $data['month'], 10)); + $payment_values[] = $data['total']; + } + + // Data for Maintenance Requests Chart + $stmt = $db->query("SELECT status, COUNT(*) as count FROM maintenance_requests GROUP BY status"); + $request_chart_data = $stmt->fetchAll(PDO::FETCH_ASSOC); + $request_labels = []; + $request_values = []; + foreach ($request_chart_data as $data) { + $request_labels[] = $data['status']; + $request_values[] = $data['count']; + } + + } elseif ($page === 'tenants') { + $stmt = $db->query('SELECT t.*, p.name AS property_name FROM tenants t LEFT JOIN properties p ON t.property_id = p.id ORDER BY t.created_at DESC'); + $tenants = $stmt->fetchAll(PDO::FETCH_ASSOC); + } elseif ($page === 'payments') { + $stmt = $db->query('SELECT pay.*, t.name AS tenant_name, p.name AS property_name FROM payments pay JOIN tenants t ON pay.tenant_id = t.id JOIN properties p ON pay.property_id = p.id ORDER BY pay.payment_date DESC'); + $payments = $stmt->fetchAll(PDO::FETCH_ASSOC); + } elseif ($page === 'maintenance') { + $stmt = $db->query('SELECT mr.*, p.name AS property_name, t.name AS tenant_name FROM maintenance_requests mr LEFT JOIN properties p ON mr.property_id = p.id LEFT JOIN tenants t ON mr.tenant_id = t.id ORDER BY mr.reported_date DESC'); + $maintenance_requests = $stmt->fetchAll(PDO::FETCH_ASSOC); + } +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} + +$success_message = ''; +if (isset($_GET['success'])) { + switch ($_GET['success']) { + case 1: $success_message = "Payment added successfully!"; break; + case 2: $success_message = "Payment updated successfully!"; break; + case 3: $success_message = "Payment deleted successfully!"; break; + } +} + +$error_message = ''; +if (isset($_GET['error'])) { + switch ($_GET['error']) { + case 1: $error_message = "Error: Missing payment ID."; break; + case 2: $error_message = "Error: Could not delete payment."; break; + } +} + +require_once 'templates/header.php'; ?> - - - - - - New Style - - - - - - - - - - - - - - - - - - - - - -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+ +
+ +
+ + +
+ + + + +
+
+
+

Dashboard

+
+
+
+
+
+
Total Properties
+

+
+
+
+
+
+
+
Total Tenants
+

+
+
+
+
+
+
+
Maintenance Requests
+

+
+
+
+
+
+
+
Total Payments
+

$

+
+
+
+
+ +
+
+
+
+
Monthly Payments (Current Year)
+ +
+
+
+
+
+
+
Maintenance Requests Status
+ +
+
+
+
+
+ +
+
+

Properties

+ + Add New Property + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
NameAddressRentActions
$ + Edit + +
+ + +
+ +
No properties found.
+
+
+
+ +
+
+

Tenants

+ + Add New Tenant + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameEmailPropertyLease EndStatusActions
+ Edit + +
+ + +
+ +
No tenants found.
+
+
+
+ +
+
+

Payments

+ + Add New Payment + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
TenantPropertyAmountPayment DateActions
$ + Edit + +
+ + +
+ +
No payments found.
+
+
+
+ +
+
+

Maintenance Requests

+ Add New Request +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTenantDescriptionStatusReported DateActions
+ Edit + +
+ + +
+ +
No maintenance requests found.
+
+
+
-
-
- Page updated: (UTC) -
- - +
+ + + + + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..6571572 --- /dev/null +++ b/login.php @@ -0,0 +1,71 @@ +prepare('SELECT id, password, role FROM users WHERE username = ?'); + $stmt->execute([$username]); + $user = $stmt->fetch(); + + if ($user && password_verify($password, $user['password'])) { + $_SESSION['user_id'] = $user['id']; + $_SESSION['role'] = $user['role']; + header('Location: index.php'); + exit; + } else { + $error = 'Invalid username or password.'; + } + } +} +?> + + + + + Login + + + +
+
+
+
+
+

Login

+
+
+ +
+ +
+
+ + +
+
+ + +
+ +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..1f4bcf7 --- /dev/null +++ b/logout.php @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/properties.php b/properties.php new file mode 100644 index 0000000..856208a --- /dev/null +++ b/properties.php @@ -0,0 +1,45 @@ +query("SELECT * FROM properties ORDER BY name ASC")->fetchAll(); + +include 'templates/header.php'; +?> + +
+

Manage Properties

+ + Add New Property + + + + + + + + + + + + + + + + + + + + +
NameAddressRent AmountActions
$ + Edit +
+ + +
+
+
+ + diff --git a/session.php b/session.php new file mode 100644 index 0000000..c672036 --- /dev/null +++ b/session.php @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/templates/footer.php b/templates/footer.php new file mode 100644 index 0000000..db17405 --- /dev/null +++ b/templates/footer.php @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/templates/header.php b/templates/header.php new file mode 100644 index 0000000..1c7e3d1 --- /dev/null +++ b/templates/header.php @@ -0,0 +1,43 @@ + + + + + + Property Management System + + + + + + + + + + +
+ + + +
\ No newline at end of file diff --git a/users.php b/users.php new file mode 100644 index 0000000..a9645d0 --- /dev/null +++ b/users.php @@ -0,0 +1,43 @@ +query("SELECT * FROM users ORDER BY username ASC")->fetchAll(); + +include 'templates/header.php'; +?> + +
+

Manage Users

+ + Add New User + + + + + + + + + + + + + + + + + + +
UsernameRoleActions
+ Edit +
+ + +
+
+
+ +