diff --git a/server/backend/citizens.lua b/server/backend/citizens.lua index 8cde669c..8453ebc4 100644 --- a/server/backend/citizens.lua +++ b/server/backend/citizens.lua @@ -84,16 +84,23 @@ local function safeQuery(query, params) return rows or {} end --- getCitizens - pulls citizens from database with pagination support +-- getCitizens - pulls citizens from database with pagination support - this shit is broken +-- this shit is now fixed. ps.registerCallback(resourceName .. ':server:getCitizens', function(source, page) local src = source - if not CheckAuth(src) then return {} end + if not CheckAuth(src) then + --added data to actually be pulled + return { data = {}, total = 0, totalPages = 1, page = 1, limit = 20 } + end + local startTime = os.clock() - page = page or 1 -- Default to page 1 if not provided + page = tonumber(page) or 1 local limit = Config.Pagination and Config.Pagination.Citizens or 20 local offset = (page - 1) * limit - -- Main query with pagination + local total = MySQL.scalar.await('SELECT COUNT(*) FROM players') or 0 + local totalPages = math.max(1, math.ceil(total / limit)) + local query = [[ SELECT mp.id, p.citizenid, JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) AS firstname, JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) AS lastname, @@ -104,10 +111,21 @@ ps.registerCallback(resourceName .. ':server:getCitizens', function(source, page FROM players AS p LEFT JOIN mdt_profiles AS mp ON CONVERT(p.citizenid USING utf8mb4) COLLATE utf8mb4_general_ci = CONVERT(mp.citizenid USING utf8mb4) COLLATE utf8mb4_general_ci + ORDER BY JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.lastname')) ASC, + JSON_UNQUOTE(JSON_EXTRACT(p.charinfo, '$.firstname')) ASC LIMIT ? OFFSET ? ]] + local result = safeQuery(query, { limit, offset }) - if not result or #result == 0 then return {} end + if not result or #result == 0 then + return { --same shit different row + data = {}, + total = total, + totalPages = totalPages, + page = page, + limit = limit + } + end local citizenids = {} for _, v in ipairs(result) do @@ -116,7 +134,7 @@ ps.registerCallback(resourceName .. ':server:getCitizens', function(source, page end end - -- Wrap flags in pcall since it queries mdt_reports_warrants / mdt_bolos which may not exist + -- Wrap flags in pcall since it queries mdt_reports_warrants / mdt_bolos which may not exist local ok, flagsByCid = pcall(collectCitizenFlags, citizenids) if not ok then ps.warn('[getCitizens] collectCitizenFlags failed: ' .. tostring(flagsByCid)) @@ -167,8 +185,8 @@ ps.registerCallback(resourceName .. ':server:getCitizens', function(source, page end end - for _, v in ipairs(result) do - v.id = _ + for i, v in ipairs(result) do + v.id = i v.cid = v.citizenid v.firstName = v.firstname v.lastName = v.lastname @@ -182,15 +200,18 @@ ps.registerCallback(resourceName .. ':server:getCitizens', function(source, page v.arrests = arrestCounts[v.citizenid] or 0 v.flags = flagsByCid[v.citizenid] or {} end + local endTime = os.clock() local elapsedTime = (endTime - startTime) * 1000 ps.debug(string.format("getCitizens callback executed in %.2f ms for page %d", elapsedTime, page)) - - if result[1] then - ps.debug('[getCitizens] Sample citizen data structure:', result[1]) - end - - return result + --no more sample citizen stuff. + return { + data = result, + total = total, + totalPages = totalPages, + page = page, + limit = limit + } end) -- searchPlayers - searches the database for citizens by provided query (first/last name, citizenid, phone number, occupation) diff --git a/web/src/pages/Citizens.svelte b/web/src/pages/Citizens.svelte index ec279964..98d639ad 100644 --- a/web/src/pages/Citizens.svelte +++ b/web/src/pages/Citizens.svelte @@ -107,12 +107,15 @@ let copyNotice = $state(""); let copyTimeout: ReturnType | null = null; + // im sure there's a better more streamlined way to do this, but here's a bandaid. let citizenPage = $state(1); - let citizenPerPage = $state(25); + let citizenPerPage = $state(20); + let citizenTotalPages = $state(1); // how many pages exist - let allFilteredCitizens = $derived.by(() => { + let filteredCitizens = $derived.by(() => { const query = searchQuery.trim().toLowerCase(); if (!query) return citizens; + return citizens.filter(({ firstName, lastName, cid, phone }) => [firstName, lastName, cid, phone].some((val) => val?.toLowerCase().includes(query), @@ -120,11 +123,12 @@ ); }); - let citizenTotalPages = $derived(Math.max(1, Math.ceil(allFilteredCitizens.length / citizenPerPage))); - - let filteredCitizens = $derived.by(() => { - const start = (citizenPage - 1) * citizenPerPage; - return allFilteredCitizens.slice(start, start + citizenPerPage); + // auto calls fetchCitizens for citizenpage + $effect(() => { + citizenPage; + if (!isEnvBrowser()) { + fetchCitizens(); + } }); // Reset to page 1 when search changes @@ -136,11 +140,16 @@ async function fetchCitizens() { loading = true; try { - const result = await fetchNui(NUI_EVENTS.CITIZEN.GET_CITIZENS); - citizens = Array.isArray(result) ? result : []; + const result = await fetchNui(NUI_EVENTS.CITIZEN.GET_CITIZENS, { + page: citizenPage + }); // this shit makes the whole world go round + + citizens = Array.isArray(result) ? result : []; // this shit shows you the world spinning + citizenTotalPages = Number(result?.totalPages) || 1; } catch (error) { globalNotifications.error("Failed to fetch citizens"); citizens = []; + citizenTotalpages = 1; } loading = false; } @@ -156,7 +165,6 @@ ]; return; } - await fetchCitizens(); }); useNuiEvent(NUI_EVENTS.CITIZEN.UPDATE_CITIZENS, (data) => {