payload-subscribers-plugin 0.0.8 → 0.0.10

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.
Files changed (60) hide show
  1. package/README.md +234 -24
  2. package/dist/components/app/RequestMagicLink.d.ts +21 -4
  3. package/dist/components/app/RequestMagicLink.js +10 -42
  4. package/dist/components/app/RequestMagicLink.js.map +1 -1
  5. package/dist/components/app/RequestOrSubscribe.d.ts +21 -4
  6. package/dist/components/app/RequestOrSubscribe.js +5 -8
  7. package/dist/components/app/RequestOrSubscribe.js.map +1 -1
  8. package/dist/components/app/SelectOptInChannels.d.ts +26 -3
  9. package/dist/components/app/SelectOptInChannels.js +4 -1
  10. package/dist/components/app/SelectOptInChannels.js.map +1 -1
  11. package/dist/components/app/Subscribe.d.ts +26 -5
  12. package/dist/components/app/Subscribe.js +63 -81
  13. package/dist/components/app/Subscribe.js.map +1 -1
  14. package/dist/components/app/SubscriberMenu.d.ts +18 -6
  15. package/dist/components/app/SubscriberMenu.js +9 -8
  16. package/dist/components/app/SubscriberMenu.js.map +1 -1
  17. package/dist/components/app/Unsubscribe.d.ts +45 -0
  18. package/dist/components/app/Unsubscribe.js +91 -0
  19. package/dist/components/app/Unsubscribe.js.map +1 -0
  20. package/dist/components/app/VerifyMagicLink.d.ts +32 -14
  21. package/dist/components/app/VerifyMagicLink.js +60 -114
  22. package/dist/components/app/VerifyMagicLink.js.map +1 -1
  23. package/dist/contexts/SubscriberProvider.js +1 -1
  24. package/dist/contexts/SubscriberProvider.js.map +1 -1
  25. package/dist/endpoints/requestMagicLink.d.ts +6 -2
  26. package/dist/endpoints/requestMagicLink.js +26 -19
  27. package/dist/endpoints/requestMagicLink.js.map +1 -1
  28. package/dist/endpoints/subscribe.d.ts +6 -2
  29. package/dist/endpoints/subscribe.js +29 -13
  30. package/dist/endpoints/subscribe.js.map +1 -1
  31. package/dist/endpoints/unsubscribe.d.ts +21 -0
  32. package/dist/endpoints/unsubscribe.js +120 -0
  33. package/dist/endpoints/unsubscribe.js.map +1 -0
  34. package/dist/endpoints/verifyMagicLink.js +3 -2
  35. package/dist/endpoints/verifyMagicLink.js.map +1 -1
  36. package/dist/exports/ui.d.ts +2 -0
  37. package/dist/exports/ui.js +1 -0
  38. package/dist/exports/ui.js.map +1 -1
  39. package/dist/helpers/token.d.ts +3 -0
  40. package/dist/helpers/token.js +12 -2
  41. package/dist/helpers/token.js.map +1 -1
  42. package/dist/helpers/utilities.d.ts +1 -0
  43. package/dist/helpers/utilities.js +6 -0
  44. package/dist/helpers/utilities.js.map +1 -0
  45. package/dist/hooks/useRequestMagicLink.d.ts +35 -0
  46. package/dist/hooks/useRequestMagicLink.js +61 -0
  47. package/dist/hooks/useRequestMagicLink.js.map +1 -0
  48. package/dist/hooks/useSubscribe.d.ts +38 -0
  49. package/dist/hooks/useSubscribe.js +62 -0
  50. package/dist/hooks/useSubscribe.js.map +1 -0
  51. package/dist/hooks/useUnsubscribe.d.ts +43 -0
  52. package/dist/hooks/useUnsubscribe.js +86 -0
  53. package/dist/hooks/useUnsubscribe.js.map +1 -0
  54. package/dist/hooks/useVerifyMagicLink.d.ts +31 -0
  55. package/dist/hooks/useVerifyMagicLink.js +74 -0
  56. package/dist/hooks/useVerifyMagicLink.js.map +1 -0
  57. package/dist/index.d.ts +8 -0
  58. package/dist/index.js +16 -2
  59. package/dist/index.js.map +1 -1
  60. package/package.json +1 -1
package/README.md CHANGED
@@ -50,7 +50,13 @@ export default buildConfig({
50
50
 
51
51
  // Provide a custom expiration for magic link tokens. The default is 30 minutes.
52
52
  tokenExpiration: 60 * 60,
53
- }),
53
+
54
+ // Provide your unsubscribe route. This route should include the Unsubscribe component. If not provided, your payload config must have serverURL defined, and the default will be serverURL+'/unsubscribe'
55
+ unsubscribeURL?: string
56
+
57
+ // Provide your verify route. This route should include the Unsubscribe component. If not provided, your payload config must have serverURL defined, and the default will be serverURL+'/verify'
58
+ verifyURL?: string
59
+ }),
54
60
  ],
55
61
  })
56
62
  ```
@@ -94,7 +100,7 @@ const Page = () => {
94
100
  }
95
101
  ```
96
102
 
97
- **_IMPORANT:_** Be sure to create a /verify route
103
+ **_IMPORTANT:_** Be sure to create a /verify route
98
104
 
