summit-registration-lite 7.0.5 → 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/e2e/promo-code-date-filter.spec.js +103 -0
- package/e2e/promo-code-discovery.spec.js +55 -7
- package/e2e/promo-code-invalid-clears-warning.spec.js +57 -0
- 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
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# Multi-Step Registration Flow
|
|
2
|
-
|
|
3
|
-
## When to Apply
|
|
4
|
-
|
|
5
|
-
Adding step-specific logic, modifying step transitions, or rendering step-dependent UI.
|
|
6
|
-
|
|
7
|
-
## Step Constants
|
|
8
|
-
|
|
9
|
-
Defined in `src/utils/constants.js`:
|
|
10
|
-
|
|
11
|
-
```javascript
|
|
12
|
-
export const STEP_SELECT_TICKET_TYPE = 0; // Ticket selection + promo code
|
|
13
|
-
export const STEP_PERSONAL_INFO = 1; // Attendee details + ticket assignment
|
|
14
|
-
export const STEP_PAYMENT = 2; // Payment form (Stripe/LawPay)
|
|
15
|
-
export const STEP_COMPLETE = 3; // Order confirmation
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Step Transitions
|
|
19
|
-
|
|
20
|
-
**Forward flow (happy path):**
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
STEP_SELECT_TICKET_TYPE → (Next/validate promo) → STEP_PERSONAL_INFO
|
|
24
|
-
STEP_PERSONAL_INFO → (submit form) → reserveTicket → STEP_PAYMENT
|
|
25
|
-
STEP_PAYMENT → (pay) → payTicketWithProvider → STEP_COMPLETE
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**Special cases:**
|
|
29
|
-
|
|
30
|
-
| Scenario | Transition |
|
|
31
|
-
|----------|------------|
|
|
32
|
-
| Free ticket (cost === 0) | `STEP_PERSONAL_INFO` → skip payment → `STEP_COMPLETE` |
|
|
33
|
-
| Pre-paid ticket | `STEP_PERSONAL_INFO` → skip payment → `STEP_COMPLETE` |
|
|
34
|
-
| Payment failure | `STEP_PAYMENT` → `removeReservedTicket()` → `STEP_PERSONAL_INFO` |
|
|
35
|
-
| No ticket selected + back | Any step → `STEP_SELECT_TICKET_TYPE` |
|
|
36
|
-
|
|
37
|
-
**Back navigation:**
|
|
38
|
-
|
|
39
|
-
- From `STEP_PERSONAL_INFO`: `changeStep(step - 1)`
|
|
40
|
-
- From `STEP_PAYMENT`: `removeReservedTicket()` (clears reservation, reducer resets to `STEP_PERSONAL_INFO`)
|
|
41
|
-
|
|
42
|
-
## Redux Integration
|
|
43
|
-
|
|
44
|
-
```javascript
|
|
45
|
-
// Action
|
|
46
|
-
export const changeStep = (step) => (dispatch, getState) => {
|
|
47
|
-
dispatch(createAction(CHANGE_STEP)(step));
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// Reducer
|
|
51
|
-
case CHANGE_STEP: {
|
|
52
|
-
return { ...state, step: payload };
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Default state: `step: STEP_SELECT_TICKET_TYPE`
|
|
57
|
-
|
|
58
|
-
## Rendering Pattern
|
|
59
|
-
|
|
60
|
-
In `registration-lite.js`, each step renders conditionally:
|
|
61
|
-
|
|
62
|
-
```javascript
|
|
63
|
-
<StepComponent isActive={step === STEP_SELECT_TICKET_TYPE} ... />
|
|
64
|
-
<StepComponent isActive={step === STEP_PERSONAL_INFO} ... />
|
|
65
|
-
<StepComponent isActive={step === STEP_PAYMENT} ... />
|
|
66
|
-
{step === STEP_COMPLETE && <PurchaseCompleteComponent ... />}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
- Steps 0-2 share layout with `ButtonBarComponent`
|
|
70
|
-
- Step 3 (complete) has its own layout, no button bar
|
|
71
|
-
- Button bar renders step-specific buttons based on current `step` value
|
|
72
|
-
|
|
73
|
-
## Common Mistakes
|
|
74
|
-
|
|
75
|
-
- Skipping `removeReservedTicket()` when going back from payment (leaves stale reservation)
|
|
76
|
-
- Not checking `reservation` existence before allowing forward navigation
|
|
77
|
-
- Adding steps without updating `ButtonBarComponent` (buttons won't render for new step)
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# Testing Patterns
|
|
2
|
-
|
|
3
|
-
## When to Apply
|
|
4
|
-
|
|
5
|
-
Writing new component tests or maintaining existing tests.
|
|
6
|
-
|
|
7
|
-
## Pattern
|
|
8
|
-
|
|
9
|
-
**Test Structure:**
|
|
10
|
-
|
|
11
|
-
```javascript
|
|
12
|
-
import React from 'react';
|
|
13
|
-
import { render, fireEvent, waitFor, screen } from '@testing-library/react';
|
|
14
|
-
import '@testing-library/jest-dom';
|
|
15
|
-
import ComponentName from '..';
|
|
16
|
-
|
|
17
|
-
const mockCallback = jest.fn();
|
|
18
|
-
|
|
19
|
-
afterEach(() => {
|
|
20
|
-
jest.clearAllMocks(); // Reset mocks between tests
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('describes expected behavior', () => {
|
|
24
|
-
const { getByTestId, getAllByTestId, queryByText } = render(
|
|
25
|
-
<ComponentName prop1={value1} callback={mockCallback} />
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
// Arrange: find elements
|
|
29
|
-
const button = getByTestId('button-id');
|
|
30
|
-
|
|
31
|
-
// Act: interact
|
|
32
|
-
fireEvent.click(button);
|
|
33
|
-
|
|
34
|
-
// Assert: verify outcome
|
|
35
|
-
expect(mockCallback).toHaveBeenCalledWith(expectedArg);
|
|
36
|
-
});
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
**Common Queries:**
|
|
40
|
-
|
|
41
|
-
```javascript
|
|
42
|
-
// Single element (throws if not found)
|
|
43
|
-
getByTestId('id') // data-testid attribute
|
|
44
|
-
getByText('text') // visible text content
|
|
45
|
-
getByRole('button') // ARIA role
|
|
46
|
-
|
|
47
|
-
// Multiple elements
|
|
48
|
-
getAllByTestId('id') // returns array
|
|
49
|
-
|
|
50
|
-
// Nullable queries (returns null if not found)
|
|
51
|
-
queryByText('text') // useful for "expect().toBeFalsy()"
|
|
52
|
-
|
|
53
|
-
// From screen utility
|
|
54
|
-
screen.queryByText('text')
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
**Async Testing:**
|
|
58
|
-
|
|
59
|
-
```javascript
|
|
60
|
-
it('handles async behavior', async () => {
|
|
61
|
-
const { getByTestId } = render(<Component />);
|
|
62
|
-
|
|
63
|
-
fireEvent.click(getByTestId('async-button'));
|
|
64
|
-
|
|
65
|
-
await waitFor(() => {
|
|
66
|
-
expect(getByTestId('result')).toBeInTheDocument();
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Key Points
|
|
72
|
-
|
|
73
|
-
- Tests live in `__tests__/` directories alongside components
|
|
74
|
-
- Use `data-testid` attributes for reliable element selection
|
|
75
|
-
- Mock callbacks with `jest.fn()`, verify with `.toHaveBeenCalled()` or `.toHaveBeenCalledWith()`
|
|
76
|
-
- Use `queryBy*` for negative assertions (`expect().toBeFalsy()`)
|
|
77
|
-
- Use `getBy*` for positive assertions (throws if element missing)
|
|
78
|
-
- `@testing-library/react` auto-cleanup enabled (no manual unmount needed)
|
|
79
|
-
- CSS/SCSS mocked via `identity-obj-proxy` (className checks work)
|
|
80
|
-
- Static assets (images) mocked via `src/__mocks__/fileMock.js`
|
|
81
|
-
|
|
82
|
-
## Test Organization
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
src/components/my-component/
|
|
86
|
-
├── index.js
|
|
87
|
-
├── my-component.module.scss
|
|
88
|
-
└── __tests__/
|
|
89
|
-
└── my-component.test.js
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Common Mistakes
|
|
93
|
-
|
|
94
|
-
- Using brittle selectors (text content that changes) instead of `data-testid`
|
|
95
|
-
- Forgetting `@testing-library/jest-dom` import (causes `.toBeInTheDocument()` to fail)
|
|
96
|
-
- Not awaiting async operations (tests pass locally, fail in CI due to timing)
|
|
97
|
-
- Testing implementation details instead of user behavior (prefer user interactions over internal state checks)
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# Utility Functions
|
|
2
|
-
|
|
3
|
-
## When to Apply
|
|
4
|
-
|
|
5
|
-
Working with ticket pricing, order status checks, payment provider resolution, or UI color logic.
|
|
6
|
-
|
|
7
|
-
## Key Functions (`src/utils/utils.js`)
|
|
8
|
-
|
|
9
|
-
### Order/Ticket Status Checks
|
|
10
|
-
|
|
11
|
-
```javascript
|
|
12
|
-
isFreeOrder(reservation) // reservation.amount === 0
|
|
13
|
-
isPrePaidOrder(reservation) // status === 'Paid' && payment_method === 'Offline'
|
|
14
|
-
isPrePaidTicketType(ticketType) // ticketType.sub_type === 'PrePaid'
|
|
15
|
-
hasDiscountApplied(ticketType) // has cost_with_applied_discount !== cost
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Used in payment providers to decide whether to skip the payment gateway.
|
|
19
|
-
|
|
20
|
-
### Pricing Display
|
|
21
|
-
|
|
22
|
-
```javascript
|
|
23
|
-
getTicketCost(ticket, quantity) // Returns JSX: strikethrough original + discounted price, or just price
|
|
24
|
-
getTicketTaxes(ticket, taxes) // Returns tax label string: " plus Tax A & Tax B"
|
|
25
|
-
formatCurrency(amount, { currency }) // From helpers/ — locale-aware currency formatting
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Payment Provider Resolution
|
|
29
|
-
|
|
30
|
-
```javascript
|
|
31
|
-
getCurrentProvider(summit)
|
|
32
|
-
// Iterates summit.payment_profiles for application_type === 'Registration'
|
|
33
|
-
// Returns { publicKey, provider } — uses test vs live key based on test_mode_enabled
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### UI Helpers
|
|
37
|
-
|
|
38
|
-
```javascript
|
|
39
|
-
getContrastingTextColor(bgColor, lightColor, darkColor) // WCAG luminance contrast
|
|
40
|
-
parseColor(input, element) // Resolves CSS variables to RGB
|
|
41
|
-
removeWhiteSpaces(value) // Strip all whitespace
|
|
42
|
-
isEmptyString(val) // Trim-aware empty check
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Error Tracking
|
|
46
|
-
|
|
47
|
-
```javascript
|
|
48
|
-
handleSentryException(err) // Sends to Sentry if window.SENTRY_DSN is set, else console.log
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Analytics
|
|
52
|
-
|
|
53
|
-
```javascript
|
|
54
|
-
buildTrackEvent(data, ticketQuantity, promoCode)
|
|
55
|
-
// Builds GA4-style event data with currency, items_array, discount
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Helper Exports (`src/helpers/`)
|
|
59
|
-
|
|
60
|
-
Barrel export from `src/helpers/index.js`:
|
|
61
|
-
|
|
62
|
-
- `capitalizeFirstLetter` — text formatting
|
|
63
|
-
- `formatCurrency` — locale-aware currency display
|
|
64
|
-
- `formatErrorMessage` — error message normalization
|
|
65
|
-
- `getTicketMaxQuantity` — ticket quantity constraints
|
|
66
|
-
|
|
67
|
-
## Common Mistakes
|
|
68
|
-
|
|
69
|
-
- Using `reservation.amount === 0` directly instead of `isFreeOrder()` (misses edge cases)
|
|
70
|
-
- Forgetting `isPrePaidOrder()` check alongside `isFreeOrder()` in payment flows
|
|
71
|
-
- Not handling `getCurrentProvider()` returning `{ publicKey: null, provider: '' }` when no payment profile exists
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: summit-registration-lite-add-provider
|
|
3
|
-
version: 1.0.0
|
|
4
|
-
description: Scaffold new payment provider with factory registration
|
|
5
|
-
triggers:
|
|
6
|
-
- add payment provider
|
|
7
|
-
- new payment gateway
|
|
8
|
-
- integrate payment
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# Add Payment Provider Workflow
|
|
12
|
-
|
|
13
|
-
Scaffolds a new payment provider class with factory registration, error handling, and test template.
|
|
14
|
-
|
|
15
|
-
## Steps
|
|
16
|
-
|
|
17
|
-
1. **Ask for provider details**
|
|
18
|
-
- Provider name (e.g., "PayPal", "Square")
|
|
19
|
-
- Provider constant (e.g., "PAYMENT_PROVIDER_PAYPAL")
|
|
20
|
-
- Gateway-specific fields needed (API keys, client IDs, etc.)
|
|
21
|
-
|
|
22
|
-
2. **Add constant to utils/constants.js**
|
|
23
|
-
```javascript
|
|
24
|
-
export const PAYMENT_PROVIDER_NEWNAME = 'new_provider_name';
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
3. **Create provider class**
|
|
28
|
-
File: `src/utils/payment-providers/{name}-provider.js`
|
|
29
|
-
|
|
30
|
-
Use StripeProvider as template:
|
|
31
|
-
- Constructor receives: `{ reservation, summitId, userProfile, access_token, apiBaseUrl, dispatch }`
|
|
32
|
-
- Implement `payTicket` method with signature:
|
|
33
|
-
```javascript
|
|
34
|
-
payTicket = ({ /* gateway-specific params */, onError = () => {} }) => async (dispatch) => {
|
|
35
|
-
// Implementation
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
- Handle free/prepaid orders (skip gateway, call `/checkout` directly)
|
|
39
|
-
- Custom error handler for HTTP status codes (404 → VALIDATION, 500 → ERROR)
|
|
40
|
-
- Success flow: checkout → CLEAR_RESERVATION → changeStep(STEP_COMPLETE)
|
|
41
|
-
- Failure flow: removeReservedTicket → changeStep(STEP_PERSONAL_INFO)
|
|
42
|
-
|
|
43
|
-
4. **Register in factory**
|
|
44
|
-
File: `src/utils/payment-providers/payment-provider-factory.js`
|
|
45
|
-
|
|
46
|
-
Add import and case:
|
|
47
|
-
```javascript
|
|
48
|
-
import { NewProvider } from './new-provider';
|
|
49
|
-
|
|
50
|
-
case PAYMENT_PROVIDER_NEWNAME: {
|
|
51
|
-
currentProvider = new NewProvider({...params});
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
5. **Add provider component** (if custom UI needed)
|
|
57
|
-
File: `src/components/{name}-component/index.js`
|
|
58
|
-
|
|
59
|
-
Handles gateway-specific UI (payment form, buttons, etc.).
|
|
60
|
-
|
|
61
|
-
6. **Create test file**
|
|
62
|
-
File: `src/utils/payment-providers/__tests__/{name}-provider.test.js`
|
|
63
|
-
|
|
64
|
-
Mock patterns:
|
|
65
|
-
- Mock API calls (putRequest)
|
|
66
|
-
- Mock gateway SDK (if any)
|
|
67
|
-
- Test free/prepaid flow
|
|
68
|
-
- Test error handling
|
|
69
|
-
|
|
70
|
-
7. **Update PaymentComponent**
|
|
71
|
-
File: `src/components/payment/index.js`
|
|
72
|
-
|
|
73
|
-
Add conditional rendering for new provider UI.
|
|
74
|
-
|
|
75
|
-
## Provider Template
|
|
76
|
-
|
|
77
|
-
```javascript
|
|
78
|
-
import { createAction, putRequest, authErrorHandler } from 'openstack-uicore-foundation/lib/utils/actions';
|
|
79
|
-
import { CLEAR_RESERVATION, PAY_RESERVATION } from '../../actions';
|
|
80
|
-
import { changeStep, removeReservedTicket, startWidgetLoading, stopWidgetLoading } from '../../actions';
|
|
81
|
-
import { isFreeOrder, isPrePaidOrder } from '../utils';
|
|
82
|
-
import { ERROR_TYPE_ERROR, ERROR_TYPE_VALIDATION, STEP_COMPLETE, STEP_PERSONAL_INFO } from '../constants';
|
|
83
|
-
|
|
84
|
-
export class NewProvider {
|
|
85
|
-
constructor({ reservation, summitId, userProfile, access_token, apiBaseUrl, dispatch }) {
|
|
86
|
-
this.reservation = reservation;
|
|
87
|
-
this.summitId = summitId;
|
|
88
|
-
this.userProfile = userProfile;
|
|
89
|
-
this.access_token = access_token;
|
|
90
|
-
this.apiBaseUrl = apiBaseUrl;
|
|
91
|
-
this.dispatch = dispatch;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
payTicket = ({ /* custom params */, onError = () => {} }) => async (dispatch) => {
|
|
95
|
-
const errorHandler = (err, res) => (dispatch, state) => {
|
|
96
|
-
let code = err.status;
|
|
97
|
-
switch (code) {
|
|
98
|
-
case 404: onError({type: ERROR_TYPE_VALIDATION, msg: res.body.message, exception: null}); break;
|
|
99
|
-
case 500: onError({type: ERROR_TYPE_ERROR, msg: res.body.message, exception: null}); break;
|
|
100
|
-
default: authErrorHandler(err, res)(dispatch, state); break;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const normalizedEntity = {
|
|
105
|
-
billing_address_1: this.userProfile?.address1 || '',
|
|
106
|
-
billing_address_2: this.userProfile?.address2 || '',
|
|
107
|
-
billing_address_city: this.userProfile?.locality || '',
|
|
108
|
-
billing_address_state: this.userProfile?.region || '',
|
|
109
|
-
billing_address_country: this.userProfile?.country || ''
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
dispatch(startWidgetLoading());
|
|
113
|
-
|
|
114
|
-
// Free/prepaid orders
|
|
115
|
-
if (isFreeOrder(this.reservation) || isPrePaidOrder(this.reservation)) {
|
|
116
|
-
return this.checkout(normalizedEntity, errorHandler, onError);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Gateway-specific payment flow here
|
|
120
|
-
// Then call this.checkout() on success
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
checkout = (normalizedEntity, errorHandler, onError) => {
|
|
124
|
-
const params = { access_token: this.access_token, expand: 'tickets,tickets.owner,...' };
|
|
125
|
-
|
|
126
|
-
return putRequest(
|
|
127
|
-
null,
|
|
128
|
-
createAction(PAY_RESERVATION),
|
|
129
|
-
`${this.apiBaseUrl}/api/v1/summits/${this.summitId}/orders/${this.reservation.hash}/checkout`,
|
|
130
|
-
normalizedEntity,
|
|
131
|
-
errorHandler
|
|
132
|
-
)(params)(this.dispatch)
|
|
133
|
-
.then((payload) => {
|
|
134
|
-
this.dispatch(stopWidgetLoading());
|
|
135
|
-
this.dispatch(createAction(CLEAR_RESERVATION)({}));
|
|
136
|
-
this.dispatch(changeStep(STEP_COMPLETE));
|
|
137
|
-
return payload;
|
|
138
|
-
})
|
|
139
|
-
.catch(e => {
|
|
140
|
-
this.dispatch(stopWidgetLoading());
|
|
141
|
-
this.dispatch(removeReservedTicket());
|
|
142
|
-
this.dispatch(changeStep(STEP_PERSONAL_INFO));
|
|
143
|
-
onError({type: ERROR_TYPE_ERROR, msg: e?.message, exception: e});
|
|
144
|
-
return e;
|
|
145
|
-
});
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## Testing
|
|
151
|
-
|
|
152
|
-
Run provider tests:
|
|
153
|
-
```bash
|
|
154
|
-
yarn test payment-providers
|
|
155
|
-
```
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: summit-registration-lite-dev-setup
|
|
3
|
-
version: 1.0.0
|
|
4
|
-
description: Clean install and start development server
|
|
5
|
-
triggers:
|
|
6
|
-
- setup dev environment
|
|
7
|
-
- start dev server
|
|
8
|
-
- clean install
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# Development Setup Workflow
|
|
12
|
-
|
|
13
|
-
Cleans existing installation and starts fresh development environment.
|
|
14
|
-
|
|
15
|
-
## Steps
|
|
16
|
-
|
|
17
|
-
### Option 1: Clean Setup (Recommended for Issues)
|
|
18
|
-
|
|
19
|
-
1. **Clean all build artifacts and dependencies**
|
|
20
|
-
```bash
|
|
21
|
-
yarn clean
|
|
22
|
-
```
|
|
23
|
-
Removes `dist/` and `node_modules/`, then reinstalls with `yarn`.
|
|
24
|
-
|
|
25
|
-
2. **Start dev server**
|
|
26
|
-
```bash
|
|
27
|
-
yarn serve
|
|
28
|
-
```
|
|
29
|
-
Starts webpack-dev-server on default port (usually 8080). Opens browser automatically.
|
|
30
|
-
|
|
31
|
-
### Option 2: Quick Start (No Clean)
|
|
32
|
-
|
|
33
|
-
1. **Install dependencies** (if `node_modules/` missing)
|
|
34
|
-
```bash
|
|
35
|
-
yarn
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
2. **Start dev server**
|
|
39
|
-
```bash
|
|
40
|
-
yarn serve
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Development Configuration
|
|
44
|
-
|
|
45
|
-
- **Webpack config:** `webpack.dev.js` (extends `webpack.common.js`)
|
|
46
|
-
- **Environment variables:**
|
|
47
|
-
- `API_BASE_URL` - API endpoint for development
|
|
48
|
-
- `ACCESS_TOKEN` - Auth token for standalone testing (stored in localStorage)
|
|
49
|
-
|
|
50
|
-
Set these in shell or `.env` file:
|
|
51
|
-
```bash
|
|
52
|
-
export API_BASE_URL=https://api.dev.example.com
|
|
53
|
-
export ACCESS_TOKEN=your_dev_token
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Standalone Testing
|
|
57
|
-
|
|
58
|
-
The widget supports standalone mode in development. Set environment variables before running `yarn serve` to test without parent app.
|
|
59
|
-
|
|
60
|
-
## Troubleshooting
|
|
61
|
-
|
|
62
|
-
| Issue | Solution |
|
|
63
|
-
|-------|----------|
|
|
64
|
-
| Port already in use | Kill process: `lsof -ti:8080 | xargs kill` or change port in webpack.dev.js |
|
|
65
|
-
| Stale cache | Run `yarn clean` |
|
|
66
|
-
| Module not found | Delete `node_modules/` and `yarn.lock`, then `yarn` |
|
|
67
|
-
| Hot reload not working | Check webpack-dev-server config, ensure `watchFiles` configured |
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: summit-registration-lite-publish
|
|
3
|
-
version: 1.0.0
|
|
4
|
-
description: Build and publish package to NPM registry
|
|
5
|
-
triggers:
|
|
6
|
-
- publish to npm
|
|
7
|
-
- release package
|
|
8
|
-
- deploy widget
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# Package Publishing Workflow
|
|
12
|
-
|
|
13
|
-
Builds the production bundle and publishes to NPM registry.
|
|
14
|
-
|
|
15
|
-
## Steps
|
|
16
|
-
|
|
17
|
-
1. **Verify clean state**
|
|
18
|
-
```bash
|
|
19
|
-
git status
|
|
20
|
-
```
|
|
21
|
-
Ensure no uncommitted changes. If changes exist, ask user to commit or stash first.
|
|
22
|
-
|
|
23
|
-
2. **Verify version**
|
|
24
|
-
```bash
|
|
25
|
-
cat package.json | grep '"version"'
|
|
26
|
-
```
|
|
27
|
-
Confirm version with user before publishing. Ask if version should be bumped (patch/minor/major).
|
|
28
|
-
|
|
29
|
-
3. **Build production bundle**
|
|
30
|
-
```bash
|
|
31
|
-
yarn build
|
|
32
|
-
```
|
|
33
|
-
Compiles with webpack.prod.js. Output goes to `dist/`.
|
|
34
|
-
|
|
35
|
-
4. **Verify build output**
|
|
36
|
-
```bash
|
|
37
|
-
ls -lh dist/
|
|
38
|
-
```
|
|
39
|
-
Check that `index.js` and `index.css` exist.
|
|
40
|
-
|
|
41
|
-
5. **Publish to NPM**
|
|
42
|
-
```bash
|
|
43
|
-
yarn publish
|
|
44
|
-
```
|
|
45
|
-
Prompts for new version (if not already updated). Requires NPM authentication.
|
|
46
|
-
|
|
47
|
-
## Alternative: Combined Command
|
|
48
|
-
|
|
49
|
-
The `yarn publish-package` script combines build and publish:
|
|
50
|
-
```bash
|
|
51
|
-
yarn publish-package
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Prerequisites
|
|
55
|
-
|
|
56
|
-
- NPM authentication configured (`npm login`)
|
|
57
|
-
- Write access to `summit-registration-lite` package on NPM
|
|
58
|
-
- Clean git working directory (or committed changes)
|
|
59
|
-
|
|
60
|
-
## Post-Publish
|
|
61
|
-
|
|
62
|
-
- Tag the release in git: `git tag v{version}`
|
|
63
|
-
- Push tag: `git push origin v{version}`
|
|
64
|
-
- Update CHANGELOG.md with release notes
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: summit-registration-lite-scaffold-component
|
|
3
|
-
version: 1.0.0
|
|
4
|
-
description: Create new component with folder structure, test file, and SCSS module
|
|
5
|
-
triggers:
|
|
6
|
-
- create new component
|
|
7
|
-
- scaffold component
|
|
8
|
-
- add component
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# Component Scaffolding Workflow
|
|
12
|
-
|
|
13
|
-
Creates a new React component with proper folder structure, SCSS module, and test boilerplate.
|
|
14
|
-
|
|
15
|
-
## Steps
|
|
16
|
-
|
|
17
|
-
1. **Ask for component details**
|
|
18
|
-
- Component name (PascalCase, e.g., "TicketSelector")
|
|
19
|
-
- Purpose/description
|
|
20
|
-
- Key props (if known)
|
|
21
|
-
|
|
22
|
-
2. **Create directory structure**
|
|
23
|
-
```
|
|
24
|
-
src/components/{component-name}/
|
|
25
|
-
├── index.js
|
|
26
|
-
├── {component-name}.module.scss
|
|
27
|
-
└── __tests__/
|
|
28
|
-
└── {component-name}.test.js
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
3. **Generate component file**
|
|
32
|
-
File: `src/components/{component-name}/index.js`
|
|
33
|
-
|
|
34
|
-
Template:
|
|
35
|
-
```javascript
|
|
36
|
-
import React from 'react';
|
|
37
|
-
import PropTypes from 'prop-types';
|
|
38
|
-
import styles from './{component-name}.module.scss';
|
|
39
|
-
|
|
40
|
-
const ComponentName = ({ prop1, prop2 }) => {
|
|
41
|
-
return (
|
|
42
|
-
<div className={styles.container}>
|
|
43
|
-
{/* Component content */}
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
ComponentName.propTypes = {
|
|
49
|
-
prop1: PropTypes.string.isRequired,
|
|
50
|
-
prop2: PropTypes.func,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
ComponentName.defaultProps = {
|
|
54
|
-
prop2: () => {},
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export default ComponentName;
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
4. **Generate SCSS module**
|
|
61
|
-
File: `src/components/{component-name}/{component-name}.module.scss`
|
|
62
|
-
|
|
63
|
-
Template:
|
|
64
|
-
```scss
|
|
65
|
-
.container {
|
|
66
|
-
// Component styles
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
5. **Generate test file**
|
|
71
|
-
File: `src/components/{component-name}/__tests__/{component-name}.test.js`
|
|
72
|
-
|
|
73
|
-
Template:
|
|
74
|
-
```javascript
|
|
75
|
-
import React from 'react';
|
|
76
|
-
import { render, fireEvent, screen } from '@testing-library/react';
|
|
77
|
-
import '@testing-library/jest-dom';
|
|
78
|
-
import ComponentName from '..';
|
|
79
|
-
|
|
80
|
-
const mockCallback = jest.fn();
|
|
81
|
-
|
|
82
|
-
afterEach(() => {
|
|
83
|
-
jest.clearAllMocks();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
describe('ComponentName', () => {
|
|
87
|
-
it('renders without crashing', () => {
|
|
88
|
-
const { getByTestId } = render(
|
|
89
|
-
<ComponentName prop1="test" prop2={mockCallback} />
|
|
90
|
-
);
|
|
91
|
-
expect(getByTestId('component-container')).toBeInTheDocument();
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('calls callback on interaction', () => {
|
|
95
|
-
const { getByTestId } = render(
|
|
96
|
-
<ComponentName prop1="test" prop2={mockCallback} />
|
|
97
|
-
);
|
|
98
|
-
fireEvent.click(getByTestId('test-button'));
|
|
99
|
-
expect(mockCallback).toHaveBeenCalled();
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
6. **Add data-testid attributes**
|
|
105
|
-
Remind user to add `data-testid` attributes to key elements for testing.
|
|
106
|
-
|
|
107
|
-
## Component Conventions
|
|
108
|
-
|
|
109
|
-
- **Props:** Use PropTypes for validation, provide defaultProps for optional props
|
|
110
|
-
- **Styles:** Use CSS modules (`.module.scss`) for scoped styles
|
|
111
|
-
- **Testing:** Use `data-testid` for reliable element selection
|
|
112
|
-
- **Exports:** Default export for component, named exports for sub-components/utils if needed
|
|
113
|
-
|
|
114
|
-
## Redux-Connected Components
|
|
115
|
-
|
|
116
|
-
For components that need Redux state, use `connect`:
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
import { connect } from 'react-redux';
|
|
120
|
-
import { someAction } from '../../actions';
|
|
121
|
-
|
|
122
|
-
const ComponentName = ({ stateValue, someAction }) => {
|
|
123
|
-
// Component implementation
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const mapStateToProps = ({ registration }) => ({
|
|
127
|
-
stateValue: registration.stateValue,
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
export default connect(mapStateToProps, { someAction })(ComponentName);
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Testing Redux Components
|
|
134
|
-
|
|
135
|
-
Wrap in Provider for testing:
|
|
136
|
-
```javascript
|
|
137
|
-
import { Provider } from 'react-redux';
|
|
138
|
-
import { getStore } from '../../store';
|
|
139
|
-
|
|
140
|
-
const renderWithStore = (component) => {
|
|
141
|
-
const store = getStore('test-client', 'http://api.test', () => 'mock-token');
|
|
142
|
-
return render(<Provider store={store}>{component}</Provider>);
|
|
143
|
-
};
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## Next Steps After Scaffolding
|
|
147
|
-
|
|
148
|
-
1. Implement component logic
|
|
149
|
-
2. Add styles
|
|
150
|
-
3. Write tests (aim for key interactions)
|
|
151
|
-
4. Import and use in parent component
|
|
152
|
-
5. Verify in dev server
|