payload-subscribers-plugin 0.0.9 → 0.0.11

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 (54) hide show
  1. package/README.md +233 -26
  2. package/dist/components/app/RequestMagicLink.d.ts +21 -4
  3. package/dist/components/app/RequestMagicLink.js +11 -56
  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 +40 -73
  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 +26 -12
  18. package/dist/components/app/Unsubscribe.js +63 -127
  19. package/dist/components/app/Unsubscribe.js.map +1 -1
  20. package/dist/components/app/VerifyMagicLink.d.ts +32 -14
  21. package/dist/components/app/VerifyMagicLink.js +60 -110
  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 -4
  26. package/dist/endpoints/requestMagicLink.js +16 -12
  27. package/dist/endpoints/requestMagicLink.js.map +1 -1
  28. package/dist/endpoints/subscribe.d.ts +6 -2
  29. package/dist/endpoints/subscribe.js +19 -17
  30. package/dist/endpoints/subscribe.js.map +1 -1
  31. package/dist/endpoints/unsubscribe.js +17 -15
  32. package/dist/endpoints/unsubscribe.js.map +1 -1
  33. package/dist/exports/ui.d.ts +4 -0
  34. package/dist/exports/ui.js +4 -0
  35. package/dist/exports/ui.js.map +1 -1
  36. package/dist/helpers/utilities.d.ts +1 -0
  37. package/dist/helpers/utilities.js +6 -0
  38. package/dist/helpers/utilities.js.map +1 -0
  39. package/dist/hooks/useRequestMagicLink.d.ts +35 -0
  40. package/dist/hooks/useRequestMagicLink.js +61 -0
  41. package/dist/hooks/useRequestMagicLink.js.map +1 -0
  42. package/dist/hooks/useSubscribe.d.ts +38 -0
  43. package/dist/hooks/useSubscribe.js +62 -0
  44. package/dist/hooks/useSubscribe.js.map +1 -0
  45. package/dist/hooks/useUnsubscribe.d.ts +43 -0
  46. package/dist/hooks/useUnsubscribe.js +86 -0
  47. package/dist/hooks/useUnsubscribe.js.map +1 -0
  48. package/dist/hooks/useVerifyMagicLink.d.ts +31 -0
  49. package/dist/hooks/useVerifyMagicLink.js +74 -0
  50. package/dist/hooks/useVerifyMagicLink.js.map +1 -0
  51. package/dist/index.d.ts +5 -1
  52. package/dist/index.js +12 -8
  53. package/dist/index.js.map +1 -1
  54. package/package.json +1 -1
package/README.md CHANGED
@@ -50,10 +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
-
54
- // Provide your unsubscribe route. This route should include the Unsubscribe component.
55
- unsubscribeUrl?: string
56
- }),
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
+ }),
57
60
  ],
58
61
  })
59
62
  ```
@@ -127,7 +130,7 @@ You can specify collections in the plugin options which will be amended to inclu
127
130
 
128
131
  #### **tokenExpiration**
129
132
 
130
- ### 🟢 Collections
133
+ ### 🔵 Collections
131
134
 
132
135
  #### **optInChannels**
133
136
 
@@ -153,7 +156,7 @@ Seeded when plugin inits.
153
156
 
154
157
  ---
155
158
 
156
- ### 🔵 Fields
159
+ ### 🔴 Fields
157
160
 
158
161
  #### **OptedInChannels**
159
162
 
@@ -163,7 +166,7 @@ This is the same field used by the plugin **collections** to amended a relationT
163
166
 
164
167
  ---
165
168
 
166
- ### 🔴 Payload endpoints
169
+ ### 🟢 Payload endpoints
167
170
 
168
171
  #### **requestMagicLink**
169
172
 
@@ -181,19 +184,193 @@ Returns all active optInChannels data.
181
184
 
182
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.
183
186
 
184
- #### TO DO: unsubscribe
187
+ #### **unsubscribe**
185
188
 
186
- 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".
187
190
 
188
191
  ---
189
192
 
190
- ### 🟢 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.
191
251
 
192
252
  ---
193
253
 
194
- ### 🔵 Provides several NextJS client components ready for use in a frontend app
254
+ ### 🔴 Client hooks
195
255
 
196
- - 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/ui'
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/ui'
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/ui'
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/ui'
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.
197
374
 
198
375
  - All App Components accept a **classNames** prop to specify CSS class names to add to the different parts of the component
199
376
 
@@ -223,14 +400,14 @@ Shows the [Subscribe](#subscribe) component to authenticated subscribers, otherw
223
400
  handleMagicLinkRequested={async (result: RequestMagicLinkResponse) => {}}
224
401
  // Called after a subscribers opt-ins have been updated. Optional
225
402
  handleSubscribe={async (result: SubscribeResponse) => {}}
226
- // Provided your own button component. Optional
403
+ // Provide your own button component. Optional
227
404
  renderButton={({ name, onClick, text }) =>
228
405
  <button name={name} onClick={onClick} type="button">
229
406
  {text}
230
407
  </button>
231
408
  }
232
- // Provide the URL to your route that has the VerifyMagicLink component on it.
233
- 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}`}
234
411
  />
