diff --git a/public/assets/js/app.js b/public/assets/js/app.js index 594f52a..c2b3b7a 100644 --- a/public/assets/js/app.js +++ b/public/assets/js/app.js @@ -1,5 +1,3 @@ -// main.js - document.addEventListener('DOMContentLoaded', function() { const addBillForm = document.getElementById('addBillForm'); if (addBillForm) { @@ -8,37 +6,12 @@ document.addEventListener('DOMContentLoaded', function() { const formData = new FormData(this); axios.post('/api/add-bill', formData) .then(function(response) { - // Handle success, e.g., close modal, refresh bill list console.log('Bill added successfully'); - loadBills(); // Reload the bills list + loadBills(); }) .catch(function(error) { - // Handle error, e.g., display error message console.error('Error adding bill:', error); }); - - document.querySelectorAll('.edit-bill-btn').forEach(button => { - button.addEventListener('click', function() { - const billId = this.getAttribute('data-bill-id'); - // Fetch bill details and populate the form in the modal - // Then, handle the form submission similar to the add bill form - }); - }); - document.querySelectorAll('.delete-bill-btn').forEach(button => { - button.addEventListener('click', function() { - const billId = this.getAttribute('data-bill-id'); - axios.post('/api/delete-bill', { id: billId }) - .then(function(response) { - // Handle success - console.log('Bill deleted successfully'); - loadBills(); // Reload the bills list - }) - .catch(function(error) { - // Handle error - console.error('Error deleting bill:', error); - }); - }); - }); }); } @@ -46,17 +19,31 @@ document.addEventListener('DOMContentLoaded', function() { if (document.getElementById('billsTable')) { loadBills(); } -}); + // Event delegation for dynamically added "Mark as Paid" buttons + document.addEventListener('click', function(e) { + if (e.target && e.target.matches('.mark-bill-paid-btn')) { + const billId = e.target.getAttribute('data-bill-id'); + axios.post('/api/mark-bill-paid', { id: billId }) + .then(function(response) { + console.log('Bill marked as paid successfully'); + loadBills(); + }) + .catch(function(error) { + console.error('Error marking bill as paid:', error); + }); + } + }); +}); function loadBills() { const billsTableBody = document.querySelector('#billsTable tbody'); - billsTableBody.innerHTML = 'Loading bills...'; // Loading indicator + billsTableBody.innerHTML = 'Loading bills...'; axios.get('/api/bills') .then(function(response) { const bills = response.data; - billsTableBody.innerHTML = ''; // Clear loading indicator + billsTableBody.innerHTML = ''; bills.forEach(function(bill) { const row = ` @@ -65,7 +52,9 @@ function loadBills() { $${parseFloat(bill.amount).toFixed(2)} ${bill.due_date} - + ${bill.is_paid ? '' : ''} + + `; @@ -74,6 +63,6 @@ function loadBills() { }) .catch(function(error) { console.error('Error loading bills:', error); - billsTableBody.innerHTML = 'Error loading bills.'; // Error message + billsTableBody.innerHTML = 'Error loading bills.'; }); } diff --git a/public/index.php b/public/index.php index 91a135c..9cac678 100644 --- a/public/index.php +++ b/public/index.php @@ -1,181 +1,41 @@ register('GET', '/', [HomeController::class, 'index']); +// Auth Routes +$router->register('GET', '/login', [AuthController::class, 'showLoginForm']); +$router->register('POST', '/login', [AuthController::class, 'login']); +$router->register('GET', '/register', [AuthController::class, 'showRegistrationForm']); +$router->register('POST', '/register', [AuthController::class, 'register']); -switch ($request) { - case '/': - require __DIR__ . '/../views/home.php'; - break; - case '/login': - if ($_SERVER['REQUEST_METHOD'] === 'POST') { - $username = $_POST['username'] ?? ''; - $password = $_POST['password'] ?? ''; - - if (empty($username) || empty($password)) { - $error = 'Username and password are required.'; - require __DIR__ . '/../views/auth/login.php'; - break; - } - - $user = new \Hpz937\BillReminder\User\User($db); - if ($user->login($username, $password)) { - header('Location: /dashboard'); - exit; - } else { - $error = 'Login failed. Please check your credentials.'; - require __DIR__ . '/../views/auth/login.php'; - } - } else { - require __DIR__ . '/../views/auth/login.php'; - } - break; - - case '/register': - if ($_SERVER['REQUEST_METHOD'] === 'POST') { - // Extract form data - $username = $_POST['username'] ?? ''; - $password = $_POST['password'] ?? ''; - $email = $_POST['email'] ?? ''; - - // Perform validation (basic example) - if (empty($username) || empty($password) || empty($email)) { - // Handle validation error - $error = 'All fields are required.'; - require __DIR__ . '/../views/auth/register.php'; - break; - } - - // Instantiate User class and call register method - $user = new \Hpz937\BillReminder\User\User($db); // Assume $db is your DatabaseInterface instance - if ($user->register($username, $password, $email)) { - // Redirect to login on success - header('Location: /'); - exit; - } else { - // Handle registration error - $error = 'Registration failed. Please try again.'; - require __DIR__ . '/../views/auth/register.php'; - } - } else { - require __DIR__ . '/../views/auth/register.php'; - } - break; - - case '/dashboard': - if (!isset($_SESSION['user_id'])) { - header('Location: /login'); - exit; - } - require __DIR__ . '/../views/dashboard.php'; - break; - - case '/settings': - if (!isset($_SESSION['user_id'])) { - header('Location: /login'); - exit; - } - require __DIR__ . '/../views/settings.php'; - break; +// Dashboard Routes +$router->register('GET', '/dashboard', [DashboardController::class, 'viewDashboard']); +$router->register('GET', '/settings', [DashboardController::class, 'viewSettings']); - case '/api/bills': - if (!isset($_SESSION['user_id'])) { - // Return an error response if the user is not logged in - echo json_encode(['error' => 'Unauthorized']); - http_response_code(401); - exit; - } +// API Routes +$router->register('GET', '/api/bills', [ApiController::class, 'getBills']); +$router->register('POST', '/api/mark-bill-paid', [ApiController::class, 'markBillPaid']); +$router->register('POST', '/api/add-bill', [ApiController::class, 'addBill']); +$router->register('POST', '/api/edit-bill', [ApiController::class, 'editBill']); +$router->register('POST', '/api/delete-bill', [ApiController::class, 'deleteBill']); - // Initialize your database and Bill class instance - $db = new SQLiteAdapter(); - $billManager = new Bill($db); +// Resolve the current request +$requestMethod = $_SERVER['REQUEST_METHOD']; +$requestUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); - $userId = $_SESSION['user_id']; - $bills = $billManager->getBillsByUserId($userId); // Assuming $billManager is your Bill class instance - - // Return the bills as JSON - header('Content-Type: application/json'); - echo json_encode($bills); - break; - - case '/api/add-bill': - if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SESSION['user_id'])) { - // Extract bill details from POST data - $userId = $_SESSION['user_id']; // Assuming you store user ID in session upon login - $description = $_POST['description'] ?? ''; - $amount = $_POST['amount'] ?? ''; - $dueDate = $_POST['due_date'] ?? ''; - - // Validate the inputs... - - // Insert the bill into the database - $result = $billManager->addBill($userId, $dueDate, $amount, $description); - - if ($result) { - echo json_encode(['success' => 'Bill added successfully']); - } else { - http_response_code(500); - echo json_encode(['error' => 'Failed to add bill']); - } - exit; - } - break; - - case '/api/edit-bill': - if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SESSION['user_id'])) { - // Extract bill details and ID from POST data - $billId = $_POST['id'] ?? ''; - $description = $_POST['description'] ?? ''; - $amount = $_POST['amount'] ?? ''; - $dueDate = $_POST['due_date'] ?? ''; - - // Validate the inputs and ensure the bill belongs to the logged-in user... - - // Update the bill in the database - $result = $billManager->editBill($billId, $dueDate, $amount, $description); - - if ($result) { - echo json_encode(['success' => 'Bill updated successfully']); - } else { - http_response_code(500); - echo json_encode(['error' => 'Failed to update bill']); - } - exit; - } - break; - case '/api/delete-bill': - if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SESSION['user_id'])) { - // Extract bill ID from POST data - $billId = $_POST['id'] ?? ''; - - // Validate the ID and ensure the bill belongs to the logged-in user... - - // Delete the bill from the database - $result = $billManager->deleteBill($billId); - - if ($result) { - echo json_encode(['success' => 'Bill deleted successfully']); - } else { - http_response_code(500); - echo json_encode(['error' => 'Failed to delete bill']); - } - exit; - } - break; - - default: - http_response_code(404); - echo 'Page not found'; - break; -} +$router->resolve($requestMethod, $requestUri); diff --git a/src/Bill/Bill.php b/src/Bill/Bill.php index 6ce8842..6d59b24 100644 --- a/src/Bill/Bill.php +++ b/src/Bill/Bill.php @@ -61,7 +61,8 @@ class Bill $this->db->query($sql, $params); return true; } catch (Exception $e) { - // Handle or log the error appropriately + //log the error + var_dump($e->getMessage()); return false; } } diff --git a/src/Controller/ApiController.php b/src/Controller/ApiController.php new file mode 100644 index 0000000..9161226 --- /dev/null +++ b/src/Controller/ApiController.php @@ -0,0 +1,77 @@ +db = new SQLiteAdapter(); + } + + public function getBills() { + if (!isset($_SESSION['user_id'])) { + echo json_encode(['error' => 'Unauthorized']); + http_response_code(401); + exit; + } + + $billManager = new Bill($this->db); + $userId = $_SESSION['user_id']; + $bills = $billManager->getBillsByUserId($userId); + + header('Content-Type: application/json'); + echo json_encode($bills); + } + + public function addBill() { + if (!isset($_SESSION['user_id'])) { + echo json_encode(['error' => 'Unauthorized or Invalid Request']); + http_response_code(401); + return; + } + + $userId = $_SESSION['user_id']; + $description = $_POST['description'] ?? ''; + $amount = $_POST['amount'] ?? ''; + $dueDate = $_POST['due_date'] ?? ''; + + // Perform necessary validation on inputs + + $billManager = new Bill($this->db); + $result = $billManager->addBill($userId, $description, $amount, $dueDate); + + if ($result) { + echo json_encode(['success' => 'Bill added successfully']); + } else { + http_response_code(500); + echo json_encode(['error' => 'Failed to add bill']); + } + } + + public function markBillPaid() { + if (!isset($_SESSION['user_id'])) { + echo json_encode(['error' => 'Unauthorized or Invalid Request']); + http_response_code(401); + return; + } + + $json = json_decode(file_get_contents("php://input"), true); + $billId = $json['id'] ?? ''; + + // Perform necessary validation on inputs + + $billManager = new Bill($this->db); + $result = $billManager->markAsPaid($billId); + + if ($result) { + echo json_encode(['success' => 'Bill marked as paid']); + } else { + http_response_code(500); + echo json_encode(['error' => 'Failed to mark bill as paid']); + } + } +} diff --git a/src/Controller/AuthController.php b/src/Controller/AuthController.php new file mode 100644 index 0000000..ca97d25 --- /dev/null +++ b/src/Controller/AuthController.php @@ -0,0 +1,62 @@ +db = new SQLiteAdapter(); + } + + public function showLoginForm() { + require PROJECT_ROOT . '/views/auth/login.php'; + } + + public function login() { + $username = $_POST['username'] ?? ''; + $password = $_POST['password'] ?? ''; + + if (empty($username) || empty($password)) { + $error = 'Username and password are required.'; + require PROJECT_ROOT . '/views/auth/login.php'; + return; + } + + $user = new User($this->db); + if ($user->login($username, $password)) { + header('Location: /dashboard'); + exit; + } else { + $error = 'Login failed. Please check your credentials.'; + require PROJECT_ROOT . '/views/auth/login.php'; + } + } + + public function showRegistrationForm() { + require PROJECT_ROOT . '/views/auth/register.php'; + } + + public function register() { + $username = $_POST['username'] ?? ''; + $password = $_POST['password'] ?? ''; + $email = $_POST['email'] ?? ''; + + if (empty($username) || empty($password) || empty($email)) { + $error = 'All fields are required.'; + require PROJECT_ROOT . '/views/auth/register.php'; + return; + } + + $user = new User($this->db); + if ($user->register($username, $password, $email)) { + header('Location: /'); + exit; + } else { + $error = 'Registration failed. Please try again.'; + require PROJECT_ROOT . '/views/auth/register.php'; + } + } +} diff --git a/src/Controller/DashboardController.php b/src/Controller/DashboardController.php new file mode 100644 index 0000000..a616fda --- /dev/null +++ b/src/Controller/DashboardController.php @@ -0,0 +1,21 @@ +connection === null) { try { - $this->connection = new PDO('sqlite:' . __DIR__ . '/../../database.db'); - $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - } catch (PDOException $e) { + $this->connection = new SQLite3(__DIR__ . '/../../database.db'); + } catch (Exception $e) { // In a real application, you might want to use a more sophisticated error handling approach die("Connection error: " . $e->getMessage()); } @@ -24,17 +28,35 @@ class SQLiteAdapter implements DatabaseInterface return $this->connection; } + /** + * Query the database and return the result + * + * @param string $query + * @param array $params + * @return array|null + */ public function query(string $query, array $params = []) { $stmt = $this->connect()->prepare($query); - if (!$stmt->execute($params)) { - // Again, consider a more sophisticated error handling in a real application - die("Query error: " . implode(", ", $stmt->errorInfo())); + foreach ($params as $key => $value) { + // var_dump($key, $value); + $stmt->bindValue($key, $value); + } + + try { + // var_dump($stmt->getSQL(true)); + $result = $stmt->execute(); + } catch (Exception $e) { + die("Query error: " . $e->getMessage()); } if (preg_match('/^(SELECT|SHOW|PRAGMA)/i', $query)) { - return $stmt->fetchAll(PDO::FETCH_ASSOC); + $output = []; + while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + $output[] = $row; + } + return $output; } return null; diff --git a/src/Routing/Router.php b/src/Routing/Router.php new file mode 100644 index 0000000..4e39633 --- /dev/null +++ b/src/Routing/Router.php @@ -0,0 +1,26 @@ +routes[$method][$path] = $action; + } + + public function resolve($method, $uri) { + if (isset($this->routes[$method][$uri])) { + $action = $this->routes[$method][$uri]; + if (is_array($action)) { + list($class, $method) = $action; + return (new $class)->$method(); + } + } + + // Handle 404 Not Found + http_response_code(404); + echo 'Page not found'; + } +} + diff --git a/src/User/User.php b/src/User/User.php index 8735d82..91a1275 100644 --- a/src/User/User.php +++ b/src/User/User.php @@ -45,9 +45,9 @@ class User try { $user = $this->db->query($sql, $params); - if ($user && password_verify($password, $user[0]['password'])) { + if ($user && password_verify($password, $user['password'])) { // Set session or token here as per your session management strategy - $_SESSION['user_id'] = $user[0]['id']; + $_SESSION['user_id'] = $user['id']; return true; } return false; diff --git a/views/dashboard.php b/views/dashboard.php index a1a5078..9f4ed41 100644 --- a/views/dashboard.php +++ b/views/dashboard.php @@ -43,7 +43,7 @@ $content = function() { /* use ($bills) if fetching bills from the database */ -
+