From d770613286bf1b4f5b6c694123239acf8ee298b1 Mon Sep 17 00:00:00 2001 From: rowell_m_soriano Date: Thu, 12 Mar 2026 16:03:02 +0800 Subject: [PATCH] Backend pagination for Item, Pr Tracking, approved pr, Deleted PR --- .../Controllers/PR/PRMgmtController.cs | 23 +- .../Controllers/Items/ItemMgmtController.cs | 22 +- .../Controllers/PR/PRMgmtController.cs | 137 +++++++++- CPRNIMS.WebApps/ViewComponents/PR/PRTabbed.cs | 2 +- .../PRMgmt/PRTabbedTable/AllPR.cshtml | 175 +++++++----- .../PRMgmt/PRTabbedTable/ApprovedPR.cshtml | 252 +++++++++--------- .../PRMgmt/PRTabbedTable/DeletedPR.cshtml | 163 +++++++++++ .../PRMgmt/PRTabbedTable/RemovedPR.cshtml | 164 ------------ CPRNIMS.WebApps/Views/ItemMgmt/Index.cshtml | 29 +- .../Views/PRMgmt/DeniedItem.cshtml | 2 - CPRNIMS.WebApps/Views/PRMgmt/Index.cshtml | 26 +- .../Views/PRMgmt/PRArchived.cshtml | 55 +++- .../Views/PRMgmt/PRTracking.cshtml | 74 ++++- .../Shared/PagesView/Item/_Scripts.cshtml | 3 +- .../Shared/PagesView/PO/_POScripts.cshtml | 2 +- .../Shared/PagesView/PR/_PRScripts.cshtml | 8 +- .../Shared/PagesView/PR/_Receiving.cshtml | 3 +- ...temManagementV7.js => ItemManagementV8.js} | 91 +++---- .../JsFunctions/PO/{ApiV4.js => ApiV5.js} | 0 .../wwwroot/JsFunctions/PR/ArchivedV2.js | 42 --- .../wwwroot/JsFunctions/PR/ArchivedV3.js | 80 ++++++ .../PR/{Configv6.js => ConfigV7.js} | 4 + .../JsFunctions/PR/DetailedPRTrackingV7.js | 106 -------- .../JsFunctions/PR/DetailedPRTrackingV8.js | 92 +++++++ .../wwwroot/JsFunctions/PR/{PRV9.js => PR.js} | 25 +- .../PR/{PRColumnV8.js => PRColumnV9.js} | 139 +++++++--- .../wwwroot/JsFunctions/PR/PRTabs.js | 17 +- .../PR/{PRViewV8.js => PRViewV9.js} | 160 +++++++---- .../JsFunctions/Utilities/ExportCSVExcel.js | 91 +++++++ .../Utilities/SearchEngine - Copy.js | 232 ---------------- CPRNIMS.WebApps/wwwroot/css/Item/Item.css | 74 +++++ 31 files changed, 1325 insertions(+), 968 deletions(-) create mode 100644 CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/DeletedPR.cshtml delete mode 100644 CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/RemovedPR.cshtml rename CPRNIMS.WebApps/wwwroot/JsFunctions/Items/{ItemManagementV7.js => ItemManagementV8.js} (57%) rename CPRNIMS.WebApps/wwwroot/JsFunctions/PO/{ApiV4.js => ApiV5.js} (100%) delete mode 100644 CPRNIMS.WebApps/wwwroot/JsFunctions/PR/ArchivedV2.js create mode 100644 CPRNIMS.WebApps/wwwroot/JsFunctions/PR/ArchivedV3.js rename CPRNIMS.WebApps/wwwroot/JsFunctions/PR/{Configv6.js => ConfigV7.js} (81%) delete mode 100644 CPRNIMS.WebApps/wwwroot/JsFunctions/PR/DetailedPRTrackingV7.js create mode 100644 CPRNIMS.WebApps/wwwroot/JsFunctions/PR/DetailedPRTrackingV8.js rename CPRNIMS.WebApps/wwwroot/JsFunctions/PR/{PRV9.js => PR.js} (90%) rename CPRNIMS.WebApps/wwwroot/JsFunctions/PR/{PRColumnV8.js => PRColumnV9.js} (59%) rename CPRNIMS.WebApps/wwwroot/JsFunctions/PR/{PRViewV8.js => PRViewV9.js} (88%) create mode 100644 CPRNIMS.WebApps/wwwroot/JsFunctions/Utilities/ExportCSVExcel.js delete mode 100644 CPRNIMS.WebApps/wwwroot/JsFunctions/Utilities/SearchEngine - Copy.js create mode 100644 CPRNIMS.WebApps/wwwroot/css/Item/Item.css diff --git a/CPRNIMS.WebApi/Controllers/PR/PRMgmtController.cs b/CPRNIMS.WebApi/Controllers/PR/PRMgmtController.cs index ff3130e..af6f3b6 100644 --- a/CPRNIMS.WebApi/Controllers/PR/PRMgmtController.cs +++ b/CPRNIMS.WebApi/Controllers/PR/PRMgmtController.cs @@ -2,19 +2,13 @@ using CPRNIMS.Domain.Contracts.PR; using CPRNIMS.Domain.Services; using CPRNIMS.Infrastructure.Dto.Items; -using CPRNIMS.Infrastructure.Dto.PO; using CPRNIMS.Infrastructure.Dto.PR; -using CPRNIMS.Infrastructure.Entities.PO; -using CPRNIMS.Infrastructure.Entities.Purchasing; using CPRNIMS.Infrastructure.Helper; using CPRNIMS.Infrastructure.Models.Common; using CPRNIMS.Infrastructure.ViewModel.Common; using CPRNIMS.Infrastructure.ViewModel.PR; using CPRNIMS.WebApi.Controllers.Base; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; -using System.Reflection.Metadata.Ecma335; using System.Text; @@ -377,6 +371,15 @@ namespace CPRNIMS.WebApi.Controllers.PR nameof(GetAllPR), false ); } + [HttpPost("GetPRArchived")] + public async Task GetPRArchived(PRDto PRDto) + { + return await ExecuteWithErrorHandling( + () => _pRequest.GetPRArchived(PRDto), + nameof(GetPRArchived), false + ); + } + [HttpPost("GetApprovedPR")] public async Task GetApprovedPR(PRDto PRDto) { @@ -385,12 +388,12 @@ namespace CPRNIMS.WebApi.Controllers.PR nameof(GetApprovedPR), false ); } - [HttpPost("GetRemovedPR")] - public async Task GetRemovedPR(PRDto PRDto) + [HttpPost("GetDeletedPR")] + public async Task GetDeletedPR(PRDto PRDto) { return await ExecuteWithErrorHandling( - () => _pRequest.GetRemovedPR(PRDto), - nameof(GetRemovedPR), false + () => _pRequest.GetDeletedPR(PRDto), + nameof(GetDeletedPR), false ); } [HttpPost("GetMyPR")] diff --git a/CPRNIMS.WebApps/Controllers/Items/ItemMgmtController.cs b/CPRNIMS.WebApps/Controllers/Items/ItemMgmtController.cs index b965084..77a7ae1 100644 --- a/CPRNIMS.WebApps/Controllers/Items/ItemMgmtController.cs +++ b/CPRNIMS.WebApps/Controllers/Items/ItemMgmtController.cs @@ -326,11 +326,25 @@ namespace CPRNIMS.WebApps.Controllers.Items throw; } } - public async Task GetItemList() + [HttpGet] + public async Task GetItemList(string searchTerm = "", int pageNumber = 1, int pageSize = 10) { - var viewModels = new ItemVM(); - response = await _item.GetItemList(GetUser(), viewModels); - return GetResponse(response); + var viewModel = new ItemVM + { + SearchTerm = searchTerm, + PageNumber = pageNumber, + PageSize = pageSize + }; + + var result = await _item.GetItemList(GetUser(), viewModel); + + return Json(new + { + draw = Request.Query["draw"].ToString(), + recordsTotal = result.TotalCount, + recordsFiltered = result.TotalCount, + data = result.Data + }); } public async Task GetItemCateg(ItemVM viewModels) { diff --git a/CPRNIMS.WebApps/Controllers/PR/PRMgmtController.cs b/CPRNIMS.WebApps/Controllers/PR/PRMgmtController.cs index 274a33f..5a49802 100644 --- a/CPRNIMS.WebApps/Controllers/PR/PRMgmtController.cs +++ b/CPRNIMS.WebApps/Controllers/PR/PRMgmtController.cs @@ -21,20 +21,134 @@ namespace CPRNIMS.WebApps.Controllers.PR _pRequest = pRequest; } #region Get - public async Task GetAllPR(PRVM viewModels) + [HttpGet] + public async Task GetAllPR( + string searchPRNo = "", string searchItemName = "", + string searchDept = "", int pageNumber = 1, int pageSize = 10) { - response = await _pRequest.GetAllPR(GetUser(), viewModels); - return GetResponse(response); + var dto = new PRVM + { + SearchPRNo = searchPRNo, + SearchItemName = searchItemName, + SearchDept = searchDept, + PageNumber = pageNumber, + PageSize = pageSize + }; + + var result = await _pRequest.GetAllPR(GetUser(),dto); + int draw = int.TryParse(Request.Query["draw"], out int d) ? d : 1; + + return Json(new + { + draw = draw, + recordsTotal = result.TotalCount, + recordsFiltered = result.TotalCount, + data = result.Data + }); } - public async Task GetApprovedPR(PRVM viewModels) + [HttpGet] + public async Task GetPRArchived( + string searchPRNo = "", string searchItemName = "", + string searchDept = "", int pageNumber = 1, int pageSize = 10) { - response = await _pRequest.GetApprovedPR(GetUser(), viewModels); - return GetResponse(response); + var dto = new PRVM + { + SearchPRNo = searchPRNo, + SearchItemName = searchItemName, + SearchDept = searchDept, + PageNumber = pageNumber, + PageSize = pageSize + }; + + var result = await _pRequest.GetPRArchived(GetUser(), dto); + int draw = int.TryParse(Request.Query["draw"], out int d) ? d : 1; + + return Json(new + { + draw = draw, + recordsTotal = result.TotalCount, + recordsFiltered = result.TotalCount, + data = result.Data + }); } - public async Task GetRemovedPR(PRVM viewModels) + public async Task GetDetailedPRTracking( + string searchPRNo = "", string searchItemName = "", string searchDept = "", string searchStatusName = "", + int pageNumber = 1, int pageSize = 10) { - response = await _pRequest.GetRemovedPR(GetUser(), viewModels); - return GetResponse(response); + var dto = new PRVM + { + SearchPRNo = searchPRNo, + SearchItemName = searchItemName, + SearchDept = searchDept, + SearchStatusName = searchStatusName, + PageNumber = pageNumber, + PageSize = pageSize + }; + + var result = await _pRequest.GetDetailedPRTracking(GetUser(), dto); + int draw = int.TryParse(Request.Query["draw"], out int d) ? d : 1; + + return Json(new + { + draw = draw, + recordsTotal = result.TotalCount, + recordsFiltered = result.TotalCount, + data = result.Data, + statusList = result.StatusList + }); + } + [HttpGet] + public async Task GetApprovedPR( + string searchPRNo = "", string searchItemName = "", string searchDept = "", string searchStatusName = "", + int pageNumber = 1, int pageSize = 10) + { + var dto = new PRVM + { + SearchPRNo = searchPRNo, + SearchItemName = searchItemName, + SearchDept = searchDept, + SearchStatusName = searchStatusName, + PageNumber = pageNumber, + PageSize = pageSize + }; + + var result = await _pRequest.GetApprovedPR(GetUser(),dto); + int draw = int.TryParse(Request.Query["draw"], out int d) ? d : 1; + + return Json(new + { + draw = draw, + recordsTotal = result.TotalCount, + recordsFiltered = result.TotalCount, + data = result.Data, + statusList = result.StatusList + }); + } + [HttpGet] + public async Task GetDeletedPR( + bool isArchived = false, string searchPRNo = "", string searchItemName = "", + string searchDept = "", int pageNumber = 1, int pageSize = 10) + { + var dto = new PRVM + { + IsArchived = isArchived, + SearchPRNo = searchPRNo, + SearchItemName = searchItemName, + SearchDept = searchDept, + PageNumber = pageNumber, + PageSize = pageSize + }; + + var result = await _pRequest.GetDeletedPR(GetUser(), dto); + int draw = int.TryParse(Request.Query["draw"], out int d) ? d : 1; + + return Json(new + { + draw = draw, + recordsTotal = result.TotalCount, + recordsFiltered = result.TotalCount, + data = result.Data + }); } [HttpGet] public async Task GetPRAttachment(string fileName) @@ -127,11 +241,6 @@ namespace CPRNIMS.WebApps.Controllers.PR response = await _pRequest.GetItemDetailForReceiving(GetUser(), viewModel); return GetResponse(response); } - public async Task GetDetailedPRTracking(PRVM viewModel) - { - response = await _pRequest.GetDetailedPRTracking(GetUser(), viewModel); - return GetResponse(response); - } public async Task GetSupplierAlternativeOffer(PRVM viewModel) { response = await _pRequest.GetSupplierAlternativeOffer(GetUser(), viewModel); diff --git a/CPRNIMS.WebApps/ViewComponents/PR/PRTabbed.cs b/CPRNIMS.WebApps/ViewComponents/PR/PRTabbed.cs index 4239372..48cc4e5 100644 --- a/CPRNIMS.WebApps/ViewComponents/PR/PRTabbed.cs +++ b/CPRNIMS.WebApps/ViewComponents/PR/PRTabbed.cs @@ -10,7 +10,7 @@ namespace CPRNIMS.WebApps.ViewComponents.PR { 1 => "~/Views/Components/PRMgmt/PRTabbedTable/AllPR.cshtml", 2 => "~/Views/Components/PRMgmt/PRTabbedTable/ApprovedPR.cshtml", - _ => "~/Views/Components/PRMgmt/PRTabbedTable/RemovedPR.cshtml" + _ => "~/Views/Components/PRMgmt/PRTabbedTable/DeletedPR.cshtml" }; return View(viewName); } diff --git a/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/AllPR.cshtml b/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/AllPR.cshtml index 53decbd..b8a0605 100644 --- a/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/AllPR.cshtml +++ b/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/AllPR.cshtml @@ -1,5 +1,53 @@ - -
+
+
+
+
+ + + + + + + + +
+
+ +
+
+ + + + + + + + +
+
+ +
+
+ + + + + + + + +
+
+
@@ -19,93 +67,84 @@ \ No newline at end of file diff --git a/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/ApprovedPR.cshtml b/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/ApprovedPR.cshtml index 671c8f1..7020958 100644 --- a/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/ApprovedPR.cshtml +++ b/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/ApprovedPR.cshtml @@ -1,4 +1,74 @@ 
+
+ + +
+
+ + + + + + +
+
+ + +
+
+ + + + + + + + +
+
+ + +
+
+ + + + + + + + +
+
+ + +
+
+ + + + + + + + +
+
+ +
@@ -23,144 +93,88 @@ \ No newline at end of file diff --git a/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/RemovedPR.cshtml b/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/RemovedPR.cshtml deleted file mode 100644 index 5a9bd68..0000000 --- a/CPRNIMS.WebApps/Views/Components/PRMgmt/PRTabbedTable/RemovedPR.cshtml +++ /dev/null @@ -1,164 +0,0 @@ -
-
- - - - - - - - - - - - - - - - - - -
PRNoItemNoItemNameQtyPR ByPR DateAttested ByAttested DateApproved ByApproved DateCharge ToRemarks
-
- - \ No newline at end of file diff --git a/CPRNIMS.WebApps/Views/ItemMgmt/Index.cshtml b/CPRNIMS.WebApps/Views/ItemMgmt/Index.cshtml index f1516d8..8562606 100644 --- a/CPRNIMS.WebApps/Views/ItemMgmt/Index.cshtml +++ b/CPRNIMS.WebApps/Views/ItemMgmt/Index.cshtml @@ -10,16 +10,37 @@ Add new
+ +
+
+ + + + + + + + + + + + +
+
Start typing to search items…
+
- + - - @@ -237,7 +258,7 @@ - + @await Html.PartialAsync("PagesView/Item/_Scripts") diff --git a/CPRNIMS.WebApps/Views/PRMgmt/DeniedItem.cshtml b/CPRNIMS.WebApps/Views/PRMgmt/DeniedItem.cshtml index b23e2a4..c883a85 100644 --- a/CPRNIMS.WebApps/Views/PRMgmt/DeniedItem.cshtml +++ b/CPRNIMS.WebApps/Views/PRMgmt/DeniedItem.cshtml @@ -17,8 +17,6 @@ - - diff --git a/CPRNIMS.WebApps/Views/PRMgmt/Index.cshtml b/CPRNIMS.WebApps/Views/PRMgmt/Index.cshtml index 414d313..b4ccf47 100644 --- a/CPRNIMS.WebApps/Views/PRMgmt/Index.cshtml +++ b/CPRNIMS.WebApps/Views/PRMgmt/Index.cshtml @@ -33,6 +33,30 @@
ItemNoItemNo ItemName ItemSpecs CategoryName Action
ItemCategory SupplierName Action
@@ -17,8 +65,6 @@ - - @@ -27,7 +73,8 @@ + @await Html.PartialAsync("PagesView/PR/_PRTracking") - + @await Html.PartialAsync("PagesView/PR/_PRScripts") \ No newline at end of file diff --git a/CPRNIMS.WebApps/Views/PRMgmt/PRTracking.cshtml b/CPRNIMS.WebApps/Views/PRMgmt/PRTracking.cshtml index d77eba6..1eb14c9 100644 --- a/CPRNIMS.WebApps/Views/PRMgmt/PRTracking.cshtml +++ b/CPRNIMS.WebApps/Views/PRMgmt/PRTracking.cshtml @@ -4,7 +4,77 @@

