diff --git a/app/composables/usePrayerStatistics.ts b/app/composables/usePrayerStatistics.ts index 6f8a2c60..2ad7df48 100644 --- a/app/composables/usePrayerStatistics.ts +++ b/app/composables/usePrayerStatistics.ts @@ -1,6 +1,7 @@ // Port of marketing-theme/js/components/src/main.ts (the -// `getPeopleGroupsStatistics` function). Fetches totals from -// `pray.doxa.life/api/people-groups/statistics` and exposes them as +// `getPeopleGroupsStatistics` function). Fetches totals from our own +// server route `/api/people-groups/statistics` (which proxies+caches +// `pray.doxa.life/api/people-groups/statistics`) and exposes them as // reactive refs plus a `reload()` method. Consumers render their own // counters and progress bars; in the original source the DOM was updated // imperatively via `#prayer-current-status`, `#adopted-current-status` @@ -8,18 +9,22 @@ // to keep the composable side-effect free. export interface PrayerStatistics { + total: number total_with_prayer: number total_with_full_prayer: number total_adopted: number } -const TOTAL_PEOPLE_GROUPS = 2085 +// Fallback denominator used only when the upstream API hasn't responded +// yet (first paint on a cold cache, or upstream failure). Prevents a +// divide-by-zero in the percent computeds. +const FALLBACK_TOTAL = 2085 export function usePrayerStatistics() { - const config = useRuntimeConfig() - const prayBaseUrl = config.public.prayBaseUrl as string + const { locale } = useI18n() const stats = useState('prayer-stats', () => ({ + total: 0, total_with_prayer: 0, total_with_full_prayer: 0, total_adopted: 0 @@ -31,9 +36,9 @@ export function usePrayerStatistics() { loading.value = true error.value = null try { - const response = await fetch(`${prayBaseUrl}/api/people-groups/statistics`) - const data = await response.json() + const data = await $fetch('/api/people-groups/statistics') stats.value = { + total: Number(data.total || 0), total_with_prayer: Number(data.total_with_prayer || 0), total_with_full_prayer: Number(data.total_with_full_prayer || 0), total_adopted: Number(data.total_adopted || 0) @@ -46,20 +51,49 @@ export function usePrayerStatistics() { } } + // SSR-friendly loader: populates the shared `stats` state during the + // server render via useAsyncData, so denominators render correctly on + // first paint without a client-side flicker. + async function ensureLoaded() { + if (stats.value.total > 0) return + await useAsyncData('prayer-stats', async () => { + const data = await $fetch('/api/people-groups/statistics') + stats.value = { + total: Number(data.total || 0), + total_with_prayer: Number(data.total_with_prayer || 0), + total_with_full_prayer: Number(data.total_with_full_prayer || 0), + total_adopted: Number(data.total_adopted || 0) + } + return stats.value + }) + } + + const totalPeopleGroups = computed(() => stats.value.total || FALLBACK_TOTAL) + // Use the active locale's grouping separator (e.g. "2.085" in de, "2 085" + // in fr/ru) but force Latin digits via the `-u-nu-latn` numbering system so + // the count matches the Western digits used everywhere else on the page — + // the raw numerator counts and the numbers hardcoded in translated strings + // (e.g. "144", "202"). Without this, ar would render Eastern-Arabic digits. + const totalPeopleGroupsFormatted = computed(() => + totalPeopleGroups.value.toLocaleString(`${locale.value}-u-nu-latn`) + ) + const prayerCoveragePercent = computed( - () => Math.min(100, (stats.value.total_with_full_prayer / TOTAL_PEOPLE_GROUPS) * 100) + () => Math.min(100, (stats.value.total_with_full_prayer / totalPeopleGroups.value) * 100) ) const adoptedPercent = computed( - () => Math.min(100, (stats.value.total_adopted / TOTAL_PEOPLE_GROUPS) * 100) + () => Math.min(100, (stats.value.total_adopted / totalPeopleGroups.value) * 100) ) return { stats: readonly(stats), loading: readonly(loading), error: readonly(error), + totalPeopleGroups, + totalPeopleGroupsFormatted, prayerCoveragePercent, adoptedPercent, reload, - TOTAL_PEOPLE_GROUPS + ensureLoaded } } diff --git a/app/pages/adopt/index.vue b/app/pages/adopt/index.vue index 353e8dce..f795af0a 100644 --- a/app/pages/adopt/index.vue +++ b/app/pages/adopt/index.vue @@ -16,7 +16,14 @@ const adoptBase = computed(() => { return p.endsWith('/') ? p : `${p}/` }) -const { stats, adoptedPercent, reload } = usePrayerStatistics() +const { + stats, + adoptedPercent, + totalPeopleGroups, + reload, + ensureLoaded +} = usePrayerStatistics() +await ensureLoaded() onMounted(() => reload()) const config = useRuntimeConfig() @@ -58,7 +65,7 @@ useTextHighlight()

