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
+
+
+
= htmlspecialchars($error) ?>
+
+
+
+
+
+
+
+
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';
+?>
+
+
+
+
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
+
+
+
+
+
+
+
+ Property
+
+ Select Property
+
+
+
+
+
+
+ Tenant (Optional)
+
+ Select Tenant
+
+
+
+
+
+
+ Description
+
+
+
+ Reported Date
+
+
+
+ Status
+
+ Open
+ In Progress
+ Closed
+
+
+ Add 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
+
+
+
+
+
+ Full Name
+
+
+
+
+ Assign to Property
+
+ None
+
+
+
+
+
+
+
+
+
+
+ Status
+
+ Active
+ Inactive
+ Moved Out
+
+
+
+ Upload Document
+
+
+ Add 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
+
+
+
+
+
+
+
+ Username
+
+
+
+ Password
+
+
+
+ Role
+
+ User
+ Admin
+
+
+ Add 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
+
+
+
= htmlspecialchars($error) ?>
+
+
+
+
+
+
+ Property
+
+
+ >= htmlspecialchars($property['name']) ?>
+
+
+
+
+ Tenant
+
+
+ >= htmlspecialchars($tenant['name']) ?>
+
+
+
+
+
+ Payment Date
+
+
+
+ Notes
+ = htmlspecialchars($payment['notes']) ?>
+
+
+ Upload New Document
+
+
+ Update 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
+
+
+
+
+
+
+
+
+
+ Property Name
+
+
+
+ Address
+
+
+
+ Rent Amount ($)
+
+
+
+
+ Upload New File
+
+
+
+ Save Changes
+ 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
+
+
+
+
+
+
+
+ Property
+
+ Select Property
+
+ >
+
+
+
+
+ Tenant (Optional)
+
+ Select Tenant
+
+ >
+
+
+
+
+ Description
+
+
+
+ Reported Date
+
+
+
+ Completed Date
+
+
+
+ Status
+
+ >Open
+ >In Progress
+ >Closed
+
+
+ Update 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
+
+
+
+
+
+
+ Full Name
+
+
+
+
+ Assign to Property
+
+ None
+
+ >
+
+
+
+
+
+
+
+
+ Status
+
+ >Active
+ >Inactive
+ >Moved Out
+
+
+
+ Upload New Document
+
+
+ Save Changes
+ 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
+
+
+
+
+
+
+
+ Username
+
+
+
+ Password (leave blank to keep current password)
+
+
+
+ Role
+
+ >User
+ >Admin
+
+
+ Update 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…
-
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
+
+
+
+ = $success_message ?>
+
+
+ = $error_message ?>
+
+
+
+
+
+
+
+
Dashboard
+
+
+
+
+
+
Total Properties
+
= $total_properties ?? 0 ?>
+
+
+
+
+
+
+
Total Tenants
+
= $total_tenants ?? 0 ?>
+
+
+
+
+
+
+
Maintenance Requests
+
= $total_requests ?? 0 ?>
+
+
+
+
+
+
+
Total Payments
+
$= number_format($total_payments ?? 0, 2) ?>
+
+
+
+
+
+
+
+
+
+
Monthly Payments (Current Year)
+
+
+
+
+
+
+
+
Maintenance Requests Status
+
+
+
+
+
+
+
+
+
+
Properties
+
+
Add New Property
+
+
+
+
+
+
+
+ Name
+ Address
+ Rent
+ Actions
+
+
+
+
+
+
+
+ $
+
+ Edit
+
+
+
+ Delete
+
+
+
+
+
+
+ No properties found.
+
+
+
+
+
+
+
+
+
+
Tenants
+
+
Add New Tenant
+
+
+
+
+
+
+
+ Name
+ Email
+ Property
+ Lease End
+ Status
+ Actions
+
+
+
+
+
+
+
+
+
+
+
+ Edit
+
+
+
+ Delete
+
+
+
+
+
+
+ No tenants found.
+
+
+
+
+
+
+
+
+
+
Payments
+
+
Add New Payment
+
+
+
+
+
+
+
+ Tenant
+ Property
+ Amount
+ Payment Date
+ Actions
+
+
+
+
+
+ = htmlspecialchars($payment['tenant_name']) ?>
+ = htmlspecialchars($payment['property_name']) ?>
+ $= htmlspecialchars(number_format($payment['amount'], 2)) ?>
+ = htmlspecialchars($payment['payment_date']) ?>
+
+ Edit
+
+
+
+ Delete
+
+
+
+
+
+
+ No payments found.
+
+
+
+
+
+
+
+
+
+
Maintenance Requests
+
Add New Request
+
+
+
+
+
+
+ Property
+ Tenant
+ Description
+ Status
+ Reported Date
+ Actions
+
+
+
+
+
+
+
+
+
+
+
+
+ Edit
+
+
+
+ Delete
+
+
+
+
+
+
+ No maintenance requests found.
+
+
+
+
+
+
+
-
-
- Page updated: = htmlspecialchars($now) ?> (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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Username
+
+
+
+ Password
+
+
+ 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
+
+
+
+
+ Name
+ Address
+ Rent Amount
+ Actions
+
+
+
+
+
+
+
+ $
+
+ Edit
+
+
+ Delete
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+