99
105
  ```typescript
100
106
  // verify/page.tsx
@@ -124,7 +130,7 @@ You can specify collections in the plugin options which will be amended to inclu
124
130
 
125
131
  #### **tokenExpiration**
126
132
 
127
- ### 🟢 Collections
133
+ ### 🔵 Collections
128
134
 
129
135
  #### **optInChannels**
130
136
 
@@ -150,7 +156,7 @@ Seeded when plugin inits.
150
156
 
151
157
  ---
152
158
 
153
- ### 🔵 Fields
159
+ ### 🔴 Fields
154
160
 
155
161
  #### **OptedInChannels**
156
162
 
@@ -160,7 +166,7 @@ This is the same field used by the plugin **collections** to amended a relationT
160
166
 
161
167
  ---
162
168
 
163
- ### 🔴 Payload endpoints
169
+ ### 🟢 Payload endpoints
164
170
 
165
171
  #### **requestMagicLink**
166
172
 
@@ -178,19 +184,193 @@ Returns all active optInChannels data.
178
184
 
179
185
  Takes an email and list of optInChannel IDs, verifies them, and if the authenticated subscriber matches the email will update the channels that subscriber is opted into.
180
186
 
181
- #### TO DO: unsubscribe
187
+ #### **unsubscribe**
182
188
 
183
- The **subscribe** endpoint will remove all optIns. But need a way to set the subscriber status to "unsubscribed"
189
+ The **unsubscribe** endpoint sets the subscriber status to "unsubscribed".
184
190
 
185
191
  ---
186
192
 
187
- ### 🟢 SubscriberProvider provider with useSubscriber context
193
+ ### 🔵 SubscriberProvider provider with useSubscriber context
194
+
195
+ **SubscriberProvider** fetches and holds the current subscriber auth state (via POST /api/subscriberAuth) and exposes it to the tree. Any component that uses **useSubscriber()**, or the plugin’s client components (RequestOrSubscribe, RequestMagicLink, Subscribe, etc.), or the plugin's client hooks (useRequestMagicLink, useSubscribe, etc.) must be a descendant of this provider.
196
+
197
+ The context value includes:
198
+
199
+ - **subscriber** — The current authenticated subscriber (or `null` if not logged in).
200
+ - **isLoaded** — `true` once the initial auth check has completed.
201
+ - **permissions** — Permissions returned from the auth endpoint (if any).
202
+ - **refreshSubscriber** — Call to refetch the current subscriber (e.g. after verifying a magic link or updating preferences).
203
+ - **logOut** — Calls POST /api/logout and clears subscriber state.
204
+
205
+ Wrap your app (or the part that uses subscriber features) with **SubscriberProvider**, then use **useSubscriber** in child components:
206
+
207
+ ```typescript
208
+ // layout.tsx (or root layout)
209
+
210
+ import { SubscriberProvider } from 'payload-subscribers-plugin/ui'
211
+
212
+ export default function Layout({ children }: { children: React.ReactNode }) {
213
+ return (
214
+ <html lang="en">
215
+ <body>
216
+ <SubscriberProvider>
217
+ {children}
218
+ </SubscriberProvider>
219
+ </body>
220
+ </html>
221
+ )
222
+ }
223
+ ```
224
+
225
+ ```typescript
226
+ // Any descendant component
227
+
228
+ import { useSubscriber } from 'payload-subscribers-plugin/ui'
229
+
230
+ function MyComponent() {
231
+ const { isLoaded, logOut, refreshSubscriber, subscriber } = useSubscriber()
232
+
233
+ if (!isLoaded) return <p>Loading…</p>
234
+ if (!subscriber) return <p>Not signed in.</p>
235
+
236
+ return (
237
+ <div>
238
+ <p>Signed in as {subscriber.email}</p>
239
+ <button type="button" onClick={() => void refreshSubscriber()}>
240
+ Refresh
241
+ </button>
242
+ <button type="button" onClick={() => void logOut()}>
243
+ Log out
244
+ </button>
245
+ </div>
246
+ )
247
+ }
248
+ ```
249
+
250
+ **Note:** `useSubscriber` throws if used outside a `SubscriberProvider`. Ensure the provider is mounted above any component that calls it.
188
251
 
189
252
  ---
190
253
 
191
- ### 🔵 Provides several NextJS client components ready for use in a frontend app
254
+ ### 🔴 Client hooks
192
255
 
193
- - All App Components are client components that consume hooks, server components, server functions. Including the useSubscriber context, and so the must be used within the children descendent tree of the SubscriberProvider provider.
256
+ Use these hooks inside components that are descendants of **SubscriberProvider**. They call the plugin endpoints and expose state and callbacks for building custom UI.
257
+
258
+ #### **useRequestMagicLink**
259
+
260
+ Requests a magic-login link by email (POST /api/emailToken). Exposes `sendMagicLink`, plus `result` and `status` for rendering messages and loading state.
261
+
262
+ ```typescript
263
+ import { useRequestMagicLink } from 'payload-subscribers-plugin/hooks'
264
+
265
+ function MySignInForm() {
266
+ const { result, sendMagicLink, status } = useRequestMagicLink({
267
+ handleMagicLinkRequested: (response) => console.log('Link sent', response),
268
+ verifyData: `forwardURL=${typeof window !== 'undefined' ? window.location.href : ''}`,
269
+ })
270
+
271
+ const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
272
+ e.preventDefault()
273
+ const email = new FormData(e.currentTarget).get('email') as string
274
+ void sendMagicLink(email)
275
+ }
276
+
277
+ return (
278
+ <form onSubmit={handleSubmit}>
279
+ <input name="email" type="email" required />
280
+ <button type="submit" disabled={status === 'sending'}>
281
+ {status === 'sending' ? 'Sending…' : 'Request magic link'}
282
+ </button>
283
+ {result && <p className={status === 'error' ? 'error' : ''}>{result}</p>}
284
+ </form>
285
+ )
286
+ }
287
+ ```
288
+
289
+ #### **useVerifyMagicLink**
290
+
291
+ Handles the verify step of the magic-link flow: reads `email` and `token` from URL search params, calls POST /api/verifyToken, and refreshes the subscriber on success. Takes no options.
292
+
293
+ ```typescript
294
+ import { useEffect } from 'react'
295
+ import { useVerifyMagicLink } from 'payload-subscribers-plugin/hooks'
296
+
297
+ function VerifyPage() {
298
+ const { isError, isLoading, result, verify } = useVerifyMagicLink()
299
+
300
+ useEffect(() => {
301
+ void verify()
302
+ }, [verify])
303
+
304
+ if (isLoading) return <p>Verifying…</p>
305
+ return <p className={isError ? 'error' : ''}>{result || 'Done.'}</p>
306
+ }
307
+ ```
308
+
309
+ #### **useSubscribe**
310
+
311
+ Updates the current subscriber’s opt-in channels (POST /api/subscribe). Exposes `updateSubscriptions`, plus `subscriber`, `result`, and `status`. Use with **SubscriberProvider** so `subscriber` and refresh are available.
312
+
313
+ ```typescript
314
+ import { useSubscribe } from 'payload-subscribers-plugin/hooks'
315
+
316
+ function MyPreferencesForm() {
317
+ const { result, status, subscriber, updateSubscriptions } = useSubscribe({
318
+ handleSubscribe: (response) => console.log('Updated', response),
319
+ verifyData: `forwardURL=${typeof window !== 'undefined' ? window.location.href : ''}`,
320
+ })
321
+
322
+ const handleSave = (e: React.FormEvent) => {
323
+ e.preventDefault()
324
+ const channelIds = ['channel-id-1', 'channel-id-2'] // from your form state
325
+ void updateSubscriptions(channelIds)
326
+ }
327
+
328
+ return (
329
+ <form onSubmit={handleSave}>
330
+ {/* your channel checkboxes, etc. */}
331
+ <button type="submit" disabled={status === 'updating'}>
332
+ {status === 'updating' ? 'Saving…' : 'Save choices'}
333
+ </button>
334
+ {result && <p>{result}</p>}
335
+ </form>
336
+ )
337
+ }
338
+ ```
339
+
340
+ #### **useUnsubscribe**
341
+
342
+ Calls POST /api/unsubscribe with email and token (from the hook args or from subscriber context). For use on unsubscribe pages linked from emails.
343
+
344
+ ```typescript
345
+ import { useEffect } from 'react'
346
+ import { useSearchParams } from 'next/navigation'
347
+ import { useUnsubscribe } from 'payload-subscribers-plugin/hooks'
348
+
349
+ function UnsubscribePage() {
350
+ const searchParams = useSearchParams()
351
+ const { isError, isLoading, result, unsubscribe } = useUnsubscribe({
352
+ handleUnsubscribe: (response) => console.log('Unsubscribed', response),
353
+ })
354
+
355
+ // With email/hash from URL (e.g. from email link)
356
+ useEffect(() => {
357
+ const email = searchParams.get('email')
358
+ const hash = searchParams.get('hash')
359
+ if (email && hash) void unsubscribe({ email, hash })
360
+ }, [searchParams, unsubscribe])
361
+
362
+ if (isLoading) return <p>Unsubscribing…</p>
363
+ return <p className={isError ? 'error' : ''}>{result}</p>
364
+ }
365
+ ```
366
+
367
+ ---
368
+
369
+ ### 🟢 Client components
370
+
371
+ The plugin provides several NextJS client components ready for use in a frontend app
372
+
373
+ - All App Components are client components that consume hooks, server components, server functions. Including the useSubscriber context, and so they must be used within the children descendent tree of the SubscriberProvider provider.
194
374
 
195
375
  - All App Components accept a **classNames** prop to specify CSS class names to add to the different parts of the component
196
376
 
@@ -220,14 +400,14 @@ Shows the [Subscribe](#subscribe) component to authenticated subscribers, otherw
220
400
  handleMagicLinkRequested={async (result: RequestMagicLinkResponse) => {}}
221
401
  // Called after a subscribers opt-ins have been updated. Optional
222
402
  handleSubscribe={async (result: SubscribeResponse) => {}}
223
- // Provided your own button component. Optional
403
+ // Provide your own button component. Optional
224
404
  renderButton={({ name, onClick, text }) =>
225
405
  <button name={name} onClick={onClick} type="button">
226
406
  {text}
227
407
  </button>
228
408
  }
229
- // Provide the URL to your route that has the VerifyMagicLink component on it.
230
- verifyUrl={verifyUrl}
409
+ // Provide a payload of data to put on any verify link sent by either Request or Subscribe components
410
+ verifyData={`forwardURL=${window.location.href}`}
231
411
  />
232
412
  ```
