import { getPayload, type Where } from 'payload' import React from 'react' import config from '@/payload.config' import './styles.css' import { PastorsTable, type PastorRow } from './PastorsTable' export const dynamic = 'force-dynamic' const PAGE_SIZE = 25 // Idioma usado para mostrar los códigos ISO de país como nombres legibles. const DISPLAY_LOCALE = 'es' const regionNames = new Intl.DisplayNames([DISPLAY_LOCALE], { type: 'region' }) const localizedCountry = (code?: string | null): string | null => { if (!code) return null try { return regionNames.of(code.toUpperCase()) ?? code } catch { return code } } // Código ISO alpha-2 -> emoji de bandera (símbolos indicadores regionales). const flag = (code?: string | null): string => { if (!code || code.length !== 2) return '' const base = 0x1f1e6 const cc = code.toUpperCase() return String.fromCodePoint(base + (cc.charCodeAt(0) - 65), base + (cc.charCodeAt(1) - 65)) } // Accent/case-insensitive normalizer for search matching ("méxico" ~ "mexico"). const normalize = (s: string): string => s .normalize('NFD') .replace(/\p{Diacritic}/gu, '') .toLowerCase() .trim() // All ISO 3166-1 alpha-2 codes, so a country typed by name resolves to its code // (country is stored as the ISO code, e.g. "MX" for México). // prettier-ignore const ALPHA2 = ['AD','AE','AF','AG','AI','AL','AM','AO','AQ','AR','AS','AT','AU','AW','AX','AZ','BA','BB','BD','BE','BF','BG','BH','BI','BJ','BL','BM','BN','BO','BQ','BR','BS','BT','BV','BW','BY','BZ','CA','CC','CD','CF','CG','CH','CI','CK','CL','CM','CN','CO','CR','CU','CV','CW','CX','CY','CZ','DE','DJ','DK','DM','DO','DZ','EC','EE','EG','EH','ER','ES','ET','FI','FJ','FK','FM','FO','FR','GA','GB','GD','GE','GF','GG','GH','GI','GL','GM','GN','GP','GQ','GR','GS','GT','GU','GW','GY','HK','HM','HN','HR','HT','HU','ID','IE','IL','IM','IN','IO','IQ','IR','IS','IT','JE','JM','JO','JP','KE','KG','KH','KI','KM','KN','KP','KR','KW','KY','KZ','LA','LB','LC','LI','LK','LR','LS','LT','LU','LV','LY','MA','MC','MD','ME','MF','MG','MH','MK','ML','MM','MN','MO','MP','MQ','MR','MS','MT','MU','MV','MW','MX','MY','MZ','NA','NC','NE','NF','NG','NI','NL','NO','NP','NR','NU','NZ','OM','PA','PE','PF','PG','PH','PK','PL','PM','PN','PR','PS','PT','PW','PY','QA','RE','RO','RS','RU','RW','SA','SB','SC','SD','SE','SG','SH','SI','SJ','SK','SL','SM','SN','SO','SR','SS','ST','SV','SX','SY','SZ','TC','TD','TF','TG','TH','TJ','TK','TL','TM','TN','TO','TR','TT','TV','TW','TZ','UA','UG','UM','US','UY','UZ','VA','VC','VE','VG','VI','VN','VU','WF','WS','YE','YT','ZA','ZM','ZW'] // Precomputed [normalizedName, code] pairs in the display locale. const COUNTRY_NAME_INDEX: [string, string][] = ALPHA2.map((code) => [ normalize(localizedCountry(code) ?? code), code, ]) // Country codes whose localized name contains the search term. const countryCodesMatching = (term: string): string[] => { const t = normalize(term) if (!t) return [] return COUNTRY_NAME_INDEX.filter(([name]) => name.includes(t)).map(([, code]) => code) } export default async function HomePage({ searchParams, }: { searchParams: Promise<{ q?: string; page?: string }> }) { const { q = '', page = '1' } = await searchParams const currentPage = Math.max(1, parseInt(page, 10) || 1) const search = q.trim() const payload = await getPayload({ config: await config }) // Country is stored as an ISO code, so resolve any country *name* in the // search term to its code(s) and match those too. const countryCodes = countryCodesMatching(search) const where: Where = search ? { or: [ { name: { like: search } }, { email: { like: search } }, { city: { like: search } }, { country: { like: search } }, ...(countryCodes.length ? [{ country: { in: countryCodes } }] : []), ], } : {} const result = await payload.find({ collection: 'pastors', where, sort: 'name', depth: 1, page: currentPage, limit: PAGE_SIZE, }) // Running total of impacted people across ALL matching records (not just the // current page). Only the number field is selected to keep this light. const impactedAgg = await payload.find({ collection: 'pastors', where, pagination: false, depth: 0, select: { impactedPeople: true }, }) const totalImpacted = impactedAgg.docs.reduce((sum, d) => sum + (d.impactedPeople ?? 0), 0) const rows: PastorRow[] = result.docs.map((p) => { const letter = p.letter && typeof p.letter === 'object' ? p.letter : null return { id: p.id, name: p.name, churchName: p.churchName ?? null, email: p.email ?? null, telephone: Array.isArray(p.telephone) ? p.telephone.filter(Boolean) : [], place: p.place ?? null, city: p.city ?? null, state: p.state ?? null, country: p.country ?? null, countryName: localizedCountry(p.country), countryFlag: flag(p.country), impactedPeople: p.impactedPeople ?? null, churchRegistered: Boolean(p.churchRegistered), registrationNumber: p.registrationNumber ?? null, inTelegram: Boolean(p.inTelegram), notes: p.notes ?? null, letterUrl: letter?.url ?? null, letterName: letter?.filename ?? null, } }) return (

Pastores

{result.totalDocs.toLocaleString('es')} registros · {totalImpacted.toLocaleString('es')} {' '} personas impactadas

{search && ( Limpiar )}

Página {result.page} de {result.totalPages}

« Anterior Siguiente »
) }