From 43f51e4e58b3ab75af56fed68c6535240908fd60 Mon Sep 17 00:00:00 2001 From: Sayan Das Date: Tue, 10 Feb 2026 13:46:39 +0530 Subject: [PATCH] initial commit --- ajax.js | 255 +++++++++++++++++++++++++++++++++++++++++++ bulk_delete.php | 7 ++ classes/database.php | 21 ++++ classes/record.php | 145 ++++++++++++++++++++++++ db.php | 14 +++ delete_record.php | 7 ++ edit_modal.php | 57 ++++++++++ fetch_records.php | 88 +++++++++++++++ formaction.php | 46 ++++++++ index.php | 114 +++++++++++++++++++ manage_records.css | 49 +++++++++ manage_records.php | 122 +++++++++++++++++++++ record.css | 138 +++++++++++++++++++++++ record.php | 131 ++++++++++++++++++++++ restore_record.php | 7 ++ status_update.php | 11 ++ style.css | 146 +++++++++++++++++++++++++ update_record.php | 37 +++++++ 18 files changed, 1395 insertions(+) create mode 100644 ajax.js create mode 100644 bulk_delete.php create mode 100644 classes/database.php create mode 100644 classes/record.php create mode 100644 db.php create mode 100644 delete_record.php create mode 100644 edit_modal.php create mode 100644 fetch_records.php create mode 100644 formaction.php create mode 100644 index.php create mode 100644 manage_records.css create mode 100644 manage_records.php create mode 100644 record.css create mode 100644 record.php create mode 100644 restore_record.php create mode 100644 status_update.php create mode 100644 style.css create mode 100644 update_record.php diff --git a/ajax.js b/ajax.js new file mode 100644 index 0000000..0a9e09d --- /dev/null +++ b/ajax.js @@ -0,0 +1,255 @@ +function showToast(message){ + + $("#toastMsg").text(message); + + let toast = new bootstrap.Toast(document.getElementById('liveToast')); + toast.show(); + +} + +$(document).ready(function(){ + + let currentPage = 1; + let currentSort = "id"; + let currentOrder = "desc"; + + function updateSortIcons(){ + + // reset all icons + $(".sort-icon") + .removeClass("bi-arrow-up bi-arrow-down") + .addClass("bi-arrow-down-up"); + + // set active icon + let icon = currentOrder === "asc" ? "bi-arrow-up" : "bi-arrow-down"; + + $(`.sort[data-column='${currentSort}'] .sort-icon`) + .removeClass("bi-arrow-down-up") + .addClass(icon); +} + + +/* ---------------- LOAD TABLE FUNCTION ---------------- */ +function loadData(status="", search="", page=currentPage) +{ + currentPage = page; + + + $.ajax({ + url: "fetch_records.php", + type: "GET", + data: { + status: status, + search: search, + page: page, + sort: currentSort, + order: currentOrder + }, + success: function(response) + { + $("#table-data").html(response); + if(bulkMode) + { + $(".select-column").removeClass("d-none"); + } + } + + }); +} + +/* ----------- CENTRAL RELOAD FUNCTION (IMPORTANT) ----------- */ +function reloadTable(){ + let status = $("#statusFilter").val(); + let search = $("#searchInput").val(); + loadData(status, search, currentPage); +} + +/* ----------- LOAD DATA WHEN PAGE OPENS ----------- */ +reloadTable(); + + +/* ---------------- STATUS FILTER ---------------- */ +$(document).on("change","#statusFilter",function(){ + currentPage = 1; + reloadTable(); +}); + + +/* ---------------- LIVE GLOBAL SEARCH ---------------- */ +$(document).on("keyup","#searchInput",function(){ + currentPage = 1; + reloadTable(); +}); + + +/* ---------------- CHANGE STATUS BUTTON ---------------- */ +$(document).on("click",".changeStatus",function(){ + + let id=$(this).data("id"); + + $.post("status_update.php",{id:id},function(){ + reloadTable(); + }); + +}); + + +/* ---------------- SELECT ALL ---------------- */ +$(document).on("click","#checkAll",function(){ + $(".rowcheck").prop("checked",this.checked); +}); + + +/* ---------------- DELETE SINGLE ---------------- */ +$(document).on("click",".deleteBtn",function(){ + + if(confirm("Delete this record?")){ + let id=$(this).data("id"); + + $.post("delete_record.php",{id:id},function(){ + reloadTable(); + }); + } + +}); + + +/* ---------------- OPEN EDIT MODAL ---------------- */ +$(document).on("click",".editBtn",function(){ + let id=$(this).data("id"); + + $("#editContent").load("edit_modal.php?id="+id,function(){ + $("#editModal").modal("show"); + }); +}); + + +/* ---------------- BULK DELETE ---------------- */ +$("#bulkDelete").click(function(){ + + let ids=[]; + $(".rowcheck:checked").each(function(){ + ids.push($(this).val()); + }); + + $.post("bulk_delete.php",{ids:ids},function(){ + reloadTable(); + }); + +}); + + + + +/* ---------------- UPDATE RECORD ---------------- */ +$(document).on("click","#updateRecord",function(){ + + let fields=[]; + $(".edit_field").each(function(){ + fields.push($(this).val()); + }); + + $.post("update_record.php",{ + id:$("#edit_id").val(), + name:$("#edit_name").val(), + email:$("#edit_email").val(), + phone:$("#edit_phone").val(), + category:$("#edit_category").val(), + description:$("#edit_description").val(), + fields:fields + },function(){ + + $("#editModal").modal("hide"); + reloadTable(); + + }); + + +}); + + +/* ---------------- ADD NEW FIELD ---------------- */ +$(document).on("click","#addField",function(){ + + $("#editFieldContainer").append(` +
+ + +
+ `); + +}); + + +/* ---------------- REMOVE FIELD ---------------- */ +$(document).on("click",".removeField",function(){ + $(this).closest(".fieldRow").remove(); +}); + +// RESTORE RECORD +$(document).on("click",".restoreBtn",function(){ + + let id=$(this).data("id"); + + $.post("restore_record.php",{id:id},function(){ + + reloadTable(); + showToast("Data restored successfully"); + + }); + +}); + +let bulkMode = false; + +$("#bulkToggle").click(function(){ + + bulkMode = !bulkMode; + + if(bulkMode){ + $(".select-column").removeClass("d-none"); + $("#bulkDelete").removeClass("d-none"); + $("#bulkToggle").text("Cancel Select"); + }else{ + $(".select-column").addClass("d-none"); + $("#bulkDelete").addClass("d-none"); + $(".rowcheck").prop("checked", false); + $("#checkAll").prop("checked", false); + $("#bulkToggle").text("Bulk Select"); + } + +}); + + +// PAGINATION CLICK +$(document).on("click",".page-btn",function(e){ + e.preventDefault(); + + let page=$(this).data("page"); + let status=$("#statusFilter").val(); + let search=$("#searchInput").val(); + currentPage = page; + loadData(status,search,page); +}); + +// SORT CLICK +$(document).on("click",".sort",function(){ + + let column=$(this).data("column"); + + if(currentSort==column){ + currentOrder = currentOrder=="asc" ? "desc":"asc"; + }else{ + currentSort=column; + currentOrder="asc"; + } + + currentPage=1; + reloadTable(); +}); + + + +}); + + diff --git a/bulk_delete.php b/bulk_delete.php new file mode 100644 index 0000000..d36bb76 --- /dev/null +++ b/bulk_delete.php @@ -0,0 +1,7 @@ + +bulkDelete($_POST['ids']); +?> diff --git a/classes/database.php b/classes/database.php new file mode 100644 index 0000000..1bbf011 --- /dev/null +++ b/classes/database.php @@ -0,0 +1,21 @@ +conn = new mysqli($this->host,$this->user,$this->pass,$this->db); + + if($this->conn->connect_error){ + die("Database Connection Failed"); + } + + return $this->conn; + } +} +?> diff --git a/classes/record.php b/classes/record.php new file mode 100644 index 0000000..d029bc8 --- /dev/null +++ b/classes/record.php @@ -0,0 +1,145 @@ +conn = $db->connect(); + } + + /* FETCH RECORDS WITH FILTER + SEARCH */ + public function getRecords($status="",$search="",$page=1,$perPage=10,$sort="id",$order="desc") + { + + $conditions = []; + + // status filter + if($status=="trash"){ + $conditions[]="is_deleted=1"; + }else{ + $conditions[]="is_deleted=0"; + if($status!=""){ + $status = $this->conn->real_escape_string($status); + $conditions[]="status='$status'"; + } + } + + // search filter + if($search!=""){ + $search = $this->conn->real_escape_string($search); + $conditions[]="( + CAST(id AS CHAR) LIKE '%$search%' OR + LOWER(name) LIKE LOWER('%$search%') OR + LOWER(email) LIKE LOWER('%$search%') OR + CAST(phone AS CHAR) LIKE '%$search%' + )"; + } + + $where = count($conditions)>0 ? "WHERE ".implode(" AND ",$conditions):""; + + $start = ($page - 1) * $perPage; + + $allowedSort = ["id","name","email","status"]; + + if(!in_array($sort,$allowedSort)) + { + $sort="id"; + } + + $order = strtolower($order)=="asc" ? "ASC":"DESC"; + + if($sort == "status"){ + if($order == "ASC"){ + // Inactive first, then Active + $orderBy = "FIELD(status,'inactive','active'), id DESC"; + }else{ + // Active first, then Inactive + $orderBy = "FIELD(status,'active','inactive'), id DESC"; + } +}else{ + $orderBy = "$sort $order"; +} + + + $sql="SELECT * FROM records $where ORDER BY $orderBy LIMIT $perPage OFFSET $start"; + + + return $this->conn->query($sql); + + } + + /* TOTAL PAGES */ +public function countFiltered($status="",$search=""){ + + $conditions = []; + + if($status=="trash"){ + $conditions[]="is_deleted=1"; + }else{ + $conditions[]="is_deleted=0"; + if($status!=""){ + $status = $this->conn->real_escape_string($status); + $conditions[]="status='$status'"; + } + } + + if($search!=""){ + $search = $this->conn->real_escape_string($search); + $conditions[]="( + CAST(id AS CHAR) LIKE '%$search%' OR + LOWER(name) LIKE LOWER('%$search%') OR + LOWER(email) LIKE LOWER('%$search%') OR + CAST(phone AS CHAR) LIKE '%$search%' + )"; + } + + $where = count($conditions)>0 ? "WHERE ".implode(" AND ",$conditions):""; + + $result = $this->conn->query("SELECT COUNT(*) as total FROM records $where"); + return $result->fetch_assoc()['total']; +} + + + /* SOFT DELETE */ + public function deleteRecord($id){ + $id = $this->conn->real_escape_string($id); + return $this->conn->query("UPDATE records SET is_deleted=1 WHERE id='$id'"); + } + + /* RESTORE RECORD */ + public function restoreRecord($id){ + $id = $this->conn->real_escape_string($id); + return $this->conn->query("UPDATE records SET is_deleted=0 WHERE id='$id'"); + } + + /* BULK DELETE */ + public function bulkDelete($ids){ + foreach($ids as $id){ + $this->deleteRecord($id); + } + } + + /* TOTAL RECORDS */ +public function countTotal(){ + $result = $this->conn->query("SELECT COUNT(*) as total FROM records WHERE is_deleted=0"); + return $result->fetch_assoc()['total']; +} + +/* ACTIVE RECORDS */ +public function countActive(){ + $result = $this->conn->query("SELECT COUNT(*) as active FROM records WHERE status='active' AND is_deleted=0"); + return $result->fetch_assoc()['active']; +} + +/* INACTIVE / PENDING RECORDS */ +public function countInactive(){ + $result = $this->conn->query("SELECT COUNT(*) as inactive FROM records WHERE status='inactive' AND is_deleted=0"); + return $result->fetch_assoc()['inactive']; +} + + +} +?> diff --git a/db.php b/db.php new file mode 100644 index 0000000..0709853 --- /dev/null +++ b/db.php @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/delete_record.php b/delete_record.php new file mode 100644 index 0000000..68985e4 --- /dev/null +++ b/delete_record.php @@ -0,0 +1,7 @@ + +deleteRecord($_POST['id']); +?> diff --git a/edit_modal.php b/edit_modal.php new file mode 100644 index 0000000..e7d4543 --- /dev/null +++ b/edit_modal.php @@ -0,0 +1,57 @@ + + + + + + + diff --git a/fetch_records.php b/fetch_records.php new file mode 100644 index 0000000..f3343b3 --- /dev/null +++ b/fetch_records.php @@ -0,0 +1,88 @@ +getRecords($status,$search,$page,10,$sort,$order); +$totalRows = $record->countFiltered($status,$search); +$perPage = 10; +$totalPages = ceil($totalRows/$perPage); + + +while($row=$result->fetch_assoc()){ +?> + + + + + + + + + + + + + +"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +$('#pagination-area').html(` + +`); +"; +?> diff --git a/formaction.php b/formaction.php new file mode 100644 index 0000000..ed20f0c --- /dev/null +++ b/formaction.php @@ -0,0 +1,46 @@ + + alert('Record Saved Successfully'); + window.location='record.php'; + "; + } + else + { + echo "Error: " . mysqli_error($conn); + } +} +?> diff --git a/index.php b/index.php new file mode 100644 index 0000000..0e84ecd --- /dev/null +++ b/index.php @@ -0,0 +1,114 @@ +countTotal(); +$activeRecord = $record->countActive(); +$inactiveRecord = $record->countInactive(); + +?> + + + + + + + + CRUD Manager + + + + + + + + + + + + + + + +
+
+

CRUD Manager

+

+ Efficiently manage, create, edit, and organize all your records in one powerful dashboard. + Track status, monitor activity, and maintain complete control over your data. +

+ + +
+
+ + +
+
+ +
+
+

Total Records

+

+ +
+
+ +
+
+

Active

+

+ +
+
+ +
+
+

Pending

+

+ +
+
+ + + +
+
+ + + diff --git a/manage_records.css b/manage_records.css new file mode 100644 index 0000000..fef7f70 --- /dev/null +++ b/manage_records.css @@ -0,0 +1,49 @@ +/* Status filter styled like button */ +.status-filter { + border-radius: 8px !important; + border: 1px solid #dee2e6 !important; + padding: 6px 30px 6px 12px !important; + font-weight: 500; + cursor: pointer; + background-color: #fff; + transition: all 0.2s ease; +} + +.status-filter:hover { + border-color: #adb5bd !important; + box-shadow: 0 0 0 0.15rem rgba(0,0,0,0.05); +} + +.status-filter:focus { + border-color: #212529 !important; + box-shadow: 0 0 0 0.15rem rgba(0,0,0,0.1) !important; +} + +.status-filter.form-select-sm { + height: 38px; +} +/* space between action buttons */ +td .btn{ + margin-right:15px; + margin-bottom:10px; +} + +/* remove space from last button */ +td .btn:last-child{ + margin-right:0; +} + +/* make sortable headers look clickable */ +th.sort{ + cursor: pointer; +} + +.sort-icon{ + margin-left:6px; + font-size:13px; + color:#9aa4b2; +} + +.sort:hover .sort-icon{ + color:#ffffff; +} diff --git a/manage_records.php b/manage_records.php new file mode 100644 index 0000000..b5ef3c4 --- /dev/null +++ b/manage_records.php @@ -0,0 +1,122 @@ + + + + +Manage Records + + + + + + + + + + + +
+ +
+ + +
+

All Records

+ + + + + +
+ + + + +
+ + + Home + + + + Add Record + + + +
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ ID + + Name + + Email +Phone + Status +Action
+
+ + + + + + + + + + +
+ +
+ + + + diff --git a/record.css b/record.css new file mode 100644 index 0000000..ad43bf2 --- /dev/null +++ b/record.css @@ -0,0 +1,138 @@ +*{ + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Segoe UI' , sans-serif; +} + +.padding { + padding: 0; +} + + +.custom-navbar{ + + background-color:#e5d696; + box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.04); + padding: 8px 40px; + + +} + +/* LOGO */ +.logo { + display: flex; + align-items: center; + font-weight: bold; + margin-left: 0; +} + +.logo-icon { + background: rgb(105, 99, 222); + color: white; + padding: 8px 12px; + border-radius: 8px; + margin-right: 8px; + font-weight : bold; +} + +/* Search */ +.search-area { + width: 350px; + position: relative; + margin: 0 auto; +} + +.search-box { + width: 100%; + padding: 8px 15px 8px 40px; + border-radius: 20px; + border: 1px solid #ccc; + background-color: #fffbe9; +} + +.search-icon { + position: absolute; + top: 50%; + left: 15px; + transform: translateY(-50%); + color: #999; + font-size: 15px; +} + +/* Navbar links */ +.nav-links { + display: flex; + align-items: center; + gap: 15px; +} + +.profile { + width:36px; + height:36px; + background: violet; + color: white; + border-radius: 50%; + display:flex; + align-items:center; + justify-content:center; +} + + + + + +/* Responsive */ +@media (max-width: 992px) { + .search-area { + display: none; + } +} + +/* FORM AREA */ +.form-container{ + display: flex; + justify-content: center; + margin-top: 60px; +} + +.card{ + background: #fff; + width: 70%; + padding: 30px; + border-radius: 12px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); +} + +.card h5{ + font-weight: 600; +} + +.card label{ + font-weight: 500; + margin-bottom: 6px; +} + +.form-control { + background: #f8f9fa; + border: 1px solid #e0e0e0; +} + +.form-control:focus{ + box-shadow: none; + border-color: #000; +} + + +.form-action{ + display:flex; + justify-content: flex-end; + gap: 15px; +} + +.form-action .btn{ + min-width:130px; + height: 42px; + font-size: 14px; + font-weight: 500; +} diff --git a/record.php b/record.php new file mode 100644 index 0000000..c1b2193 --- /dev/null +++ b/record.php @@ -0,0 +1,131 @@ + + + + + + Document + + + + + + + + + + + +
+
+
Create New Record
+

Fill in the form below to create a new record

+ +
+
+
+ + +
+
+
+ +
+
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+ +
+
+
+
Additional Fields
+

Add multiple rows of custom data

+ + + +
+
+ + + +
+
+ + +
+
+
+ + +
+ +
+
+ + \ No newline at end of file diff --git a/restore_record.php b/restore_record.php new file mode 100644 index 0000000..95eb83a --- /dev/null +++ b/restore_record.php @@ -0,0 +1,7 @@ + +restoreRecord($_POST['id']); +?> diff --git a/status_update.php b/status_update.php new file mode 100644 index 0000000..fd2544d --- /dev/null +++ b/status_update.php @@ -0,0 +1,11 @@ + diff --git a/style.css b/style.css new file mode 100644 index 0000000..cb00194 --- /dev/null +++ b/style.css @@ -0,0 +1,146 @@ +:root { + --bs-body-bg: #ffffff; +} + +html, body { + background: #ffffff; +} + +body { + background-color: #ffffff; + font-family: Arial, sans-serif; +} + + + +.padding { + padding: 0; +} + +.navbar { + display: flex; + align-items: center; + justify-content: space-between; + background-color:#ffffff; + box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.04); + padding: 12px 25px; + min-height: 65px; + + + } + + +.logo { + display: flex; + align-items: center; + font-weight: bold; + margin-left: 150px; +} + +.logo-icon { + background: rgb(105, 99, 222); + color: white; + padding: 8px 12px; + border-radius: 8px; + margin-right: 8px; +} + +/* Search */ +.search-area { + width: 35%; + position: relative; +} + +.search-box { + width: 40%; + padding: 8px 15px 8px 40px; + border-radius: 20px; + border: 1px solid #ccc; + background-color: #ffffff; +} + +.search-icon { + position: absolute; + top: 50%; + left: 15px; + transform: translateY(-50%); + color: #999; + font-size: 15px; +} + + +/* Navbar links */ +.nav-links { + display: flex; + align-items: center; + gap: 15px; +} + +.profile { + background: violet; + color: white; + padding: 8px 10px; + border-radius: 50%; +} + +/* Main Card */ +.top-space { + margin-top: 40px; +} + +.main-card { + background: #ffffff; + padding: 40px; + text-align: center; + border-radius: 15px; + box-shadow: 0px 8px 25px rgba(0, 0, 0, 0.12); +} + +.button-group { + margin-top: 20px; + display: flex; + justify-content: center; + gap: 15px; +} + +/* Statistics */ +.stat-box { + background: #ffffff; + padding: 25px; + border-radius: 12px; + position: relative; + box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.12); +} + +.stat-box i { + position: absolute; + top: 20px; + right: 20px; + font-size: 22px; +} +.icon-blue { + color: rgb(105, 99, 222); +} +.search-area { + width: 35%; +} + +/* Records button */ +.nav-link-btn { + text-decoration: none; + padding: 8px 18px; + border-radius: 20px; + color: black; + font-weight: 500; +} + +.nav-link-btn:hover { + background-color: #eee; +} + +/* Make navbar responsive */ +@media (max-width: 992px) { + .search-area { + display: none; + } +} diff --git a/update_record.php b/update_record.php new file mode 100644 index 0000000..9c82f5d --- /dev/null +++ b/update_record.php @@ -0,0 +1,37 @@ +