Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/ai-preferences/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Before committing, run these checks:

```bash
# Validate specific PHP file
php -l src/EditEventAttendees.php
php -l src/Checkin.php

# Check all modified PHP files
git diff --name-only | grep '.php$' | xargs php -l
Expand Down Expand Up @@ -58,7 +58,7 @@ grep -r "align=\|valign=\|nowrap\|<center>\|<font" src/ | grep -v "//" || true
```

Examples:
- Fix SQL injection in EditEventAttendees
- Fix validation in Checkin form
- Replace deprecated HTML attributes with Bootstrap CSS
- Add missing element ID for test selector

Expand Down
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ cat src/logs/$(date +%Y-%m-%d)-app.log # App events

Commit messages:
- Format: Imperative mood, < 72 chars, no file paths
- Examples: "Fix SQL injection in EditEventAttendees", "Replace deprecated HTML attributes with Bootstrap CSS", "Add missing element ID for test selector"
- Examples: "Fix validation in Checkin form", "Replace deprecated HTML attributes with Bootstrap CSS", "Add missing element ID for test selector"
- Wrong: "Fixed the bug in src/EventEditor.php"

PR organization:
Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/ui/admin/admin.event.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ describe("Admin Event", () => {
it("Event List", () => {
cy.visit("ListEvents.php");
cy.contains("Listing All Church Events");
cy.contains("Select Event Types To Display");
cy.contains("Display Events in Year");
cy.contains("Filter Events");
cy.contains("Event Type");
cy.contains("Add New Event");
});

Expand Down
6 changes: 3 additions & 3 deletions cypress/e2e/ui/admin/admin.event.types.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe("Event Types Management", () => {
cy.visit("EventNames.php");
cy.contains("Event Types");
cy.get(".table tbody tr").should("exist");
cy.get(".table thead").should("contain", "Event Type");
cy.get(".table thead").should("contain", "Name");
cy.get(".table tbody").should("contain", "Church Service");
cy.get(".table tbody").should("contain", "Sunday School");
});
Expand All @@ -22,8 +22,8 @@ describe("Event Types Management", () => {
cy.contains("Add Event Type").click();

cy.get('input[name="newEvtName"]').type(eventTypeName);
cy.get('input[name="newEvtTypeCntLst"]').type(5);
cy.get('#save-event-type').click();
cy.get('input[name="newEvtTypeCntLst"]').type("Members, Visitors");
cy.contains("Save Event Type").click();

cy.contains(eventTypeName).should("exist");
});
Expand Down
41 changes: 15 additions & 26 deletions cypress/e2e/ui/events/standard.events.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,29 @@

describe("Standard User Session", () => {
beforeEach(() => cy.setupStandardSession());

it("Visit Event Attendance", () => {
cy.visit("EventAttendance.php");
cy.contains("Church Service");
});

it("Visit Church Servers", () => {
cy.visit(
"EventAttendance.php?Action=List&Event=1&Type=Church%20Service",
);
cy.contains("Christmas Service");
cy.get("#Non-Attending-1").click();
cy.contains("Berry, Miss Brianna");
});

it("View Event via URL", () => {
cy.visit("EditEventAttendees.php?eventId=3");
cy.contains("Attendees for Event : Summer Camp");
it("View Event Checkin via URL", () => {
cy.visit("Checkin.php?eventId=3");
cy.contains("Event Checkin");
cy.contains("Summer Camp");
});

it("View Event via Bad URL", () => {
cy.visit("EditEventAttendees.php");
cy.contains("Listing All Church Events");
it("View Checkin page without event", () => {
cy.visit("Checkin.php");
cy.contains("Event Checkin");
cy.contains("Select event");
});

it("View Event via invalid URL id", () => {
cy.visit("EditEventAttendees.php?eventId=99999");
cy.contains("Listing All Church Events");
it("CheckIn People", () => {
cy.visit("Checkin.php");
cy.contains("Event Checkin");
cy.get("#EventID").select(3);
cy.contains("Check In Person");
});

it("CheckIn People", () => {
it("Filter events by type", () => {
cy.visit("Checkin.php");
cy.contains("Event Checkin");
cy.get("#EventID").select("Summer Camp");
cy.contains("Add Attendees for Event:");
cy.get("#EventTypeFilter").should("exist");
});
});
163 changes: 125 additions & 38 deletions src/CartToEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

use ChurchCRM\Authentication\AuthenticationManager;
use ChurchCRM\dto\Cart;
use ChurchCRM\dto\SystemURLs;
use ChurchCRM\model\ChurchCRM\EventAttend;
use ChurchCRM\model\ChurchCRM\EventQuery;
use ChurchCRM\model\ChurchCRM\EventTypeQuery;
use ChurchCRM\model\ChurchCRM\PersonQuery;
use ChurchCRM\Utils\InputUtils;
use ChurchCRM\Utils\LoggerUtils;
use ChurchCRM\Utils\RedirectUtils;
Expand Down Expand Up @@ -33,53 +37,136 @@
}
Cart::emptyAll();

$sGlobalMessage = $iCount . ' records(s) successfully added to selected Event.';
// TODO: do this in API
RedirectUtils::redirect('v2/cart?Action=EmptyCart&Message=aMessage&iCount=' . $iCount . '&iEID=' . $iEventID);
// Redirect to checkin page with count notification
RedirectUtils::redirect('Checkin.php?EventID=' . $iEventID . '&AddedCount=' . $iCount);
}

$sPageTitle = gettext('Add Cart to Event');
require_once 'Include/Header.php';

if (count($_SESSION['aPeopleCart']) > 0) {
$sSQL = 'SELECT event_id, event_title FROM events_event';
$rsEvents = RunQuery($sSQL); ?>
<div class="card">
<p class="text-center"><?= gettext('Select the event to which you would like to add your cart') ?>:</p>
<form name="CartToEvent" action="CartToEvent.php" method="POST">
<table class="mx-auto">
<?php if ($sGlobalMessage) {
?>
<tr>
<td colspan="2"><?= $sGlobalMessage ?></td>
</tr>
<?php
} ?>
<tr>
<td class="LabelColumn"><?= gettext('Select Event') ?>:</td>
<td class="TextColumn">
<?php
// Create the group select drop-down
echo '<select name="EventID">';
while ($aRow = mysqli_fetch_array($rsEvents)) {
echo '<option value="' . $aRow['event_id'] . '">' . $aRow['event_title'] . '</option>';
}
echo '</select>'; ?>
</td>
</tr>
</table>
<p class="text-center">
<BR>
<input type="submit" name="Submit" value=<?= '"' . gettext('Add Cart to Event') . '"' ?> class="btn btn-primary">
<BR><BR>--<?= gettext('OR') ?>--<BR><BR>
<a href="EventEditor.php" class="btn btn-info"><?= gettext('Add New Event') ?></a>
<BR><BR>
</p>
</form>
// Get filter parameter
$selectedEventType = isset($_POST['EventTypeFilter']) ? (int)InputUtils::legacyFilterInput($_POST['EventTypeFilter'], 'int') : 0;

// Build event query with optional type filter
$eventQuery = EventQuery::create();
if ($selectedEventType > 0) {
$eventType = EventTypeQuery::create()->findOneById($selectedEventType);
if ($eventType) {
$eventQuery->filterByEventType($eventType);
}
}
$aEvents = $eventQuery->find();

// Get all event types for filter dropdown
$aEventTypes = EventTypeQuery::create()->find();

$aPeopleInCart = PersonQuery::create()
->filterById($_SESSION['aPeopleCart'])
->find();
?>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 offset-md-2">
<!-- Cart Contents -->
<div class="card mb-4">
<div class="card-header bg-light">
<h3 class="card-title"><?= gettext('People in Cart') ?></h3>
</div>
<div class="card-body">
<table class="table table-sm table-hover">
<thead class="table-light">
<tr>
<th><?= gettext('Name') ?></th>
<th><?= gettext('Classification') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($aPeopleInCart as $person) { ?>
<tr>
<td>
<img data-image-entity-type="person"
data-image-entity-id="<?= $person->getId() ?>"
class="photo-tiny">&nbsp
<a href="PersonView.php?PersonID=<?= $person->getId() ?>">
<?= $person->getFullName() ?>
</a>
</td>
<td><?= $person->getClsid() ? $person->getClassification()->getOptionName() : '<em class="text-muted">' . gettext('Unclassified') . '</em>' ?></td>
</tr>
<?php } ?>
</tbody>
</table>
<div class="alert alert-info mt-3 mb-0">
<strong><?= count($aPeopleInCart) ?></strong> <?= ngettext('person', 'people', count($aPeopleInCart)) ?> <?= gettext('in cart') ?>
</div>
</div>
</div>

<!-- Add to Event Form -->
<div class="card">
<div class="card-header bg-light">
<h3 class="card-title"><?= gettext('Check In to Event') ?></h3>
</div>
<div class="card-body">
<p class="text-center text-muted mb-4"><?= gettext('Select the event to check in your cart members') ?>:</p>

<!-- Event Type Filter -->
<form method="POST" action="CartToEvent.php" class="mb-4">
<div class="form-group">
<label for="EventTypeFilter"><?= gettext('Filter by Event Type') ?></label>
<div class="input-group">
<select id="EventTypeFilter" name="EventTypeFilter" class="form-control" onchange="this.form.submit()">
<option value="0" <?= ($selectedEventType == 0) ? 'selected' : '' ?>><?= gettext('All Event Types') ?></option>
<?php foreach ($aEventTypes as $eventType) { ?>
<option value="<?= $eventType->getId() ?>" <?= ($selectedEventType == $eventType->getId()) ? 'selected' : '' ?>>
<?= $eventType->getName() ?>
</option>
<?php } ?>
</select>
</div>
</div>
</form>

<!-- Event Selection Form -->
<form name="CartToEvent" action="CartToEvent.php" method="POST">
<div class="form-group">
<label for="EventID"><?= gettext('Select Event') ?></label>
<select id="EventID" name="EventID" class="form-control" required>
<option value="" disabled selected><?= gettext('Choose an event...') ?></option>
<?php foreach ($aEvents as $evt) { ?>
<option value="<?= $evt->getId() ?>"><?= $evt->getTitle() ?></option>
<?php } ?>
</select>
</div>
<div class="text-center">
<button type="submit" name="Submit" class="btn btn-primary btn-lg"><?= gettext('Check In to Event') ?></button>
</div>
</form>
</div>
<div class="card-footer bg-light text-center">
<small class="text-muted"><?= gettext('OR') ?></small>
<div class="mt-3">
<a href="EventEditor.php" class="btn btn-outline-info"><?= gettext('Create New Event') ?></a>
</div>
</div>
</div>
</div>
</div>
</div>
<?php
} else {
echo '<p class="text-center alert alert-warning">' . gettext('Your cart is empty!') . '</p>';
?>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 offset-md-2">
<div class="alert alert-warning text-center">
<i class="fa fa-info-circle"></i> <?= gettext('Your cart is empty!') ?>
</div>
</div>
</div>
</div>
<?php
}

require_once 'Include/Footer.php';
Loading
Loading