233
413
 
@@ -258,8 +438,8 @@ Form to input email address and get a magic link email sent.
258
438
  {text}
259
439
  </button>
260
440
  }
261
- // Provide the URL to your route that has the VerifyMagicLink component on it.
262
- verifyUrl={verifyUrl}
441
+ // Provide a payload of data to put on any verify link sent
442
+ verifyData={`forwardURL=${window.location.href}`}
263
443
  />
264
444
  ```
265
445
 
@@ -301,13 +481,11 @@ Component that verifies a magic link using expected url parameters.
301
481
  {text}
302
482
  </button>
303
483
  }
304
- // Provide the URL to your route that has the VerifyMagicLink component on it.
305
- // Used when this VerifyMagicLink component provides an option to request another link
306
- // when verifying the current one fails.
307
- verifyUrl={verifyUrl}
484
+ // Provide a payload of data to put on "request another" link sent
485
+ verifyData={`forwardURL=${window.location.href}`}
308
486
  >
309
487
  // Provide children to render after link is verified. Optional
310
- // Since you provide the verifyUrl to any of the plugin components, you can include a forwardUrl
488
+ // Since you provide the verifyURL to any of the plugin components, you can include a forwardUrl
311
489
  // as a search param, which your route can then use here.
312
490
  <a href={forwardUrl}>
313
491
  <button className={'customCss'} name={'continue'} type="button">
@@ -358,8 +536,8 @@ Allows a subscriber to select from among all active optInChannels.
358
536
  {text}
359
537
  </button>
360
538
  }
361
- // Provide the URL to your route that has the VerifyMagicLink component on it.
362
- verifyUrl={verifyUrl}
539
+ // Provide a payload of data to put on any verify link sent
540
+ verifyData={`forwardURL=${window.location.href}`}
363
541
  />
364
542
  ```
365
543
 
@@ -407,7 +585,7 @@ A simple user menu, most useful for testing. Seen in the screenshots above. Incl
407
585
  button: 'customCssClassNames',
408
586
  container: 'customCssClassNames',
409
587
  }}
410
- subscribeUrl={new URL('/subscribe', serverURL)}
588
+ subscribeURL={new URL('/subscribe', serverURL)}
411
589
  />
412
590
 
413
591
  ```
@@ -418,7 +596,7 @@ A simple user menu, most useful for testing. Seen in the screenshots above. Incl
418
596
  <div class="subscribers-group">
419
597
  <div class="subscribers-welcome">Welcome, {subscriber email}</div>
420
598
  <div class="subscribers-subs-link">
421
- <a href="{subscribeUrl}">Manage subscriptions</a>
599
+ <a href="{subscribeURL}">Manage subscriptions</a>
422
600
  </div>
423
601
  <div class="subscribers-logout">
424
602
  <button class="subscribers-button" type="button">Log out</button>
@@ -427,6 +605,38 @@ A simple user menu, most useful for testing. Seen in the screenshots above. Incl
427
605
  </div>
428
606
  ```
429
607
 
