diff --git a/css/style.css b/css/style.css index ff711d4..6fc0530 100644 --- a/css/style.css +++ b/css/style.css @@ -581,6 +581,9 @@ .mr-auto { margin-right: auto; } + .mb-0 { + margin-bottom: calc(var(--spacing) * 0); + } .mb-2 { margin-bottom: calc(var(--spacing) * 2); } @@ -608,6 +611,9 @@ .inline { display: inline; } + .inline-block { + display: inline-block; + } .inline-flex { display: inline-flex; } @@ -650,6 +656,12 @@ .resize { resize: both; } + .list-disc { + list-style-type: disc; + } + .list-none { + list-style-type: none; + } .grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } @@ -718,6 +730,9 @@ .bg-gray-300 { background-color: var(--color-gray-300); } + .bg-green-500 { + background-color: var(--color-green-500); + } .bg-red-300 { background-color: var(--color-red-300); } @@ -757,6 +772,15 @@ .py-2 { padding-block: calc(var(--spacing) * 2); } + .pb-1 { + padding-bottom: calc(var(--spacing) * 1); + } + .pl-0 { + padding-left: calc(var(--spacing) * 0); + } + .pl-5 { + padding-left: calc(var(--spacing) * 5); + } .text-2xl { font-size: var(--text-2xl); line-height: var(--tw-leading, var(--text-2xl--line-height)); @@ -765,6 +789,10 @@ font-size: var(--text-4xl); line-height: var(--tw-leading, var(--text-4xl--line-height)); } + .text-lg { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); + } .text-sm { font-size: var(--text-sm); line-height: var(--tw-leading, var(--text-sm--line-height)); @@ -781,6 +809,10 @@ --tw-font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium); } + .font-semibold { + --tw-font-weight: var(--font-weight-semibold); + font-weight: var(--font-weight-semibold); + } .text-gray-500 { color: var(--color-gray-500); } @@ -820,6 +852,13 @@ } } } + .hover\:bg-green-600 { + &:hover { + @media (hover: hover) { + background-color: var(--color-green-600); + } + } + } .hover\:bg-red-400 { &:hover { @media (hover: hover) { @@ -849,6 +888,11 @@ grid-template-columns: repeat(5, minmax(0, 1fr)); } } + .lg\:grid-cols-2 { + @media (width >= 64rem) { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } .lg\:grid-cols-4 { @media (width >= 64rem) { grid-template-columns: repeat(4, minmax(0, 1fr)); diff --git a/includes/api.php b/includes/api.php index 1edbec2..c715b84 100644 --- a/includes/api.php +++ b/includes/api.php @@ -18,18 +18,25 @@ try { switch($action) { case 'add': $data = [ - 'date' => (new DateTime($_POST['date']))->format('Y-m-d'), - 'payeeId' => $_POST['payeeId'], // Payee ID instead of name - 'amount' => (float)$_POST['amount'], + 'date' => (new DateTime($_POST['date']))->format('Y-m-d'), + 'payeeId' => $_POST['payeeId'], // Payee ID instead of name + 'amount' => (float)$_POST['amount'], 'paymentId' => $_POST['paymentId'], - 'comment' => $_POST['comment'] ?? '', - 'year' => (int)explode('-', $_POST['date'])[0] + 'comment' => $_POST['comment'] ?? '', + 'year' => (int)explode('-', $_POST['date'])[0] ]; + // Validate required fields + if (empty($data['date']) || empty($data['payeeId']) || $data['amount'] <= 0) { + echo json_encode(['error' => 'Missing required fields.']); + exit; + } + $stmt = DB::connect()->prepare(" INSERT INTO bills (billDate, payeeId, amount, paymentId, comment, year) VALUES (?, ?, ?, ?, ?, ?) "); + $result = $stmt->execute([ $data['date'], $data['payeeId'], @@ -49,27 +56,27 @@ try { $data = [ 'id' => $_POST['id'], 'date' => (new DateTime($_POST['date']))->format('Y-m-d'), - 'billName' => $_POST['billName'], + 'payeeId' => $_POST['payeeId'], 'amount' => (float)$_POST['amount'], 'paymentId' => $_POST['paymentId'], 'comment' => $_POST['comment'] ?? '' ]; // Validate required fields - if (empty($data['id']) || empty($data['date']) || empty($data['billName']) || $data['amount'] <= 0) { + if (empty($data['id']) || empty($data['date']) || empty($data['payeeId']) || $data['amount'] <= 0) { throw new MissingRequiredException('Missing required fields.'); } // Prepare and execute the update statement $stmt = DB::connect()->prepare(" UPDATE bills - SET billDate = ?, billName = ?, amount = ?, paymentId = ?, comment = ? + SET billDate = ?, payeeId = ?, amount = ?, paymentId = ?, comment = ? WHERE id = ? "); $result = $stmt->execute([ $data['date'], - $data['billName'], + $data['payeeId'], $data['amount'], $data['paymentId'], $data['comment'], @@ -93,9 +100,18 @@ try { case 'getById': $id = $_GET['id']; - $stmt = DB::connect()->prepare("SELECT * FROM bills WHERE id = ?"); + + $stmt = DB::connect()->prepare(" + SELECT bills.*, payees.name AS payeeName, payees.id AS payeeId + FROM bills + JOIN payees ON bills.payeeId = payees.id + WHERE bills.id = ? + "); $stmt->execute([$id]); - echo json_encode($stmt->fetch(PDO::FETCH_ASSOC)); + + $bill = $stmt->fetch(PDO::FETCH_ASSOC); + + echo json_encode($bill); break; case 'getTotals': @@ -150,6 +166,37 @@ try { } break; + case 'getYtdAmounts': + $year = $_GET['year'] ?? date('Y'); + + // Fetch YTD amounts for each payee + $stmt = DB::connect()->prepare(" + SELECT payees.name AS payeeName, SUM(bills.amount) AS totalAmount + FROM bills + JOIN payees ON bills.payeeId = payees.id + WHERE bills.year = ? + GROUP BY payees.name + ORDER BY payees.name ASC + "); + $stmt->execute([$year]); + $payeeAmounts = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Fetch overall YTD amount + $stmt = DB::connect()->prepare(" + SELECT SUM(amount) AS overallAmount + FROM bills + WHERE year = ? + "); + $stmt->execute([$year]); + + $overallAmount = $stmt->fetch(PDO::FETCH_ASSOC)['overallAmount'] ?? 0; + + echo json_encode([ + 'payeeAmounts' => $payeeAmounts, + 'overallAmount' => $overallAmount + ]); + break; + default: throw new InvalidActionException('Invalid action'); } diff --git a/index.php b/index.php index 5733fe0..9e66b91 100644 --- a/index.php +++ b/index.php @@ -18,13 +18,13 @@