Add DonorWall site view — public donor recognition by level

This commit is contained in:
Jonathan Miller
2026-06-18 11:12:43 -05:00
parent c5058cf99d
commit a704e716bf
2 changed files with 95 additions and 0 deletions
@@ -0,0 +1,50 @@
<?php
namespace Moko\Component\MokoSuiteNpo\Site\View\DonorWall;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\Database\DatabaseInterface;
/**
* Public donor recognition wall — shows donors by level with recognition names.
*/
class HtmlView extends BaseHtmlView
{
public array $levels = [];
public object $stats;
public function display($tpl = null): void
{
$db = Factory::getContainer()->get(DatabaseInterface::class);
// Get donors grouped by level (exclude anonymous)
$levelOrder = ['legacy', 'major', 'repeat', 'first_time'];
foreach ($levelOrder as $level) {
$db->setQuery($db->getQuery(true)
->select('d.recognition_name, d.donor_level, d.lifetime_giving')
->from($db->quoteName('#__mokosuitenpo_donors', 'd'))
->where($db->quoteName('d.donor_level') . ' = ' . $db->quote($level))
->where($db->quoteName('d.anonymous_giving') . ' = 0')
->where('d.recognition_name IS NOT NULL AND d.recognition_name != ' . $db->quote(''))
->order('d.lifetime_giving DESC'), 0, 50);
$donors = $db->loadObjectList() ?: [];
if (!empty($donors)) {
$this->levels[$level] = $donors;
}
}
// Overall stats
$db->setQuery($db->getQuery(true)
->select('COUNT(DISTINCT d.id) AS total_donors')
->select('COALESCE(SUM(d.lifetime_giving), 0) AS total_raised')
->from($db->quoteName('#__mokosuitenpo_donors', 'd'))
->where($db->quoteName('d.lifetime_giving') . ' > 0'));
$this->stats = $db->loadObject() ?: (object) ['total_donors' => 0, 'total_raised' => 0];
parent::display($tpl);
}
}
@@ -0,0 +1,45 @@
<?php defined('_JEXEC') or die;
$levelLabels = [
'legacy' => ['label' => 'Legacy Donors', 'icon' => 'star', 'color' => 'warning'],
'major' => ['label' => 'Major Donors', 'icon' => 'diamond', 'color' => 'primary'],
'repeat' => ['label' => 'Sustaining Donors', 'icon' => 'heart', 'color' => 'success'],
'first_time' => ['label' => 'Welcome New Donors', 'icon' => 'seedling','color' => 'info'],
];
?>
<div class="npo-donor-wall">
<div class="text-center mb-5">
<h2>Thank You To Our Generous Donors</h2>
<div class="row g-3 justify-content-center mt-3">
<div class="col-md-4"><div class="card text-center border-primary"><div class="card-body">
<h3 class="text-primary"><?php echo number_format((int) $this->stats->total_donors); ?></h3>
<p class="mb-0">Donors</p>
</div></div></div>
<div class="col-md-4"><div class="card text-center border-success"><div class="card-body">
<h3 class="text-success">$<?php echo number_format((float) $this->stats->total_raised); ?></h3>
<p class="mb-0">Total Raised</p>
</div></div></div>
</div>
</div>
<?php foreach ($this->levels as $level => $donors) :
$info = $levelLabels[$level] ?? ['label' => ucfirst($level), 'color' => 'secondary'];
?>
<div class="mb-4">
<h4 class="text-<?php echo $info['color']; ?>"><?php echo $info['label']; ?></h4>
<div class="row g-2">
<?php foreach ($donors as $d) : ?>
<div class="col-md-3 col-sm-4 col-6">
<div class="card h-100"><div class="card-body py-2 px-3 text-center">
<strong><?php echo htmlspecialchars($d->recognition_name); ?></strong>
</div></div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
<?php if (empty($this->levels)) : ?>
<div class="alert alert-info text-center">Be the first to appear on our donor wall!</div>
<?php endif; ?>
</div>