Author: Pedro Lucas Porcellis <porcellis@eletrotupi.com>
bills: add new bills with filtering page
app/controllers/BillsController.php | 13 +++++ app/daos/BillDAO.php | 56 ++++++++++++++++++++++++ app/views/bills.php | 72 ++++++++++++++++++++++++++++++ app/views/layout.php | 1 config/routes.php | 6 ++
diff --git a/app/controllers/BillsController.php b/app/controllers/BillsController.php index 6a1d1a27cb81055d031f64ac8ac9f94285850f3b..fbafefe31c24055153b5629fbaa7b9fd836fd727 100644 --- a/app/controllers/BillsController.php +++ b/app/controllers/BillsController.php @@ -13,6 +13,19 @@ $this->billDAO = new BillDAO(); $this->tagDAO = new TagDAO(); } + public function index() { + $tags = $this->tagDAO->getAllTagsFromUser($_SESSION['user_id']); + + $bills = $this->billDAO->getBillsByTagIdWithinRange( + $_SESSION['user_id'], + $_GET['tag_id'] ?? null , + $_GET['start_date'] ?? null, + $_GET['end_date'] ?? null + ); + + return Template::render('bills', ['bills' => $bills, 'tags' => $tags]); + } + public function create() { $tags = $this->tagDAO->getAllTagsFromUser($_SESSION['user_id']); diff --git a/app/daos/BillDAO.php b/app/daos/BillDAO.php index 14480ac3137645249a28a284bbef4af72126bd08..5b57045bfeed168afda2718765641d2d6c1b5514 100644 --- a/app/daos/BillDAO.php +++ b/app/daos/BillDAO.php @@ -39,6 +39,62 @@ return $bills; } + public function getBillsByTagIdWithinRange($userId, $tagId, $startDate, $endDate) { + $sql = 'SELECT b.*, GROUP_CONCAT(t.name, ", ") AS tags + FROM bills b + LEFT JOIN bill_tags bt ON b.id = bt.bill_id + LEFT JOIN tags t ON bt.tag_id = t.id + WHERE b.user_id = :user_id'; + + if ($tagId) { + $sql .= ' AND b.id IN ( + SELECT bill_id FROM bill_tags WHERE tag_id = :tag_id + )'; + } + + if ($startDate) { + $sql .= ' AND b.due_date >= :start_date'; + } + + if ($endDate) { + $sql .= ' AND b.due_date <= :end_date'; + } + + $sql .= ' GROUP BY b.id ORDER BY b.due_date DESC'; + + $stmt = $this->db->prepare($sql); + if ($tagId) { + $stmt->bindValue(':tag_id', $tagId); + } + + if ($startDate) { + $stmt->bindValue(':start_date', $startDate); + } + + if ($endDate) { + $stmt->bindValue(':end_date', $endDate); + } + + $stmt->bindValue(':user_id', $userId); + $stmt->execute(); + + $bills = []; + + while ($billData = $stmt->fetch(PDO::FETCH_ASSOC)) { + $bills[] = new Bill( + $billData['id'], + $billData['title'], + $billData['amount'], + $billData['due_date'], + $billData['paid'], + $billData['user_id'], + $billData['tags'] + ); + } + + return $bills; + } + public function create(Bill $bill, $tagIds) { $this->db->beginTransaction(); diff --git a/app/views/bills.php b/app/views/bills.php new file mode 100644 index 0000000000000000000000000000000000000000..4dab882dbddd4ffd619bead59e5f13680d081c47 --- /dev/null +++ b/app/views/bills.php @@ -0,0 +1,72 @@ +<div class="container mx-auto mt-10"> + <div class="bg-white shadow-md rounded-lg p-6 mb-6"> + <form method="GET" action="/bills" class="flex flex-wrap gap-4"> + <div class="flex-1"> + <label for="start_date" class="block text-gray-700 text-sm font-bold mb-2">Data Inicial</label> + <input type="date" name="start_date" id="start_date" value="<?= htmlspecialchars($_GET['start_date'] ?? '') ?>" + class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-600"> + </div> + <div class="flex-1"> + <label for="end_date" class="block text-gray-700 text-sm font-bold mb-2">Data Final</label> + <input type="date" name="end_date" id="end_date" value="<?= htmlspecialchars($_GET['end_date'] ?? '') ?>" + class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-600"> + </div> + + <div class="flex-1"> + <label for="tag_id" class="block text-gray-700 text-sm font-bold mb-2">Tags</label> + <select name="tag_id" id="tag" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-600"> + <option value="">Todas as tags</option> + <?php foreach ($tags as $tag) : ?> + <option value="<?= $tag->getId() ?>" <?= (isset($_GET['tag_id']) && $_GET['tag_id'] == $tag->getId()) ? 'selected' : '' ?>> + <?= htmlspecialchars($tag->getName()) ?> + </option> + <?php endforeach; ?> + </select> + </div> + <div class="flex items-end"> + <button type="submit" class="bg-blue-600 text-white py-2 px-4 rounded hover:bg-blue-700"> + Filtrar + </button> + </div> + </form> + </div> + + <?php if (empty($bills)) : ?> + <div class="text-center py-10 bg-white rounded-lg shadow-md"> + <p class="text-xl text-gray-600">Nenhum gasto encontrado.</p> + <p class="text-gray-500 mt-2">Quem sabe tenta ajustar os filtros?</p> + </div> + <?php else : ?> + <div class="bg-white shadow-md rounded-lg overflow-hidden"> + <table class="min-w-full table-auto"> + <thead> + <tr class="bg-gray-200"> + <th class="py-3 px-6 text-left">Título</th> + <th class="py-3 px-6 text-left">Valor</th> + <th class="py-3 px-6 text-left">Vencimento</th> + <th class="py-3 px-6 text-left">Tags</th> + <th class="py-3 px-6 text-left">Pago?</th> + <th class="py-3 px-6 text-left">Ações</th> + </tr> + </thead> + <tbody> + <?php foreach ($bills as $bill) : ?> + <tr class="border-b"> + <td class="py-3 px-6"><?= htmlspecialchars($bill->getTitle()) ?></td> + <td class="py-3 px-6">R$ <?= number_format($bill->getAmount(), 2, ',', '.') ?></td> + <td class="py-3 px-6"><?= date('d/m/Y', strtotime($bill->getDueDate())) ?></td> + <td class="py-3 px-6"><?= htmlspecialchars($bill->getTags()) ?></td> + <td class="py-3 px-6"><?= $bill->isPaid() ? 'Sim' : 'Não' ?></td> + <td class="py-3 px-6 flex space-x-2"> + <a href="/bills/edit/<?= $bill->getId() ?>" class="text-yellow-600 hover:text-yellow-700">Editar</a> + <a href="/bills/delete/<?= $bill->getId() ?>" class="text-red-600 hover:text-red-700">Apagar</a> + </td> + </tr> + <?php endforeach; ?> + </tbody> + </table> + </div> + <?php endif; ?> +</div> +</div> + diff --git a/app/views/layout.php b/app/views/layout.php index 8a0b476d8b41a0670a50dc6beefa158ebe806eee..6db2a2ea2eeaef7a6fec31ab366b7a9109ca8f27 100644 --- a/app/views/layout.php +++ b/app/views/layout.php @@ -18,6 +18,7 @@ <? if (isset($_SESSION['user_id'])): ?> <nav class="max-w-4xl mx-auto px-4 py-2"> <a href="/tags" class="text-blue-700 mr-5">Tags</a> + <a href="/bills" class="text-blue-700 mr-5">Gastos</a> <a href="/logout" class="text-blue-700">Sair</a> </nav> <? endif; ?> diff --git a/config/routes.php b/config/routes.php index dfd8f161435c39ae55557cedc818fe1b59fae0c7..03883b1ff0f723d5c92fbea1978fb7a07e2d2bba 100644 --- a/config/routes.php +++ b/config/routes.php @@ -8,7 +8,7 @@ require_once '../app/controllers/BillsController.php'; require_once '../app/controllers/TagsController.php'; return function() { - $uri = trim($_SERVER['REQUEST_URI'], '/'); + $uri = explode('?', trim($_SERVER['REQUEST_URI'], '/'))[0]; $method = $_SERVER['REQUEST_METHOD']; // TODO: Meio burro isso @@ -34,6 +34,10 @@ // GET /dashboard } elseif ($uri === 'dashboard') { return (new DashboardController())->index(); + + // GET /bills + } elseif ($uri === 'bills' && $method === 'GET') { + return (new BillsController())->index(); // GET /bills/create } elseif ($uri === 'bills/create' && $method === 'GET') {