From 3b0daa72e40b074596b925b6c9557de4199790f1 Mon Sep 17 00:00:00 2001 From: Myron Blair Date: Fri, 22 May 2026 21:52:56 +0000 Subject: [PATCH] Add customers CRUD section to admin panel --- admin/index.php | 238 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 236 insertions(+), 2 deletions(-) diff --git a/admin/index.php b/admin/index.php index d3aaae1..23a0a40 100644 --- a/admin/index.php +++ b/admin/index.php @@ -241,6 +241,36 @@ if ($isAjax) { echo json_encode(['ok'=>true]); exit; } + + if ($action === 'customer_save') { + $cid = (int)($_POST['id'] ?? 0); + $name = substr(trim($_POST['name'] ?? ''), 0, 150); + $email = trim($_POST['email'] ?? ''); + $phone = substr(trim($_POST['phone'] ?? ''), 0, 30); + $dob = preg_match('/^\d{4}-\d{2}-\d{2}$/', $_POST['dob'] ?? '') ? $_POST['dob'] : null; + $addr = substr(trim($_POST['address'] ?? ''), 0, 500); + $notes = substr(trim($_POST['notes'] ?? ''), 0, 1000); + $active = (int)($_POST['is_active'] ?? 1); + if (!$name || !filter_var($email, FILTER_VALIDATE_EMAIL)) { + echo json_encode(['error' => 'Name and valid email are required']); exit; + } + if ($cid) { + db()->prepare("UPDATE pcs_customers SET name=?,email=?,phone=?,dob=?,address=?,notes=?,is_active=? WHERE id=?") + ->execute([$name,$email,$phone,$dob,$addr,$notes,$active,$cid]); + } else { + db()->prepare("INSERT INTO pcs_customers (name,email,phone,dob,address,notes,is_active) VALUES (?,?,?,?,?,?,?)") + ->execute([$name,$email,$phone,$dob,$addr,$notes,1]); + $cid = (int)db()->lastInsertId(); + } + echo json_encode(['ok'=>true,'id'=>$cid]); exit; + } + + if ($action === 'customer_delete') { + $cid = (int)($_POST['id'] ?? 0); + if ($cid) db()->prepare("DELETE FROM pcs_customers WHERE id=?")->execute([$cid]); + echo json_encode(['ok'=>true]); exit; + } + exit; } @@ -285,8 +315,13 @@ button:hover{background:#ea580c} query("SELECT * FROM bookings ORDER BY rental_date ASC, created_at DESC")->fetchAll(); -$blocked = db()->query("SELECT * FROM blocked_dates ORDER BY block_date ASC")->fetchAll(); +$bookings = db()->query("SELECT * FROM bookings ORDER BY rental_date ASC, created_at DESC")->fetchAll(); +$blocked = db()->query("SELECT * FROM blocked_dates ORDER BY block_date ASC")->fetchAll(); +$customers = db()->query(" + SELECT c.*, + (SELECT COUNT(*) FROM bookings WHERE email=c.email) AS booking_count + FROM pcs_customers c ORDER BY c.created_at DESC +")->fetchAll(); $stats = db()->query(" SELECT @@ -413,6 +448,21 @@ textarea.notes-ta:focus{border-color:#f97316} .del-btn{background:none;border:none;color:#dc2626;cursor:pointer;font-size:1rem;padding:0;line-height:1} @media(max-width:700px){.main{padding:1rem}.stat-val{font-size:1.5rem}} + +/* Customer card */ +.cust-search{border:1px solid #e5e7eb;border-radius:6px;padding:.45rem .75rem;font-size:.875rem;width:100%;max-width:280px} +.cust-form{background:#f9fafb;border-top:1px solid #f3f4f6;padding:1.25rem 1.5rem;display:none} +.cust-form.open{display:block} +.cust-form .fg{display:grid;grid-template-columns:1fr 1fr;gap:.75rem;margin-bottom:.75rem} +@media(max-width:600px){.cust-form .fg{grid-template-columns:1fr}} +.cust-form label{font-size:.78rem;color:#6b7280;display:block;margin-bottom:.2rem} +.cust-form input,.cust-form textarea{width:100%;border:1px solid #e5e7eb;border-radius:6px;padding:.45rem .65rem;font-size:.875rem;font-family:inherit;outline:none} +.cust-form input:focus,.cust-form textarea:focus{border-color:#f97316} +.cust-form textarea{resize:vertical;min-height:60px} +.cust-form .form-actions{display:flex;gap:.5rem;margin-top:.75rem} +.cust-badge{display:inline-block;padding:.15rem .5rem;border-radius:999px;font-size:.7rem;font-weight:700} +.cust-active{background:#dcfce7;color:#15803d} +.cust-inactive{background:#f3f4f6;color:#9ca3af} @@ -784,6 +834,93 @@ textarea.notes-ta:focus{border-color:#f97316} + +
+
+

Customers

+
+ + +
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ +
+ + +
No customers yet.
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameEmailPhoneDOBBookingsStatusAdded
+ + +
+
+ +
+