235
412
  ```
236
413
 
@@ -261,8 +438,8 @@ Form to input email address and get a magic link email sent.
261
438
  {text}
262
439
  </button>
263
440
  }
264
- // Provide the URL to your route that has the VerifyMagicLink component on it.
265
- verifyUrl={verifyUrl}
441
+ // Provide a payload of data to put on any verify link sent
442
+ verifyData={`forwardURL=${window.location.href}`}
266
443
  />
267
444
  ```
268
445
 
@@ -304,13 +481,11 @@ Component that verifies a magic link using expected url parameters.
304
481
  {text}
305
482
  </button>
306
483
  }
307
- // Provide the URL to your route that has the VerifyMagicLink component on it.
308
- // Used when this VerifyMagicLink component provides an option to request another link
309
- // when verifying the current one fails.
310
- verifyUrl={verifyUrl}
484
+ // Provide a payload of data to put on "request another" link sent
485
+ verifyData={`forwardURL=${window.location.href}`}
311
486
  >
312
487
  // Provide children to render after link is verified. Optional
313
- // 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
314
489
  // as a search param, which your route can then use here.
315
490
  <a href={forwardUrl}>
316
491
  <button className={'customCss'} name={'continue'} type="button">
@@ -361,8 +536,8 @@ Allows a subscriber to select from among all active optInChannels.
361
536
  {text}
362
537
  </button>
363
538
  }
364
- // Provide the URL to your route that has the VerifyMagicLink component on it.
365
- verifyUrl={verifyUrl}
539
+ // Provide a payload of data to put on any verify link sent
540
+ verifyData={`forwardURL=${window.location.href}`}
366
541
  />
367
542
  ```
368
543
 
@@ -410,7 +585,7 @@ A simple user menu, most useful for testing. Seen in the screenshots above. Incl
410
585
  button: 'customCssClassNames',
411
586
  container: 'customCssClassNames',
412
587
  }}
413
- subscribeUrl={new URL('/subscribe', serverURL)}
588
+ subscribeURL={new URL('/subscribe', serverURL)}
414
589
  />
415
590
 
416
591
  ```
@@ -421,7 +596,7 @@ A simple user menu, most useful for testing. Seen in the screenshots above. Incl
421
596
  <div class="subscribers-group">
422
597
  <div class="subscribers-welcome">Welcome, {subscriber email}</div>
423
598
  <div class="subscribers-subs-link">
424
- <a href="{subscribeUrl}">Manage subscriptions</a>
599
+ <a href="{subscribeURL}">Manage subscriptions</a>
425
600
  </div>
426
601
  <div class="subscribers-logout">
427
602
  <button class="subscribers-button" type="button">Log out</button>
@@ -430,6 +605,38 @@ A simple user menu, most useful for testing. Seen in the screenshots above. Incl
430
605
  </div>
