diff --git a/MoneyMap/Pages/CategoryMappings.cshtml b/MoneyMap/Pages/CategoryMappings.cshtml
index a975a1f..a6ba96c 100644
--- a/MoneyMap/Pages/CategoryMappings.cshtml
+++ b/MoneyMap/Pages/CategoryMappings.cshtml
@@ -304,73 +304,5 @@ else
@section Scripts {
-
+
}
diff --git a/MoneyMap/Pages/EditTransaction.cshtml b/MoneyMap/Pages/EditTransaction.cshtml
index dfdc8b9..defed2f 100644
--- a/MoneyMap/Pages/EditTransaction.cshtml
+++ b/MoneyMap/Pages/EditTransaction.cshtml
@@ -263,75 +263,11 @@
@section Scripts {
+
}
-
-
-
diff --git a/MoneyMap/Pages/Merchants.cshtml b/MoneyMap/Pages/Merchants.cshtml
index 61b4eb5..513bb0c 100644
--- a/MoneyMap/Pages/Merchants.cshtml
+++ b/MoneyMap/Pages/Merchants.cshtml
@@ -152,35 +152,5 @@ else
@section Scripts {
-
+
}
diff --git a/MoneyMap/Pages/Transactions.cshtml b/MoneyMap/Pages/Transactions.cshtml
index 8deda2a..ba9d51c 100644
--- a/MoneyMap/Pages/Transactions.cshtml
+++ b/MoneyMap/Pages/Transactions.cshtml
@@ -304,47 +304,6 @@ else
}
@section Scripts {
-
+
}
diff --git a/MoneyMap/Pages/Upload.cshtml b/MoneyMap/Pages/Upload.cshtml
index f517b99..aea6bed 100644
--- a/MoneyMap/Pages/Upload.cshtml
+++ b/MoneyMap/Pages/Upload.cshtml
@@ -235,116 +235,5 @@ else
@section Scripts {
-
+
}
diff --git a/MoneyMap/wwwroot/js/category-mappings.js b/MoneyMap/wwwroot/js/category-mappings.js
new file mode 100644
index 0000000..b240db4
--- /dev/null
+++ b/MoneyMap/wwwroot/js/category-mappings.js
@@ -0,0 +1,69 @@
+// Category Mappings Page JavaScript
+
+function openEditModal(id, category, pattern, priority, merchant) {
+ console.log('Opening modal for:', id, category, pattern, priority, merchant);
+
+ document.getElementById('editId').value = id;
+ document.getElementById('editCategory').value = category;
+ document.getElementById('editPattern').value = pattern;
+ document.getElementById('editPriority').value = priority;
+ document.getElementById('editMerchant').value = merchant || '';
+
+ var modalElement = document.getElementById('editModal');
+ if (modalElement && typeof bootstrap !== 'undefined') {
+ var modal = new bootstrap.Modal(modalElement);
+ modal.show();
+ } else {
+ console.error('Bootstrap modal not available');
+ alert('Error: Modal system not loaded. Please refresh the page.');
+ }
+}
+
+document.addEventListener('DOMContentLoaded', function() {
+
+ // Debug: Log form values before submission
+ var addForm = document.querySelector('#addModal form');
+ if (addForm) {
+ addForm.addEventListener('submit', function(e) {
+ var categoryInput = document.getElementById('addCategory');
+ var patternInput = document.getElementById('addPattern');
+ var priorityInput = document.getElementById('addPriority');
+
+ console.log('=== ADD FORM SUBMISSION ===');
+ console.log('Category:', categoryInput.value, 'Name:', categoryInput.name);
+ console.log('Pattern:', patternInput.value, 'Name:', patternInput.name);
+ console.log('Priority:', priorityInput.value, 'Name:', priorityInput.name);
+ console.log('Form Data:');
+ var formData = new FormData(addForm);
+ for (var pair of formData.entries()) {
+ console.log(' ' + pair[0] + ': ' + pair[1]);
+ }
+ });
+ }
+
+ var editForm = document.querySelector('#editModal form');
+ if (editForm) {
+ editForm.addEventListener('submit', function(e) {
+ var id = document.getElementById('editId').value;
+ var category = document.getElementById('editCategory').value;
+ var pattern = document.getElementById('editPattern').value;
+ var priority = document.getElementById('editPriority').value;
+ console.log('Submitting Edit form:', { id, category, pattern, priority });
+ console.log('Category input name:', document.getElementById('editCategory').name);
+ });
+ }
+
+ // Reopen modals if there are validation errors
+ var addCategoryInput = document.getElementById('addCategory');
+ var editCategoryInput = document.getElementById('editCategory');
+
+ if (addCategoryInput && addCategoryInput.classList.contains('input-validation-error')) {
+ var addModal = new bootstrap.Modal(document.getElementById('addModal'));
+ addModal.show();
+ }
+
+ if (editCategoryInput && editCategoryInput.classList.contains('input-validation-error')) {
+ var editModal = new bootstrap.Modal(document.getElementById('editModal'));
+ editModal.show();
+ }
+});
diff --git a/MoneyMap/wwwroot/js/edit-transaction.js b/MoneyMap/wwwroot/js/edit-transaction.js
new file mode 100644
index 0000000..d1b1eb5
--- /dev/null
+++ b/MoneyMap/wwwroot/js/edit-transaction.js
@@ -0,0 +1,73 @@
+// Edit Transaction Page JavaScript
+
+function handleCategoryChange() {
+ const select = document.getElementById('categorySelect');
+ const customInputDiv = document.getElementById('customCategoryInput');
+ const categoryInput = document.getElementById('categoryInput');
+
+ if (select.value === '__custom__') {
+ customInputDiv.style.display = 'block';
+ categoryInput.value = '';
+ categoryInput.focus();
+ } else {
+ customInputDiv.style.display = 'none';
+ categoryInput.value = select.value;
+ }
+}
+
+function handleMerchantChange() {
+ const select = document.getElementById('merchantSelect');
+ const customInput = document.getElementById('customMerchantInput');
+ const hiddenInput = document.getElementById('merchantHidden');
+ const merchantNameInput = document.querySelector('input[name="Transaction.MerchantName"]');
+
+ if (select.value === '__custom__') {
+ customInput.style.display = 'block';
+ hiddenInput.value = '';
+ merchantNameInput.value = '';
+ merchantNameInput.focus();
+ } else {
+ customInput.style.display = 'none';
+ hiddenInput.value = select.value;
+ merchantNameInput.value = '';
+ }
+}
+
+function copyTransactionId(transactionId) {
+ if (navigator.clipboard && window.isSecureContext) {
+ navigator.clipboard.writeText(transactionId.toString());
+ } else {
+ var ta = document.createElement('textarea');
+ ta.value = transactionId;
+ document.body.appendChild(ta);
+ ta.select();
+ document.execCommand('copy');
+ document.body.removeChild(ta);
+ }
+ var btns = document.querySelectorAll('button[onclick*="copyTransactionId"]');
+ btns.forEach(function(btn) {
+ var old = btn.textContent;
+ btn.textContent = 'Copied!';
+ setTimeout(function() {
+ btn.textContent = old;
+ }, 1500);
+ });
+}
+
+// Update hidden field when custom input changes
+document.addEventListener('DOMContentLoaded', function() {
+ const categoryInput = document.querySelector('input[name="Transaction.Category"]');
+ const categorySelect = document.getElementById('categorySelect');
+
+ if (categoryInput) {
+ categoryInput.addEventListener('input', function() {
+ if (categorySelect.value === '__custom__') {
+ // Keep custom selected when typing
+ }
+ });
+ }
+
+ // Initialize on page load
+ handleCategoryChange();
+ handleMerchantChange();
+});
diff --git a/MoneyMap/wwwroot/js/merchants.js b/MoneyMap/wwwroot/js/merchants.js
new file mode 100644
index 0000000..a684a92
--- /dev/null
+++ b/MoneyMap/wwwroot/js/merchants.js
@@ -0,0 +1,31 @@
+// Merchants Page JavaScript
+
+function openEditModal(id, name) {
+ document.getElementById('editId').value = id;
+ document.getElementById('editName').value = name;
+
+ var modalElement = document.getElementById('editModal');
+ if (modalElement && typeof bootstrap !== 'undefined') {
+ var modal = new bootstrap.Modal(modalElement);
+ modal.show();
+ } else {
+ console.error('Bootstrap modal not available');
+ alert('Error: Modal system not loaded. Please refresh the page.');
+ }
+}
+
+document.addEventListener('DOMContentLoaded', function() {
+ // Reopen modals if there are validation errors
+ var addNameInput = document.getElementById('addName');
+ var editNameInput = document.getElementById('editName');
+
+ if (addNameInput && addNameInput.classList.contains('input-validation-error')) {
+ var addModal = new bootstrap.Modal(document.getElementById('addModal'));
+ addModal.show();
+ }
+
+ if (editNameInput && editNameInput.classList.contains('input-validation-error')) {
+ var editModal = new bootstrap.Modal(document.getElementById('editModal'));
+ editModal.show();
+ }
+});
diff --git a/MoneyMap/wwwroot/js/transactions.js b/MoneyMap/wwwroot/js/transactions.js
new file mode 100644
index 0000000..93e7c89
--- /dev/null
+++ b/MoneyMap/wwwroot/js/transactions.js
@@ -0,0 +1,44 @@
+// Transactions Page JavaScript
+
+// Initialize Bootstrap tooltips for notes badges
+document.addEventListener('DOMContentLoaded', function() {
+ var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
+ var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
+ return new bootstrap.Tooltip(tooltipTriggerEl);
+ });
+});
+
+// Quick date range functions
+function formatDate(date) {
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, '0');
+ const day = String(date.getDate()).padStart(2, '0');
+ return `${year}-${month}-${day}`;
+}
+
+function setDateRange(days) {
+ const endDate = new Date();
+ const startDate = new Date();
+ startDate.setDate(startDate.getDate() - days);
+
+ document.getElementById('startDateInput').value = formatDate(startDate);
+ document.getElementById('endDateInput').value = formatDate(endDate);
+}
+
+function setDateRangeThisMonth() {
+ const now = new Date();
+ const startDate = new Date(now.getFullYear(), now.getMonth(), 1);
+ const endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0);
+
+ document.getElementById('startDateInput').value = formatDate(startDate);
+ document.getElementById('endDateInput').value = formatDate(endDate);
+}
+
+function setDateRangeLastMonth() {
+ const now = new Date();
+ const startDate = new Date(now.getFullYear(), now.getMonth() - 1, 1);
+ const endDate = new Date(now.getFullYear(), now.getMonth(), 0);
+
+ document.getElementById('startDateInput').value = formatDate(startDate);
+ document.getElementById('endDateInput').value = formatDate(endDate);
+}
diff --git a/MoneyMap/wwwroot/js/upload.js b/MoneyMap/wwwroot/js/upload.js
new file mode 100644
index 0000000..8604fa1
--- /dev/null
+++ b/MoneyMap/wwwroot/js/upload.js
@@ -0,0 +1,116 @@
+// Upload Page JavaScript
+let currentPage = 0;
+const pageSize = 100;
+let totalRows = 0;
+
+function togglePaymentSelection() {
+ const mode = document.querySelector('input[name="PaymentMode"]:checked').value;
+ const cardRow = document.getElementById('cardSelectRow');
+ const accountRow = document.getElementById('accountSelectRow');
+
+ cardRow.style.display = mode === 'Card' ? 'block' : 'none';
+ accountRow.style.display = mode === 'Account' ? 'block' : 'none';
+}
+
+function toggleAllCheckboxes() {
+ const selectAll = document.getElementById('selectAll');
+ const checkboxes = document.querySelectorAll('.transaction-checkbox');
+ checkboxes.forEach(cb => cb.checked = selectAll.checked);
+ updateSelectedCount();
+}
+
+function updateSelectedCount() {
+ const checkboxes = document.querySelectorAll('.transaction-checkbox:checked');
+ const count = checkboxes.length;
+ const selectedCountEl = document.getElementById('selectedCount');
+ const selectedCountButtonEl = document.getElementById('selectedCountButton');
+ if (selectedCountEl) selectedCountEl.textContent = count;
+ if (selectedCountButtonEl) selectedCountButtonEl.textContent = count;
+}
+
+function updateAllTransactionAccounts() {
+ // Called when the global account dropdown changes
+ // No action needed - we'll read the global account on form submit
+}
+
+function showPage(pageNum) {
+ const rows = document.querySelectorAll('.transaction-row');
+ const start = pageNum * pageSize;
+ const end = start + pageSize;
+
+ rows.forEach((row, index) => {
+ row.style.display = (index >= start && index < end) ? '' : 'none';
+ });
+
+ // Update pagination display
+ const pageStartEl = document.getElementById('pageStart');
+ const pageEndEl = document.getElementById('pageEnd');
+ if (pageStartEl && pageEndEl) {
+ pageStartEl.textContent = start + 1;
+ pageEndEl.textContent = Math.min(end, totalRows);
+ }
+
+ currentPage = pageNum;
+}
+
+function nextPage() {
+ const maxPage = Math.ceil(totalRows / pageSize) - 1;
+ if (currentPage < maxPage) {
+ showPage(currentPage + 1);
+ }
+}
+
+function previousPage() {
+ if (currentPage > 0) {
+ showPage(currentPage - 1);
+ }
+}
+
+function prepareFormData() {
+ // Collect selected indices
+ const selectedIndices = [];
+ document.querySelectorAll('.transaction-checkbox:checked').forEach(cb => {
+ selectedIndices.push(cb.getAttribute('data-index'));
+ });
+ document.getElementById('selectedIndices').value = selectedIndices.join(',');
+
+ // Get the global account ID
+ const globalAccountId = document.getElementById('globalAccountId')?.value;
+ if (!globalAccountId) {
+ alert('Please select an account for all transactions');
+ return false;
+ }
+
+ // Collect payment data (account + optional card + category per transaction)
+ const paymentData = {};
+ document.querySelectorAll('.card-select').forEach((select) => {
+ const index = select.getAttribute('data-index');
+ const cardId = select.value ? parseInt(select.value) : null;
+
+ // Get category for this transaction
+ const categoryInput = document.querySelector(`.category-input[data-index="${index}"]`);
+ const category = categoryInput ? categoryInput.value.trim() : '';
+
+ paymentData[index] = {
+ AccountId: parseInt(globalAccountId),
+ CardId: cardId,
+ Category: category
+ };
+ });
+ document.getElementById('paymentData').value = JSON.stringify(paymentData);
+
+ return true; // Allow form submission
+}
+
+// Initialize on page load
+document.addEventListener('DOMContentLoaded', function() {
+ togglePaymentSelection();
+
+ // Get total rows from the preview transactions count
+ const previewCount = document.querySelectorAll('.transaction-row').length;
+ totalRows = previewCount;
+
+ if (totalRows > pageSize) {
+ showPage(0);
+ }
+});