|
1 | | -window.onload = function() { |
2 | | - var searchForm = document.querySelector("#search-form"); |
| 1 | +// Predefined queries data structure |
| 2 | +const predefinedQueries = [ |
| 3 | + { |
| 4 | + category: "Files", |
| 5 | + queries: [ |
| 6 | + { name: "Recent Files", query: ` |
| 7 | +SELECT |
| 8 | + file_id, filename, file_creation_date as creation_date, file_creation_time as creation_time, |
| 9 | + immediate_destination_name as destination, immediate_origin_name as origin , |
| 10 | + total_debit_entry_dollar_amount as debits, total_credit_entry_dollar_amount as credits |
3 | 11 |
|
4 | | - searchForm.addEventListener('submit', function(event) { |
| 12 | +FROM ach_files |
| 13 | +WHERE created_at >= datetime('now', '-7 days') |
| 14 | +ORDER BY created_at DESC |
| 15 | +LIMIT 5; |
| 16 | +`}, |
| 17 | + ], |
| 18 | + }, |
| 19 | + { |
| 20 | + category: "Entries", |
| 21 | + queries: [ |
| 22 | + { name: "Entries By Name or Account Number", query: ` |
| 23 | +SELECT |
| 24 | + -- e.entry_id, e.file_id, |
| 25 | + e.transaction_code, e.amount, |
| 26 | + e.dfi_account_number, e.individual_name, |
| 27 | + e.trace_number, f.filename, f.file_creation_date |
| 28 | +
|
| 29 | +FROM ach_entries e |
| 30 | +JOIN ach_files f ON e.file_id = f.file_id |
| 31 | +
|
| 32 | +WHERE |
| 33 | + e.individual_name LIKE '%' |
| 34 | + -- e.dfi_account_number LIKE '%1234' |
| 35 | + AND created_at >= datetime('now', '-7 days') |
| 36 | +
|
| 37 | +ORDER BY f.created_at DESC |
| 38 | +LIMIT 10; |
| 39 | +` }, |
| 40 | + ], |
| 41 | + }, |
| 42 | + { |
| 43 | + category: "Exceptions", |
| 44 | + queries: [ |
| 45 | + { name: "Recent Returns and Corrections", query: ` |
| 46 | +SELECT |
| 47 | + -- e.entry_id, |
| 48 | + e.individual_name, e.dfi_account_number, e.amount, |
| 49 | + e.trace_number, a.return_code, |
| 50 | + -- a.payment_related_information, |
| 51 | + f.filename, f.file_creation_date |
| 52 | +
|
| 53 | +FROM ach_entries e |
| 54 | +JOIN ach_addendas a ON e.entry_id = a.entry_id AND e.file_id = a.file_id |
| 55 | +JOIN ach_files f ON e.file_id = f.file_id |
| 56 | +
|
| 57 | +WHERE a.return_code IS NOT NULL OR a.change_code IS NOT NULL |
| 58 | +
|
| 59 | +ORDER BY f.created_at DESC |
| 60 | +LIMIT 10; |
| 61 | +`}, |
| 62 | + ], |
| 63 | + }, |
| 64 | +]; |
| 65 | + |
| 66 | +// Function to format date as YYYY-MM-DD |
| 67 | +function yyyymmdd(date) { |
| 68 | + if (!date || isNaN(date)) return "Unknown"; |
| 69 | + const year = date.getFullYear(); |
| 70 | + const month = String(date.getMonth() + 1).padStart(2, "0"); |
| 71 | + const day = String(date.getDate()).padStart(2, "0"); |
| 72 | + return `${year}-${month}-${day}`; |
| 73 | +} |
| 74 | + |
| 75 | +// Function to calculate new date ranges for pagination |
| 76 | +function calculateDateRangeUrls() { |
| 77 | + const params = new URLSearchParams(window.location.search); |
| 78 | + let startDate = params.get("startDate") ? new Date(params.get("startDate")) : new Date(); |
| 79 | + let endDate = params.get("endDate") ? new Date(params.get("endDate")) : new Date(); |
| 80 | + |
| 81 | + // Default to a 7-day range if dates are invalid |
| 82 | + if (isNaN(startDate) || isNaN(endDate)) { |
| 83 | + endDate = new Date(); |
| 84 | + startDate = new Date(); |
| 85 | + startDate.setDate(endDate.getDate() - 7); |
| 86 | + } |
| 87 | + |
| 88 | + // Calculate "Older" range (shift back 7 days) |
| 89 | + const olderStart = new Date(startDate); |
| 90 | + olderStart.setDate(startDate.getDate() - 7); |
| 91 | + const olderEnd = new Date(endDate); |
| 92 | + olderEnd.setDate(endDate.getDate() - 7); |
| 93 | + |
| 94 | + // Calculate "Newer" range (shift forward 7 days) |
| 95 | + const newerStart = new Date(startDate); |
| 96 | + newerStart.setDate(startDate.getDate() + 7); |
| 97 | + const newerEnd = new Date(endDate); |
| 98 | + newerEnd.setDate(endDate.getDate() + 7); |
| 99 | + |
| 100 | + // Generate URLs |
| 101 | + const olderUrl = `./?startDate=${yyyymmdd(olderStart)}&endDate=${yyyymmdd(olderEnd)}`; |
| 102 | + const newerUrl = `./?startDate=${yyyymmdd(newerStart)}&endDate=${yyyymmdd(newerEnd)}`; |
| 103 | + |
| 104 | + return { olderUrl, newerUrl }; |
| 105 | +} |
| 106 | + |
| 107 | +// Function to update date range text and pagination URLs |
| 108 | +function updateDateRangeAndLinks() { |
| 109 | + const params = new URLSearchParams(window.location.search); |
| 110 | + const startDate = params.get("startDate") ? new Date(params.get("startDate")) : new Date(); |
| 111 | + const endDate = params.get("endDate") ? new Date(params.get("endDate")) : new Date(); |
| 112 | + const dateRangeElement = document.querySelector("#date-range"); |
| 113 | + |
| 114 | + dateRangeElement.textContent = `Searching Files from ${yyyymmdd(startDate)} to ${yyyymmdd(endDate)}`; |
| 115 | + |
| 116 | + // Update pagination link URLs |
| 117 | + const { olderUrl, newerUrl } = calculateDateRangeUrls(); |
| 118 | + document.querySelector("#older-link").setAttribute("data-url", olderUrl); |
| 119 | + document.querySelector("#newer-link").setAttribute("data-url", newerUrl); |
| 120 | +} |
| 121 | + |
| 122 | +// Function to populate the accordion |
| 123 | +function populateAccordion() { |
| 124 | + const accordionContainer = document.querySelector("#accordion-container"); |
| 125 | + |
| 126 | + predefinedQueries.forEach((category, index) => { |
| 127 | + const accordionItem = document.createElement("div"); |
| 128 | + accordionItem.classList.add("accordion-item"); |
| 129 | + |
| 130 | + const header = document.createElement("button"); |
| 131 | + header.classList.add("accordion-header"); |
| 132 | + header.textContent = category.category; |
| 133 | + header.setAttribute("aria-expanded", "false"); |
| 134 | + header.setAttribute("aria-controls", `accordion-content-${index}`); |
| 135 | + |
| 136 | + const content = document.createElement("div"); |
| 137 | + content.classList.add("accordion-content"); |
| 138 | + content.id = `accordion-content-${index}`; |
| 139 | + |
| 140 | + category.queries.forEach((query) => { |
| 141 | + const option = document.createElement("button"); |
| 142 | + option.classList.add("query-option"); |
| 143 | + option.textContent = query.name; |
| 144 | + option.setAttribute("data-query", query.query); |
| 145 | + option.addEventListener("click", () => { |
| 146 | + document.querySelector("#query").value = query.query; |
| 147 | + }); |
| 148 | + content.appendChild(option); |
| 149 | + }); |
| 150 | + |
| 151 | + header.addEventListener("click", () => { |
| 152 | + const isActive = content.classList.contains("active"); |
| 153 | + document.querySelectorAll(".accordion-content").forEach((c) => { |
| 154 | + c.classList.remove("active"); |
| 155 | + c.previousElementSibling.setAttribute("aria-expanded", "false"); |
| 156 | + }); |
| 157 | + if (!isActive) { |
| 158 | + content.classList.add("active"); |
| 159 | + header.setAttribute("aria-expanded", "true"); |
| 160 | + } |
| 161 | + }); |
| 162 | + |
| 163 | + accordionItem.appendChild(header); |
| 164 | + accordionItem.appendChild(content); |
| 165 | + accordionContainer.appendChild(accordionItem); |
| 166 | + }); |
| 167 | +} |
| 168 | + |
| 169 | +// Main initialization |
| 170 | +window.onload = function () { |
| 171 | + // Populate the accordion |
| 172 | + populateAccordion(); |
| 173 | + |
| 174 | + // Update date range text and pagination URLs on load |
| 175 | + updateDateRangeAndLinks(); |
| 176 | + |
| 177 | + // Handle pagination link clicks |
| 178 | + const olderLink = document.querySelector("#older-link"); |
| 179 | + const newerLink = document.querySelector("#newer-link"); |
| 180 | + |
| 181 | + olderLink.addEventListener("click", (event) => { |
| 182 | + event.preventDefault(); |
| 183 | + const newUrl = olderLink.getAttribute("data-url"); |
| 184 | + window.history.pushState({ startDate: new URLSearchParams(newUrl).get("startDate"), endDate: new URLSearchParams(newUrl).get("endDate") }, "", newUrl); |
| 185 | + updateDateRangeAndLinks(); |
| 186 | + }); |
| 187 | + |
| 188 | + newerLink.addEventListener("click", (event) => { |
5 | 189 | event.preventDefault(); |
| 190 | + const newUrl = newerLink.getAttribute("data-url"); |
| 191 | + window.history.pushState({ startDate: new URLSearchParams(newUrl).get("startDate"), endDate: new URLSearchParams(newUrl).get("endDate") }, "", newUrl); |
| 192 | + updateDateRangeAndLinks(); |
| 193 | + }); |
6 | 194 |
|
7 | | - var query = document.querySelector("#query"); |
| 195 | + // Handle browser back/forward navigation |
| 196 | + window.addEventListener("popstate", () => { |
| 197 | + updateDateRangeAndLinks(); |
| 198 | + }); |
| 199 | + |
| 200 | + // Handle search form submission |
| 201 | + const searchForm = document.querySelector("#search-form"); |
| 202 | + searchForm.addEventListener("submit", function (event) { |
| 203 | + event.preventDefault(); |
| 204 | + const query = document.querySelector("#query"); |
8 | 205 | performSearch(query.value); |
9 | 206 | }); |
10 | 207 | }; |
11 | 208 |
|
12 | 209 | function performSearch(body) { |
13 | 210 | const currentParams = new URLSearchParams(window.location.search); |
14 | | - |
15 | 211 | const queryParams = new URLSearchParams(); |
16 | | - var startDate = currentParams.get('startDate'); |
| 212 | + const startDate = currentParams.get("startDate"); |
17 | 213 | if (startDate != null) { |
18 | 214 | queryParams.set("startDate", startDate); |
19 | 215 | } |
20 | | - var endDate = currentParams.get('endDate'); |
| 216 | + const endDate = currentParams.get("endDate"); |
21 | 217 | if (endDate != null) { |
22 | 218 | queryParams.set("endDate", endDate); |
23 | 219 | } |
24 | 220 |
|
| 221 | + // Clear error message before search |
| 222 | + const errorElm = document.querySelector("#error"); |
| 223 | + if (errorElm) { |
| 224 | + errorElm.textContent = ""; |
| 225 | + } |
| 226 | + |
25 | 227 | fetch(`./search?${queryParams.toString()}`, { |
26 | | - method: 'POST', |
| 228 | + method: "POST", |
27 | 229 | headers: { |
28 | | - 'Content-Type': 'text/plain' |
| 230 | + "Content-Type": "text/plain", |
29 | 231 | }, |
30 | 232 | body: body, |
31 | 233 | }) |
32 | | - .then(response => response.json()) |
33 | | - .then(data => { |
34 | | - populateSearchResponse(data) |
| 234 | + .then((response) => response.json()) |
| 235 | + .then((data) => { |
| 236 | + populateSearchResponse(data); |
35 | 237 | }) |
36 | | - .catch(error => { |
37 | | - var elm = document.querySelector("#error"); |
| 238 | + .catch((error) => { |
| 239 | + const elm = document.querySelector("#error"); |
38 | 240 | if (elm) { |
39 | 241 | elm.textContent = error.message; |
40 | 242 | } else { |
41 | | - console.error('Error element (#error) not found'); |
| 243 | + console.error("Error element (#error) not found"); |
42 | 244 | } |
43 | | - console.error('Fetch error:', error); |
| 245 | + console.error("Fetch error:", error); |
44 | 246 | }); |
45 | 247 | } |
46 | 248 |
|
47 | 249 | function populateSearchResponse(data) { |
48 | | - var table = document.querySelector("#results"); |
49 | | - table.innerHTML = ''; // Clear the previous rows |
| 250 | + const table = document.querySelector("#results"); |
| 251 | + table.innerHTML = ""; // Clear the previous rows |
50 | 252 |
|
51 | 253 | // Add the Headers |
52 | | - const headers = document.createElement("tr"); // Fixed typo |
| 254 | + const headers = document.createElement("tr"); |
53 | 255 | if (data.Headers) { |
54 | | - data.Headers.Columns.forEach(col => { |
55 | | - const th = document.createElement("th"); // Use <th> for headers |
| 256 | + data.Headers.Columns.forEach((col) => { |
| 257 | + const th = document.createElement("th"); |
56 | 258 | th.innerHTML = col; |
57 | | - |
58 | 259 | headers.append(th); |
59 | 260 | }); |
60 | 261 | table.append(headers); |
61 | 262 | } |
62 | 263 |
|
63 | 264 | // Add the rows |
64 | 265 | if (data.Rows) { |
65 | | - data.Rows.forEach(r => { |
| 266 | + data.Rows.forEach((r) => { |
66 | 267 | const row = document.createElement("tr"); |
67 | | - |
68 | | - r.Columns.forEach(col => { |
| 268 | + r.Columns.forEach((col) => { |
69 | 269 | const td = document.createElement("td"); |
70 | 270 | td.innerHTML = col; |
71 | | - |
72 | 271 | row.append(td); |
73 | 272 | }); |
74 | | - |
75 | 273 | table.append(row); |
76 | 274 | }); |
77 | 275 | } |
78 | 276 |
|
79 | 277 | // Show an error if one exists |
80 | 278 | if (data.error) { |
81 | | - var elm = document.querySelector("#error"); |
| 279 | + const elm = document.querySelector("#error"); |
82 | 280 | elm.textContent = data.error; |
83 | 281 | } |
84 | 282 | } |
0 commit comments