PR Tracking

-
+
+
+ + +
+
+ + + + + + +
+
+ + +
+
+ + + + + + + + +
+
+ + +
+
+ + + + + + + + +
+
+ + +
+
+ + + + + + + + +
+
+ +
DateNeeded ChargeTo Action
@@ -45,6 +115,6 @@ - + @await Html.PartialAsync("PagesView/PR/_PRScripts") \ No newline at end of file diff --git a/CPRNIMS.WebApps/Views/Shared/PagesView/Item/_Scripts.cshtml b/CPRNIMS.WebApps/Views/Shared/PagesView/Item/_Scripts.cshtml index b8831d1..a146756 100644 --- a/CPRNIMS.WebApps/Views/Shared/PagesView/Item/_Scripts.cshtml +++ b/CPRNIMS.WebApps/Views/Shared/PagesView/Item/_Scripts.cshtml @@ -1,4 +1,5 @@ - + + diff --git a/CPRNIMS.WebApps/Views/Shared/PagesView/PO/_POScripts.cshtml b/CPRNIMS.WebApps/Views/Shared/PagesView/PO/_POScripts.cshtml index 6ba3676..88f14f9 100644 --- a/CPRNIMS.WebApps/Views/Shared/PagesView/PO/_POScripts.cshtml +++ b/CPRNIMS.WebApps/Views/Shared/PagesView/PO/_POScripts.cshtml @@ -18,7 +18,7 @@ - + diff --git a/CPRNIMS.WebApps/Views/Shared/PagesView/PR/_PRScripts.cshtml b/CPRNIMS.WebApps/Views/Shared/PagesView/PR/_PRScripts.cshtml index 911b995..a8ec9f0 100644 --- a/CPRNIMS.WebApps/Views/Shared/PagesView/PR/_PRScripts.cshtml +++ b/CPRNIMS.WebApps/Views/Shared/PagesView/PR/_PRScripts.cshtml @@ -1,20 +1,22 @@  + - - + + - + + diff --git a/CPRNIMS.WebApps/Views/Shared/PagesView/PR/_Receiving.cshtml b/CPRNIMS.WebApps/Views/Shared/PagesView/PR/_Receiving.cshtml index 4021b62..07e3ed6 100644 --- a/CPRNIMS.WebApps/Views/Shared/PagesView/PR/_Receiving.cshtml +++ b/CPRNIMS.WebApps/Views/Shared/PagesView/PR/_Receiving.cshtml @@ -1,5 +1,4 @@ - - +
+
+ `); + + const tempTable = $(`#${tempTableId}`).DataTable({ + data: data, + columns: exportColumns, + dom: 'Brt', + buttons: [ + { + extend: format, + title: reportTitle, + exportOptions: { + columns: ':visible', + format: { + body: function (data) { + // Strip any remaining HTML tags + return $('
').html(data).text(); + } + } + } + } + ], + paging: false, + searching: false, + info: false + }); + + setTimeout(function () { + tempTable.button(0).trigger(); + }, 500); + + setTimeout(function () { + tempTable.destroy(); + $('#tempExportWrapper').remove(); + }, 2000); +} \ No newline at end of file diff --git a/CPRNIMS.WebApps/wwwroot/JsFunctions/Utilities/SearchEngine - Copy.js b/CPRNIMS.WebApps/wwwroot/JsFunctions/Utilities/SearchEngine - Copy.js deleted file mode 100644 index a075e06..0000000 --- a/CPRNIMS.WebApps/wwwroot/JsFunctions/Utilities/SearchEngine - Copy.js +++ /dev/null @@ -1,232 +0,0 @@ -// =========================================== -// REUSABLE DATATABLE COLUMN SEARCH UTILITY -// =========================================== - -/** - * Initialize column-specific search functionality for DataTable - * @param {Object} config - Configuration object - * @param {string} config.tableId - DataTable selector (e.g., '#PRItemTable') - * @param {Object} config.dataTable - DataTable instance - * @param {Array} config.searchableColumns - Array of column configurations - * @param {string} config.containerId - Container ID for search inputs (optional) - * @param {string} config.searchInputClass - CSS class for search inputs (optional) - */ -function initializeColumnSearch(config) { - const { - tableId, - dataTable, - searchableColumns, - containerId = null, - searchInputClass = 'column-search-input' - } = config; - - // Create search container if not provided - let searchContainer; - if (containerId) { - searchContainer = $('#' + containerId); - } else { - // Create default search container above the table - searchContainer = $('
'); - $(tableId).parent().prepend(searchContainer); - } - - // Clear existing search inputs - searchContainer.empty(); - - // Create search inputs for each specified column - searchableColumns.forEach(function (columnConfig) { - const columnIndex = columnConfig.columnIndex; - const columnName = columnConfig.columnName; - const placeholder = columnConfig.placeholder; - const searchType = columnConfig.searchType || 'text'; - const searchMode = columnConfig.searchMode || 'contains'; - const selectOptions = columnConfig.selectOptions || null; - const width = columnConfig.width || 'auto'; - - // Create input wrapper - const inputWrapper = $('
'); - - let searchInput; - - // Create different input types based on searchType - switch (searchType) { - case 'select': - searchInput = $(''); - - // Add options if provided - if (selectOptions && Array.isArray(selectOptions)) { - selectOptions.forEach(function (option) { - searchInput.append(''); - }); - } - break; - - case 'date': - searchInput = $(''); - break; - - case 'number': - searchInput = $(''); - break; - - default: // text - searchInput = $(''); - } - - inputWrapper.append(searchInput); - searchContainer.append(inputWrapper); - }); - - // Add clear all button - const clearButton = $('
'); - searchContainer.append(clearButton); - - // Bind search events - bindColumnSearchEvents(dataTable, searchInputClass); -} - -/** - * Bind search events to column search inputs - * @param {Object} dataTable - DataTable instance - * @param {string} searchInputClass - CSS class for search inputs - */ -function bindColumnSearchEvents(dataTable, searchInputClass) { - // Individual column search - $('.' + searchInputClass).off('keyup change').on('keyup change', function () { - const columnIndex = $(this).data('column'); - const searchValue = $(this).val(); - const searchMode = $(this).data('search-mode') || 'contains'; - - // Apply column-specific search with regex based on search mode - let searchRegex = ''; - - if (searchValue) { - switch (searchMode) { - case 'exact': - // Exact match - search for the exact value - searchRegex = '^' + escapeRegex(searchValue) + '$'; - break; - case 'starts': - // Starts with - search for values that start with the input - searchRegex = '^' + escapeRegex(searchValue); - break; - case 'ends': - // Ends with - search for values that end with the input - searchRegex = escapeRegex(searchValue) + '$'; - break; - default: // 'contains' - // Contains - default DataTable behavior (no regex needed) - searchRegex = searchValue; - } - } - - // Apply search with regex if needed - if (searchMode !== 'contains' && searchValue) { - dataTable.column(columnIndex).search(searchRegex, true, false).draw(); - } else { - dataTable.column(columnIndex).search(searchValue).draw(); - } - - // Update URL parameters (optional) - updateSearchParams($(this).data('column-name'), searchValue); - }); - - // Clear all searches - $('.clear-column-search').off('click').on('click', function () { - $('.' + searchInputClass).val(''); - - // Clear all column searches - dataTable.columns().search('').draw(); - - // Clear URL parameters (optional) - clearAllSearchParams(); - }); -} - -/** - * Escape special regex characters - * @param {string} string - String to escape - * @returns {string} Escaped string - */ -function escapeRegex(string) { - return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); -} - -/** - * Populate select options dynamically from table data - * @param {Object} dataTable - DataTable instance - * @param {number} columnIndex - Column index to extract unique values - * @param {string} selectSelector - jQuery selector for the select element - */ -function populateSelectOptions(dataTable, columnIndex, selectSelector) { - // Get unique values from the column - const uniqueValues = dataTable.column(columnIndex).data().unique().sort(); - const selectElement = $(selectSelector); - - // Clear existing options (except the first "All" option) - selectElement.find('option:not(:first)').remove(); - - // Add unique values as options - uniqueValues.each(function (value) { - if (value && value.toString().trim() !== '') { - selectElement.append(''); - } - }); -} - -/** - * Update URL search parameters (optional feature) - * @param {string} paramName - Parameter name - * @param {string} paramValue - Parameter value - */ -function updateSearchParams(paramName, paramValue) { - if (typeof URLSearchParams === 'undefined') return; - - const url = new URL(window.location); - if (paramValue && paramValue.trim() !== '') { - url.searchParams.set('search_' + paramName, paramValue); - } else { - url.searchParams.delete('search_' + paramName); - } - window.history.replaceState({}, '', url); -} - -/** - * Clear all search parameters from URL - */ -function clearAllSearchParams() { - if (typeof URLSearchParams === 'undefined') return; - - const url = new URL(window.location); - const keysToDelete = []; - - for (const key of url.searchParams.keys()) { - if (key.indexOf('search_') === 0) { - keysToDelete.push(key); - } - } - - keysToDelete.forEach(function (key) { - url.searchParams.delete(key); - }); - window.history.replaceState({}, '', url); -} - -/** - * Restore search values from URL parameters - * @param {string} searchInputClass - CSS class for search inputs - */ -function restoreSearchFromURL(searchInputClass) { - if (typeof URLSearchParams === 'undefined') return; - - const url = new URL(window.location); - - $('.' + searchInputClass).each(function () { - const columnName = $(this).data('column-name'); - const searchValue = url.searchParams.get('search_' + columnName); - - if (searchValue) { - $(this).val(searchValue).trigger('change'); - } - }); -} \ No newline at end of file diff --git a/CPRNIMS.WebApps/wwwroot/css/Item/Item.css b/CPRNIMS.WebApps/wwwroot/css/Item/Item.css new file mode 100644 index 0000000..7ebd6a8 --- /dev/null +++ b/CPRNIMS.WebApps/wwwroot/css/Item/Item.css @@ -0,0 +1,74 @@ +.search-wrapper { + margin-bottom: 1rem; +} + +.search-inner { + position: relative; + display: flex; + align-items: center; + background: #fff; + border: 1.5px solid #d0e8e5; + border-radius: 10px; + box-shadow: 0 2px 8px rgba(26, 122, 110, 0.08); + transition: border-color 0.2s ease, box-shadow 0.2s ease; + overflow: hidden; +} + + .search-inner:focus-within { + border-color: #1a7a6e; + box-shadow: 0 0 0 3px rgba(26, 122, 110, 0.15), 0 2px 8px rgba(26, 122, 110, 0.1); + } + +.search-icon { + display: flex; + align-items: center; + padding: 0 12px 0 14px; + color: #1a7a6e; + opacity: 0.6; + transition: opacity 0.2s; + flex-shrink: 0; +} + +.search-inner:focus-within .search-icon { + opacity: 1; +} + +.search-input { + flex: 1; + border: none; + outline: none; + padding: 11px 4px; + font-size: 0.9rem; + color: #2d2d2d; + background: transparent; + letter-spacing: 0.01em; +} + + .search-input::placeholder { + color: #aab8b6; + font-style: italic; + } + +.search-clear { + display: none; + align-items: center; + justify-content: center; + padding: 0 12px; + cursor: pointer; + color: #888; + transition: color 0.15s; + flex-shrink: 0; +} + + .search-clear:hover { + color: #1a7a6e; + } + +.search-hint { + font-size: 0.76rem; + color: #9ab5b1; + margin-top: 5px; + padding-left: 2px; + min-height: 1.1em; + transition: color 0.2s; +}