{{ t('Current Status') }}

- {{ stats.total_adopted }} / 2085 + {{ stats.total_adopted }} / {{ totalPeopleGroups }}

{{ t('people groups adopted') }}

diff --git a/app/pages/index.vue b/app/pages/index.vue index 4f49565f..4fa9aa24 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -19,6 +19,9 @@ function openVideo() { videoModalRef.value?.open() } +const { totalPeopleGroupsFormatted, ensureLoaded } = usePrayerStatistics() +await ensureLoaded() + const mapboxToken = config.public.mapboxToken as string // Preload the heading font (Bebas Neue) for the homepage hero h1 (the LCP text) @@ -118,7 +121,7 @@ useTextHighlight()

- {{ t('{0} unengaged people groups', ['2,085']) }} + {{ t('{0} unengaged people groups', [totalPeopleGroupsFormatted]) }}

{{ t('Our hope is to see each of them covered in 24-hour prayer, and your church can be part of it.') }} @@ -203,7 +206,7 @@ useTextHighlight()

{{ t('Unengaged') }}

{{ t('{0} Million', ['202']) }} - {{ t('{0} People Groups', ['2,085']) }} + {{ t('{0} People Groups', [totalPeopleGroupsFormatted]) }}
@@ -247,7 +250,7 @@ useTextHighlight()

