From 0daa780a65aee21bc4f56d4ee3dc3cb90c2c1413 Mon Sep 17 00:00:00 2001 From: Jacob Coffee Date: Mon, 27 Apr 2026 21:24:06 -0500 Subject: [PATCH] fix(scanners): hide swag in Door Check and sessions in Swag Pickup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both scanner pages call /check_in/redeemable/ to populate their category chips and product list, and that endpoint returns the full union of redeemable categories (sessions + merchandise). CategorySerializer only emits (id, name), so there's no render_type or other discriminator on the wire — the result is that Door Check showed t-shirt categories and Swag Pickup showed Tutorials / Sponsor Presentations / Summits / etc. Filter the response client-side by category name: - Door Check keeps anything *not* matching /shirt|swag/i. - Swag Pickup keeps anything *matching* /shirt|swag/i. Products are filtered to those whose category survived, so the "All sessions in this category" / search list also stays consistent. Both filters carry a comment pointing at the long-term fix (expose render_type on CategorySerializer in pycon-site). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/app/pages/door-check/door-check.page.ts | 14 ++++++++++++-- .../t-shirt-redemption/t-shirt-redemption.page.ts | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/app/pages/door-check/door-check.page.ts b/src/app/pages/door-check/door-check.page.ts index d894d63f..f374c343 100644 --- a/src/app/pages/door-check/door-check.page.ts +++ b/src/app/pages/door-check/door-check.page.ts @@ -331,8 +331,18 @@ export class DoorCheckPage implements OnInit, OnDestroy { this.syncAllPending(); this.pycon.fetchCheckInProducts().then((data) => { data.subscribe(redeemable => { - this.redeemable_products = redeemable?.redeemable_products; - this.redeemable_categories = redeemable?.redeemable_categories; + // /check_in/redeemable/ returns the union of every redeemable + // category (sessions + swag) and CategorySerializer omits + // render_type, so we have to discriminate by name. Door check + // is for sessions/events only — drop the merch categories and + // any products hanging off them. Long-term fix: expose + // render_type (==10 for presentations) on the API. + const categories = (redeemable?.redeemable_categories ?? []) + .filter(c => !/shirt|swag/i.test(c?.name ?? '')); + const keepIds = new Set(categories.map(c => c.id)); + this.redeemable_categories = categories; + this.redeemable_products = (redeemable?.redeemable_products ?? []) + .filter(p => keepIds.has(p.category)); }) }) } diff --git a/src/app/pages/t-shirt-redemption/t-shirt-redemption.page.ts b/src/app/pages/t-shirt-redemption/t-shirt-redemption.page.ts index eb57180f..6738bfdb 100644 --- a/src/app/pages/t-shirt-redemption/t-shirt-redemption.page.ts +++ b/src/app/pages/t-shirt-redemption/t-shirt-redemption.page.ts @@ -214,8 +214,18 @@ export class TShirtRedemptionPage implements OnInit, OnDestroy { this.ios = this.config.get('mode') === `ios`; this.pycon.fetchCheckInProducts().then((data) => { data.subscribe(redeemable => { - this.redeemable_products = redeemable?.redeemable_products; - this.redeemable_categories = redeemable?.redeemable_categories; + // /check_in/redeemable/ returns the union of every redeemable + // category (sessions + swag) and CategorySerializer omits + // render_type, so we have to discriminate by name. Swag pickup + // only redeems merch — keep T-Shirt categories (and any + // future "swag-*" naming) and drop the rest. Long-term fix: + // expose render_type on the API. + const categories = (redeemable?.redeemable_categories ?? []) + .filter(c => /shirt|swag/i.test(c?.name ?? '')); + const keepIds = new Set(categories.map(c => c.id)); + this.redeemable_categories = categories; + this.redeemable_products = (redeemable?.redeemable_products ?? []) + .filter(p => keepIds.has(p.category)); }) }) }