431
606
  ```
432
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
+
433
640
  ## Contributing
434
641
 
435
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;
@@ -2,14 +2,17 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from 'react';
4
4
  import { useSubscriber } from '../../contexts/SubscriberProvider.js';
5
- import { useServerUrl } from '../../react-hooks/useServerUrl.js';
5
+ import { useRequestMagicLink } from '../../hooks/useRequestMagicLink.js';
6
6
  import { mergeClassNames } from './helpers.js';
7
7
  import styles from './shared.module.css';
8
8
  /**
9
9
  * Form component that lets users request a magic-login link by email. Submits to POST /api/emailToken
10
10
  * and shows success or error message. Uses SubscriberProvider for pre-filling email when available.
11
11
  *
12
- * @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)
13
16
  * @returns Form UI with email input and "Request magic link" button
14
17
  */ export const RequestMagicLink = ({ classNames = {
15
18
  button: '',
@@ -18,19 +21,12 @@ import styles from './shared.module.css';
18
21
  error: '',
19
22
  form: '',
20
23
  message: ''
21
- }, handleMagicLinkRequested, verifyUrl })=>{
24
+ }, handleMagicLinkRequested, verifyData })=>{
22
25
  const { subscriber } = useSubscriber();
23
- const { serverURL } = useServerUrl();
24
- if (!verifyUrl && serverURL) {
25
- console.log('verifyUrl DEFAULT');
26
- verifyUrl = `${serverURL ? serverURL : ''}/verify`;
27
- }
28
- if (typeof verifyUrl == 'string') {
29
- console.log('verifyUrl STRING: ', verifyUrl);
30
- verifyUrl = new URL(verifyUrl);
31
- }
32
- const [status, setStatus] = useState('default');
33
- const [result, setResult] = useState();
26
+ const { result, sendMagicLink, status } = useRequestMagicLink({
27
+ handleMagicLinkRequested,
28
+ verifyData
29
+ });
34
30
  const [email, setEmail] = useState(subscriber?.email || '');
35
31
  useEffect(()=>{
36
32
  setEmail(subscriber?.email || '');
@@ -39,48 +35,7 @@ import styles from './shared.module.css';
39
35
  ]);
40
36
  const handleSubmit = async (e)=>{
41
37
  e.preventDefault();
42
- if (!verifyUrl) {
43
- setStatus('error');
44
- setResult(`An error occured. Please try again. \n(No verify URL available.)`);
45
- } else {
46
- // const emailTokenResponse = await sdk.request({
47
- // json: {
48
- // email,
49
- // verifyUrl: verifyUrl?.href,
50
- // },
51
- // method: 'POST',
52
- // path: '/api/emailToken',
53
- // })
54
- const emailTokenResponse = await fetch(`${serverURL ? serverURL : ''}/api/emailToken`, {
55
- body: JSON.stringify({
56
- email,
57
- verifyUrl: verifyUrl?.href
58
- }),
59
- method: 'POST'
60
- });
61
- if (emailTokenResponse.ok) {
62
- const emailTokenResponseJson = await emailTokenResponse.json();
63
- if (handleMagicLinkRequested) {
64
- handleMagicLinkRequested(emailTokenResponseJson);
65
- }
66
- // @ts-expect-error One or the other exists
67
- const { emailResult, error } = emailTokenResponseJson;
68
- if (error) {
69
- setStatus('error');
70
- setResult(`An error occured. Please try again. \n ${error}`);
71
- } else if (emailResult) {
72
- setStatus('sent');
73
- setResult('An email has been sent containing your magic link.');
74
- } else {
75
- setStatus('error');
76
- setResult(`An error occured. Please try again. \nResult unknown`);
77
- }
78
- } else {
79
- const emailTokenResponseText = await emailTokenResponse.text();
80
- setStatus('error');
81
- setResult(`An error occured. Please try again. \n${emailTokenResponseText}`);
82
- }
83
- }
38
+ await sendMagicLink(email);
84
39
  };
85
40
  return /*#__PURE__*/ _jsxs("div", {
86
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 const { subscriber } = useSubscriber()\n const { serverURL } = useServerUrl()\n\n if (!verifyUrl && serverURL) {\n console.log('verifyUrl DEFAULT')\n verifyUrl = `${serverURL ? serverURL : ''}/verify`\n }\n if (typeof verifyUrl == 'string') {\n console.log('verifyUrl STRING: ', verifyUrl)\n verifyUrl = new URL(verifyUrl)\n }\n\n const [status, setStatus] = useState<statusValues>('default')\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 if (!verifyUrl) {\n setStatus('error')\n setResult(`An error occured. Please try again. \\n(No verify URL available.)`)\n } else {\n // const emailTokenResponse = await sdk.request({\n // json: {\n // email,\n // verifyUrl: verifyUrl?.href,\n // },\n // method: 'POST',\n // path: '/api/emailToken',\n // })\n const emailTokenResponse = await fetch(`${serverURL ? serverURL : ''}/api/emailToken`, {\n body: JSON.stringify({\n email,\n verifyUrl: verifyUrl?.href,\n }),\n method: 'POST',\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":["useEffect","useState","useSubscriber","useServerUrl","mergeClassNames","styles","RequestMagicLink","classNames","button","container","emailInput","error","form","message","handleMagicLinkRequested","verifyUrl","subscriber","serverURL","console","log","URL","status","setStatus","result","setResult","email","setEmail","handleSubmit","e","preventDefault","emailTokenResponse","fetch","body","JSON","stringify","href","method","ok","emailTokenResponseJson","json","emailResult","emailTokenResponseText","text","div","className","p","onSubmit","input","aria-label","onChange","target","value","placeholder","type"],"mappings":"AAAA;;AAGA,SAA6CA,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAK/E,SAASC,aAAa,QAAQ,uCAAsC;AACpE,SAASC,YAAY,QAAQ,oCAAmC;AAChE,SAASC,eAAe,QAAQ,eAAc;AAC9C,OAAOC,YAAY,sBAAqB;AA0BxC;;;;;;CAMC,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,SAAS,EACS;IAClB,MAAM,EAAEC,UAAU,EAAE,GAAGd;IACvB,MAAM,EAAEe,SAAS,EAAE,GAAGd;IAEtB,IAAI,CAACY,aAAaE,WAAW;QAC3BC,QAAQC,GAAG,CAAC;QACZJ,YAAY,GAAGE,YAAYA,YAAY,GAAG,OAAO,CAAC;IACpD;IACA,IAAI,OAAOF,aAAa,UAAU;QAChCG,QAAQC,GAAG,CAAC,sBAAsBJ;QAClCA,YAAY,IAAIK,IAAIL;IACtB;IAEA,MAAM,CAACM,QAAQC,UAAU,GAAGrB,SAAuB;IAEnD,MAAM,CAACsB,QAAQC,UAAU,GAAGvB;IAC5B,MAAM,CAACwB,OAAOC,SAAS,GAAGzB,SAASe,YAAYS,SAAS;IAExDzB,UAAU;QACR0B,SAASV,YAAYS,SAAS;IAChC,GAAG;QAACT;KAAW;IAEf,MAAMW,eAAe,OAAOC;QAC1BA,EAAEC,cAAc;QAChB,IAAI,CAACd,WAAW;YACdO,UAAU;YACVE,UAAU,CAAC,gEAAgE,CAAC;QAC9E,OAAO;YACL,iDAAiD;YACjD,YAAY;YACZ,aAAa;YACb,kCAAkC;YAClC,OAAO;YACP,oBAAoB;YACpB,6BAA6B;YAC7B,KAAK;YACL,MAAMM,qBAAqB,MAAMC,MAAM,GAAGd,YAAYA,YAAY,GAAG,eAAe,CAAC,EAAE;gBACrFe,MAAMC,KAAKC,SAAS,CAAC;oBACnBT;oBACAV,WAAWA,WAAWoB;gBACxB;gBACAC,QAAQ;YACV;YACA,IAAIN,mBAAmBO,EAAE,EAAE;gBACzB,MAAMC,yBAAmD,MAAMR,mBAAmBS,IAAI;gBACtF,IAAIzB,0BAA0B;oBAC5BA,yBAAyBwB;gBAC3B;gBACA,2CAA2C;gBAC3C,MAAM,EAAEE,WAAW,EAAE7B,KAAK,EAAE,GAAG2B;gBAC/B,IAAI3B,OAAO;oBACTW,UAAU;oBACVE,UAAU,CAAC,uCAAuC,EAAEb,OAAO;gBAC7D,OAAO,IAAI6B,aAAa;oBACtBlB,UAAU;oBACVE,UAAU;gBACZ,OAAO;oBACLF,UAAU;oBACVE,UAAU,CAAC,oDAAoD,CAAC;gBAClE;YACF,OAAO;gBACL,MAAMiB,yBAAyB,MAAMX,mBAAmBY,IAAI;gBAC5DpB,UAAU;gBACVE,UAAU,CAAC,sCAAsC,EAAEiB,wBAAwB;YAC7E;QACF;IACF;IACA,qBACE,MAACE;QACCC,WAAWxC,gBAAgB;YACzB;YACAC,OAAOI,SAAS;YAChBF,WAAWE,SAAS;SACrB;;YAEAc,uBACC,KAACsB;gBACCD,WAAWxC,gBAAgB;oBACzB;oBACAC,OAAOQ,OAAO;oBACdN,WAAWM,OAAO;oBAClBQ,UAAU,UAAU;wBAAC;wBAAqBhB,OAAOM,KAAK;wBAAEJ,WAAWI,KAAK;qBAAC,GAAG,EAAE;iBAC/E;0BAEAY;+BAGH;0BAEF,MAACX;gBACCgC,WAAWxC,gBAAgB;oBAAC;oBAAoBC,OAAOO,IAAI;oBAAEL,WAAWK,IAAI;iBAAC;gBAC7EwB,QAAO;gBACPU,UAAUnB;;kCAEV,KAACoB;wBACCC,cAAW;wBACXJ,WAAWxC,gBAAgB;4BACzB;4BACAC,OAAOK,UAAU;4BACjBH,WAAWG,UAAU;yBACtB;wBACDuC,UAAU,CAACrB,IAAqCF,SAASE,EAAEsB,MAAM,CAACC,KAAK;wBACvEC,aAAY;wBACZC,MAAK;wBACLF,OAAO1B;;kCAET,KAACjB;wBACCoC,WAAWxC,gBAAgB;4BAAC;4BAAsBC,OAAOG,MAAM;4BAAED,WAAWC,MAAM;yBAAC;wBACnF6C,MAAK;kCACN;;;;;;AAMT,EAAC"}
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"}