608
+ #### **Unsubscribe**
609
+
610
+ A component that uses URL parameters to execute the /api/unsubscribe end point. Should be used on your own route, as specified in the **unsubscribeURL** plugin option.
611
+
612
+ ```typescript
613
+ // Unsubscribe with a custom "resubscribe" button
614
+
615
+ <Unsubscribe
616
+ classNames={{ button: 'customCss', container: 'customCss', emailInput: 'customCss' }}
617
+ handleUnsubscribe={handleUnsubscribe}
618
+ >
619
+ // <!-- children are rendered after unsubscribe is successful -->
620
+ <a href={'/subscribe'}>
621
+ <button name={'resubscribe'} type="button">
622
+ Resubscribe
623
+ </button>
624
+ </a>
625
+ </Unsubscribe>
626
+
627
+ ```
628
+
629
+ ```html
630
+ <!-- The HTML scaffolding of the built-in render layout, with global CSS classes you can use -->
631
+ <div class="subscribers-container">
632
+ <!-- While loading -->
633
+ <p class="subscribers-loading">unsubscribing...</p>
634
+ <!-- After loading -->
635
+ <p class="subscribers-message">{result}</p>
636
+ <div class="subscribers-form">{children}</div>
637
+ </div>
638
+ ```
639
+
430
640
  ## Contributing
431
641
 
432
642
  Community contributions are welcome! I haven't organized around that yet, so let me know if you're interested by opening an issue on the GitHub repo.
@@ -2,14 +2,28 @@ import type { RequestMagicLinkResponse } from '../../endpoints/requestMagicLink.
2
2
  export { RequestMagicLinkResponse };
3
3
  /**
4
4
  * Props for the RequestMagicLink component.
5
+ *
6
+ * @property classNames - Optional CSS class overrides for the component elements
7
+ * @property handleMagicLinkRequested - Callback when a magic link is requested
8
+ * @property props - Optional passthrough props (reserved for future use)
9
+ * @property verifyData - Optional data for magic-link verification (e.g. passed from URL)
5
10
  */
6
11
  export interface IRequestMagicLink {
7
12
  classNames?: RequestMagicLinkClasses;
8
13
  handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void;
9
14
  props?: any;
10
- verifyUrl?: string | URL;
15
+ verifyData?: string;
11
16
  }
