Split attendees and badge printing; add a 3-step event create flow.
Deploy Ladill Events / deploy (push) Successful in 35s

Give each area its own sidebar entry and hub pages, and walk new events through details, QR design, then review before publish.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-06-07 12:27:42 +00:00
co-authored by Cursor
parent 51745193da
commit 5e00f319a5
12 changed files with 488 additions and 101 deletions
@@ -18,6 +18,93 @@ class AttendeeController extends Controller
{
public function __construct(private readonly SmsService $sms) {}
public function hub(Request $request): View
{
$account = ladill_account();
$search = trim((string) $request->query('search', ''));
$events = $account->qrCodes()
->where('type', QrCode::TYPE_EVENT)
->when($search !== '', fn ($q) => $q->where('label', 'like', "%{$search}%"))
->latest()
->get()
->map(function (QrCode $event) {
$event->confirmed_count = $event->eventRegistrations()
->where('status', QrEventRegistration::STATUS_CONFIRMED)
->count();
$event->checked_in_count = $event->eventRegistrations()
->whereNotNull('checked_in_at')
->count();
return $event;
});
return view('events.attendees-hub', [
'events' => $events,
'search' => $search,
]);
}
public function badgesHub(Request $request): View
{
$account = ladill_account();
$search = trim((string) $request->query('search', ''));
$events = $account->qrCodes()
->where('type', QrCode::TYPE_EVENT)
->when($search !== '', fn ($q) => $q->where('label', 'like', "%{$search}%"))
->latest()
->get()
->map(function (QrCode $event) {
$event->printable_count = $event->eventRegistrations()
->where('status', QrEventRegistration::STATUS_CONFIRMED)
->count();
return $event;
});
return view('events.badges-hub', [
'events' => $events,
'search' => $search,
]);
}
public function badgePrinting(Request $request, QrCode $event): View
{
$this->authorize('view', $event);
abort_unless($event->type === QrCode::TYPE_EVENT, 404);
$isContribution = ($event->content()['mode'] ?? 'ticketing') === 'contributions';
if ($isContribution) {
abort(404);
}
$query = $event->eventRegistrations()
->where('status', QrEventRegistration::STATUS_CONFIRMED)
->latest();
if ($search = trim((string) $request->query('search', ''))) {
$query->where(function ($q) use ($search) {
$q->where('attendee_name', 'like', "%{$search}%")
->orWhere('attendee_email', 'like', "%{$search}%")
->orWhere('badge_code', 'like', "%{$search}%");
});
}
$registrations = $query->paginate(40)->withQueryString();
$badgeSize = $event->content()['badge_size'] ?? '4x3';
return view('events.badge-printing', [
'qrCode' => $event,
'event' => $event,
'registrations' => $registrations,
'badgeSize' => $badgeSize,
'printableCount' => $event->eventRegistrations()
->where('status', QrEventRegistration::STATUS_CONFIRMED)
->count(),
]);
}
public function index(Request $request, QrCode $event): View
{
$this->authorize('view', $event);