{{ t('In partnership with the global church, our vision is for...') }}

    -
  • {{ t('Daily 24-hour prayer coverage for all 2,085 unengaged peoples') }}
  • +
  • {{ t('Daily 24-hour prayer coverage for all {0} unengaged peoples', [totalPeopleGroupsFormatted]) }}
  • {{ t('No unengaged people groups by 2033') }}
  • {{ t('Mobilization of 20,000+ DOXA partnership missionaries') }}
  • {{ t('Fruitful engagement among frontier peoples and the under-engaged') }}
  • diff --git a/app/pages/pray.vue b/app/pages/pray.vue index 92fa9a34..fa1cfad9 100644 --- a/app/pages/pray.vue +++ b/app/pages/pray.vue @@ -14,8 +14,15 @@ const selectUrl = computed(() => const translations = computed(() => buildUupgListTranslations(t)) -const { stats, prayerCoveragePercent } = usePrayerStatistics() -const { reload } = usePrayerStatistics() +const { + stats, + prayerCoveragePercent, + totalPeopleGroups, + totalPeopleGroupsFormatted, + reload, + ensureLoaded +} = usePrayerStatistics() +await ensureLoaded() onMounted(() => reload()) const mapboxToken = config.public.mapboxToken as string @@ -54,12 +61,12 @@ useTextHighlight()

    {{ t('Prayer Goal') }}

    {{ t('24-Hour Prayer Coverage') }}

    -

    {{ t('Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups') }}

    +

    {{ t('Mobilize 144+ people praying 10 minutes a day for all {0} people groups', [totalPeopleGroupsFormatted]) }}

    {{ t('Current Status') }}

    - {{ stats.total_with_full_prayer }} / 2085 + {{ stats.total_with_full_prayer }} / {{ totalPeopleGroups }}

    {{ t('People groups with committed 24-hour prayer coverage') }}

    diff --git a/i18n/locales/ar/common.json b/i18n/locales/ar/common.json index e27affaa..c8dbe788 100644 --- a/i18n/locales/ar/common.json +++ b/i18n/locales/ar/common.json @@ -52,7 +52,7 @@ "DOXA Playbook Slides": "عرض شرائح دليل دوكسا", "DOXA Promo Video": "الفيديو الترويجي لدليل دوكسا", "DOXA is the Greek word for \"GLORY\".": "دوكسا هي الكلمة اليونانية التي تعني \"المجد\".", - "Daily 24-hour prayer coverage for all 2,085 unengaged peoples": "توفير تغطية صلاة يومية على مدار 24 ساعة لمجموعة الشعوب الغير مخدومة روحيا والبالغ عدوهم 2.085", + "Daily 24-hour prayer coverage for all {0} unengaged peoples": "توفير تغطية صلاة يومية على مدار 24 ساعة لمجموعة الشعوب الغير مخدومة روحيا والبالغ عدوهم {0}", "Definitions": "التعريفات", "Disciple & church multiplication": "تضاعف التلاميذ والكنيسة", "Discussion Guide": "دليل النقاش", @@ -124,7 +124,7 @@ "Message": "الرسالة", "Mobilization of 20,000+ DOXA partnership missionaries": "حشد أكثر من 20.000 مبشّر بالتعاون مع شركاء دوكسا لتحقيق الرسالة المشتركة", "Mobilize": "حشد المؤمنين", - "Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups": "حشد أكثر من 144 شخص للصلاة لمدة 10 دقائق يوميا من أجل جميع المجموعات العرقية البالغ عددها 2,085 مجموعة", + "Mobilize 144+ people praying 10 minutes a day for all {0} people groups": "حشد أكثر من 144 شخص للصلاة لمدة 10 دقائق يوميا من أجل جميع المجموعات العرقية البالغ عددها {0} مجموعة", "Mobilize others in your church to join in prayer": "شجّعوا الآخرين في كنيستك على المشاركة في الصلاة", "Mobilize toward the goal of at least 144 prayer partners to cover the people group in continuous, daily prayer (10 minutes each, 24 hours a day).": "تعبئة المشاركين نحو هدف الحصول على ما يقل عن 144 شريك صلاة لتغطية المجموعة البشرية بصلاة مستمرة يوميا، (10 دقائق كل شخص، على مدار 24 ساعة).", "More": "المزيد", diff --git a/i18n/locales/de/common.json b/i18n/locales/de/common.json index 79de8d86..86d9f53b 100644 --- a/i18n/locales/de/common.json +++ b/i18n/locales/de/common.json @@ -52,7 +52,7 @@ "DOXA Playbook Slides": "DOXA-Playbook-Folien", "DOXA Promo Video": "DOXA-Werbevideo", "DOXA is the Greek word for \"GLORY\".": "DOXA ist das griechische Wort für „EHRE“.", - "Daily 24-hour prayer coverage for all 2,085 unengaged peoples": "Täglich alle 2085 völlig unerreichte Volksgruppen durch kontinuierliches Gebet abzudecken", + "Daily 24-hour prayer coverage for all {0} unengaged peoples": "Täglich alle {0} völlig unerreichte Volksgruppen durch kontinuierliches Gebet abzudecken", "Definitions": "Begriffsbestimmungen", "Disciple & church multiplication": "Jüngerschaft & Gemeindemultiplikation", "Discussion Guide": "Diskussionsleitfaden", @@ -124,7 +124,7 @@ "Message": "Nachricht", "Mobilization of 20,000+ DOXA partnership missionaries": "20,000 DOXA-Partnerschafts-Missionare zu mobilisieren", "Mobilize": "Mobilize", - "Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups": "Mobilisiere 144+ Fürbitter, welche 10 Minuten am Tag für alle 2085 Volksgruppen beten", + "Mobilize 144+ people praying 10 minutes a day for all {0} people groups": "Mobilisiere 144+ Fürbitter, welche 10 Minuten am Tag für alle {0} Volksgruppen beten", "Mobilize others in your church to join in prayer": "Mobilisieren Sie andere in Ihrer Gemeinde, sich dem Gebet anzuschließen", "Mobilize toward the goal of at least 144 prayer partners to cover the people group in continuous, daily prayer (10 minutes each, 24 hours a day).": "Mobilisiere für das Ziel, mindestens 144 Gebetspartner zu gewinnen, die diese Volksgruppe täglich ununterbrochen im Gebet begleiten (jeweils 10 Minuten, innerhalb 24 Stunden eines Tages).", "More": "Mehr", diff --git a/i18n/locales/en/common.json b/i18n/locales/en/common.json index e4f37f1a..b383616d 100644 --- a/i18n/locales/en/common.json +++ b/i18n/locales/en/common.json @@ -52,7 +52,7 @@ "DOXA Playbook Slides": "DOXA Playbook Slides", "DOXA Promo Video": "DOXA Promo Video", "DOXA is the Greek word for \"GLORY\".": "DOXA is the Greek word for \"GLORY\".", - "Daily 24-hour prayer coverage for all 2,085 unengaged peoples": "Daily 24-hour prayer coverage for all 2,085 unengaged peoples", + "Daily 24-hour prayer coverage for all {0} unengaged peoples": "Daily 24-hour prayer coverage for all {0} unengaged peoples", "Definitions": "Definitions", "Disciple & church multiplication": "Disciple & church multiplication", "Discussion Guide": "Discussion Guide", @@ -124,7 +124,7 @@ "Message": "Message", "Mobilization of 20,000+ DOXA partnership missionaries": "Mobilization of 20,000+ DOXA partnership missionaries", "Mobilize": "Mobilize", - "Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups": "Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups", + "Mobilize 144+ people praying 10 minutes a day for all {0} people groups": "Mobilize 144+ people praying 10 minutes a day for all {0} people groups", "Mobilize others in your church to join in prayer": "Mobilize others in your church to join in prayer", "Mobilize toward the goal of at least 144 prayer partners to cover the people group in continuous, daily prayer (10 minutes each, 24 hours a day).": "Mobilize toward the goal of at least 144 prayer partners to cover the people group in continuous, daily prayer (10 minutes each, 24 hours a day).", "More": "More", diff --git a/i18n/locales/es/common.json b/i18n/locales/es/common.json index b5e9d0c7..0098c47c 100644 --- a/i18n/locales/es/common.json +++ b/i18n/locales/es/common.json @@ -52,7 +52,7 @@ "DOXA Playbook Slides": "Diapositivas del manual de DOXA", "DOXA Promo Video": "Vídeo promocional de DOXA", "DOXA is the Greek word for \"GLORY\".": "DOXA es la palabra griega para «GLORIA».", - "Daily 24-hour prayer coverage for all 2,085 unengaged peoples": "Cobertura diaria de oración las 24 horas por los 2.085 pueblos no evangelizados", + "Daily 24-hour prayer coverage for all {0} unengaged peoples": "Cobertura diaria de oración las 24 horas por los {0} pueblos no evangelizados", "Definitions": "Definiciones", "Disciple & church multiplication": "Discípulo y multiplicación de iglesias", "Discussion Guide": "Guía para el debate", @@ -124,7 +124,7 @@ "Message": "Mensaje", "Mobilization of 20,000+ DOXA partnership missionaries": "Movilización de más de 20.000 misioneros asociados a DOXA", "Mobilize": "Movilizar", - "Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups": "Movilizar a más de 144 personas para que recen 10 minutos al día por los 2085 grupos étnicos.", + "Mobilize 144+ people praying 10 minutes a day for all {0} people groups": "Movilizar a más de 144 personas para que recen 10 minutos al día por los {0} grupos étnicos.", "Mobilize others in your church to join in prayer": "Anima a otros miembros de tu iglesia a unirse a la oración", "Mobilize toward the goal of at least 144 prayer partners to cover the people group in continuous, daily prayer (10 minutes each, 24 hours a day).": "Movilízate con el objetivo de conseguir al menos 144 compañeros de oración para cubrir al grupo étnico con oraciones continuas y diarias (10 minutos cada uno, las 24 horas del día).", "More": "Más", diff --git a/i18n/locales/fr/common.json b/i18n/locales/fr/common.json index 8ceaacc0..aba52909 100644 --- a/i18n/locales/fr/common.json +++ b/i18n/locales/fr/common.json @@ -52,7 +52,7 @@ "DOXA Playbook Slides": "Diapositives du guide pratique DOXA", "DOXA Promo Video": "Vidéo promotionnelle DOXA", "DOXA is the Greek word for \"GLORY\".": "DOXA est le mot grec qui signifie « GLOIRE ».", - "Daily 24-hour prayer coverage for all 2,085 unengaged peoples": "Prière quotidienne 24 heures sur 24 pour les 2 085 peuples non ciblés", + "Daily 24-hour prayer coverage for all {0} unengaged peoples": "Prière quotidienne 24 heures sur 24 pour les {0} peuples non ciblés", "Definitions": "Définitions", "Disciple & church multiplication": "Disciple et multiplication d'églises", "Discussion Guide": "Guide de discussion", @@ -124,7 +124,7 @@ "Message": "Message", "Mobilization of 20,000+ DOXA partnership missionaries": "Mobilisation de plus de 20 000 missionnaires partenaires de DOXA", "Mobilize": "Mobiliser", - "Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups": "Mobiliser plus de 144 personnes pour prier 10 minutes par jour pour les 2 085 groupes ethniques.", + "Mobilize 144+ people praying 10 minutes a day for all {0} people groups": "Mobiliser plus de 144 personnes pour prier 10 minutes par jour pour les {0} groupes ethniques.", "Mobilize others in your church to join in prayer": "Mobilisez les autres membres de votre paroisse pour qu'ils se joignent à vous dans la prière", "Mobilize toward the goal of at least 144 prayer partners to cover the people group in continuous, daily prayer (10 minutes each, 24 hours a day).": "Mobilisez-vous pour atteindre l'objectif d'au moins 144 partenaires de prière afin de couvrir ce groupe ethnique par une prière quotidienne et continue (10 minutes chacun, 24 heures sur 24).", "More": "Plus", diff --git a/i18n/locales/hi/common.json b/i18n/locales/hi/common.json index ac6cc5ec..bab06091 100644 --- a/i18n/locales/hi/common.json +++ b/i18n/locales/hi/common.json @@ -52,7 +52,7 @@ "DOXA Playbook Slides": "डॉक्सा प्लेबुक स्लाइड्स", "DOXA Promo Video": "डॉक्सा प्रमो वीडियो", "DOXA is the Greek word for \"GLORY\".": "DOXA ग्रीक शब्द है जिसका अर्थ \"महिमा\" है।", - "Daily 24-hour prayer coverage for all 2,085 unengaged peoples": "सभी 2,085 असंलग्न लोगों के लिए प्रतिदिन 24 घंटे प्रार्थना कवरेज", + "Daily 24-hour prayer coverage for all {0} unengaged peoples": "सभी {0} असंलग्न लोगों के लिए प्रतिदिन 24 घंटे प्रार्थना कवरेज", "Definitions": "परिभाषाएँ", "Disciple & church multiplication": "शिष्य और चर्च की वृद्धि", "Discussion Guide": "चर्चा मार्गदर्शिका", @@ -124,7 +124,7 @@ "Message": "संदेश", "Mobilization of 20,000+ DOXA partnership missionaries": "20,000+ DOXA साझेदारी मिशनरियों का संगठित होना", "Mobilize": "लगातार सक्रिय रहो", - "Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups": "सभी 2,085 जनसमूहों के लिए प्रतिदिन 10 मिनट प्रार्थना करने हेतु 144+ लोगों को सक्रिय करें।", + "Mobilize 144+ people praying 10 minutes a day for all {0} people groups": "सभी {0} जनसमूहों के लिए प्रतिदिन 10 मिनट प्रार्थना करने हेतु 144+ लोगों को सक्रिय करें।", "Mobilize others in your church to join in prayer": "अपने चर्च में दूसरों को प्रार्थना में शामिल होने के लिए प्रेरित करें।", "Mobilize toward the goal of at least 144 prayer partners to cover the people group in continuous, daily prayer (10 minutes each, 24 hours a day).": "लोगों के समूह को निरंतर, दैनिक प्रार्थना (प्रत्येक 10 मिनट, दिन में 24 घंटे) के माध्यम से आच्छादित करने के लिए कम से कम 144 प्रार्थना साझेदारों को जुटाएँ।", "More": "और ज्यादा", diff --git a/i18n/locales/pt/common.json b/i18n/locales/pt/common.json index 9b31f0f0..ad76c2b7 100644 --- a/i18n/locales/pt/common.json +++ b/i18n/locales/pt/common.json @@ -52,7 +52,7 @@ "DOXA Playbook Slides": "Slides do Manual do DOXA", "DOXA Promo Video": "Vídeo promocional da DOXA", "DOXA is the Greek word for \"GLORY\".": "DOXA é a palavra grega para «GLÓRIA».", - "Daily 24-hour prayer coverage for all 2,085 unengaged peoples": "Cobertura diária de oração 24 horas por dia para todos os 2.085 povos não engajados", + "Daily 24-hour prayer coverage for all {0} unengaged peoples": "Cobertura diária de oração 24 horas por dia para todos os {0} povos não engajados", "Definitions": "Definições", "Disciple & church multiplication": "Multiplicação de discípulos e igrejas", "Discussion Guide": "Guia de discussão", @@ -124,7 +124,7 @@ "Message": "Mensagem", "Mobilization of 20,000+ DOXA partnership missionaries": "Mobilização de mais de 20.000 missionários parceiros da DOXA", "Mobilize": "Mobilize", - "Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups": "Mobilizar mais de 144 pessoas para orar 10 minutos por dia por todos os 2.085 grupos étnicos", + "Mobilize 144+ people praying 10 minutes a day for all {0} people groups": "Mobilizar mais de 144 pessoas para orar 10 minutos por dia por todos os {0} grupos étnicos", "Mobilize others in your church to join in prayer": "Mobilize outros membros da sua igreja para se unirem em oração", "Mobilize toward the goal of at least 144 prayer partners to cover the people group in continuous, daily prayer (10 minutes each, 24 hours a day).": "Mobilize-se com o objetivo de ter pelo menos 144 parceiros de oração para cobrir o grupo étnico em oração contínua e diária (10 minutos cada, 24 horas por dia).", "More": "Mais", diff --git a/i18n/locales/ru/common.json b/i18n/locales/ru/common.json index 5080b6df..36177c74 100644 --- a/i18n/locales/ru/common.json +++ b/i18n/locales/ru/common.json @@ -52,7 +52,7 @@ "DOXA Playbook Slides": "Слайды из руководства DOXA", "DOXA Promo Video": "Промо-ролик DOXA", "DOXA is the Greek word for \"GLORY\".": "DOXA — это греческое слово, означающее «СЛАВА».", - "Daily 24-hour prayer coverage for all 2,085 unengaged peoples": "Ежедневная 24-часовая молитвенная поддержка для всех 2085 незадействованных народов", + "Daily 24-hour prayer coverage for all {0} unengaged peoples": "Ежедневная 24-часовая молитвенная поддержка для всех {0} незадействованных народов", "Definitions": "Определения", "Disciple & church multiplication": "Ученики и умножение церквей", "Discussion Guide": "Руководство по обсуждению", @@ -124,7 +124,7 @@ "Message": "Сообщение", "Mobilization of 20,000+ DOXA partnership missionaries": "Мобилизация более 20 000 миссионеров-партнеров DOXA", "Mobilize": "Мобилизовать", - "Mobilize 144+ people praying 10 minutes a day for all 2,085 people groups": "Мобилизуйте 144+ человек для молитвы по 10 минут в день за все 2 085 народностей", + "Mobilize 144+ people praying 10 minutes a day for all {0} people groups": "Мобилизуйте 144+ человек для молитвы по 10 минут в день за все {0} народностей", "Mobilize others in your church to join in prayer": "Призовите других членов вашей церкви присоединиться к молитве", "Mobilize toward the goal of at least 144 prayer partners to cover the people group in continuous, daily prayer (10 minutes each, 24 hours a day).": "Мобилизуйтесь для достижения цели: собрать как минимум 144 молитвенных партнера, которые будут ежедневно, непрерывно молиться за эту народность (по 10 минут каждый, 24 часа в сутки).", "More": "Больше", diff --git a/server/api/people-groups/statistics.get.ts b/server/api/people-groups/statistics.get.ts new file mode 100644 index 00000000..ea618afe --- /dev/null +++ b/server/api/people-groups/statistics.get.ts @@ -0,0 +1,40 @@ +// Server-side cached proxy to campaigns-sever's `/api/people-groups/statistics`. +// The composable `usePrayerStatistics` calls this so the upstream is only hit +// once per cache window per server instance — and so `total` (the live count +// of people groups) can drive the denominator that used to be hardcoded as +// 2,085 in templates. + +import { defineCachedEventHandler } from 'nitropack/runtime' + +export interface PrayerStatisticsResponse { + total: number + total_with_prayer: number + total_with_full_prayer: number + total_adopted: number + people_committed: string + committed_duration: string +} + +export default defineCachedEventHandler( + async (): Promise => { + const config = useRuntimeConfig() + const prayBaseUrl = String(config.public.prayBaseUrl || '').replace(/\/$/, '') + const data = await $fetch>( + `${prayBaseUrl}/api/people-groups/statistics`, + { timeout: 10_000 } + ) + return { + total: Number(data.total || 0), + total_with_prayer: Number(data.total_with_prayer || 0), + total_with_full_prayer: Number(data.total_with_full_prayer || 0), + total_adopted: Number(data.total_adopted || 0), + people_committed: String(data.people_committed || '0'), + committed_duration: String(data.committed_duration || '0') + } + }, + { + maxAge: 60 * 60, + swr: true, + name: 'people-groups-statistics' + } +)