-
Notifications
You must be signed in to change notification settings - Fork 0
Allow querying and fulfilling purchases by email #379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds DynamoDB-backed user purchase fetchers and a GET /purchases/:email API, introduces POST /users/findUserByUin, updates ticket routes to use /event/:eventId, refactors ScanTicketsPage for manual UIN/email lookup and multi-ticket selection, and adds tests and Terraform/front-end endpoint adjustments. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API as GET /purchases/:email
participant Tickets as getUserTicketingPurchases
participant Merch as getUserMerchPurchases
participant DynamoDB
Client->>API: Fetch user purchases
rect rgb(200, 220, 255)
Note over API: Concurrent fetch
par
API->>Tickets: Call with email
Tickets->>DynamoDB: QueryCommand (TicketPurchasesTableName, UserIndex)
DynamoDB-->>Tickets: Items[]
Tickets->>Tickets: Transform to TicketInfoEntry[]
Tickets-->>API: tickets[]
and
API->>Merch: Call with email
Merch->>DynamoDB: QueryCommand (MerchStorePurchasesTableName, UserIndex)
DynamoDB-->>Merch: Items[]
Merch->>Merch: Transform to TicketInfoEntry[]
Merch-->>API: merch[]
end
end
alt Success
API->>Client: 200 { merch, tickets }
else Error
API->>Client: DatabaseFetchError
end
sequenceDiagram
participant User
participant ScanTickets as ScanTicketsPage
participant API
participant UinAPI as POST /users/findUserByUin
participant DynamoDB
User->>ScanTickets: Enter UIN or Email
alt UIN Entry
ScanTickets->>ScanTickets: Validate 9 digits
ScanTickets->>UinAPI: Hash UIN & search
UinAPI->>DynamoDB: Query UinHashIndex
DynamoDB-->>UinAPI: User item
UinAPI-->>ScanTickets: email
ScanTickets->>ScanTickets: Set email
else Email Entry
ScanTickets->>ScanTickets: Validate email format
ScanTickets->>ScanTickets: Set email
end
ScanTickets->>API: GET /purchases/:email
API-->>ScanTickets: { tickets[], merch[] }
alt Multiple valid items
ScanTickets->>User: Show item selection modal
User->>ScanTickets: Select ticket/merch item
else Single item
ScanTickets->>ScanTickets: Auto-select
end
User->>ScanTickets: Initiate check-in (camera/manual)
ScanTickets->>API: POST checkInTicket
API-->>ScanTickets: Success
ScanTickets->>User: Show confirmation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Pre-merge checks and finishing touches✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Cache: Disabled due to data retention organization setting Knowledge base: Disabled due to data retention organization setting 📒 Files selected for processing (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
🔇 Additional comments (2)
Comment |
💰 Infracost reportMonthly estimate generatedThis comment will be updated when code changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/api/routes/tickets.ts (1)
262-273: Always emit boolean defaults forrefunded/fulfilled
ticketInfoEntryZodrequires these fields to be booleans, but many historical purchases never set either attribute. Whenunmarshallreturnsundefined,reply.senddrops the property entirely during JSON serialization, so clients get objects that fail your documented schema. Default both fields tofalse(e.g.Boolean(unmarshalled.refunded)) before sending. (developer.mozilla.org)issuedTickets.push({ type: "merch", valid: true, ticketId: unmarshalled.stripe_pi, - refunded: unmarshalled.refunded, - fulfilled: unmarshalled.fulfilled, + refunded: Boolean(unmarshalled.refunded), + fulfilled: Boolean(unmarshalled.fulfilled), purchaserData: { email: unmarshalled.email, productId: eventId,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (7)
src/api/functions/tickets.ts(1 hunks)src/api/routes/tickets.ts(8 hunks)src/ui/pages/tickets/SelectEventId.page.tsx(1 hunks)src/ui/pages/tickets/ViewTickets.page.tsx(1 hunks)tests/live/tickets.test.ts(1 hunks)tests/unit/functions/tickets.test.ts(1 hunks)tests/unit/tickets.test.ts(3 hunks)
🧰 Additional context used
🪛 ESLint
tests/unit/functions/tickets.test.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/AqbsrpCfmG'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:233:12)
at checkFileExtension (/home/jailuser/git/node_modules/eslint-plugin-import/lib/rules/extensions.js:205:53)
at checkSourceValue (/home/jailuser/git/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
(import/extensions)
[error] 2-5: Replace ⏎··DynamoDBClient,⏎··QueryCommand,⏎ with ·DynamoDBClient,·QueryCommand·
(prettier/prettier)
[error] 6-6: Replace ·getUserMerchPurchases,·getUserTicketingPurchases· with ⏎··getUserMerchPurchases,⏎··getUserTicketingPurchases,⏎
(prettier/prettier)
[error] 6-6: Unexpected use of file extension "js" for "../../../src/api/functions/tickets.js"
(import/extensions)
[error] 7-7: Unexpected use of file extension "js" for "../../../src/common/config.js"
(import/extensions)
[error] 10-10: Unexpected use of file extension "js" for "../../../src/common/errors/index.js"
(import/extensions)
[error] 134-134: Insert ,
(prettier/prettier)
[error] 149-149: Insert ,
(prettier/prettier)
[error] 164-164: Insert ,
(prettier/prettier)
[error] 282-282: Insert ,
(prettier/prettier)
[error] 297-297: Insert ,
(prettier/prettier)
[error] 312-312: Insert ,
(prettier/prettier)
src/api/functions/tickets.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/opILUcQNos'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:233:12)
at checkFileExtension (/home/jailuser/git/node_modules/eslint-plugin-import/lib/rules/extensions.js:205:53)
at checkSourceValue (/home/jailuser/git/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
(import/extensions)
[error] 3-3: Unexpected use of file extension "js" for "api/routes/tickets.js"
(import/extensions)
[error] 4-4: Unexpected use of file extension "js" for "api/types.js"
(import/extensions)
[error] 5-5: Unexpected use of file extension "js" for "common/config.js"
(import/extensions)
[error] 6-6: Unexpected use of file extension "js" for "common/errors/index.js"
(import/extensions)
src/api/routes/tickets.ts
[error] 34-34: Unexpected use of file extension "js" for "api/functions/tickets.js"
(import/extensions)
tests/live/tickets.test.ts
[error] 50-50: ["merch"] is better written in dot notation.
(dot-notation)
[error] 51-51: ["tickets"] is better written in dot notation.
(dot-notation)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build Application
- GitHub Check: Run Unit Tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
tests/unit/functions/tickets.test.ts (1)
223-233: Assert the real merch quantity returned by the helperThis fixture defines
quantity: 2, yet the expectation still forcespurchaserData.quantityto1. That hides the production bug we just flagged and diverges from the contract other tests enforce. Please assert the stored value so the test fails if the helper stops returning the actual quantity.purchaserData: { email: testEmail, productId: "merch-001", - quantity: 1, + quantity: 2, },src/api/functions/tickets.ts (1)
118-125: Use the actual merch quantity when mapping purchases
RawMerchEntry.quantityalready carries what the customer bought, but the transformation clamps it to1. Any multi-quantity merch order will therefore be under-reported to the API caller. Please forward the stored value (falling back to 1 only if it’s missing) so the endpoint reflects reality.purchaserData: { email: item.email, productId: item.item_id, - quantity: 1, + quantity: + typeof item.quantity === "number" && Number.isFinite(item.quantity) + ? item.quantity + : 1, },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (3)
src/api/functions/tickets.ts(1 hunks)tests/unit/functions/tickets.test.ts(1 hunks)tests/unit/tickets.test.ts(3 hunks)
🧰 Additional context used
🪛 ESLint
tests/unit/functions/tickets.test.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/xOrGKCtoqu'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:233:12)
at checkFileExtension (/home/jailuser/git/node_modules/eslint-plugin-import/lib/rules/extensions.js:205:53)
at checkSourceValue (/home/jailuser/git/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
(import/extensions)
[error] 2-5: Replace ⏎··DynamoDBClient,⏎··QueryCommand,⏎ with ·DynamoDBClient,·QueryCommand·
(prettier/prettier)
[error] 6-6: Replace ·getUserMerchPurchases,·getUserTicketingPurchases· with ⏎··getUserMerchPurchases,⏎··getUserTicketingPurchases,⏎
(prettier/prettier)
[error] 6-6: Unexpected use of file extension "js" for "../../../src/api/functions/tickets.js"
(import/extensions)
[error] 7-7: Unexpected use of file extension "js" for "../../../src/common/config.js"
(import/extensions)
[error] 10-10: Unexpected use of file extension "js" for "../../../src/common/errors/index.js"
(import/extensions)
[error] 134-134: Insert ,
(prettier/prettier)
[error] 149-149: Insert ,
(prettier/prettier)
[error] 164-164: Insert ,
(prettier/prettier)
[error] 282-282: Insert ,
(prettier/prettier)
[error] 297-297: Insert ,
(prettier/prettier)
[error] 312-312: Insert ,
(prettier/prettier)
src/api/functions/tickets.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/mFcmVmwZVk'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:233:12)
at checkFileExtension (/home/jailuser/git/node_modules/eslint-plugin-import/lib/rules/extensions.js:205:53)
at checkSourceValue (/home/jailuser/git/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
(import/extensions)
[error] 3-3: Unexpected use of file extension "js" for "api/routes/tickets.js"
(import/extensions)
[error] 4-4: Unexpected use of file extension "js" for "api/types.js"
(import/extensions)
[error] 5-5: Unexpected use of file extension "js" for "common/config.js"
(import/extensions)
[error] 6-6: Unexpected use of file extension "js" for "common/errors/index.js"
(import/extensions)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build Application
- GitHub Check: Run Unit Tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (3)
src/api/functions/tickets.ts(1 hunks)tests/unit/functions/tickets.test.ts(1 hunks)tests/unit/tickets.test.ts(3 hunks)
🧰 Additional context used
🪛 ESLint
src/api/functions/tickets.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/SJDWChrxMv'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:233:12)
at checkFileExtension (/home/jailuser/git/node_modules/eslint-plugin-import/lib/rules/extensions.js:205:53)
at checkSourceValue (/home/jailuser/git/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
(import/extensions)
[error] 3-3: Unexpected use of file extension "js" for "api/routes/tickets.js"
(import/extensions)
[error] 4-4: Unexpected use of file extension "js" for "api/types.js"
(import/extensions)
[error] 5-5: Unexpected use of file extension "js" for "common/config.js"
(import/extensions)
[error] 6-6: Unexpected use of file extension "js" for "common/errors/index.js"
(import/extensions)
tests/unit/functions/tickets.test.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/UAZDjrDOfF'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:233:12)
at checkFileExtension (/home/jailuser/git/node_modules/eslint-plugin-import/lib/rules/extensions.js:205:53)
at checkSourceValue (/home/jailuser/git/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
(import/extensions)
[error] 2-5: Replace ⏎··DynamoDBClient,⏎··QueryCommand,⏎ with ·DynamoDBClient,·QueryCommand·
(prettier/prettier)
[error] 6-6: Replace ·getUserMerchPurchases,·getUserTicketingPurchases· with ⏎··getUserMerchPurchases,⏎··getUserTicketingPurchases,⏎
(prettier/prettier)
[error] 6-6: Unexpected use of file extension "js" for "../../../src/api/functions/tickets.js"
(import/extensions)
[error] 7-7: Unexpected use of file extension "js" for "../../../src/common/config.js"
(import/extensions)
[error] 10-10: Unexpected use of file extension "js" for "../../../src/common/errors/index.js"
(import/extensions)
[error] 134-134: Insert ,
(prettier/prettier)
[error] 149-149: Insert ,
(prettier/prettier)
[error] 164-164: Insert ,
(prettier/prettier)
[error] 282-282: Insert ,
(prettier/prettier)
[error] 297-297: Insert ,
(prettier/prettier)
[error] 312-312: Insert ,
(prettier/prettier)
🔇 Additional comments (5)
tests/unit/tickets.test.ts (3)
29-29: LGTM! Appropriate import for test data preparation.The
marshallimport is correctly used in the new test suite to prepare DynamoDB item mocks.
501-501: LGTM! Route paths updated consistently.The path changes from
/:eventIdto/event/:eventIdare applied consistently across the test suite.Also applies to: 513-513
521-768: Excellent test coverage! Quantity issue from past review is now fixed.The new test suite comprehensively covers the user purchases endpoint with proper handling of the stored quantity values. Line 584 correctly expects
quantity: 2matching the mocked merch item at line 546, addressing the previous concern about hardcoded quantities.Coverage includes:
- Happy paths: all purchases, no purchases, tickets only, merch only, multiple items
- Sad paths: invalid email format, database errors on both queries
tests/unit/functions/tickets.test.ts (1)
1-356: LGTM! Comprehensive unit tests with proper quantity handling.This test file provides excellent coverage of the new purchase retrieval functions. Key strengths:
- Line 230 correctly expects
quantity: 2from the mocked merch data, properly addressing the past review concern about hardcoded quantities- Thorough error handling validation (Items undefined, query failures, BaseError rethrow)
- Query parameter correctness verification
- Proper testing of optional fields (scanIsoTimestamp, scannerEmail)
The ESLint formatting errors flagged by static analysis are non-critical and can be auto-fixed by the formatter.
src/api/functions/tickets.ts (1)
117-128: LGTM! Merch quantity now correctly uses stored value.Line 124 now properly uses
item.quantityinstead of hardcoding to 1, addressing the issue flagged in past reviews. This ensures multi-quantity merch purchases are accurately reported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (2)
src/ui/pages/tickets/ScanTickets.page.test.tsx(1 hunks)src/ui/pages/tickets/ScanTickets.page.tsx(10 hunks)
🧰 Additional context used
🪛 ESLint
src/ui/pages/tickets/ScanTickets.page.test.tsx
[error] 1-1: Resolve error: EACCES: permission denied, open '/JYuaAKvgHp'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:233:12)
at checkFileExtension (/home/jailuser/git/node_modules/eslint-plugin-import/lib/rules/extensions.js:205:53)
at checkSourceValue (/home/jailuser/git/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
(import/extensions)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Run Unit Tests
- GitHub Check: Build Application
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/ui/pages/tickets/ScanTickets.page.tsx (3)
179-196: UIN→email lookup is now implemented.The
getEmailFromUINDefaultfunction now properly calls the/api/v1/users/findUserByUinAPI, addressing the critical issue from the previous review.However, the ValidationError handling pattern (lines 184-192) is unnecessarily complex.
Consider simplifying the error handling:
- const samp = new ValidationError({ - message: "Failed to convert UIN to email.", - }); - if ( - error.response?.status === samp.httpStatusCode && - error.response?.data.id === samp.id - ) { - const validationData = error.response.data; - throw new ValidationError(validationData.message || samp.message); - } + if (error.response?.status === 400 && error.response?.data?.name === "ValidationError") { + throw new ValidationError(error.response.data.message || "Failed to convert UIN to email."); + }
254-271: Consider simplifying the active/inactive logic.The current logic works but is somewhat convoluted with the double check of
itemSalesActive !== falsefollowed by the string type check.Consider this clearer pattern:
- const isActive = - ticket.itemSalesActive !== false && - (typeof ticket.itemSalesActive === "string" - ? new Date(ticket.itemSalesActive) <= now - : false); + const isActive = + typeof ticket.itemSalesActive === "string" && + new Date(ticket.itemSalesActive) <= now;This simplifies the logic since
itemSalesActiveis typed asstring | false, and only string values represent active items.
607-645: LGTM! Ticket marking logic correctly handles both ticket and merch types.The function properly constructs the appropriate QR data structure for each product type and handles the check-in flow with proper error handling.
Optional: Extract duplicated error handling.
The error handling pattern (lines 632-637) is duplicated in
handleManualInputSubmit,handleSuccessfulScan, andmarkTicket.Consider extracting to a helper:
const formatErrorMessage = (err: any): string => { if (err.response?.data) { return err.response.data ? `Error ${err.response.data.id} (${err.response.data.name}): ${err.response.data.message}` : "System encountered a failure, please contact the ACM Infra Chairs."; } return err instanceof Error ? err.message : "Failed to process ticket"; };src/common/types/user.ts (1)
3-5: Require numeric-only UIN input.Length-check alone accepts any 9-character string (e.g., letters, hyphenated UINs, whitespace-padded values). Those hash to a value that will never match DynamoDB, so valid lookups fail. Trim and enforce exactly nine digits before hashing.
-export const searchUserByUinRequest = z.object({ - uin: z.string().length(9) -}); +export const searchUserByUinRequest = z.object({ + uin: z + .string() + .trim() + .regex(/^\d{9}$/, "UIN must be exactly nine digits"), +});
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (4)
src/api/index.ts(2 hunks)src/api/routes/user.ts(1 hunks)src/common/types/user.ts(1 hunks)src/ui/pages/tickets/ScanTickets.page.tsx(11 hunks)
🧰 Additional context used
🪛 ESLint
src/api/routes/user.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/PydKaXOXCZ'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:233:12)
at checkFileExtension (/home/jailuser/git/node_modules/eslint-plugin-import/lib/rules/extensions.js:205:53)
at checkSourceValue (/home/jailuser/git/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
(import/extensions)
[error] 2-2: Unexpected use of file extension "js" for "api/plugins/rateLimiter.js"
(import/extensions)
[error] 3-3: Unexpected use of file extension "js" for "api/components/index.js"
(import/extensions)
[error] 4-4: Unexpected use of file extension "js" for "api/functions/organizations.js"
(import/extensions)
[error] 9-9: Unexpected use of file extension "js" for "common/errors/index.js"
(import/extensions)
[error] 14-14: Unexpected use of file extension "js" for "common/types/user.js"
(import/extensions)
[error] 15-15: Unexpected use of file extension "js" for "api/functions/uin.js"
(import/extensions)
[error] 18-18: Unexpected use of file extension "js" for "common/config.js"
(import/extensions)
src/api/index.ts
[error] 64-64: Unexpected use of file extension "js" for "./routes/user.js"
(import/extensions)
src/common/types/user.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/hZqryFUXnj'
at Object.writeFileSync (node:fs:2409:20)
at l (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:13685)
at createFilesMatcher (/home/jailuser/git/node_modules/get-tsconfig/dist/index.cjs:7:14437)
at Object.resolve (/home/jailuser/git/node_modules/eslint-import-resolver-typescript/lib/index.cjs:298:107)
at withResolver (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:180:23)
at fullResolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:201:22)
at relative (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:217:10)
at resolve (/home/jailuser/git/node_modules/eslint-module-utils/resolve.js:233:12)
at checkFileExtension (/home/jailuser/git/node_modules/eslint-plugin-import/lib/rules/extensions.js:205:53)
at checkSourceValue (/home/jailuser/git/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
(import/extensions)
[error] 4-4: Insert ,
(prettier/prettier)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build Application
- GitHub Check: Run Unit Tests
🔇 Additional comments (4)
src/ui/pages/tickets/ScanTickets.page.tsx (4)
48-60: LGTM! New interfaces support the purchase lookup flow.The addition of
refundedandfulfilledfields toAPIResponseSchemaand the newPurchasesByEmailResponseinterface properly support the manual entry and purchase lookup functionality.
82-103: LGTM! Props interface enables dependency injection for testing.The
ScanTicketsPagePropsinterface properly defines all injectable dependencies as optional, which allows for both production usage (with defaults) and testing (with mocks).
673-763: LGTM! UI properly implements the manual entry and camera scanning flow.The conditional rendering based on
selectedItemFilterensures users select an event/item before proceeding. The manual input field withautoFocusandonKeyDownhandler provides good UX for both typing and card swiping scenarios.
823-877: LGTM! Ticket selection modal provides clear multi-ticket handling.The modal properly displays all available tickets with relevant details and allows users to select the correct one when multiple valid tickets exist for the same event.
Summary by CodeRabbit
New Features
Changes
Tests