Ui updated
This commit is contained in:
parent
e3f4c148f6
commit
cf95a3c019
154
Transactions_Only_Paginated.postman_collection.json
Normal file
154
Transactions_Only_Paginated.postman_collection.json
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"name": "Dubai DLD - Transactions Only (Paginated)",
|
||||||
|
"_postman_id": "c0a5b3e6-6b0f-4b9e-9f77-transactions-only-v2",
|
||||||
|
"description": "Only /api/transactions/recent examples, covering filters, legacy limit, and server-side pagination.",
|
||||||
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||||
|
},
|
||||||
|
"variable": [
|
||||||
|
{ "key": "baseUrl", "value": "http://localhost:3000" }
|
||||||
|
],
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "Recent - No filters (all rows, no LIMIT)",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [ { "key": "Accept", "value": "application/json" } ],
|
||||||
|
"url": { "raw": "{{baseUrl}}/api/transactions/recent", "host": ["{{baseUrl}}"], "path": ["api","transactions","recent"] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Legacy: limit only (top N without OFFSET)",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [ { "key": "Accept", "value": "application/json" } ],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/transactions/recent?limit=7",
|
||||||
|
"host": ["{{baseUrl}}"],
|
||||||
|
"path": ["api","transactions","recent"],
|
||||||
|
"query": [ {"key":"limit","value":"7"} ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pagination: page 1, size 30",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [ { "key": "Accept", "value": "application/json" } ],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/transactions/recent?page=1&page_size=30",
|
||||||
|
"host": ["{{baseUrl}}"],
|
||||||
|
"path": ["api","transactions","recent"],
|
||||||
|
"query": [ {"key":"page","value":"1"}, {"key":"page_size","value":"30"} ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pagination: page 2, size 30",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [ { "key": "Accept", "value": "application/json" } ],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/transactions/recent?page=2&page_size=30",
|
||||||
|
"host": ["{{baseUrl}}"],
|
||||||
|
"path": ["api","transactions","recent"],
|
||||||
|
"query": [ {"key":"page","value":"2"}, {"key":"page_size","value":"30"} ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Filter: area_name + pagination",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [ { "key": "Accept", "value": "application/json" } ],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/transactions/recent?area_name=business%20bay&page=1&page_size=50",
|
||||||
|
"host": ["{{baseUrl}}"],
|
||||||
|
"path": ["api","transactions","recent"],
|
||||||
|
"query": [
|
||||||
|
{"key":"area_name","value":"business bay"},
|
||||||
|
{"key":"page","value":"1"},
|
||||||
|
{"key":"page_size","value":"50"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Filter: property_type + beds + pagination",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [ { "key": "Accept", "value": "application/json" } ],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/transactions/recent?property_type=apartment&beds=2&page=1&page_size=30",
|
||||||
|
"host": ["{{baseUrl}}"],
|
||||||
|
"path": ["api","transactions","recent"],
|
||||||
|
"query": [
|
||||||
|
{"key":"property_type","value":"apartment"},
|
||||||
|
{"key":"beds","value":"2"},
|
||||||
|
{"key":"page","value":"1"},
|
||||||
|
{"key":"page_size","value":"30"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Filter: size range + pagination",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [ { "key": "Accept", "value": "application/json" } ],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/transactions/recent?size_min=1000&size_max=5000&page=1&page_size=30",
|
||||||
|
"host": ["{{baseUrl}}"],
|
||||||
|
"path": ["api","transactions","recent"],
|
||||||
|
"query": [
|
||||||
|
{"key":"size_min","value":"1000"},
|
||||||
|
{"key":"size_max","value":"5000"},
|
||||||
|
{"key":"page","value":"1"},
|
||||||
|
{"key":"page_size","value":"30"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Filter: project + pagination",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [ { "key": "Accept", "value": "application/json" } ],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/transactions/recent?project=29%20boulevard&page=1&page_size=30",
|
||||||
|
"host": ["{{baseUrl}}"],
|
||||||
|
"path": ["api","transactions","recent"],
|
||||||
|
"query": [
|
||||||
|
{"key":"project","value":"29 boulevard"},
|
||||||
|
{"key":"page","value":"1"},
|
||||||
|
{"key":"page_size","value":"30"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Combined filters + pagination",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [ { "key": "Accept", "value": "application/json" } ],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/transactions/recent?area_name=business%20bay&property_type=apartment&beds=2&project=29%20boulevard&size_min=800&size_max=1600&page=1&page_size=50",
|
||||||
|
"host": ["{{baseUrl}}"],
|
||||||
|
"path": ["api","transactions","recent"],
|
||||||
|
"query": [
|
||||||
|
{"key":"area_name","value":"business bay"},
|
||||||
|
{"key":"property_type","value":"apartment"},
|
||||||
|
{"key":"beds","value":"2"},
|
||||||
|
{"key":"project","value":"29 boulevard"},
|
||||||
|
{"key":"size_min","value":"800"},
|
||||||
|
{"key":"size_max","value":"1600"},
|
||||||
|
{"key":"page","value":"1"},
|
||||||
|
{"key":"page_size","value":"50"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -128,7 +128,10 @@ function formatCurrency(amount) {
|
|||||||
return 'AED ' + parseFloat(amount).toLocaleString('en-US', { maximumFractionDigits: 0 });
|
return 'AED ' + parseFloat(amount).toLocaleString('en-US', { maximumFractionDigits: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function searchTransactions() {
|
let currentPage = 1;
|
||||||
|
let lastPaging = { total: 0, page: null, page_size: 30, total_pages: 1, has_next: false, has_prev: false };
|
||||||
|
|
||||||
|
async function searchTransactions(pageOverride) {
|
||||||
const formData = new FormData(document.getElementById('filtersForm'));
|
const formData = new FormData(document.getElementById('filtersForm'));
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
@ -138,7 +141,8 @@ async function searchTransactions() {
|
|||||||
const size_max = formData.get('size_max');
|
const size_max = formData.get('size_max');
|
||||||
const beds = formData.get('beds');
|
const beds = formData.get('beds');
|
||||||
const project = formData.get('project');
|
const project = formData.get('project');
|
||||||
const limit = formData.get('limit') || '30';
|
const pageSize = formData.get('page_size') || '30';
|
||||||
|
const page = pageOverride != null ? pageOverride : (formData.get('page') || currentPage || 1);
|
||||||
|
|
||||||
if (area_name) params.append('area_name', area_name);
|
if (area_name) params.append('area_name', area_name);
|
||||||
if (property_type && property_type !== 'all') params.append('property_type', property_type);
|
if (property_type && property_type !== 'all') params.append('property_type', property_type);
|
||||||
@ -146,7 +150,9 @@ async function searchTransactions() {
|
|||||||
if (size_max && !isNaN(parseFloat(size_max))) params.append('size_max', size_max);
|
if (size_max && !isNaN(parseFloat(size_max))) params.append('size_max', size_max);
|
||||||
if (beds && beds !== 'all') params.append('beds', beds);
|
if (beds && beds !== 'all') params.append('beds', beds);
|
||||||
if (project && project !== 'all') params.append('project', project);
|
if (project && project !== 'all') params.append('project', project);
|
||||||
params.append('limit', limit);
|
// pagination params
|
||||||
|
if (page) params.append('page', page);
|
||||||
|
if (pageSize) params.append('page_size', pageSize);
|
||||||
|
|
||||||
showLoading(true);
|
showLoading(true);
|
||||||
hideError();
|
hideError();
|
||||||
@ -156,6 +162,15 @@ async function searchTransactions() {
|
|||||||
const response = await fetch(`${API_BASE}/transactions/recent?${params.toString()}`);
|
const response = await fetch(`${API_BASE}/transactions/recent?${params.toString()}`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
|
currentPage = data.data.page || 1;
|
||||||
|
lastPaging = {
|
||||||
|
total: data.data.total ?? data.data.count,
|
||||||
|
page: data.data.page,
|
||||||
|
page_size: data.data.page_size ?? parseInt(pageSize,10),
|
||||||
|
total_pages: data.data.total_pages ?? 1,
|
||||||
|
has_next: !!data.data.has_next,
|
||||||
|
has_prev: !!data.data.has_prev
|
||||||
|
};
|
||||||
displayResults(data.data);
|
displayResults(data.data);
|
||||||
} else {
|
} else {
|
||||||
showError(data.message || 'Failed to fetch transactions');
|
showError(data.message || 'Failed to fetch transactions');
|
||||||
@ -168,10 +183,24 @@ async function searchTransactions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function displayResults(data) {
|
function displayResults(data) {
|
||||||
const { transactions, count } = data;
|
const { transactions, count, total, page, page_size, total_pages, has_next, has_prev } = data;
|
||||||
const tbody = document.getElementById('transactionsBody');
|
const tbody = document.getElementById('transactionsBody');
|
||||||
const resultsCount = document.getElementById('resultsCount');
|
const resultsCount = document.getElementById('resultsCount');
|
||||||
resultsCount.textContent = `Found ${count} transaction${count !== 1 ? 's' : ''}`;
|
const showing = count;
|
||||||
|
const grandTotal = total ?? count;
|
||||||
|
resultsCount.textContent = `Showing ${showing} of ${grandTotal} transactions`;
|
||||||
|
const pageInfo = document.getElementById('pageInfo');
|
||||||
|
if (pageInfo) {
|
||||||
|
if (page && total_pages) {
|
||||||
|
pageInfo.textContent = `Page ${page} of ${total_pages}`;
|
||||||
|
} else {
|
||||||
|
pageInfo.textContent = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const prevBtn = document.getElementById('prevPage');
|
||||||
|
const nextBtn = document.getElementById('nextPage');
|
||||||
|
if (prevBtn) prevBtn.disabled = !(has_prev);
|
||||||
|
if (nextBtn) nextBtn.disabled = !(has_next);
|
||||||
|
|
||||||
if (transactions.length === 0) {
|
if (transactions.length === 0) {
|
||||||
const colCount = document.querySelectorAll('#transactionsTable thead th').length;
|
const colCount = document.querySelectorAll('#transactionsTable thead th').length;
|
||||||
@ -300,13 +329,40 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
document.getElementById('filtersForm').addEventListener('submit', async (e) => {
|
document.getElementById('filtersForm').addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await searchTransactions();
|
currentPage = 1;
|
||||||
|
const pageInput = document.getElementById('page');
|
||||||
|
if (pageInput) pageInput.value = '1';
|
||||||
|
await searchTransactions(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
const resetBtn = document.getElementById('resetBtn');
|
const resetBtn = document.getElementById('resetBtn');
|
||||||
if (resetBtn) {
|
if (resetBtn) {
|
||||||
resetBtn.addEventListener('click', resetFilters);
|
resetBtn.addEventListener('click', resetFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pagination buttons
|
||||||
|
const prevBtn = document.getElementById('prevPage');
|
||||||
|
const nextBtn = document.getElementById('nextPage');
|
||||||
|
if (prevBtn) {
|
||||||
|
prevBtn.addEventListener('click', async () => {
|
||||||
|
if (lastPaging.has_prev && currentPage > 1) {
|
||||||
|
currentPage -= 1;
|
||||||
|
const pageInput2 = document.getElementById('page');
|
||||||
|
if (pageInput2) pageInput2.value = String(currentPage);
|
||||||
|
await searchTransactions(currentPage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (nextBtn) {
|
||||||
|
nextBtn.addEventListener('click', async () => {
|
||||||
|
if (lastPaging.has_next) {
|
||||||
|
currentPage += 1;
|
||||||
|
const pageInput3 = document.getElementById('page');
|
||||||
|
if (pageInput3) pageInput3.value = String(currentPage);
|
||||||
|
await searchTransactions(currentPage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -411,8 +411,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filter-group">
|
<div class="filter-group">
|
||||||
<label for="limit">Results Limit</label>
|
<label for="page_size">Page Size</label>
|
||||||
<input type="number" id="limit" name="limit" value="30" min="1" max="100">
|
<select id="page_size" name="page_size">
|
||||||
|
<option value="10">10</option>
|
||||||
|
<option value="20">20</option>
|
||||||
|
<option value="30" selected>30</option>
|
||||||
|
<option value="50">50</option>
|
||||||
|
<option value="100">100</option>
|
||||||
|
</select>
|
||||||
|
<input type="hidden" id="page" name="page" value="1">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filter-group">
|
<div class="filter-group">
|
||||||
@ -452,6 +459,11 @@
|
|||||||
<div class="results-section" id="resultsSection" style="display: none;">
|
<div class="results-section" id="resultsSection" style="display: none;">
|
||||||
<div class="results-header">
|
<div class="results-header">
|
||||||
<div class="results-count" id="resultsCount"></div>
|
<div class="results-count" id="resultsCount"></div>
|
||||||
|
<div class="pagination-controls" style="display:flex;gap:10px;align-items:center;">
|
||||||
|
<button type="button" class="btn btn-secondary" id="prevPage">Prev</button>
|
||||||
|
<div id="pageInfo" style="font-weight:600;color:#333;"></div>
|
||||||
|
<button type="button" class="btn btn-secondary" id="nextPage">Next</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-container" id="tableContainer">
|
<div class="table-container" id="tableContainer">
|
||||||
<table id="transactionsTable">
|
<table id="transactionsTable">
|
||||||
|
|||||||
@ -306,6 +306,9 @@ router.get('/transactions/recent', async (req, res) => {
|
|||||||
size_max,
|
size_max,
|
||||||
beds,
|
beds,
|
||||||
project,
|
project,
|
||||||
|
// pagination params
|
||||||
|
page,
|
||||||
|
page_size,
|
||||||
limit
|
limit
|
||||||
} = req.query;
|
} = req.query;
|
||||||
|
|
||||||
@ -322,22 +325,18 @@ router.get('/transactions/recent', async (req, res) => {
|
|||||||
limitNum = parsed;
|
limitNum = parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build SQL query with optional filters
|
// Build base WHERE with optional filters
|
||||||
let sql = `
|
let baseWhere = ' WHERE 1=1';
|
||||||
SELECT *
|
|
||||||
FROM transactions
|
|
||||||
WHERE 1=1
|
|
||||||
`;
|
|
||||||
const params = [];
|
const params = [];
|
||||||
|
|
||||||
// Apply filters (case-insensitive matching where applicable)
|
// Apply filters (case-insensitive matching where applicable)
|
||||||
if (area_name && area_name.trim() !== '') {
|
if (area_name && area_name.trim() !== '') {
|
||||||
sql += ' AND LOWER(area_en) LIKE ?';
|
baseWhere += ' AND LOWER(area_en) LIKE ?';
|
||||||
params.push(`%${area_name.toLowerCase().trim()}%`);
|
params.push(`%${area_name.toLowerCase().trim()}%`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property_type && property_type.trim() !== '' && property_type !== 'all') {
|
if (property_type && property_type.trim() !== '' && property_type !== 'all') {
|
||||||
sql += ' AND (LOWER(prop_type_en) LIKE ? OR LOWER(prop_sb_type_en) LIKE ?)';
|
baseWhere += ' AND (LOWER(prop_type_en) LIKE ? OR LOWER(prop_sb_type_en) LIKE ?)';
|
||||||
const propType = `%${property_type.toLowerCase().trim()}%`;
|
const propType = `%${property_type.toLowerCase().trim()}%`;
|
||||||
params.push(propType, propType);
|
params.push(propType, propType);
|
||||||
}
|
}
|
||||||
@ -348,13 +347,13 @@ router.get('/transactions/recent', async (req, res) => {
|
|||||||
const hasMin = minNum !== undefined && !isNaN(minNum);
|
const hasMin = minNum !== undefined && !isNaN(minNum);
|
||||||
const hasMax = maxNum !== undefined && !isNaN(maxNum);
|
const hasMax = maxNum !== undefined && !isNaN(maxNum);
|
||||||
if (hasMin && hasMax) {
|
if (hasMin && hasMax) {
|
||||||
sql += ' AND actual_area BETWEEN ? AND ?';
|
baseWhere += ' AND actual_area BETWEEN ? AND ?';
|
||||||
params.push(minNum, maxNum);
|
params.push(minNum, maxNum);
|
||||||
} else if (hasMin) {
|
} else if (hasMin) {
|
||||||
sql += ' AND actual_area >= ?';
|
baseWhere += ' AND actual_area >= ?';
|
||||||
params.push(minNum);
|
params.push(minNum);
|
||||||
} else if (hasMax) {
|
} else if (hasMax) {
|
||||||
sql += ' AND actual_area <= ?';
|
baseWhere += ' AND actual_area <= ?';
|
||||||
params.push(maxNum);
|
params.push(maxNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,46 +361,96 @@ router.get('/transactions/recent', async (req, res) => {
|
|||||||
const bedsStr = beds.toString().trim();
|
const bedsStr = beds.toString().trim();
|
||||||
// Match beds - handle formats like "3 b/r", "3.0", "3", "studio"
|
// Match beds - handle formats like "3 b/r", "3.0", "3", "studio"
|
||||||
if (bedsStr.toLowerCase() === 'studio') {
|
if (bedsStr.toLowerCase() === 'studio') {
|
||||||
sql += ' AND LOWER(rooms_en) = ?';
|
baseWhere += ' AND LOWER(rooms_en) = ?';
|
||||||
params.push('studio');
|
params.push('studio');
|
||||||
} else if (bedsStr.toLowerCase() === 'null' || bedsStr === '') {
|
} else if (bedsStr.toLowerCase() === 'null' || bedsStr === '') {
|
||||||
sql += ' AND (rooms_en IS NULL OR rooms_en = "")';
|
baseWhere += ' AND (rooms_en IS NULL OR rooms_en = "")';
|
||||||
} else {
|
} else {
|
||||||
sql += ' AND (rooms_en LIKE ? OR rooms_en = ? OR rooms_en = ?)';
|
baseWhere += ' AND (rooms_en LIKE ? OR rooms_en = ? OR rooms_en = ?)';
|
||||||
params.push(`%${bedsStr}%`, bedsStr, `${bedsStr}.0`);
|
params.push(`%${bedsStr}%`, bedsStr, `${bedsStr}.0`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (project && project.trim() !== '' && project !== 'all') {
|
if (project && project.trim() !== '' && project !== 'all') {
|
||||||
sql += ' AND (LOWER(project_en) LIKE ? OR LOWER(master_project_en) LIKE ?)';
|
baseWhere += ' AND (LOWER(project_en) LIKE ? OR LOWER(master_project_en) LIKE ?)';
|
||||||
const projectName = `%${project.toLowerCase().trim()}%`;
|
const projectName = `%${project.toLowerCase().trim()}%`;
|
||||||
params.push(projectName, projectName);
|
params.push(projectName, projectName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order by most recent first; apply LIMIT only if provided
|
// Pagination decision: page/page_size OR legacy limit triggers bounded fetch; otherwise full data
|
||||||
sql += ' ORDER BY instance_date DESC';
|
const rawPageSize = page_size ?? undefined;
|
||||||
if (limitNum !== undefined) {
|
const wantsPagination = (page !== undefined) || (rawPageSize !== undefined) || (limitNum !== undefined);
|
||||||
sql += ` LIMIT ${limitNum}`;
|
const defaultPage = 1;
|
||||||
|
const defaultPageSize = 30;
|
||||||
|
const pageNum = (() => { const n = parseInt(page ?? defaultPage, 10); return isNaN(n) || n < 1 ? defaultPage : n; })();
|
||||||
|
const pageSizeNum = (() => { const n = parseInt((rawPageSize ?? (limitNum !== undefined ? limitNum : defaultPageSize)), 10); return isNaN(n) || n < 1 ? defaultPageSize : n; })();
|
||||||
|
const offsetNum = (pageNum - 1) * pageSizeNum;
|
||||||
|
|
||||||
|
const orderBy = ' ORDER BY instance_date DESC, transaction_id DESC';
|
||||||
|
let dataSql;
|
||||||
|
let total = null;
|
||||||
|
if (!wantsPagination) {
|
||||||
|
dataSql = `
|
||||||
|
SELECT *
|
||||||
|
FROM transactions
|
||||||
|
${baseWhere}
|
||||||
|
${orderBy}
|
||||||
|
`;
|
||||||
|
} else if (limitNum !== undefined && page === undefined && page_size === undefined) {
|
||||||
|
// Legacy behavior: only limit provided (no paging), apply LIMIT without OFFSET
|
||||||
|
dataSql = `
|
||||||
|
SELECT *
|
||||||
|
FROM transactions
|
||||||
|
${baseWhere}
|
||||||
|
${orderBy}
|
||||||
|
LIMIT ${limitNum}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
// Full pagination with COUNT
|
||||||
|
const countSql = `
|
||||||
|
SELECT COUNT(*) AS total
|
||||||
|
FROM transactions
|
||||||
|
${baseWhere}
|
||||||
|
`;
|
||||||
|
const countRows = await database.query(countSql, params);
|
||||||
|
total = countRows && countRows[0] ? countRows[0].total : 0;
|
||||||
|
dataSql = `
|
||||||
|
SELECT *
|
||||||
|
FROM transactions
|
||||||
|
${baseWhere}
|
||||||
|
${orderBy}
|
||||||
|
LIMIT ${pageSizeNum} OFFSET ${offsetNum}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`🔍 Fetching recent transactions with filters:`, {
|
console.log(`🔍 Fetching recent transactions with filters:`, {
|
||||||
area_name, property_type, size, size_min, size_max, beds, project, limit: limitNum
|
area_name, property_type, size, size_min, size_max, beds, project, limit: limitNum, page, page_size
|
||||||
});
|
});
|
||||||
|
|
||||||
const transactions = await database.query(sql, params);
|
const transactions = await database.query(dataSql, params);
|
||||||
|
|
||||||
|
const totalPages = (total !== null) ? Math.max(1, Math.ceil(total / pageSizeNum)) : 1;
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
transactions: transactions,
|
transactions: transactions,
|
||||||
count: transactions.length,
|
count: transactions.length,
|
||||||
|
total: total !== null ? total : transactions.length,
|
||||||
|
page: total !== null ? pageNum : null,
|
||||||
|
page_size: total !== null ? pageSizeNum : (limitNum !== undefined ? limitNum : null),
|
||||||
|
total_pages: total !== null ? totalPages : 1,
|
||||||
|
has_next: total !== null ? pageNum < totalPages : false,
|
||||||
|
has_prev: total !== null ? pageNum > 1 : false,
|
||||||
filters: {
|
filters: {
|
||||||
area_name: area_name || null,
|
area_name: area_name || null,
|
||||||
property_type: property_type || null,
|
property_type: property_type || null,
|
||||||
size: size || null,
|
size: size || null,
|
||||||
beds: beds || null,
|
beds: beds || null,
|
||||||
project: project || null,
|
project: project || null,
|
||||||
limit: limitNum ?? null
|
limit: limitNum ?? null,
|
||||||
|
page: total !== null ? pageNum : null,
|
||||||
|
page_size: total !== null ? pageSizeNum : (limitNum !== undefined ? limitNum : null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user