summit-registration-lite 7.0.6 → 7.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/index.js +85 -32
- package/dist/components/index.js.map +1 -1
- package/dist/components/registration-form.js +85 -32
- package/dist/components/registration-form.js.map +1 -1
- package/dist/components/registration-modal.js +85 -32
- package/dist/components/registration-modal.js.map +1 -1
- package/dist/index.js +85 -32
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/.claude/rules/summit-registration-lite-component-props.md +0 -95
- package/.claude/rules/summit-registration-lite-i18n.md +0 -62
- package/.claude/rules/summit-registration-lite-payment-providers.md +0 -69
- package/.claude/rules/summit-registration-lite-project.md +0 -80
- package/.claude/rules/summit-registration-lite-redux-actions.md +0 -65
- package/.claude/rules/summit-registration-lite-step-flow.md +0 -77
- package/.claude/rules/summit-registration-lite-testing.md +0 -97
- package/.claude/rules/summit-registration-lite-utils.md +0 -71
- package/.claude/skills/summit-registration-lite-add-provider/SKILL.md +0 -155
- package/.claude/skills/summit-registration-lite-dev-setup/SKILL.md +0 -67
- package/.claude/skills/summit-registration-lite-publish/SKILL.md +0 -64
- package/.claude/skills/summit-registration-lite-scaffold-component/SKILL.md +0 -152
- package/.codegraph/config.json +0 -141
- package/.codegraph/daemon.pid +0 -6
|
@@ -2234,7 +2234,7 @@ module.exports = require("sweetalert2");
|
|
|
2234
2234
|
/***/ ((module) => {
|
|
2235
2235
|
|
|
2236
2236
|
"use strict";
|
|
2237
|
-
module.exports = JSON.parse('{"purchase_complete_step":{"title":" Your order is complete","initial_order_complete_1st_paragraph_label":"A ticket has been assigned to {attendee}. To complete {adv} additional ticket details, please click the \\"{button}\\" button.","initial_order_complete_button":"Finish Now","order_complete_1st_paragraph_label":"You may visit the \\"My Orders/Tickets\\" tab in the top right-hand corner of the navigation bar to\\n assign/reassign tickets or to complete any required ticket details.","order_complete_button":"View My Orders/Tickets","access_event_button":"Access Event Now","initial_order_footer_label":"If you wish to transfer your assigned ticket, close this window and visit the \\"My Orders/Tickets\\" tab in the top navigation bar. ","footer_assistance_text":"For further assistance, please email <a href=\\"mailto:{supportEmail}\\">{supportEmail}</a>","event_will_start_text":"The event will start on {date} at {time} {time_zone_label}"},"ticket_type":{"ticket_quantity_tooltip":"Only one ticket type can be selected per order. To purchase multiple ticket types, please place a separate registration order for each ticket type.","no_tickets_available":"There are no tickets currently available for purchase. If you have a promo code, enter it below to check for eligible tickets.","max_per_order_one":"This ticket type is limited to 1 per order.","max_per_order_other":"This ticket type is limited to {limit} per order."},"promo_code":{"promo_code_tooltip":"Only one promo code can be used per order; the code will be applied to all tickets in this order. If you\'d like to use multiple promo codes, please place a separate registration order for each promo code.","default_label":"Do you have a promo code?","auto_applied_label":"Following promo code was automatically applied:","applied_label":"Applied promo code:","applying_label":"Applying promo code...","suggestion_label":"You qualify for the following promo code:","per_account_limit_one":"Promo code limits {limit} ticket per account.","per_account_limit_other":"Promo code limits {limit} tickets per account.","non_transferable":"This ticket will be automatically assigned to you and cannot be reassigned.","unapplied_code_warning":"You entered a promo code but it hasn\'t been applied. Make sure to click the \'Apply\' button or remove it before continuing.","invalid_code":"Promo code entered is not valid.","validation_error":"An error occurred while validating the promo code."}}');
|
|
2237
|
+
module.exports = JSON.parse('{"purchase_complete_step":{"title":" Your order is complete","initial_order_complete_1st_paragraph_label":"A ticket has been assigned to {attendee}. To complete {adv} additional ticket details, please click the \\"{button}\\" button.","initial_order_complete_button":"Finish Now","order_complete_1st_paragraph_label":"You may visit the \\"My Orders/Tickets\\" tab in the top right-hand corner of the navigation bar to\\n assign/reassign tickets or to complete any required ticket details.","order_complete_button":"View My Orders/Tickets","access_event_button":"Access Event Now","initial_order_footer_label":"If you wish to transfer your assigned ticket, close this window and visit the \\"My Orders/Tickets\\" tab in the top navigation bar. ","footer_assistance_text":"For further assistance, please email <a href=\\"mailto:{supportEmail}\\">{supportEmail}</a>","event_will_start_text":"The event will start on {date} at {time} {time_zone_label}"},"ticket_type":{"ticket_quantity_tooltip":"Only one ticket type can be selected per order. To purchase multiple ticket types, please place a separate registration order for each ticket type.","no_tickets_available":"There are no tickets currently available for purchase. If you have a promo code, enter it below to check for eligible tickets.","max_per_order_one":"This ticket type is limited to 1 per order.","max_per_order_other":"This ticket type is limited to {limit} per order."},"promo_code":{"promo_code_tooltip":"Only one promo code can be used per order; the code will be applied to all tickets in this order. If you\'d like to use multiple promo codes, please place a separate registration order for each promo code.","default_label":"Do you have a promo code?","auto_applied_label":"Following promo code was automatically applied:","applied_label":"Applied promo code:","applying_label":"Applying promo code...","suggestion_label":"You qualify for the following promo code:","suggestion_label_switch":"Following promo code applies to a different ticket. Apply to switch.","per_account_limit_one":"Promo code limits {limit} ticket per account.","per_account_limit_other":"Promo code limits {limit} tickets per account.","non_transferable":"This ticket will be automatically assigned to you and cannot be reassigned.","unapplied_code_warning":"You entered a promo code but it hasn\'t been applied. Make sure to click the \'Apply\' button or remove it before continuing.","invalid_code":"Promo code entered is not valid.","validation_error":"An error occurred while validating the promo code."}}');
|
|
2238
2238
|
|
|
2239
2239
|
/***/ })
|
|
2240
2240
|
|
|
@@ -2458,10 +2458,12 @@ const usePromoCode = ({
|
|
|
2458
2458
|
//
|
|
2459
2459
|
// Note on concurrency: the two call sites (early-auto-apply effect and
|
|
2460
2460
|
// onTicketSelected's auto-apply branch) operate on disjoint states by design
|
|
2461
|
-
// (the effect requires `!
|
|
2462
|
-
//
|
|
2463
|
-
//
|
|
2464
|
-
//
|
|
2461
|
+
// (the effect requires `!isApplied`, the branch fires only on a user-driven
|
|
2462
|
+
// ticket selection — by which point isApplied is already true if early
|
|
2463
|
+
// auto-apply ran), so a true concurrent invocation is unreachable in
|
|
2464
|
+
// practice. If a future change makes that overlap possible, gate this body
|
|
2465
|
+
// with a ref-tracked in-flight flag rather than `applyingCode` (which is
|
|
2466
|
+
// captured stale here).
|
|
2465
2467
|
|
|
2466
2468
|
const tryAutoApply = (0,external_react_.useCallback)(async ticket => {
|
|
2467
2469
|
setIsAutoApplied(true);
|
|
@@ -2489,8 +2491,14 @@ const usePromoCode = ({
|
|
|
2489
2491
|
}
|
|
2490
2492
|
}, [discoveredPromoCode, applyPromoCode, onRevalidate, handleValidationError]);
|
|
2491
2493
|
const onTicketSelected = (0,external_react_.useCallback)(async ticket => {
|
|
2492
|
-
const qualifies = discoveredPromoCode && isCodeValidForTicket(ticket);
|
|
2493
|
-
|
|
2494
|
+
const qualifies = discoveredPromoCode && isCodeValidForTicket(ticket); // Only turn the suggestion on when the current ticket qualifies; don't
|
|
2495
|
+
// turn it off otherwise. With auto-switch-on-Apply, the suggestion is
|
|
2496
|
+
// still useful when the user has a non-qualifying ticket selected
|
|
2497
|
+
// (Apply will switch them to the qualifying one). The status logic
|
|
2498
|
+
// hides the banner whenever a code is applied, so leaving this true
|
|
2499
|
+
// doesn't surface a stale suggestion.
|
|
2500
|
+
|
|
2501
|
+
if (qualifies) setSuggestionActive(true);
|
|
2494
2502
|
setSuggestionDismissed(false);
|
|
2495
2503
|
setManualError(null); // Manual (non-discovered) code is applied: re-validate for new ticket
|
|
2496
2504
|
|
|
@@ -2499,17 +2507,15 @@ const usePromoCode = ({
|
|
|
2499
2507
|
return;
|
|
2500
2508
|
}
|
|
2501
2509
|
|
|
2502
|
-
if (!discoveredPromoCode) return; // Discovered code is currently applied
|
|
2510
|
+
if (!discoveredPromoCode) return; // Discovered code is currently applied — re-validate against the new
|
|
2511
|
+
// ticket. The backend rejects if the code doesn't apply, surfacing
|
|
2512
|
+
// INVALID to the user (they can then choose to Remove or pick another
|
|
2513
|
+
// ticket). Previously we silently removed the code on a non-qualifying
|
|
2514
|
+
// pick, which hid the rejection.
|
|
2503
2515
|
|
|
2504
2516
|
if (isDiscoveredCode) {
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
removePromoCode();
|
|
2508
|
-
} else {
|
|
2509
|
-
const valid = await onRevalidate(ticket, 1);
|
|
2510
|
-
if (!valid) setIsAutoApplied(false);
|
|
2511
|
-
}
|
|
2512
|
-
|
|
2517
|
+
const valid = await onRevalidate(ticket, 1);
|
|
2518
|
+
if (!valid) setIsAutoApplied(false);
|
|
2513
2519
|
return;
|
|
2514
2520
|
} // No code applied, ticket qualifies, auto-apply configured, single code only
|
|
2515
2521
|
|
|
@@ -2517,19 +2523,20 @@ const usePromoCode = ({
|
|
|
2517
2523
|
if (!isApplied && qualifies && discoveredPromoCode.auto_apply && !userRemovedAutoApply && discoveredPromoCodes.length === 1) {
|
|
2518
2524
|
await tryAutoApply(ticket);
|
|
2519
2525
|
}
|
|
2520
|
-
}, [discoveredPromoCode, isApplied, isDiscoveredCode, userRemovedAutoApply, discoveredPromoCodes, isCodeValidForTicket,
|
|
2521
|
-
//
|
|
2522
|
-
//
|
|
2526
|
+
}, [discoveredPromoCode, isApplied, isDiscoveredCode, userRemovedAutoApply, discoveredPromoCodes, isCodeValidForTicket, onRevalidate, tryAutoApply]); // Early auto-apply on load (per SDS: silently apply a discovered single
|
|
2527
|
+
// auto_apply code when no code is currently applied). Wait on
|
|
2528
|
+
// ticketDataLoaded only to avoid racing the initial fetch. On failure,
|
|
2529
|
+
// mark as removed to prevent re-fire loops.
|
|
2523
2530
|
|
|
2524
2531
|
(0,external_react_.useEffect)(() => {
|
|
2525
2532
|
if (userRemovedAutoApply || isApplied) return;
|
|
2526
|
-
if (!ticketDataLoaded
|
|
2533
|
+
if (!ticketDataLoaded) return;
|
|
2527
2534
|
if (!discoveredPromoCode?.auto_apply) return;
|
|
2528
2535
|
if (discoveredPromoCodes.length !== 1) return;
|
|
2529
2536
|
tryAutoApply(null).then(success => {
|
|
2530
2537
|
if (!success) setUserRemovedAutoApply(true);
|
|
2531
2538
|
});
|
|
2532
|
-
}, [userRemovedAutoApply, ticketDataLoaded,
|
|
2539
|
+
}, [userRemovedAutoApply, ticketDataLoaded, discoveredPromoCode, discoveredPromoCodes, isApplied, tryAutoApply]);
|
|
2533
2540
|
const onApply = (0,external_react_.useCallback)(async (code, ticket, quantity) => {
|
|
2534
2541
|
setManualError(null);
|
|
2535
2542
|
setApplyingCode(true);
|
|
@@ -2568,11 +2575,20 @@ const usePromoCode = ({
|
|
|
2568
2575
|
status,
|
|
2569
2576
|
isReady,
|
|
2570
2577
|
validationError,
|
|
2578
|
+
// True while applyPromoCode is in flight (covers the window where
|
|
2579
|
+
// promoCode is set but the refreshed ticketTypes haven't landed
|
|
2580
|
+
// yet). Callers should defer ticket-list-driven side effects
|
|
2581
|
+
// until this clears to avoid acting on a stale list.
|
|
2582
|
+
applyingCode,
|
|
2571
2583
|
// Applied code origin
|
|
2572
2584
|
isDiscoveredCode,
|
|
2573
2585
|
isAutoApplied,
|
|
2574
2586
|
// Discovery / suggestion
|
|
2575
2587
|
suggestedCode,
|
|
2588
|
+
// Predicate the caller can use to find a ticket the discovered
|
|
2589
|
+
// promo applies to (auto-selection after auto-apply, ticket
|
|
2590
|
+
// switching on Apply).
|
|
2591
|
+
isCodeValidForTicket,
|
|
2576
2592
|
// Quantity caps from the active discovered code
|
|
2577
2593
|
maxQuantityFromPromo,
|
|
2578
2594
|
perAccountLimit
|
|
@@ -3863,6 +3879,7 @@ const PromoCodeInput = ({
|
|
|
3863
3879
|
promoCode,
|
|
3864
3880
|
suggestedCode,
|
|
3865
3881
|
isAutoApplied,
|
|
3882
|
+
isCurrentTicketQualifying,
|
|
3866
3883
|
onApply,
|
|
3867
3884
|
onRemove,
|
|
3868
3885
|
onInputChange,
|
|
@@ -3895,12 +3912,16 @@ const PromoCodeInput = ({
|
|
|
3895
3912
|
return undefined;
|
|
3896
3913
|
|
|
3897
3914
|
case constants.PROMO_STATUS.SUGGESTED:
|
|
3898
|
-
|
|
3915
|
+
// The suggestion banner stays visible across non-qualifying ticket
|
|
3916
|
+
// picks (so the "Apply will switch you" affordance persists). Swap
|
|
3917
|
+
// the copy so it stays accurate: tell the user the code applies to
|
|
3918
|
+
// a different ticket and that Apply will switch them.
|
|
3919
|
+
return isCurrentTicketQualifying ? external_i18n_react_default().translate('promo_code.suggestion_label') : external_i18n_react_default().translate('promo_code.suggestion_label_switch');
|
|
3899
3920
|
|
|
3900
3921
|
default:
|
|
3901
3922
|
return undefined;
|
|
3902
3923
|
}
|
|
3903
|
-
}, [promoStatus, isAutoApplied]);
|
|
3924
|
+
}, [promoStatus, isAutoApplied, isCurrentTicketQualifying]);
|
|
3904
3925
|
const canApply = !isLocked && !!inputValue;
|
|
3905
3926
|
|
|
3906
3927
|
const handleInputChange = value => {
|
|
@@ -4101,9 +4122,19 @@ const TicketTypeComponent = ({
|
|
|
4101
4122
|
// When promo code changes, the API returns updated ticket types with/without discount.
|
|
4102
4123
|
// Sync the selected ticket with the refreshed data.
|
|
4103
4124
|
if (!ticket) {
|
|
4104
|
-
// Auto-select
|
|
4105
|
-
|
|
4106
|
-
|
|
4125
|
+
// Auto-select after a promo code is applied. Defer while applyingCode is
|
|
4126
|
+
// true: the reducer sets promoCode synchronously before the refreshed
|
|
4127
|
+
// ticketTypes land, so acting now would auto-select from a stale list.
|
|
4128
|
+
// Once apply settles, prefer the first ticket the discovered code applies
|
|
4129
|
+
// to (so per-ticket validation succeeds); fall back to the only ticket
|
|
4130
|
+
// when there's a single option.
|
|
4131
|
+
// Scan allowedTicketTypes (date-filtered) so we never auto-select
|
|
4132
|
+
// a ticket the user couldn't have picked themselves from the dropdown.
|
|
4133
|
+
if (promoCode && !promoState.applyingCode && allowedTicketTypes.length > 0) {
|
|
4134
|
+
const isValid = promoState.isCodeValidForTicket;
|
|
4135
|
+
const qualifying = isValid && allowedTicketTypes.find(isValid);
|
|
4136
|
+
const toSelect = qualifying || (allowedTicketTypes.length === 1 ? allowedTicketTypes[0] : null);
|
|
4137
|
+
if (toSelect) handleTicketChange(toSelect);
|
|
4107
4138
|
}
|
|
4108
4139
|
|
|
4109
4140
|
return;
|
|
@@ -4120,7 +4151,7 @@ const TicketTypeComponent = ({
|
|
|
4120
4151
|
setTicket(null);
|
|
4121
4152
|
setQuantity(minQuantity);
|
|
4122
4153
|
}
|
|
4123
|
-
}, [promoCode, originalTicketTypes]);
|
|
4154
|
+
}, [promoCode, promoState.applyingCode, allowedTicketTypes, originalTicketTypes]);
|
|
4124
4155
|
const showTicketSelector = allowedTicketTypes.length > 0;
|
|
4125
4156
|
const isPrePaidReservation = (0,external_react_.useMemo)(() => reservation ? (0,utils/* isPrePaidOrder */.xm)(reservation) : false, [reservation]); // check if reassignment is allowed by both promo code AND ticket type
|
|
4126
4157
|
|
|
@@ -4171,7 +4202,24 @@ const TicketTypeComponent = ({
|
|
|
4171
4202
|
const decrementQuantity = () => setQuantity(quantity - 1);
|
|
4172
4203
|
|
|
4173
4204
|
const handleApplyPromoCode = async code => {
|
|
4174
|
-
|
|
4205
|
+
// If the user applies the suggested/discovered code while a
|
|
4206
|
+
// non-qualifying ticket is selected, deselect first. The qualifying
|
|
4207
|
+
// ticket may not yet be in originalTicketTypes (it's revealed by the
|
|
4208
|
+
// code-filtered refetch inside applyPromoCode). After apply resolves,
|
|
4209
|
+
// the post-apply effect picks the qualifying ticket from the
|
|
4210
|
+
// refreshed list. Manual non-discovered codes still validate against
|
|
4211
|
+
// the current ticket — backend decides.
|
|
4212
|
+
const isDiscovered = code === promoState.suggestedCode;
|
|
4213
|
+
const isValid = promoState.isCodeValidForTicket;
|
|
4214
|
+
let targetTicket = ticket;
|
|
4215
|
+
|
|
4216
|
+
if (isDiscovered && isValid && ticket && !isValid(ticket)) {
|
|
4217
|
+
setTicket(null);
|
|
4218
|
+
setQuantity(minQuantity);
|
|
4219
|
+
targetTicket = null;
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
await promoActions.onApply(code, targetTicket, quantity);
|
|
4175
4223
|
};
|
|
4176
4224
|
|
|
4177
4225
|
return /*#__PURE__*/external_react_default().createElement("div", {
|
|
@@ -4281,6 +4329,7 @@ const TicketTypeComponent = ({
|
|
|
4281
4329
|
promoCode: promoCode,
|
|
4282
4330
|
suggestedCode: promoState.suggestedCode,
|
|
4283
4331
|
isAutoApplied: promoState.isAutoApplied,
|
|
4332
|
+
isCurrentTicketQualifying: promoState.isCodeValidForTicket(ticket),
|
|
4284
4333
|
onInputChange: promoActions.onInputChange,
|
|
4285
4334
|
onApply: handleApplyPromoCode,
|
|
4286
4335
|
onRemove: promoActions.onRemove,
|
|
@@ -4886,14 +4935,18 @@ const RegistrationFormContent = _ref => {
|
|
|
4886
4935
|
} = promo; // Error rendered in the promo notice slot — form-level warning layered on top
|
|
4887
4936
|
// of the hook's own validation error (API rejection or status-derived).
|
|
4888
4937
|
|
|
4889
|
-
const ticketStepError = unappliedCodeWarning ?? promoState.validationError; // Clear the unapplied-code warning once
|
|
4890
|
-
//
|
|
4938
|
+
const ticketStepError = unappliedCodeWarning ?? promoState.validationError; // Clear the unapplied-code warning once it's no longer the right message to show.
|
|
4939
|
+
// The hook's own validationError takes precedence: if the user actually clicked
|
|
4940
|
+
// Apply and the backend rejected, surfacing "you didn't apply" would mask the
|
|
4941
|
+
// specific rejection reason. Depending on validationError (rather than on
|
|
4942
|
+
// applyPromoCode's brief Redux promoCode=truthy window) keeps the cleanup
|
|
4943
|
+
// robust against refactors of the apply action's sequencing.
|
|
4891
4944
|
|
|
4892
4945
|
(0,external_react_.useEffect)(() => {
|
|
4893
|
-
if (!formValues?.promoCode || promoCode || promoState.status === constants.PROMO_STATUS.SUGGESTED) {
|
|
4946
|
+
if (!formValues?.promoCode || promoCode || promoState.status === constants.PROMO_STATUS.SUGGESTED || promoState.validationError) {
|
|
4894
4947
|
setUnappliedCodeWarning(null);
|
|
4895
4948
|
}
|
|
4896
|
-
}, [formValues?.promoCode, promoCode, promoState.status]);
|
|
4949
|
+
}, [formValues?.promoCode, promoCode, promoState.status, promoState.validationError]);
|
|
4897
4950
|
const [ref, {
|
|
4898
4951
|
height
|
|
4899
4952
|
}] = (0,external_react_use_namespaceObject.useMeasure)();
|