From efeee14752edac90e405d913923d1603e2c9805a Mon Sep 17 00:00:00 2001 From: Julio Ruiz Date: Thu, 13 Aug 2026 22:53:03 -0500 Subject: [PATCH] Add impacted-people total and letter deletion - Home header shows a running sum of impacted people across all matching records (respects the current search filter), next to the record count - Letters can be deleted from the table (trash button next to Download), which unlinks the pastor and removes the upload doc so a new file can be uploaded in its place Co-Authored-By: Claude Opus 4.8 --- src/app/(frontend)/PastorsTable.tsx | 84 +++++++++++++++++++++-------- src/app/(frontend)/actions.ts | 25 +++++++++ src/app/(frontend)/page.tsx | 16 ++++++ 3 files changed, 104 insertions(+), 21 deletions(-) diff --git a/src/app/(frontend)/PastorsTable.tsx b/src/app/(frontend)/PastorsTable.tsx index 6bc1fc1..f8653ce 100644 --- a/src/app/(frontend)/PastorsTable.tsx +++ b/src/app/(frontend)/PastorsTable.tsx @@ -3,7 +3,7 @@ import React, { useRef, useState, useTransition } from 'react' import { useRouter } from 'next/navigation' -import { createPastor, updatePastor, uploadLetter } from './actions' +import { createPastor, deleteLetter, updatePastor, uploadLetter } from './actions' export type PastorRow = { id: number @@ -136,26 +136,7 @@ export function PastorsTable({ rows }: { rows: PastorRow[] }) { { key: 'letter', label: 'Carta', - cell: (p) => - p.letterUrl ? ( - - Descargar - - ) : ( - - ), + cell: (p) => setUploading(p)} />, }, ] @@ -282,6 +263,67 @@ export function PastorsTable({ rows }: { rows: PastorRow[] }) { ) } +function LetterActions({ pastor, onUpload }: { pastor: PastorRow; onUpload: () => void }) { + const router = useRouter() + const [pending, startTransition] = useTransition() + + if (!pastor.letterUrl) { + return ( + + ) + } + + const onDelete = () => { + if (!window.confirm('¿Eliminar la carta? Podrás subir una nueva después.')) return + startTransition(async () => { + await deleteLetter(pastor.id) + router.refresh() + }) + } + + return ( +
+ + Descargar + + +
+ ) +} + function PastorModal({ pastor, onClose }: { pastor: PastorRow | null; onClose: () => void }) { const router = useRouter() const isCreate = pastor === null diff --git a/src/app/(frontend)/actions.ts b/src/app/(frontend)/actions.ts index 76fd683..99185a2 100644 --- a/src/app/(frontend)/actions.ts +++ b/src/app/(frontend)/actions.ts @@ -80,6 +80,31 @@ export async function updatePastor(id: number, data: PastorUpdateInput) { return { ok: true } } +/** + * Elimina la carta asociada a un pastor: desvincula el campo `letter` y borra + * el documento de subida, de modo que se pueda subir uno nuevo en su lugar. + */ +export async function deleteLetter(pastorId: number) { + const payload = await getPayload({ config: await config }) + + const pastor = await payload.findByID({ collection: 'pastors', id: pastorId, depth: 0 }) + const letterId = + pastor.letter && typeof pastor.letter === 'object' ? pastor.letter.id : pastor.letter + + await payload.update({ collection: 'pastors', id: pastorId, data: { letter: null } }) + + if (letterId) { + try { + await payload.delete({ collection: 'pastor-letters', id: letterId }) + } catch { + // The upload doc may already be gone; unlinking the pastor is enough. + } + } + + revalidatePath('/') + return { ok: true } +} + /** * Sube una carta (PDF o Word) y la asocia a un pastor. El archivo se guarda en * la colección de subidas `pastor-letters`, que valida los tipos de archivo diff --git a/src/app/(frontend)/page.tsx b/src/app/(frontend)/page.tsx index c5748e8..13ff2fc 100644 --- a/src/app/(frontend)/page.tsx +++ b/src/app/(frontend)/page.tsx @@ -61,6 +61,17 @@ export default async function HomePage({ 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 { @@ -90,6 +101,11 @@ export default async function HomePage({

Pastores

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