12
- /** Optional CSS class overrides for RequestMagicLink elements. */
17
+ /**
18
+ * Optional CSS class overrides for RequestMagicLink elements.
19
+ *
20
+ * @property button - Class for the submit button
21
+ * @property container - Class for the main container
22
+ * @property emailInput - Class for the email input field
23
+ * @property error - Class for error messages
24
+ * @property form - Class for the form
25
+ * @property message - Class for success/error message text
26
+ */
13
27
  export type RequestMagicLinkClasses = {
14
28
  button?: string;
15
29
  container?: string;
@@ -22,7 +36,10 @@ export type RequestMagicLinkClasses = {
22
36
  * Form component that lets users request a magic-login link by email. Submits to POST /api/emailToken
23
37
  * and shows success or error message. Uses SubscriberProvider for pre-filling email when available.
24
38
  *
25
- * @param props - See IRequestMagicLink
39
+ * @param props - Component props (see IRequestMagicLink)
40
+ * @param props.classNames - Optional class overrides for the component elements
41
+ * @param props.handleMagicLinkRequested - Callback when a magic link is requested
42
+ * @param props.verifyData - Optional data to send to the magic-link verification (e.g. passed from URL)
26
43
  * @returns Form UI with email input and "Request magic link" button
27
44
  */
28
- export declare const RequestMagicLink: ({ classNames, handleMagicLinkRequested, verifyUrl, }: IRequestMagicLink) => import("react").JSX.Element;
45
+ export declare const RequestMagicLink: ({ classNames, handleMagicLinkRequested, verifyData, }: IRequestMagicLink) => import("react").JSX.Element;
@@ -1,16 +1,18 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { PayloadSDK } from '@payloadcms/sdk';
4
3
  import { useEffect, useState } from 'react';
5
4
  import { useSubscriber } from '../../contexts/SubscriberProvider.js';
6
- import { useServerUrl } from '../../react-hooks/useServerUrl.js';
5
+ import { useRequestMagicLink } from '../../hooks/useRequestMagicLink.js';
7
6
  import { mergeClassNames } from './helpers.js';
8
7
  import styles from './shared.module.css';
9
8
  /**
10
9
  * Form component that lets users request a magic-login link by email. Submits to POST /api/emailToken
11
10
  * and shows success or error message. Uses SubscriberProvider for pre-filling email when available.
12
11
  *
13
- * @param props - See IRequestMagicLink
12
+ * @param props - Component props (see IRequestMagicLink)
13
+ * @param props.classNames - Optional class overrides for the component elements
14
+ * @param props.handleMagicLinkRequested - Callback when a magic link is requested
15
+ * @param props.verifyData - Optional data to send to the magic-link verification (e.g. passed from URL)
14
16
  * @returns Form UI with email input and "Request magic link" button
15
17
  */ export const RequestMagicLink = ({ classNames = {
16
18
  button: '',
@@ -19,17 +21,12 @@ import styles from './shared.module.css';
19
21
  error: '',
20
22
  form: '',
21
23
  message: ''
22
- }, handleMagicLinkRequested, verifyUrl })=>{
23
- if (typeof verifyUrl == 'string') {
24
- verifyUrl = new URL(verifyUrl);
25
- }
24
+ }, handleMagicLinkRequested, verifyData })=>{
26
25
  const { subscriber } = useSubscriber();
27
- const { serverURL } = useServerUrl();
28
- const [status, setStatus] = useState('default');
29
- const sdk = new PayloadSDK({
30
- baseURL: serverURL || ''
26
+ const { result, sendMagicLink, status } = useRequestMagicLink({
27
+ handleMagicLinkRequested,
28
+ verifyData
31
29
  });
32
- const [result, setResult] = useState();
33
30
  const [email, setEmail] = useState(subscriber?.email || '');
34
31
  useEffect(()=>{
35
32
  setEmail(subscriber?.email || '');
@@ -38,36 +35,7 @@ import styles from './shared.module.css';
38
35
  ]);
39
36
  const handleSubmit = async (e)=>{
40
37
  e.preventDefault();
41
- const emailTokenResponse = await sdk.request({
42
- json: {
43
- email,
44
- verifyUrl: verifyUrl?.href
45
- },
46
- method: 'POST',
47
- path: '/api/emailToken'
48
- });
49
- if (emailTokenResponse.ok) {
50
- const emailTokenResponseJson = await emailTokenResponse.json();
51
- if (handleMagicLinkRequested) {
52
- handleMagicLinkRequested(emailTokenResponseJson);
53
- }
54
- // @ts-expect-error One or the other exists
55
- const { emailResult, error } = emailTokenResponseJson;
56
- if (error) {
57
- setStatus('error');
58
- setResult(`An error occured. Please try again. \n ${error}`);
59
- } else if (emailResult) {
60
- setStatus('sent');
61
- setResult('An email has been sent containing your magic link.');
62
- } else {
63
- setStatus('error');
64
- setResult(`An error occured. Please try again. \nResult unknown`);
65
- }
66
- } else {
67
- const emailTokenResponseText = await emailTokenResponse.text();
68
- setStatus('error');
69
- setResult(`An error occured. Please try again. \n${emailTokenResponseText}`);
70
- }
38
+ await sendMagicLink(email);
71
39
  };
72
40
  return /*#__PURE__*/ _jsxs("div", {
73
41
  className: mergeClassNames([
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/app/RequestMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ChangeEvent, type SubmitEvent, useEffect, useState } from 'react'\n\nimport type { Config } from '../../copied/payload-types.js'\nimport type { RequestMagicLinkResponse } from '../../endpoints/requestMagicLink.js'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../../react-hooks/useServerUrl.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\nexport { RequestMagicLinkResponse }\n\n/**\n * Props for the RequestMagicLink component.\n */\nexport interface IRequestMagicLink {\n classNames?: RequestMagicLinkClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n props?: any\n verifyUrl?: string | URL\n}\n\n/** Optional CSS class overrides for RequestMagicLink elements. */\nexport type RequestMagicLinkClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n message?: string\n}\n\ntype statusValues = 'default' | 'error' | 'sent'\n\n/**\n * Form component that lets users request a magic-login link by email. Submits to POST /api/emailToken\n * and shows success or error message. Uses SubscriberProvider for pre-filling email when available.\n *\n * @param props - See IRequestMagicLink\n * @returns Form UI with email input and \"Request magic link\" button\n */\nexport const RequestMagicLink = ({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n message: '',\n },\n handleMagicLinkRequested,\n verifyUrl,\n}: IRequestMagicLink) => {\n if (typeof verifyUrl == 'string') {\n verifyUrl = new URL(verifyUrl)\n }\n\n const { subscriber } = useSubscriber()\n const { serverURL } = useServerUrl()\n const [status, setStatus] = useState<statusValues>('default')\n\n const sdk = new PayloadSDK<Config>({\n baseURL: serverURL || '',\n })\n\n const [result, setResult] = useState<string>()\n const [email, setEmail] = useState(subscriber?.email || '')\n\n useEffect(() => {\n setEmail(subscriber?.email || '')\n }, [subscriber])\n\n const handleSubmit = async (e: SubmitEvent<HTMLFormElement>) => {\n e.preventDefault()\n const emailTokenResponse = await sdk.request({\n json: {\n email,\n verifyUrl: verifyUrl?.href,\n },\n method: 'POST',\n path: '/api/emailToken',\n })\n if (emailTokenResponse.ok) {\n const emailTokenResponseJson: RequestMagicLinkResponse = await emailTokenResponse.json()\n if (handleMagicLinkRequested) {\n handleMagicLinkRequested(emailTokenResponseJson)\n }\n // @ts-expect-error One or the other exists\n const { emailResult, error } = emailTokenResponseJson\n if (error) {\n setStatus('error')\n setResult(`An error occured. Please try again. \\n ${error}`)\n } else if (emailResult) {\n setStatus('sent')\n setResult('An email has been sent containing your magic link.')\n } else {\n setStatus('error')\n setResult(`An error occured. Please try again. \\nResult unknown`)\n }\n } else {\n const emailTokenResponseText = await emailTokenResponse.text()\n setStatus('error')\n setResult(`An error occured. Please try again. \\n${emailTokenResponseText}`)\n }\n }\n\n return (\n <div\n className={mergeClassNames([\n 'subscribers-request subscribers-container',\n styles.container,\n classNames.container,\n ])}\n >\n {result ? (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n status == 'error' ? ['subscribers-error', styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n ) : (\n <></>\n )}\n <form\n className={mergeClassNames(['subscribers-form', styles.form, classNames.form])}\n method=\"POST\"\n onSubmit={handleSubmit}\n >\n <input\n aria-label=\"enter your email\"\n className={mergeClassNames([\n 'subscribers-emailInput',\n styles.emailInput,\n classNames.emailInput,\n ])}\n onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}\n placeholder=\"enter your email\"\n type=\"email\"\n value={email}\n />\n <button\n className={mergeClassNames(['subscribers-button', styles.button, classNames.button])}\n type=\"submit\"\n >\n Request magic link\n </button>\n </form>\n </div>\n )\n}\n"],"names":["PayloadSDK","useEffect","useState","useSubscriber","useServerUrl","mergeClassNames","styles","RequestMagicLink","classNames","button","container","emailInput","error","form","message","handleMagicLinkRequested","verifyUrl","URL","subscriber","serverURL","status","setStatus","sdk","baseURL","result","setResult","email","setEmail","handleSubmit","e","preventDefault","emailTokenResponse","request","json","href","method","path","ok","emailTokenResponseJson","emailResult","emailTokenResponseText","text","div","className","p","onSubmit","input","aria-label","onChange","target","value","placeholder","type"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/app/RequestMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { type ChangeEvent, type SubmitEvent, useEffect, useState } from 'react'\n\nimport type { RequestMagicLinkResponse } from '../../endpoints/requestMagicLink.js'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport { useRequestMagicLink } from '../../hooks/useRequestMagicLink.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\nexport { RequestMagicLinkResponse }\n\n/**\n * Props for the RequestMagicLink component.\n *\n * @property classNames - Optional CSS class overrides for the component elements\n * @property handleMagicLinkRequested - Callback when a magic link is requested\n * @property props - Optional passthrough props (reserved for future use)\n * @property verifyData - Optional data for magic-link verification (e.g. passed from URL)\n */\nexport interface IRequestMagicLink {\n classNames?: RequestMagicLinkClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n props?: any\n verifyData?: string\n}\n\n/**\n * Optional CSS class overrides for RequestMagicLink elements.\n *\n * @property button - Class for the submit button\n * @property container - Class for the main container\n * @property emailInput - Class for the email input field\n * @property error - Class for error messages\n * @property form - Class for the form\n * @property message - Class for success/error message text\n */\nexport type RequestMagicLinkClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n message?: string\n}\n\n/**\n * Form component that lets users request a magic-login link by email. Submits to POST /api/emailToken\n * and shows success or error message. Uses SubscriberProvider for pre-filling email when available.\n *\n * @param props - Component props (see IRequestMagicLink)\n * @param props.classNames - Optional class overrides for the component elements\n * @param props.handleMagicLinkRequested - Callback when a magic link is requested\n * @param props.verifyData - Optional data to send to the magic-link verification (e.g. passed from URL)\n * @returns Form UI with email input and \"Request magic link\" button\n */\nexport const RequestMagicLink = ({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n message: '',\n },\n handleMagicLinkRequested,\n verifyData,\n}: IRequestMagicLink) => {\n const { subscriber } = useSubscriber()\n const { result, sendMagicLink, status } = useRequestMagicLink({\n handleMagicLinkRequested,\n verifyData,\n })\n\n const [email, setEmail] = useState(subscriber?.email || '')\n\n useEffect(() => {\n setEmail(subscriber?.email || '')\n }, [subscriber])\n\n const handleSubmit = async (e: SubmitEvent<HTMLFormElement>) => {\n e.preventDefault()\n\n await sendMagicLink(email)\n }\n return (\n <div\n className={mergeClassNames([\n 'subscribers-request subscribers-container',\n styles.container,\n classNames.container,\n ])}\n >\n {result ? (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n status == 'error' ? ['subscribers-error', styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n ) : (\n <></>\n )}\n <form\n className={mergeClassNames(['subscribers-form', styles.form, classNames.form])}\n method=\"POST\"\n onSubmit={handleSubmit}\n >\n <input\n aria-label=\"enter your email\"\n className={mergeClassNames([\n 'subscribers-emailInput',\n styles.emailInput,\n classNames.emailInput,\n ])}\n onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}\n placeholder=\"enter your email\"\n type=\"email\"\n value={email}\n />\n <button\n className={mergeClassNames(['subscribers-button', styles.button, classNames.button])}\n type=\"submit\"\n >\n Request magic link\n </button>\n </form>\n </div>\n )\n}\n"],"names":["useEffect","useState","useSubscriber","useRequestMagicLink","mergeClassNames","styles","RequestMagicLink","classNames","button","container","emailInput","error","form","message","handleMagicLinkRequested","verifyData","subscriber","result","sendMagicLink","status","email","setEmail","handleSubmit","e","preventDefault","div","className","p","method","onSubmit","input","aria-label","onChange","target","value","placeholder","type"],"mappings":"AAAA;;AAEA,SAA6CA,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAI/E,SAASC,aAAa,QAAQ,uCAAsC;AACpE,SAASC,mBAAmB,QAAQ,qCAAoC;AACxE,SAASC,eAAe,QAAQ,eAAc;AAC9C,OAAOC,YAAY,sBAAqB;AAsCxC;;;;;;;;;CASC,GACD,OAAO,MAAMC,mBAAmB,CAAC,EAC/BC,aAAa;IACXC,QAAQ;IACRC,WAAW;IACXC,YAAY;IACZC,OAAO;IACPC,MAAM;IACNC,SAAS;AACX,CAAC,EACDC,wBAAwB,EACxBC,UAAU,EACQ;IAClB,MAAM,EAAEC,UAAU,EAAE,GAAGd;IACvB,MAAM,EAAEe,MAAM,EAAEC,aAAa,EAAEC,MAAM,EAAE,GAAGhB,oBAAoB;QAC5DW;QACAC;IACF;IAEA,MAAM,CAACK,OAAOC,SAAS,GAAGpB,SAASe,YAAYI,SAAS;IAExDpB,UAAU;QACRqB,SAASL,YAAYI,SAAS;IAChC,GAAG;QAACJ;KAAW;IAEf,MAAMM,eAAe,OAAOC;QAC1BA,EAAEC,cAAc;QAEhB,MAAMN,cAAcE;IACtB;IACA,qBACE,MAACK;QACCC,WAAWtB,gBAAgB;YACzB;YACAC,OAAOI,SAAS;YAChBF,WAAWE,SAAS;SACrB;;YAEAQ,uBACC,KAACU;gBACCD,WAAWtB,gBAAgB;oBACzB;oBACAC,OAAOQ,OAAO;oBACdN,WAAWM,OAAO;oBAClBM,UAAU,UAAU;wBAAC;wBAAqBd,OAAOM,KAAK;wBAAEJ,WAAWI,KAAK;qBAAC,GAAG,EAAE;iBAC/E;0BAEAM;+BAGH;0BAEF,MAACL;gBACCc,WAAWtB,gBAAgB;oBAAC;oBAAoBC,OAAOO,IAAI;oBAAEL,WAAWK,IAAI;iBAAC;gBAC7EgB,QAAO;gBACPC,UAAUP;;kCAEV,KAACQ;wBACCC,cAAW;wBACXL,WAAWtB,gBAAgB;4BACzB;4BACAC,OAAOK,UAAU;4BACjBH,WAAWG,UAAU;yBACtB;wBACDsB,UAAU,CAACT,IAAqCF,SAASE,EAAEU,MAAM,CAACC,KAAK;wBACvEC,aAAY;wBACZC,MAAK;wBACLF,OAAOd;;kCAET,KAACZ;wBACCkB,WAAWtB,gBAAgB;4BAAC;4BAAsBC,OAAOG,MAAM;4BAAED,WAAWC,MAAM;yBAAC;wBACnF4B,MAAK;kCACN;;;;;;AAMT,EAAC"}
@@ -2,14 +2,30 @@ import { type RequestMagicLinkResponse, type SubscribeResponse } from '../../exp
2
2
  export type { RequestMagicLinkResponse, SubscribeResponse };
3
3
  /**
4
4
  * Props for the RequestOrSubscribe component.
5
+ *
6
+ * @property classNames - Optional CSS class overrides for the component and its children
7
+ * @property handleMagicLinkRequested - Callback when a magic link is requested (no subscriber yet)
8
+ * @property handleSubscribe - Callback when subscription/opt-ins are updated (subscriber present)
9
+ * @property verifyData - Optional data passed to child components (e.g. for magic-link verification)
5
10
  */
6
11
  export interface IRequestOrSubscribe {
7
12
  classNames?: RequestOrSubscribeClasses;
8
13
  handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void;
9
14
  handleSubscribe?: (result: SubscribeResponse) => void;
10
- verifyUrl?: string | URL;
15
+ verifyData?: string;
11
16
  }
12
- /** Optional CSS class overrides for RequestOrSubscribe and its child components. */
17
+ /**
18
+ * Optional CSS class overrides for RequestOrSubscribe and its child components.
19
+ *
20
+ * @property button - Class for buttons
21
+ * @property container - Class for the main container
22
+ * @property emailInput - Class for the email input field
23
+ * @property error - Class for error messages
24
+ * @property form - Class for forms
25
+ * @property loading - Class for loading state
26
+ * @property message - Class for message text
27
+ * @property section - Class for section wrappers
28
+ */
13
29
  export type RequestOrSubscribeClasses = {
14
30
  button?: string;
15
31
  container?: string;
@@ -24,10 +40,11 @@ export type RequestOrSubscribeClasses = {
24
40
  * Composite component that shows Subscribe when a subscriber is authenticated, otherwise
25
41
  * RequestMagicLink. Used as a single entry point for "sign in or manage subscriptions."
26
42
  *
43
+ * @param props - Component props (see IRequestOrSubscribe)
27
44
  * @param props.classNames - Optional class overrides passed to child components
28
45
  * @param props.handleMagicLinkRequested - Callback when a magic link is requested (no subscriber yet)
29
46
  * @param props.handleSubscribe - Callback when subscription/opt-ins are updated (subscriber present)
30
- * @param props.verifyUrl - Base URL for verify links in emails
47
+ * @param props.verifyData - Optional data passed to child components (e.g. for magic-link verification)
31
48
  * @returns Either Subscribe or RequestMagicLink based on subscriber context
32
49
  */
33
- export declare function RequestOrSubscribe({ classNames, handleMagicLinkRequested, handleSubscribe, verifyUrl, }: IRequestOrSubscribe): import("react").JSX.Element;
50
+ export declare function RequestOrSubscribe({ classNames, handleMagicLinkRequested, handleSubscribe, verifyData, }: IRequestOrSubscribe): import("react").JSX.Element;
@@ -6,10 +6,11 @@ import { RequestMagicLink, Subscribe } from '../../exports/ui.js';
6
6
  * Composite component that shows Subscribe when a subscriber is authenticated, otherwise
7
7
  * RequestMagicLink. Used as a single entry point for "sign in or manage subscriptions."
8
8
  *
9
+ * @param props - Component props (see IRequestOrSubscribe)
9
10
  * @param props.classNames - Optional class overrides passed to child components
10
11
  * @param props.handleMagicLinkRequested - Callback when a magic link is requested (no subscriber yet)
11
12
  * @param props.handleSubscribe - Callback when subscription/opt-ins are updated (subscriber present)
12
- * @param props.verifyUrl - Base URL for verify links in emails
13
+ * @param props.verifyData - Optional data passed to child components (e.g. for magic-link verification)
13
14
  * @returns Either Subscribe or RequestMagicLink based on subscriber context
14
15
  */ export function RequestOrSubscribe({ classNames = {
15
16
  button: '',
@@ -20,21 +21,17 @@ import { RequestMagicLink, Subscribe } from '../../exports/ui.js';
20
21
  loading: '',
21
22
  message: '',
22
23
  section: ''
23
- }, handleMagicLinkRequested, handleSubscribe, verifyUrl }) {
24
- if (typeof verifyUrl == 'string') {
25
- verifyUrl = new URL(verifyUrl);
26
- }
24
+ }, handleMagicLinkRequested, handleSubscribe, verifyData }) {
27
25
  const { subscriber } = useSubscriber();
28
- // Example: Conditionally render something or pass the state to children
29
26
  return /*#__PURE__*/ _jsx(_Fragment, {
30
27
  children: subscriber ? /*#__PURE__*/ _jsx(Subscribe, {
31
28
  classNames: classNames,
32
29
  handleSubscribe: handleSubscribe,
33
- verifyUrl: verifyUrl
30
+ verifyData: verifyData
34
31
  }) : /*#__PURE__*/ _jsx(RequestMagicLink, {
35
32
  classNames: classNames,
36
33
  handleMagicLinkRequested: handleMagicLinkRequested,
37
- verifyUrl: verifyUrl
34
+ verifyData: verifyData
38
35
  })
39
36
  });
40
37
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/app/RequestOrSubscribe.tsx"],"sourcesContent":["'use client'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport {\n RequestMagicLink,\n type RequestMagicLinkResponse,\n Subscribe,\n type SubscribeResponse,\n} from '../../exports/ui.js'\n\nexport type { RequestMagicLinkResponse, SubscribeResponse }\n\n/**\n * Props for the RequestOrSubscribe component.\n */\nexport interface IRequestOrSubscribe {\n classNames?: RequestOrSubscribeClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n handleSubscribe?: (result: SubscribeResponse) => void\n verifyUrl?: string | URL\n}\n\n/** Optional CSS class overrides for RequestOrSubscribe and its child components. */\nexport type RequestOrSubscribeClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n loading?: string\n message?: string\n section?: string\n}\n\n/**\n * Composite component that shows Subscribe when a subscriber is authenticated, otherwise\n * RequestMagicLink. Used as a single entry point for \"sign in or manage subscriptions.\"\n *\n * @param props.classNames - Optional class overrides passed to child components\n * @param props.handleMagicLinkRequested - Callback when a magic link is requested (no subscriber yet)\n * @param props.handleSubscribe - Callback when subscription/opt-ins are updated (subscriber present)\n * @param props.verifyUrl - Base URL for verify links in emails\n * @returns Either Subscribe or RequestMagicLink based on subscriber context\n */\nexport function RequestOrSubscribe({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n section: '',\n },\n handleMagicLinkRequested,\n handleSubscribe,\n verifyUrl,\n}: IRequestOrSubscribe) {\n if (typeof verifyUrl == 'string') {\n verifyUrl = new URL(verifyUrl)\n }\n\n const { subscriber } = useSubscriber()\n\n // Example: Conditionally render something or pass the state to children\n return (\n <>\n {subscriber ? (\n <Subscribe\n classNames={classNames}\n handleSubscribe={handleSubscribe}\n verifyUrl={verifyUrl}\n />\n ) : (\n <RequestMagicLink\n classNames={classNames}\n handleMagicLinkRequested={handleMagicLinkRequested}\n verifyUrl={verifyUrl}\n />\n )}\n {/* <div>subscriber = {JSON.stringify(subscriber)}</div> */}\n </>\n )\n}\n"],"names":["useSubscriber","RequestMagicLink","Subscribe","RequestOrSubscribe","classNames","button","container","emailInput","error","form","loading","message","section","handleMagicLinkRequested","handleSubscribe","verifyUrl","URL","subscriber"],"mappings":"AAAA;;AAEA,SAASA,aAAa,QAAQ,uCAAsC;AACpE,SACEC,gBAAgB,EAEhBC,SAAS,QAEJ,sBAAqB;AA0B5B;;;;;;;;;CASC,GACD,OAAO,SAASC,mBAAmB,EACjCC,aAAa;IACXC,QAAQ;IACRC,WAAW;IACXC,YAAY;IACZC,OAAO;IACPC,MAAM;IACNC,SAAS;IACTC,SAAS;IACTC,SAAS;AACX,CAAC,EACDC,wBAAwB,EACxBC,eAAe,EACfC,SAAS,EACW;IACpB,IAAI,OAAOA,aAAa,UAAU;QAChCA,YAAY,IAAIC,IAAID;IACtB;IAEA,MAAM,EAAEE,UAAU,EAAE,GAAGjB;IAEvB,wEAAwE;IACxE,qBACE;kBACGiB,2BACC,KAACf;YACCE,YAAYA;YACZU,iBAAiBA;YACjBC,WAAWA;2BAGb,KAACd;YACCG,YAAYA;YACZS,0BAA0BA;YAC1BE,WAAWA;;;AAMrB"}
1
+ {"version":3,"sources":["../../../src/components/app/RequestOrSubscribe.tsx"],"sourcesContent":["'use client'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport {\n RequestMagicLink,\n type RequestMagicLinkResponse,\n Subscribe,\n type SubscribeResponse,\n} from '../../exports/ui.js'\n\nexport type { RequestMagicLinkResponse, SubscribeResponse }\n\n/**\n * Props for the RequestOrSubscribe component.\n *\n * @property classNames - Optional CSS class overrides for the component and its children\n * @property handleMagicLinkRequested - Callback when a magic link is requested (no subscriber yet)\n * @property handleSubscribe - Callback when subscription/opt-ins are updated (subscriber present)\n * @property verifyData - Optional data passed to child components (e.g. for magic-link verification)\n */\nexport interface IRequestOrSubscribe {\n classNames?: RequestOrSubscribeClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n handleSubscribe?: (result: SubscribeResponse) => void\n verifyData?: string\n}\n\n/**\n * Optional CSS class overrides for RequestOrSubscribe and its child components.\n *\n * @property button - Class for buttons\n * @property container - Class for the main container\n * @property emailInput - Class for the email input field\n * @property error - Class for error messages\n * @property form - Class for forms\n * @property loading - Class for loading state\n * @property message - Class for message text\n * @property section - Class for section wrappers\n */\nexport type RequestOrSubscribeClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n loading?: string\n message?: string\n section?: string\n}\n\n/**\n * Composite component that shows Subscribe when a subscriber is authenticated, otherwise\n * RequestMagicLink. Used as a single entry point for \"sign in or manage subscriptions.\"\n *\n * @param props - Component props (see IRequestOrSubscribe)\n * @param props.classNames - Optional class overrides passed to child components\n * @param props.handleMagicLinkRequested - Callback when a magic link is requested (no subscriber yet)\n * @param props.handleSubscribe - Callback when subscription/opt-ins are updated (subscriber present)\n * @param props.verifyData - Optional data passed to child components (e.g. for magic-link verification)\n * @returns Either Subscribe or RequestMagicLink based on subscriber context\n */\nexport function RequestOrSubscribe({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n section: '',\n },\n handleMagicLinkRequested,\n handleSubscribe,\n verifyData,\n}: IRequestOrSubscribe) {\n const { subscriber } = useSubscriber()\n\n return (\n <>\n {subscriber ? (\n <Subscribe\n classNames={classNames}\n handleSubscribe={handleSubscribe}\n verifyData={verifyData}\n />\n ) : (\n <RequestMagicLink\n classNames={classNames}\n handleMagicLinkRequested={handleMagicLinkRequested}\n verifyData={verifyData}\n />\n )}\n {/* <div>subscriber = {JSON.stringify(subscriber)}</div> */}\n </>\n )\n}\n"],"names":["useSubscriber","RequestMagicLink","Subscribe","RequestOrSubscribe","classNames","button","container","emailInput","error","form","loading","message","section","handleMagicLinkRequested","handleSubscribe","verifyData","subscriber"],"mappings":"AAAA;;AAEA,SAASA,aAAa,QAAQ,uCAAsC;AACpE,SACEC,gBAAgB,EAEhBC,SAAS,QAEJ,sBAAqB;AA0C5B;;;;;;;;;;CAUC,GACD,OAAO,SAASC,mBAAmB,EACjCC,aAAa;IACXC,QAAQ;IACRC,WAAW;IACXC,YAAY;IACZC,OAAO;IACPC,MAAM;IACNC,SAAS;IACTC,SAAS;IACTC,SAAS;AACX,CAAC,EACDC,wBAAwB,EACxBC,eAAe,EACfC,UAAU,EACU;IACpB,MAAM,EAAEC,UAAU,EAAE,GAAGhB;IAEvB,qBACE;kBACGgB,2BACC,KAACd;YACCE,YAAYA;YACZU,iBAAiBA;YACjBC,YAAYA;2BAGd,KAACd;YACCG,YAAYA;YACZS,0BAA0BA;YAC1BE,YAAYA;;;AAMtB"}