@queuezero/react 0.1.3
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/README.md +214 -0
- package/dist/index.d.mts +283 -0
- package/dist/index.d.ts +283 -0
- package/dist/index.js +438 -0
- package/dist/index.mjs +403 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# @queuezero/react
|
|
2
|
+
|
|
3
|
+
React components and hooks for QueueZero viral waitlists.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @queuezero/react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { WaitlistProvider, WaitlistForm, WaitlistStatus, ReferralShare } from '@queuezero/react';
|
|
15
|
+
|
|
16
|
+
function App() {
|
|
17
|
+
// Get referral code from URL if present
|
|
18
|
+
const referrerCode = new URLSearchParams(window.location.search).get('ref');
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<WaitlistProvider
|
|
22
|
+
campaign="my-campaign"
|
|
23
|
+
config={{ apiUrl: 'https://api.queuezero.io' }}
|
|
24
|
+
>
|
|
25
|
+
<WaitlistForm
|
|
26
|
+
referrerCode={referrerCode || undefined}
|
|
27
|
+
onSuccess={(res) => console.log('Joined at position:', res.position)}
|
|
28
|
+
/>
|
|
29
|
+
<WaitlistStatus />
|
|
30
|
+
<ReferralShare showSocialButtons />
|
|
31
|
+
</WaitlistProvider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Components
|
|
37
|
+
|
|
38
|
+
### WaitlistProvider
|
|
39
|
+
|
|
40
|
+
Wraps your app to provide waitlist context to all child components.
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<WaitlistProvider
|
|
44
|
+
campaign="my-campaign"
|
|
45
|
+
config={{
|
|
46
|
+
apiUrl: 'https://api.queuezero.io',
|
|
47
|
+
baseUrl: 'https://myapp.com'
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
</WaitlistProvider>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### WaitlistForm
|
|
55
|
+
|
|
56
|
+
A ready-to-use signup form.
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
// Basic
|
|
60
|
+
<WaitlistForm />
|
|
61
|
+
|
|
62
|
+
// With options
|
|
63
|
+
<WaitlistForm
|
|
64
|
+
referrerCode="ABC123"
|
|
65
|
+
metadata={{ role: 'Developer' }}
|
|
66
|
+
placeholder="Enter your work email"
|
|
67
|
+
buttonText="Get Early Access"
|
|
68
|
+
onSuccess={(response) => console.log(response)}
|
|
69
|
+
onError={(error) => console.error(error)}
|
|
70
|
+
/>
|
|
71
|
+
|
|
72
|
+
// Custom render
|
|
73
|
+
<WaitlistForm>
|
|
74
|
+
{({ email, setEmail, submit, loading, error }) => (
|
|
75
|
+
<div>
|
|
76
|
+
<input value={email} onChange={(e) => setEmail(e.target.value)} />
|
|
77
|
+
<button onClick={submit}>{loading ? '...' : 'Join'}</button>
|
|
78
|
+
</div>
|
|
79
|
+
)}
|
|
80
|
+
</WaitlistForm>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### WaitlistStatus
|
|
84
|
+
|
|
85
|
+
Displays position, score, and referral count.
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
// Basic
|
|
89
|
+
<WaitlistStatus />
|
|
90
|
+
|
|
91
|
+
// With options
|
|
92
|
+
<WaitlistStatus
|
|
93
|
+
showScore
|
|
94
|
+
showReferrals
|
|
95
|
+
positionLabel="Your position:"
|
|
96
|
+
/>
|
|
97
|
+
|
|
98
|
+
// Custom render
|
|
99
|
+
<WaitlistStatus>
|
|
100
|
+
{(status) => (
|
|
101
|
+
<div>
|
|
102
|
+
<h2>#{status.position}</h2>
|
|
103
|
+
<p>{status.priority_score} points</p>
|
|
104
|
+
</div>
|
|
105
|
+
)}
|
|
106
|
+
</WaitlistStatus>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### ReferralShare
|
|
110
|
+
|
|
111
|
+
Share referral link with copy and social buttons.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
// Basic
|
|
115
|
+
<ReferralShare />
|
|
116
|
+
|
|
117
|
+
// With social buttons
|
|
118
|
+
<ReferralShare
|
|
119
|
+
showSocialButtons
|
|
120
|
+
shareMessage="Join me on this awesome waitlist!"
|
|
121
|
+
/>
|
|
122
|
+
|
|
123
|
+
// Custom render
|
|
124
|
+
<ReferralShare>
|
|
125
|
+
{({ link, code, copy, copied }) => (
|
|
126
|
+
<div>
|
|
127
|
+
<code>{code}</code>
|
|
128
|
+
<button onClick={copy}>{copied ? 'Copied!' : 'Copy'}</button>
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
</ReferralShare>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Hooks
|
|
135
|
+
|
|
136
|
+
### useWaitlistContext
|
|
137
|
+
|
|
138
|
+
Access waitlist state inside the provider.
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import { useWaitlistContext } from '@queuezero/react';
|
|
142
|
+
|
|
143
|
+
function MyComponent() {
|
|
144
|
+
const { status, loading, join, getReferralLink } = useWaitlistContext();
|
|
145
|
+
|
|
146
|
+
if (loading) return <div>Loading...</div>;
|
|
147
|
+
if (!status) return <button onClick={() => join('user@example.com')}>Join</button>;
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<div>
|
|
151
|
+
<p>Position: #{status.position}</p>
|
|
152
|
+
<p>Share: {getReferralLink()}</p>
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### useWaitlist
|
|
159
|
+
|
|
160
|
+
Standalone hook (without provider) for simpler use cases.
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import { useWaitlist } from '@queuezero/react';
|
|
164
|
+
|
|
165
|
+
function WaitlistPage() {
|
|
166
|
+
const { status, join, loading, getReferralLink } = useWaitlist('my-campaign', {
|
|
167
|
+
apiUrl: 'https://api.queuezero.io',
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// ...
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Styling
|
|
175
|
+
|
|
176
|
+
Components use `qz-*` class names for easy styling:
|
|
177
|
+
|
|
178
|
+
```css
|
|
179
|
+
/* Form */
|
|
180
|
+
.qz-form { }
|
|
181
|
+
.qz-form-row { display: flex; gap: 8px; }
|
|
182
|
+
.qz-form-input { flex: 1; padding: 12px; }
|
|
183
|
+
.qz-form-button { padding: 12px 24px; }
|
|
184
|
+
.qz-form-error { color: red; margin-top: 8px; }
|
|
185
|
+
|
|
186
|
+
/* Status */
|
|
187
|
+
.qz-status { display: flex; gap: 16px; }
|
|
188
|
+
.qz-status-item { }
|
|
189
|
+
.qz-status-label { font-size: 12px; color: #666; }
|
|
190
|
+
.qz-status-value { font-size: 24px; font-weight: bold; }
|
|
191
|
+
|
|
192
|
+
/* Share */
|
|
193
|
+
.qz-share { }
|
|
194
|
+
.qz-share-input { flex: 1; padding: 8px; }
|
|
195
|
+
.qz-share-copy-button { padding: 8px 16px; }
|
|
196
|
+
.qz-share-social { display: flex; gap: 8px; margin-top: 8px; }
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## TypeScript
|
|
200
|
+
|
|
201
|
+
Full TypeScript support with exported types:
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import type {
|
|
205
|
+
WaitlistProviderProps,
|
|
206
|
+
WaitlistFormProps,
|
|
207
|
+
UserStatus,
|
|
208
|
+
SubmitResponse
|
|
209
|
+
} from '@queuezero/react';
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { QueueZeroConfig, UserStatus, UserMetadata, SubmitResponse, PublicCampaignConfig } from 'queuezero';
|
|
3
|
+
export { BrandingConfig, FeatureFlags, FormField, InMemoryStorageAdapter, LeadStatus, LocalStorageAdapter, QueueZeroClient, QueueZeroConfig, SubmitResponse, UserMetadata, UserStatus } from 'queuezero';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @queuezero/react - Types
|
|
7
|
+
*
|
|
8
|
+
* TypeScript type definitions for React components and hooks.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Props for WaitlistProvider
|
|
13
|
+
*/
|
|
14
|
+
interface WaitlistProviderProps {
|
|
15
|
+
/** Campaign slug/identifier */
|
|
16
|
+
campaign: string;
|
|
17
|
+
/** API configuration */
|
|
18
|
+
config?: QueueZeroConfig;
|
|
19
|
+
/** Children components */
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Waitlist context value
|
|
24
|
+
*/
|
|
25
|
+
interface WaitlistContextValue {
|
|
26
|
+
/** Current loading state */
|
|
27
|
+
loading: boolean;
|
|
28
|
+
/** Current user status (if joined) */
|
|
29
|
+
status: UserStatus | null;
|
|
30
|
+
/** Last error (if any) */
|
|
31
|
+
error: Error | null;
|
|
32
|
+
/** Whether the user has joined */
|
|
33
|
+
isJoined: boolean;
|
|
34
|
+
/** Campaign slug */
|
|
35
|
+
campaign: string;
|
|
36
|
+
/** Join the waitlist */
|
|
37
|
+
join: (email: string, metadata?: UserMetadata, referrerCode?: string) => Promise<SubmitResponse | null>;
|
|
38
|
+
/** Refresh status */
|
|
39
|
+
refresh: () => Promise<UserStatus | null>;
|
|
40
|
+
/** Get referral link */
|
|
41
|
+
getReferralLink: () => string | null;
|
|
42
|
+
/** Get referral code */
|
|
43
|
+
getReferralCode: () => string | null;
|
|
44
|
+
/** Reset/logout */
|
|
45
|
+
reset: () => void;
|
|
46
|
+
/** Public configuration fetched from the API */
|
|
47
|
+
config: PublicConfig | null;
|
|
48
|
+
/** Whether the config is loading */
|
|
49
|
+
configLoading: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type PublicConfig = PublicCampaignConfig;
|
|
53
|
+
/**
|
|
54
|
+
* Props for WaitlistForm component
|
|
55
|
+
*/
|
|
56
|
+
interface WaitlistFormProps {
|
|
57
|
+
/** Called on successful submission */
|
|
58
|
+
onSuccess?: (response: SubmitResponse) => void;
|
|
59
|
+
/** Called on error */
|
|
60
|
+
onError?: (error: Error) => void;
|
|
61
|
+
/** Referral code (if from a referral link) */
|
|
62
|
+
referrerCode?: string;
|
|
63
|
+
/** Additional metadata to include */
|
|
64
|
+
metadata?: UserMetadata;
|
|
65
|
+
/** Custom class name */
|
|
66
|
+
className?: string;
|
|
67
|
+
/** Custom placeholder text */
|
|
68
|
+
placeholder?: string;
|
|
69
|
+
/** Custom button text */
|
|
70
|
+
buttonText?: string;
|
|
71
|
+
/** Custom loading text */
|
|
72
|
+
loadingText?: string;
|
|
73
|
+
/** Show labels */
|
|
74
|
+
showLabel?: boolean;
|
|
75
|
+
/** Label text */
|
|
76
|
+
labelText?: string;
|
|
77
|
+
/** Children for custom rendering */
|
|
78
|
+
children?: React.ReactNode;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Props for WaitlistStatus component
|
|
82
|
+
*/
|
|
83
|
+
interface WaitlistStatusProps {
|
|
84
|
+
/** Custom class name */
|
|
85
|
+
className?: string;
|
|
86
|
+
/** Show referral stats */
|
|
87
|
+
showReferrals?: boolean;
|
|
88
|
+
/** Show score */
|
|
89
|
+
showScore?: boolean;
|
|
90
|
+
/** Custom position label */
|
|
91
|
+
positionLabel?: string;
|
|
92
|
+
/** Custom score label */
|
|
93
|
+
scoreLabel?: string;
|
|
94
|
+
/** Custom referrals label */
|
|
95
|
+
referralsLabel?: string;
|
|
96
|
+
/** Children for custom rendering */
|
|
97
|
+
children?: (status: UserStatus) => React.ReactNode;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Props for ReferralShare component
|
|
101
|
+
*/
|
|
102
|
+
interface ReferralShareProps {
|
|
103
|
+
/** Custom class name */
|
|
104
|
+
className?: string;
|
|
105
|
+
/** Text to display before the link */
|
|
106
|
+
label?: string;
|
|
107
|
+
/** Button text for copy action */
|
|
108
|
+
copyButtonText?: string;
|
|
109
|
+
/** Text shown after copying */
|
|
110
|
+
copiedText?: string;
|
|
111
|
+
/** Called when link is copied */
|
|
112
|
+
onCopy?: (link: string) => void;
|
|
113
|
+
/** Custom message for sharing */
|
|
114
|
+
shareMessage?: string;
|
|
115
|
+
/** Show social share buttons */
|
|
116
|
+
showSocialButtons?: boolean;
|
|
117
|
+
/** Children for custom rendering */
|
|
118
|
+
children?: (props: {
|
|
119
|
+
link: string;
|
|
120
|
+
code: string;
|
|
121
|
+
copy: () => void;
|
|
122
|
+
copied: boolean;
|
|
123
|
+
}) => React.ReactNode;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* WaitlistProvider - Provides waitlist functionality to all child components
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```tsx
|
|
131
|
+
* function App() {
|
|
132
|
+
* return (
|
|
133
|
+
* <WaitlistProvider campaign="my-campaign" config={{ apiUrl: 'https://api.example.com' }}>
|
|
134
|
+
* <WaitlistForm />
|
|
135
|
+
* <WaitlistStatus />
|
|
136
|
+
* </WaitlistProvider>
|
|
137
|
+
* );
|
|
138
|
+
* }
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
declare function WaitlistProvider({ campaign, config, children }: WaitlistProviderProps): react_jsx_runtime.JSX.Element;
|
|
142
|
+
/**
|
|
143
|
+
* useWaitlistContext - Access the waitlist context
|
|
144
|
+
*
|
|
145
|
+
* @throws Error if used outside of WaitlistProvider
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```tsx
|
|
149
|
+
* function MyComponent() {
|
|
150
|
+
* const { status, join, loading } = useWaitlistContext();
|
|
151
|
+
* // ...
|
|
152
|
+
* }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
declare function useWaitlistContext(): WaitlistContextValue;
|
|
156
|
+
/**
|
|
157
|
+
* useWaitlist - Standalone hook (without provider)
|
|
158
|
+
*
|
|
159
|
+
* For simple use cases where you don't need to share state across components.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```tsx
|
|
163
|
+
* function WaitlistPage() {
|
|
164
|
+
* const { status, join, loading } = useWaitlist('my-campaign');
|
|
165
|
+
* // ...
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
declare function useWaitlist(campaign: string, config?: WaitlistProviderProps['config']): {
|
|
170
|
+
loading: boolean;
|
|
171
|
+
status: UserStatus | null;
|
|
172
|
+
error: Error | null;
|
|
173
|
+
isJoined: boolean;
|
|
174
|
+
campaign: string;
|
|
175
|
+
join: (email: string, metadata?: UserMetadata, referrerCode?: string) => Promise<SubmitResponse | null>;
|
|
176
|
+
refresh: () => Promise<UserStatus | null>;
|
|
177
|
+
getReferralLink: () => string | null;
|
|
178
|
+
getReferralCode: () => string | null;
|
|
179
|
+
reset: () => void;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @queuezero/react - WaitlistForm Component
|
|
184
|
+
*
|
|
185
|
+
* A pre-built form component for joining the waitlist.
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* WaitlistForm - Ready-to-use form for waitlist signup
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```tsx
|
|
193
|
+
* // Basic usage
|
|
194
|
+
* <WaitlistForm onSuccess={(res) => console.log('Joined!', res)} />
|
|
195
|
+
*
|
|
196
|
+
* // With referral code from URL
|
|
197
|
+
* const referrerCode = new URLSearchParams(window.location.search).get('ref');
|
|
198
|
+
* <WaitlistForm referrerCode={referrerCode || undefined} />
|
|
199
|
+
*
|
|
200
|
+
* // With custom styling
|
|
201
|
+
* <WaitlistForm
|
|
202
|
+
* className="my-form"
|
|
203
|
+
* placeholder="Enter your work email"
|
|
204
|
+
* buttonText="Get Early Access"
|
|
205
|
+
* />
|
|
206
|
+
*
|
|
207
|
+
* // With custom rendering
|
|
208
|
+
* <WaitlistForm>
|
|
209
|
+
* {({ email, setEmail, submit, loading, error }) => (
|
|
210
|
+
* <div>
|
|
211
|
+
* <input value={email} onChange={(e) => setEmail(e.target.value)} />
|
|
212
|
+
* <button onClick={submit} disabled={loading}>Join</button>
|
|
213
|
+
* {error && <span>{error.message}</span>}
|
|
214
|
+
* </div>
|
|
215
|
+
* )}
|
|
216
|
+
* </WaitlistForm>
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
declare function WaitlistForm({ onSuccess, onError, referrerCode, metadata, className, placeholder, buttonText, loadingText, showLabel, labelText, children, }: WaitlistFormProps): any;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* WaitlistStatus - Shows current position, score, and referral count
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```tsx
|
|
226
|
+
* // Basic usage
|
|
227
|
+
* <WaitlistStatus />
|
|
228
|
+
*
|
|
229
|
+
* // With custom labels
|
|
230
|
+
* <WaitlistStatus
|
|
231
|
+
* positionLabel="You're #"
|
|
232
|
+
* scoreLabel="Points:"
|
|
233
|
+
* referralsLabel="Friends referred:"
|
|
234
|
+
* />
|
|
235
|
+
*
|
|
236
|
+
* // Hide certain stats
|
|
237
|
+
* <WaitlistStatus showScore={false} />
|
|
238
|
+
*
|
|
239
|
+
* // With custom rendering
|
|
240
|
+
* <WaitlistStatus>
|
|
241
|
+
* {(status) => (
|
|
242
|
+
* <div className="custom-status">
|
|
243
|
+
* <h2>#{status.position}</h2>
|
|
244
|
+
* <p>{status.priority_score} pts</p>
|
|
245
|
+
* </div>
|
|
246
|
+
* )}
|
|
247
|
+
* </WaitlistStatus>
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
declare function WaitlistStatus({ className, showReferrals, showScore, positionLabel, scoreLabel, referralsLabel, children, }: WaitlistStatusProps): react_jsx_runtime.JSX.Element | null;
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* ReferralShare - Share referral link with copy and social buttons
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```tsx
|
|
257
|
+
* // Basic usage
|
|
258
|
+
* <ReferralShare />
|
|
259
|
+
*
|
|
260
|
+
* // With custom text
|
|
261
|
+
* <ReferralShare
|
|
262
|
+
* label="Share your link:"
|
|
263
|
+
* copyButtonText="Copy Link"
|
|
264
|
+
* copiedText="Copied!"
|
|
265
|
+
* />
|
|
266
|
+
*
|
|
267
|
+
* // With social sharing
|
|
268
|
+
* <ReferralShare showSocialButtons />
|
|
269
|
+
*
|
|
270
|
+
* // With custom rendering
|
|
271
|
+
* <ReferralShare>
|
|
272
|
+
* {({ link, code, copy, copied }) => (
|
|
273
|
+
* <div>
|
|
274
|
+
* <code>{code}</code>
|
|
275
|
+
* <button onClick={copy}>{copied ? '✓' : 'Copy'}</button>
|
|
276
|
+
* </div>
|
|
277
|
+
* )}
|
|
278
|
+
* </ReferralShare>
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
declare function ReferralShare({ className, label, copyButtonText, copiedText, onCopy, shareMessage, showSocialButtons, children, }: ReferralShareProps): react_jsx_runtime.JSX.Element | null;
|
|
282
|
+
|
|
283
|
+
export { type PublicConfig, ReferralShare, type ReferralShareProps, type WaitlistContextValue, WaitlistForm, type WaitlistFormProps, WaitlistProvider, type WaitlistProviderProps, WaitlistStatus, type WaitlistStatusProps, useWaitlist, useWaitlistContext };
|