payload-subscribers-plugin 0.0.11 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -383,8 +383,6 @@ Shows the [Subscribe](#subscribe) component to authenticated subscribers, otherw
383
383
 
384
384
  ```typescript
385
385
  <RequestOrSubscribe
386
- // Provide the URL the user should go to after clicking the link in the email and having it verified
387
- afterVerifyUrl={new URL(window.href)}
388
386
  // Provide your own global class names to add to the component elements. Optional
389
387
  classNames={{
390
388
  button: 'customCssClassNames',
@@ -400,11 +398,6 @@ Shows the [Subscribe](#subscribe) component to authenticated subscribers, otherw
400
398
  handleMagicLinkRequested={async (result: RequestMagicLinkResponse) => {}}
401
399
  // Called after a subscribers opt-ins have been updated. Optional
402
400
  handleSubscribe={async (result: SubscribeResponse) => {}}
403
- // Provide your own button component. Optional
404
- renderButton={({ name, onClick, text }) =>
405
- <button name={name} onClick={onClick} type="button">
406
- {text}
407
- </button>
408
401
  }
409
402
  // Provide a payload of data to put on any verify link sent by either Request or Subscribe components
410
403
  verifyData={`forwardURL=${window.location.href}`}
@@ -419,8 +412,6 @@ Form to input email address and get a magic link email sent.
419
412
 
420
413
  ```typescript
421
414
  <RequestMagicLink
422
- // Provide the URL the user should go to after clicking the link in the email and having it verified
423
- afterVerifyUrl={new URL(window.href)}
424
415
  // Provide your own global class names to add to the component elements. Optional
425
416
  classNames={{
426
417
  button: 'customCssClassNames',
@@ -432,12 +423,6 @@ Form to input email address and get a magic link email sent.
432
423
  }}
433
424
  // Called after a subscribers opt-ins have been updated. Optional
434
425
  handleMagicLinkRequested={async (result: RequestMagicLinkResponse) => {}}
435
- // Provided your own button component. Optional
436
- renderButton={({ name, onClick, text }) =>
437
- <button name={name} onClick={onClick} type="button">
438
- {text}
439
- </button>
440
- }
441
426
  // Provide a payload of data to put on any verify link sent
442
427
  verifyData={`forwardURL=${window.location.href}`}
443
428
  />
@@ -475,12 +460,6 @@ Component that verifies a magic link using expected url parameters.
475
460
  handleMagicLinkRequested={async (result: RequestMagicLinkResponse) => {}}
476
461
  // Called after a magic link has been verified. Optional
477
462
  handleMagicLinkVerified={async (result: RequestMagicLinkResponse) => {}}
478
- // Provided your own button component. Optional
479
- renderButton={({ name, onClick, text }) =>
480
- <button name={name} onClick={onClick} type="button">
481
- {text}
482
- </button>
483
- }
484
463
  // Provide a payload of data to put on "request another" link sent
485
464
  verifyData={`forwardURL=${window.location.href}`}
486
465
  >
@@ -501,8 +480,8 @@ Component that verifies a magic link using expected url parameters.
501
480
  <p class="subscribers-loading">verifying...</p>
502
481
  <p class="subscribers-message">{result}</p>
503
482
  <div class="subscribers-form">
504
- {renderButton({ name: "request", onClick: handleRequestAnother, text:"Request another magic
505
- link", })} {children}
483
+ <!-- Form elements render here, before the component children provided -->
484
+ {children}
506
485
  </div>
507
486
  </div>
508
487
  ```
@@ -515,8 +494,6 @@ Allows a subscriber to select from among all active optInChannels.
515
494
 
516
495
  ```typescript
517
496
  <Subscribe
518
- // Provide the URL the user should go to after clicking the link in the email and having it verified
519
- afterVerifyUrl={new URL(window.href)}
520
497
  // Provide your own global class names to add to the component elements. Optional
521
498
  classNames={{
522
499
  button: 'customCssClassNames',
@@ -530,12 +507,6 @@ Allows a subscriber to select from among all active optInChannels.
530
507
  }}
531
508
  // Called after a subscribers opt-ins have been updated. Optional
532
509
  handleSubscribe={async (result: SubscribeResponse) => {}}
533
- // Provided your own button component. Optional
534
- renderButton={({ name, onClick, text }) =>
535
- <button name={name} onClick={onClick} type="button">
536
- {text}
537
- </button>
538
- }
539
510
  // Provide a payload of data to put on any verify link sent
540
511
  verifyData={`forwardURL=${window.location.href}`}
541
512
  />
@@ -9,7 +9,8 @@ import type { OptInChannel } from '../../copied/payload-types.js';
9
9
  */
10
10
  export interface ISelectOptInChannels {
11
11
  classNames?: SelectOptInChannelsClasses;
12
- handleOptInChannelsSelected?: (result: OptInChannel[]) => void;
12
+ handleOptInChannelsSelected?: (isLoaded: OptInChannel[]) => void;
13
+ optInChannels?: OptInChannel[];
13
14
  props?: any;
14
15
  selectedOptInChannelIDs?: string[];
15
16
  }
@@ -49,4 +50,4 @@ export type SelectOptInChannelsClasses = {
49
50
  * @param props.selectedOptInChannelIDs - Optional channel IDs to pre-select
50
51
  * @returns Section titled "Opt-in Channels" with checkboxes and loading/error state
51
52
  */
52
- export declare const SelectOptInChannels: ({ classNames, handleOptInChannelsSelected, selectedOptInChannelIDs, }: ISelectOptInChannels) => import("react").JSX.Element;
53
+ export declare const SelectOptInChannels: ({ classNames, handleOptInChannelsSelected, optInChannels, selectedOptInChannelIDs, }: ISelectOptInChannels) => import("react").JSX.Element;
@@ -1,8 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { PayloadSDK } from '@payloadcms/sdk';
4
3
  import { useEffect, useState } from 'react';
5
- import { useServerUrl } from '../../react-hooks/useServerUrl.js';
6
4
  import { mergeClassNames } from './helpers.js';
7
5
  import styles from './shared.module.css';
8
6
  /**
@@ -25,40 +23,21 @@ import styles from './shared.module.css';
25
23
  optInCheckboxItem: '',
26
24
  optInCheckboxLabel: '',
27
25
  optionsGroup: ''
28
- }, handleOptInChannelsSelected, selectedOptInChannelIDs })=>{
29
- const { serverURL } = useServerUrl();
30
- const [result, setResult] = useState();
26
+ }, handleOptInChannelsSelected, optInChannels, selectedOptInChannelIDs })=>{
27
+ const [isLoaded, setIsLoaded] = useState(false);
31
28
  const [allOptInChannels, setAllOptInChannels] = useState([]);
32
29
  useEffect(()=>{
33
- async function verify() {
34
- const sdk = new PayloadSDK({
35
- baseURL: serverURL || ''
36
- });
37
- console.log('calling optinchannels endpoint');
38
- const result = await sdk.request({
39
- method: 'GET',
40
- path: '/api/optinchannels'
41
- });
42
- if (result.ok) {
43
- const resultJson = await result.json();
44
- setResult(resultJson);
45
- } else {
46
- const resultText = await result.text();
47
- setResult(resultText);
48
- }
49
- }
50
- void verify();
51
- }, [
52
- serverURL
53
- ]);
54
- useEffect(()=>{
55
- const channels = result?.optInChannels?.map((channel)=>({
30
+ setIsLoaded(false);
31
+ const channels = optInChannels?.map((channel)=>({
56
32
  ...channel,
57
33
  isChecked: selectedOptInChannelIDs?.includes(channel.id)
58
34
  }));
59
- setAllOptInChannels(channels);
35
+ if (channels) {
36
+ setAllOptInChannels(channels);
37
+ }
38
+ setIsLoaded(true);
60
39
  }, [
61
- result,
40
+ optInChannels,
62
41
  selectedOptInChannelIDs
63
42
  ]);
64
43
  return /*#__PURE__*/ _jsxs("div", {
@@ -70,12 +49,12 @@ import styles from './shared.module.css';
70
49
  /*#__PURE__*/ _jsx("h3", {
71
50
  children: "Opt-in Channels"
72
51
  }),
73
- !result ? /*#__PURE__*/ _jsx("p", {
52
+ !isLoaded ? /*#__PURE__*/ _jsx("p", {
74
53
  className: mergeClassNames([
75
54
  styles.loading,
76
55
  classNames.loading
77
56
  ]),
78
- children: "verifying..."
57
+ children: "loading..."
79
58
  }) : /*#__PURE__*/ _jsx("div", {
80
59
  className: mergeClassNames([
81
60
  styles.optionsGroup,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/app/SelectOptInChannels.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { useEffect, useState } from 'react'\n\nimport type { Config, OptInChannel } from '../../copied/payload-types.js'\nimport type { GetOptInChannelsResponse } from '../../endpoints/getOptInChannels.js'\n\nimport { useServerUrl } from '../../react-hooks/useServerUrl.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\n/**\n * Props for the SelectOptInChannels component.\n *\n * @property classNames - Optional CSS class overrides for the component elements\n * @property handleOptInChannelsSelected - Callback with the list of selected opt-in channels\n * @property props - Optional passthrough props (reserved for future use)\n * @property selectedOptInChannelIDs - Optional channel IDs to pre-select\n */\nexport interface ISelectOptInChannels {\n classNames?: SelectOptInChannelsClasses\n handleOptInChannelsSelected?: (result: OptInChannel[]) => void\n props?: any\n selectedOptInChannelIDs?: string[]\n}\n\n/**\n * Optional CSS class overrides for SelectOptInChannels elements.\n *\n * @property button - Class for buttons\n * @property container - Class for the main container\n * @property error - Class for error messages\n * @property form - Class for the form\n * @property loading - Class for loading state\n * @property message - Class for message text\n * @property optInCheckbox - Class for each checkbox input\n * @property optInCheckboxItem - Class for each checkbox row/item\n * @property optInCheckboxLabel - Class for checkbox labels\n * @property optionsGroup - Class for the group wrapping all checkboxes\n */\nexport type SelectOptInChannelsClasses = {\n button?: string\n container?: string\n error?: string\n form?: string\n loading?: string\n message?: string\n optInCheckbox?: string\n optInCheckboxItem?: string\n optInCheckboxLabel?: string\n optionsGroup?: string\n}\n\n/**\n * Fetches active opt-in channels from GET /api/optinchannels and renders a list of checkboxes.\n * Reports selected channels via handleOptInChannelsSelected. Supports pre-selection via selectedOptInChannelIDs.\n *\n * @param props - Component props (see ISelectOptInChannels)\n * @param props.classNames - Optional class overrides for the component elements\n * @param props.handleOptInChannelsSelected - Callback with the list of selected opt-in channels\n * @param props.selectedOptInChannelIDs - Optional channel IDs to pre-select\n * @returns Section titled \"Opt-in Channels\" with checkboxes and loading/error state\n */\nexport const SelectOptInChannels = ({\n classNames = {\n button: '',\n container: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n optInCheckbox: '',\n optInCheckboxItem: '',\n optInCheckboxLabel: '',\n optionsGroup: '',\n },\n handleOptInChannelsSelected,\n selectedOptInChannelIDs,\n}: ISelectOptInChannels) => {\n const { serverURL } = useServerUrl()\n // const { serverURL } = { serverURL: 'http://localhost:3001' }\n type OptInChannelCheckbox = {\n isChecked: boolean\n } & OptInChannel\n const [result, setResult] = useState<any>()\n const [allOptInChannels, setAllOptInChannels] = useState<OptInChannelCheckbox[]>([])\n\n useEffect(() => {\n async function verify() {\n const sdk = new PayloadSDK<Config>({\n baseURL: serverURL || '',\n })\n\n console.log('calling optinchannels endpoint')\n const result = await sdk.request({\n method: 'GET',\n path: '/api/optinchannels',\n })\n if (result.ok) {\n const resultJson: GetOptInChannelsResponse = await result.json()\n setResult(resultJson)\n } else {\n const resultText = await result.text()\n setResult(resultText)\n }\n }\n void verify()\n }, [serverURL])\n\n useEffect(() => {\n const channels = result?.optInChannels?.map((channel: OptInChannel) => ({\n ...channel,\n isChecked: selectedOptInChannelIDs?.includes(channel.id),\n }))\n setAllOptInChannels(channels)\n }, [result, selectedOptInChannelIDs])\n\n return (\n <div className={mergeClassNames([styles.container, classNames.container])}>\n <h3>Opt-in Channels</h3>\n {!result ? (\n <p className={mergeClassNames([styles.loading, classNames.loading])}>verifying...</p>\n ) : (\n <div className={mergeClassNames([styles.optionsGroup, classNames.optionsGroup])}>\n {// Map over the tasks array to render each checkbox\n allOptInChannels?.map((channel) => (\n <div\n className={mergeClassNames([styles.optInCheckboxItem, classNames.optInCheckboxItem])}\n key={channel.id}\n >\n <label\n className={mergeClassNames([\n styles.optInCheckboxLabel,\n classNames.optInCheckboxLabel,\n ])}\n >\n <input\n aria-label={channel.title}\n // The checked prop is controlled by the state\n checked={channel.isChecked}\n className={mergeClassNames([styles.optInCheckbox, classNames.optInCheckbox])}\n // The onChange handler calls the update function with the item's ID\n onChange={(event) => {\n event.preventDefault()\n\n const checked = event.target.checked\n\n if (handleOptInChannelsSelected) {\n handleOptInChannelsSelected(\n allOptInChannels\n .map((channel) => ({\n ...channel,\n isChecked:\n channel.title == event.target.value ? checked : channel.isChecked,\n }))\n .filter((c) => c.isChecked)\n .map((channel) => ({ ...channel, isChecked: undefined })),\n )\n }\n }}\n type=\"checkbox\"\n value={channel.title}\n />\n {channel.title}\n </label>\n </div>\n ))}\n </div>\n )}\n </div>\n )\n}\n"],"names":["PayloadSDK","useEffect","useState","useServerUrl","mergeClassNames","styles","SelectOptInChannels","classNames","button","container","error","form","loading","message","optInCheckbox","optInCheckboxItem","optInCheckboxLabel","optionsGroup","handleOptInChannelsSelected","selectedOptInChannelIDs","serverURL","result","setResult","allOptInChannels","setAllOptInChannels","verify","sdk","baseURL","console","log","request","method","path","ok","resultJson","json","resultText","text","channels","optInChannels","map","channel","isChecked","includes","id","div","className","h3","p","label","input","aria-label","title","checked","onChange","event","preventDefault","target","value","filter","c","undefined","type"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/app/SelectOptInChannels.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\n\nimport type { OptInChannel } from '../../copied/payload-types.js'\n\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\n/**\n * Props for the SelectOptInChannels component.\n *\n * @property classNames - Optional CSS class overrides for the component elements\n * @property handleOptInChannelsSelected - Callback with the list of selected opt-in channels\n * @property props - Optional passthrough props (reserved for future use)\n * @property selectedOptInChannelIDs - Optional channel IDs to pre-select\n */\nexport interface ISelectOptInChannels {\n classNames?: SelectOptInChannelsClasses\n handleOptInChannelsSelected?: (isLoaded: OptInChannel[]) => void\n optInChannels?: OptInChannel[]\n props?: any\n selectedOptInChannelIDs?: string[]\n}\n\n/**\n * Optional CSS class overrides for SelectOptInChannels elements.\n *\n * @property button - Class for buttons\n * @property container - Class for the main container\n * @property error - Class for error messages\n * @property form - Class for the form\n * @property loading - Class for loading state\n * @property message - Class for message text\n * @property optInCheckbox - Class for each checkbox input\n * @property optInCheckboxItem - Class for each checkbox row/item\n * @property optInCheckboxLabel - Class for checkbox labels\n * @property optionsGroup - Class for the group wrapping all checkboxes\n */\nexport type SelectOptInChannelsClasses = {\n button?: string\n container?: string\n error?: string\n form?: string\n loading?: string\n message?: string\n optInCheckbox?: string\n optInCheckboxItem?: string\n optInCheckboxLabel?: string\n optionsGroup?: string\n}\n\n/**\n * Fetches active opt-in channels from GET /api/optinchannels and renders a list of checkboxes.\n * Reports selected channels via handleOptInChannelsSelected. Supports pre-selection via selectedOptInChannelIDs.\n *\n * @param props - Component props (see ISelectOptInChannels)\n * @param props.classNames - Optional class overrides for the component elements\n * @param props.handleOptInChannelsSelected - Callback with the list of selected opt-in channels\n * @param props.selectedOptInChannelIDs - Optional channel IDs to pre-select\n * @returns Section titled \"Opt-in Channels\" with checkboxes and loading/error state\n */\nexport const SelectOptInChannels = ({\n classNames = {\n button: '',\n container: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n optInCheckbox: '',\n optInCheckboxItem: '',\n optInCheckboxLabel: '',\n optionsGroup: '',\n },\n handleOptInChannelsSelected,\n optInChannels,\n selectedOptInChannelIDs,\n}: ISelectOptInChannels) => {\n // const { serverURL } = { serverURL: 'http://localhost:3001' }\n type OptInChannelCheckbox = {\n isChecked?: boolean\n } & OptInChannel\n const [isLoaded, setIsLoaded] = useState<boolean>(false)\n const [allOptInChannels, setAllOptInChannels] = useState<OptInChannelCheckbox[]>([])\n\n useEffect(() => {\n setIsLoaded(false)\n const channels = optInChannels?.map((channel: OptInChannel) => ({\n ...channel,\n isChecked: selectedOptInChannelIDs?.includes(channel.id),\n }))\n if (channels) {\n setAllOptInChannels(channels)\n }\n setIsLoaded(true)\n }, [optInChannels, selectedOptInChannelIDs])\n\n return (\n <div className={mergeClassNames([styles.container, classNames.container])}>\n <h3>Opt-in Channels</h3>\n {!isLoaded ? (\n <p className={mergeClassNames([styles.loading, classNames.loading])}>loading...</p>\n ) : (\n <div className={mergeClassNames([styles.optionsGroup, classNames.optionsGroup])}>\n {// Map over the tasks array to render each checkbox\n allOptInChannels?.map((channel) => (\n <div\n className={mergeClassNames([styles.optInCheckboxItem, classNames.optInCheckboxItem])}\n key={channel.id}\n >\n <label\n className={mergeClassNames([\n styles.optInCheckboxLabel,\n classNames.optInCheckboxLabel,\n ])}\n >\n <input\n aria-label={channel.title}\n // The checked prop is controlled by the state\n checked={channel.isChecked}\n className={mergeClassNames([styles.optInCheckbox, classNames.optInCheckbox])}\n // The onChange handler calls the update function with the item's ID\n onChange={(event) => {\n event.preventDefault()\n\n const checked = event.target.checked\n\n if (handleOptInChannelsSelected) {\n handleOptInChannelsSelected(\n allOptInChannels\n .map((channel) => ({\n ...channel,\n isChecked:\n channel.title == event.target.value ? checked : channel.isChecked,\n }))\n .filter((c) => c.isChecked)\n .map((channel) => ({ ...channel, isChecked: undefined })),\n )\n }\n }}\n type=\"checkbox\"\n value={channel.title}\n />\n {channel.title}\n </label>\n </div>\n ))}\n </div>\n )}\n </div>\n )\n}\n"],"names":["useEffect","useState","mergeClassNames","styles","SelectOptInChannels","classNames","button","container","error","form","loading","message","optInCheckbox","optInCheckboxItem","optInCheckboxLabel","optionsGroup","handleOptInChannelsSelected","optInChannels","selectedOptInChannelIDs","isLoaded","setIsLoaded","allOptInChannels","setAllOptInChannels","channels","map","channel","isChecked","includes","id","div","className","h3","p","label","input","aria-label","title","checked","onChange","event","preventDefault","target","value","filter","c","undefined","type"],"mappings":"AAAA;;AAEA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAI3C,SAASC,eAAe,QAAQ,eAAc;AAC9C,OAAOC,YAAY,sBAAqB;AA6CxC;;;;;;;;;CASC,GACD,OAAO,MAAMC,sBAAsB,CAAC,EAClCC,aAAa;IACXC,QAAQ;IACRC,WAAW;IACXC,OAAO;IACPC,MAAM;IACNC,SAAS;IACTC,SAAS;IACTC,eAAe;IACfC,mBAAmB;IACnBC,oBAAoB;IACpBC,cAAc;AAChB,CAAC,EACDC,2BAA2B,EAC3BC,aAAa,EACbC,uBAAuB,EACF;IAKrB,MAAM,CAACC,UAAUC,YAAY,GAAGnB,SAAkB;IAClD,MAAM,CAACoB,kBAAkBC,oBAAoB,GAAGrB,SAAiC,EAAE;IAEnFD,UAAU;QACRoB,YAAY;QACZ,MAAMG,WAAWN,eAAeO,IAAI,CAACC,UAA2B,CAAA;gBAC9D,GAAGA,OAAO;gBACVC,WAAWR,yBAAyBS,SAASF,QAAQG,EAAE;YACzD,CAAA;QACA,IAAIL,UAAU;YACZD,oBAAoBC;QACtB;QACAH,YAAY;IACd,GAAG;QAACH;QAAeC;KAAwB;IAE3C,qBACE,MAACW;QAAIC,WAAW5B,gBAAgB;YAACC,OAAOI,SAAS;YAAEF,WAAWE,SAAS;SAAC;;0BACtE,KAACwB;0BAAG;;YACH,CAACZ,yBACA,KAACa;gBAAEF,WAAW5B,gBAAgB;oBAACC,OAAOO,OAAO;oBAAEL,WAAWK,OAAO;iBAAC;0BAAG;+BAErE,KAACmB;gBAAIC,WAAW5B,gBAAgB;oBAACC,OAAOY,YAAY;oBAAEV,WAAWU,YAAY;iBAAC;0BAE5EM,kBAAkBG,IAAI,CAACC,wBACrB,KAACI;wBACCC,WAAW5B,gBAAgB;4BAACC,OAAOU,iBAAiB;4BAAER,WAAWQ,iBAAiB;yBAAC;kCAGnF,cAAA,MAACoB;4BACCH,WAAW5B,gBAAgB;gCACzBC,OAAOW,kBAAkB;gCACzBT,WAAWS,kBAAkB;6BAC9B;;8CAED,KAACoB;oCACCC,cAAYV,QAAQW,KAAK;oCACzB,8CAA8C;oCAC9CC,SAASZ,QAAQC,SAAS;oCAC1BI,WAAW5B,gBAAgB;wCAACC,OAAOS,aAAa;wCAAEP,WAAWO,aAAa;qCAAC;oCAC3E,oEAAoE;oCACpE0B,UAAU,CAACC;wCACTA,MAAMC,cAAc;wCAEpB,MAAMH,UAAUE,MAAME,MAAM,CAACJ,OAAO;wCAEpC,IAAIrB,6BAA6B;4CAC/BA,4BACEK,iBACGG,GAAG,CAAC,CAACC,UAAa,CAAA;oDACjB,GAAGA,OAAO;oDACVC,WACED,QAAQW,KAAK,IAAIG,MAAME,MAAM,CAACC,KAAK,GAAGL,UAAUZ,QAAQC,SAAS;gDACrE,CAAA,GACCiB,MAAM,CAAC,CAACC,IAAMA,EAAElB,SAAS,EACzBF,GAAG,CAAC,CAACC,UAAa,CAAA;oDAAE,GAAGA,OAAO;oDAAEC,WAAWmB;gDAAU,CAAA;wCAE5D;oCACF;oCACAC,MAAK;oCACLJ,OAAOjB,QAAQW,KAAK;;gCAErBX,QAAQW,KAAK;;;uBAnCXX,QAAQG,EAAE;;;;AA2C7B,EAAC"}
@@ -36,7 +36,7 @@ import styles from './shared.module.css';
36
36
  handleMagicLinkRequested,
37
37
  verifyData
38
38
  });
39
- const { result: subscribeResult, status: subscribeStatus, subscriber, updateSubscriptions } = useSubscribe({
39
+ const { optInChannels, result: subscribeResult, status: subscribeStatus, subscriber, updateSubscriptions } = useSubscribe({
40
40
  handleSubscribe,
41
41
  verifyData
42
42
  });
@@ -77,6 +77,7 @@ import styles from './shared.module.css';
77
77
  }),
78
78
  /*#__PURE__*/ _jsx(SelectOptInChannels, {
79
79
  handleOptInChannelsSelected: handleOptInChannelsSelected,
80
+ optInChannels: optInChannels,
80
81
  selectedOptInChannelIDs: selectedChannelIDs
81
82
  })
82
83
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/app/Subscribe.tsx"],"sourcesContent":["'use client'\n\nimport { type ChangeEvent, useEffect, useState } from 'react'\n\nimport type { OptInChannel, Subscriber } from '../../copied/payload-types.js'\nimport type { SubscribeResponse } from '../../endpoints/subscribe.js'\n\nexport { SubscribeResponse }\n\nimport type { RequestMagicLinkStatusValue } from '../../hooks/useRequestMagicLink.js'\nimport type { UpdateSubscriptionStatusValue } from '../../hooks/useSubscribe.js'\n\nimport { useRequestMagicLink } from '../../hooks/useRequestMagicLink.js'\nimport { useSubscribe } from '../../hooks/useSubscribe.js'\nimport { useUnsubscribe } from '../../hooks/useUnsubscribe.js'\nimport { mergeClassNames } from './helpers.js'\nimport { SelectOptInChannels } from './SelectOptInChannels.js'\nimport styles from './shared.module.css'\n\n/**\n * Props for the Subscribe component.\n *\n * @property classNames - Optional CSS class overrides for the component elements\n * @property handleSubscribe - Callback when subscription/opt-ins are updated\n * @property props - Optional passthrough props (reserved for future use)\n * @property verifyData - Optional data for verification (e.g. passed from magic-link URL)\n */\nexport interface ISubscribe {\n classNames?: SubscribeClasses\n handleSubscribe?: (result: SubscribeResponse) => void\n props?: any\n verifyData?: string\n}\n\n/**\n * Optional CSS class overrides for Subscribe elements.\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 the form\n * @property loading - Class for loading state\n * @property message - Class for status message text\n * @property section - Class for section wrappers\n */\nexport type SubscribeClasses = {\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 * Subscribe/preferences form for authenticated subscribers. Shows SelectOptInChannels and an email\n * input when not yet authenticated. Submits to POST /api/subscribe to update opt-ins or trigger\n * verification email. Calls refreshSubscriber and handleSubscribe on success.\n *\n * @param props - Component props (see ISubscribe)\n * @param props.classNames - Optional class overrides for the component elements\n * @param props.handleSubscribe - Callback when subscription/opt-ins are updated\n * @param props.verifyData - Optional data for verification (e.g. passed from magic-link URL)\n * @returns Form with channel checkboxes, optional email field, \"Save choices\" button, and status message\n */\nexport const Subscribe = ({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n section: '',\n },\n handleSubscribe,\n verifyData,\n}: ISubscribe) => {\n const { unsubscribe } = useUnsubscribe({ handleUnsubscribe: () => {} })\n\n const [email, setEmail] = useState<string>('')\n\n const handleMagicLinkRequested = () => {}\n const {\n result: requestResult,\n sendMagicLink,\n status: requestStatus,\n } = useRequestMagicLink({\n handleMagicLinkRequested,\n verifyData,\n })\n const {\n result: subscribeResult,\n status: subscribeStatus,\n subscriber,\n updateSubscriptions,\n } = useSubscribe({\n handleSubscribe,\n verifyData,\n })\n\n const flattenChannels = (channels: (OptInChannel | string)[] | null | undefined) => {\n if (!channels) {\n return []\n }\n return channels.map((channel: OptInChannel | string) =>\n typeof channel == 'string' ? channel : channel.id,\n )\n }\n\n const [selectedChannelIDs, setSelectedChannelIDs] = useState<string[]>(() =>\n flattenChannels(subscriber?.optIns),\n )\n\n useEffect(() => {\n setSelectedChannelIDs(flattenChannels(subscriber?.optIns))\n }, [subscriber])\n\n const handleOptInChannelsSelected = (result: OptInChannel[]) => {\n setSelectedChannelIDs(result.map((channel) => channel.id))\n }\n\n return (\n <div\n className={mergeClassNames([\n 'subscribers-subscribe subscribers-container',\n styles.container,\n classNames.container,\n ])}\n >\n <h2>Subscribe</h2>\n <div className={mergeClassNames(['subscribers-section', styles.section, classNames.section])}>\n {subscriber?.status == 'unsubscribed' && <p>You are unsubscribed</p>}\n <SelectOptInChannels\n handleOptInChannelsSelected={handleOptInChannelsSelected}\n selectedOptInChannelIDs={selectedChannelIDs}\n />\n </div>\n <form\n className={mergeClassNames(['subscribers-form', styles.form, classNames.form])}\n method=\"POST\"\n onSubmit={async (e) => {\n e.preventDefault()\n if (subscriber) {\n await updateSubscriptions(selectedChannelIDs)\n } else {\n await sendMagicLink(email)\n }\n }}\n >\n <div\n className={mergeClassNames(['subscribers-section', styles.section, classNames.section])}\n >\n {!subscriber && (\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 )}\n <button\n className={mergeClassNames(['subscribers-button', styles.button, classNames.button])}\n type=\"submit\"\n >\n {!subscriber && <>Subscribe</>}\n {subscriber && subscriber?.status != 'unsubscribed' && <>Save choices</>}\n {subscriber?.status == 'unsubscribed' && <>Subscribe and save choices</>}\n </button>\n {subscriber && subscriber?.status != 'unsubscribed' && (\n <button\n className={mergeClassNames(['subscribers-button', styles.button, classNames.button])}\n onClick={async () => {\n await unsubscribe()\n }}\n type=\"button\"\n >\n Unsubscribe from all\n </button>\n )}\n </div>\n </form>\n {(!!requestResult || !!subscribeResult) && (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n requestStatus == 'error' || subscribeStatus == 'error'\n ? ['subscribers-error', styles.error, classNames.error]\n : [],\n ])}\n >\n {requestResult || subscribeResult}\n </p>\n )}\n </div>\n )\n}\n"],"names":["useEffect","useState","useRequestMagicLink","useSubscribe","useUnsubscribe","mergeClassNames","SelectOptInChannels","styles","Subscribe","classNames","button","container","emailInput","error","form","loading","message","section","handleSubscribe","verifyData","unsubscribe","handleUnsubscribe","email","setEmail","handleMagicLinkRequested","result","requestResult","sendMagicLink","status","requestStatus","subscribeResult","subscribeStatus","subscriber","updateSubscriptions","flattenChannels","channels","map","channel","id","selectedChannelIDs","setSelectedChannelIDs","optIns","handleOptInChannelsSelected","div","className","h2","p","selectedOptInChannelIDs","method","onSubmit","e","preventDefault","input","aria-label","onChange","target","value","placeholder","type","onClick"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/app/Subscribe.tsx"],"sourcesContent":["'use client'\n\nimport { type ChangeEvent, useEffect, useState } from 'react'\n\nimport type { OptInChannel, Subscriber } from '../../copied/payload-types.js'\nimport type { GetOptInChannelsResponse } from '../../endpoints/getOptInChannels.js'\nimport type { SubscribeResponse } from '../../endpoints/subscribe.js'\n\nexport { SubscribeResponse }\n\nimport type { RequestMagicLinkStatusValue } from '../../hooks/useRequestMagicLink.js'\nimport type { UpdateSubscriptionStatusValue } from '../../hooks/useSubscribe.js'\n\nimport { useRequestMagicLink } from '../../hooks/useRequestMagicLink.js'\nimport { useSubscribe } from '../../hooks/useSubscribe.js'\nimport { useUnsubscribe } from '../../hooks/useUnsubscribe.js'\nimport { useServerUrl } from '../../react-hooks/useServerUrl.js'\nimport { mergeClassNames } from './helpers.js'\nimport { SelectOptInChannels } from './SelectOptInChannels.js'\nimport styles from './shared.module.css'\n\n/**\n * Props for the Subscribe component.\n *\n * @property classNames - Optional CSS class overrides for the component elements\n * @property handleSubscribe - Callback when subscription/opt-ins are updated\n * @property props - Optional passthrough props (reserved for future use)\n * @property verifyData - Optional data for verification (e.g. passed from magic-link URL)\n */\nexport interface ISubscribe {\n classNames?: SubscribeClasses\n handleSubscribe?: (result: SubscribeResponse) => void\n props?: any\n verifyData?: string\n}\n\n/**\n * Optional CSS class overrides for Subscribe elements.\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 the form\n * @property loading - Class for loading state\n * @property message - Class for status message text\n * @property section - Class for section wrappers\n */\nexport type SubscribeClasses = {\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 * Subscribe/preferences form for authenticated subscribers. Shows SelectOptInChannels and an email\n * input when not yet authenticated. Submits to POST /api/subscribe to update opt-ins or trigger\n * verification email. Calls refreshSubscriber and handleSubscribe on success.\n *\n * @param props - Component props (see ISubscribe)\n * @param props.classNames - Optional class overrides for the component elements\n * @param props.handleSubscribe - Callback when subscription/opt-ins are updated\n * @param props.verifyData - Optional data for verification (e.g. passed from magic-link URL)\n * @returns Form with channel checkboxes, optional email field, \"Save choices\" button, and status message\n */\nexport const Subscribe = ({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n section: '',\n },\n handleSubscribe,\n verifyData,\n}: ISubscribe) => {\n const { unsubscribe } = useUnsubscribe({ handleUnsubscribe: () => {} })\n\n const [email, setEmail] = useState<string>('')\n\n const handleMagicLinkRequested = () => {}\n const {\n result: requestResult,\n sendMagicLink,\n status: requestStatus,\n } = useRequestMagicLink({\n handleMagicLinkRequested,\n verifyData,\n })\n const {\n optInChannels,\n result: subscribeResult,\n status: subscribeStatus,\n subscriber,\n updateSubscriptions,\n } = useSubscribe({\n handleSubscribe,\n verifyData,\n })\n\n const flattenChannels = (channels: (OptInChannel | string)[] | null | undefined) => {\n if (!channels) {\n return []\n }\n return channels.map((channel: OptInChannel | string) =>\n typeof channel == 'string' ? channel : channel.id,\n )\n }\n\n const [selectedChannelIDs, setSelectedChannelIDs] = useState<string[]>(() =>\n flattenChannels(subscriber?.optIns),\n )\n\n useEffect(() => {\n setSelectedChannelIDs(flattenChannels(subscriber?.optIns))\n }, [subscriber])\n\n const handleOptInChannelsSelected = (result: OptInChannel[]) => {\n setSelectedChannelIDs(result.map((channel) => channel.id))\n }\n\n return (\n <div\n className={mergeClassNames([\n 'subscribers-subscribe subscribers-container',\n styles.container,\n classNames.container,\n ])}\n >\n <h2>Subscribe</h2>\n <div className={mergeClassNames(['subscribers-section', styles.section, classNames.section])}>\n {subscriber?.status == 'unsubscribed' && <p>You are unsubscribed</p>}\n <SelectOptInChannels\n handleOptInChannelsSelected={handleOptInChannelsSelected}\n optInChannels={optInChannels}\n selectedOptInChannelIDs={selectedChannelIDs}\n />\n </div>\n <form\n className={mergeClassNames(['subscribers-form', styles.form, classNames.form])}\n method=\"POST\"\n onSubmit={async (e) => {\n e.preventDefault()\n if (subscriber) {\n await updateSubscriptions(selectedChannelIDs)\n } else {\n await sendMagicLink(email)\n }\n }}\n >\n <div\n className={mergeClassNames(['subscribers-section', styles.section, classNames.section])}\n >\n {!subscriber && (\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 )}\n <button\n className={mergeClassNames(['subscribers-button', styles.button, classNames.button])}\n type=\"submit\"\n >\n {!subscriber && <>Subscribe</>}\n {subscriber && subscriber?.status != 'unsubscribed' && <>Save choices</>}\n {subscriber?.status == 'unsubscribed' && <>Subscribe and save choices</>}\n </button>\n {subscriber && subscriber?.status != 'unsubscribed' && (\n <button\n className={mergeClassNames(['subscribers-button', styles.button, classNames.button])}\n onClick={async () => {\n await unsubscribe()\n }}\n type=\"button\"\n >\n Unsubscribe from all\n </button>\n )}\n </div>\n </form>\n {(!!requestResult || !!subscribeResult) && (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n requestStatus == 'error' || subscribeStatus == 'error'\n ? ['subscribers-error', styles.error, classNames.error]\n : [],\n ])}\n >\n {requestResult || subscribeResult}\n </p>\n )}\n </div>\n )\n}\n"],"names":["useEffect","useState","useRequestMagicLink","useSubscribe","useUnsubscribe","mergeClassNames","SelectOptInChannels","styles","Subscribe","classNames","button","container","emailInput","error","form","loading","message","section","handleSubscribe","verifyData","unsubscribe","handleUnsubscribe","email","setEmail","handleMagicLinkRequested","result","requestResult","sendMagicLink","status","requestStatus","optInChannels","subscribeResult","subscribeStatus","subscriber","updateSubscriptions","flattenChannels","channels","map","channel","id","selectedChannelIDs","setSelectedChannelIDs","optIns","handleOptInChannelsSelected","div","className","h2","p","selectedOptInChannelIDs","method","onSubmit","e","preventDefault","input","aria-label","onChange","target","value","placeholder","type","onClick"],"mappings":"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"}
@@ -1,12 +1,14 @@
1
1
  import { type ReactNode } from 'react';
2
- import type { Subscriber } from '../copied/payload-types.js';
2
+ import type { OptInChannel, Subscriber } from '../copied/payload-types.js';
3
3
  /** Value provided by SubscriberProvider: current subscriber, auth state, and actions. */
4
4
  export type SubscriberContextType = {
5
5
  isLoaded: boolean;
6
6
  logOut: () => void;
7
7
  permissions: any;
8
8
  refreshSubscriber: () => void;
9
- subscriber: null | Subscriber;
9
+ subscriber: ({
10
+ optIns?: null | OptInChannel[];
11
+ } & Omit<Subscriber, 'optIns'>) | null;
10
12
  };
11
13
  /** Props for SubscriberProvider. */
12
14
  interface ProviderProps {
@@ -28,7 +28,9 @@ const SubscriberContext = /*#__PURE__*/ createContext(undefined);
28
28
  });
29
29
  if (authResponse.ok) {
30
30
  // Call the server function to get the user data
31
- const { permissions, subscriber } = await authResponse.json();
31
+ const authResponseJson = await authResponse.json();
32
+ // console.log('authResponseJson', JSON.stringify(authResponseJson, undefined, 2))
33
+ const { permissions, subscriber } = authResponseJson;
32
34
  // console.log(`subscriber = `, subscriber)
33
35
  // console.log(`permissions = `, permissions)
34
36
  setPermissions(permissions);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/contexts/SubscriberProvider.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ReactNode, useCallback, useEffect } from 'react'\nimport { createContext, useContext, useMemo, useState } from 'react'\n\nimport type { Config, Subscriber } from '../copied/payload-types.js'\n\nimport { useServerUrl } from '../react-hooks/useServerUrl.js'\n\n/** Value provided by SubscriberProvider: current subscriber, auth state, and actions. */\nexport type SubscriberContextType = {\n isLoaded: boolean\n logOut: () => void\n permissions: any\n refreshSubscriber: () => void\n subscriber: null | Subscriber\n}\n\nconst SubscriberContext = createContext<SubscriberContextType | undefined>(undefined)\n\n/** Props for SubscriberProvider. */\ninterface ProviderProps {\n children?: ReactNode\n}\n\n/**\n * Provider that fetches and holds the current subscriber auth state (via POST /api/subscriberAuth).\n * Exposes subscriber, permissions, refreshSubscriber, and logOut to descendants. Must wrap any\n * component that uses useSubscriber().\n *\n * @param props.children - React tree to wrap\n * @returns SubscriberContext.Provider with current auth state and actions\n */\nexport function SubscriberProvider({ children }: ProviderProps) {\n // eslint-disable-next-line\n const [subscriber, setSubscriber] = useState<null | (Subscriber & { optIns: string[] })>(null)\n\n const { serverURL } = useServerUrl()\n\n // Keep track of if the selection content is loaded yet\n const [isLoaded, setIsLoaded] = useState(false)\n\n const [permissions, setPermissions] = useState<any>()\n\n const refreshSubscriber = useCallback(async () => {\n const initSubscriber = async () => {\n setIsLoaded(false)\n try {\n const authResponse = await fetch('/api/subscriberAuth', {\n // body: JSON.stringify({}),\n method: 'POST',\n })\n\n if (authResponse.ok) {\n // Call the server function to get the user data\n const { permissions, subscriber } = await authResponse.json()\n // console.log(`subscriber = `, subscriber)\n // console.log(`permissions = `, permissions)\n setPermissions(permissions)\n setSubscriber(subscriber)\n } else {\n setPermissions(null)\n setSubscriber(null)\n }\n } catch (error: unknown) {\n console.log(`authResponse error`, error)\n }\n setIsLoaded(true)\n }\n await initSubscriber()\n }, [serverURL])\n\n const logOut = useCallback(async () => {\n setIsLoaded(false)\n try {\n // const sdk = new PayloadSDK<Config>({\n // baseURL: serverURL || '',\n // })\n // const logoutResponse = await sdk.request({\n // json: {},\n // method: 'POST',\n // path: '/api/logout',\n // })\n // Unsure why sdk isn't working here\n const logoutResponse = await fetch('/api/logout', {\n method: 'POST',\n })\n\n // console.log(`logoutResponse`, logoutResponse)\n\n if (logoutResponse.ok) {\n setSubscriber(null)\n setPermissions(null)\n }\n } catch (error: unknown) {\n console.log(`logoutResponse error`, error)\n }\n setIsLoaded(true)\n }, [])\n\n useEffect(() => {\n void refreshSubscriber()\n }, [refreshSubscriber])\n\n // Memoize the value to prevent unnecessary re-renders in consumers\n const contextValue: SubscriberContextType = useMemo(\n () => ({\n isLoaded,\n logOut,\n permissions,\n refreshSubscriber,\n subscriber,\n }),\n [isLoaded, logOut, permissions, refreshSubscriber, subscriber],\n )\n\n return <SubscriberContext.Provider value={contextValue}>{children}</SubscriberContext.Provider>\n}\n\n/**\n * Consumes SubscriberContext. Use only inside a SubscriberProvider.\n *\n * @returns Current subscriber (or null), permissions, isLoaded, refreshSubscriber, and logOut\n * @throws Error if used outside SubscriberProvider\n */\nexport function useSubscriber() {\n const context = useContext(SubscriberContext)\n if (context === undefined) {\n throw new Error('useSubscriber must be used within a SubscriberProvider')\n }\n return context\n}\n"],"names":["useCallback","useEffect","createContext","useContext","useMemo","useState","useServerUrl","SubscriberContext","undefined","SubscriberProvider","children","subscriber","setSubscriber","serverURL","isLoaded","setIsLoaded","permissions","setPermissions","refreshSubscriber","initSubscriber","authResponse","fetch","method","ok","json","error","console","log","logOut","logoutResponse","contextValue","Provider","value","useSubscriber","context","Error"],"mappings":"AAAA;;AAGA,SAAyBA,WAAW,EAAEC,SAAS,QAAQ,QAAO;AAC9D,SAASC,aAAa,EAAEC,UAAU,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAIpE,SAASC,YAAY,QAAQ,iCAAgC;AAW7D,MAAMC,kCAAoBL,cAAiDM;AAO3E;;;;;;;CAOC,GACD,OAAO,SAASC,mBAAmB,EAAEC,QAAQ,EAAiB;IAC5D,2BAA2B;IAC3B,MAAM,CAACC,YAAYC,cAAc,GAAGP,SAAqD;IAEzF,MAAM,EAAEQ,SAAS,EAAE,GAAGP;IAEtB,uDAAuD;IACvD,MAAM,CAACQ,UAAUC,YAAY,GAAGV,SAAS;IAEzC,MAAM,CAACW,aAAaC,eAAe,GAAGZ;IAEtC,MAAMa,oBAAoBlB,YAAY;QACpC,MAAMmB,iBAAiB;YACrBJ,YAAY;YACZ,IAAI;gBACF,MAAMK,eAAe,MAAMC,MAAM,uBAAuB;oBACtD,4BAA4B;oBAC5BC,QAAQ;gBACV;gBAEA,IAAIF,aAAaG,EAAE,EAAE;oBACnB,gDAAgD;oBAChD,MAAM,EAAEP,WAAW,EAAEL,UAAU,EAAE,GAAG,MAAMS,aAAaI,IAAI;oBAC3D,2CAA2C;oBAC3C,6CAA6C;oBAC7CP,eAAeD;oBACfJ,cAAcD;gBAChB,OAAO;oBACLM,eAAe;oBACfL,cAAc;gBAChB;YACF,EAAE,OAAOa,OAAgB;gBACvBC,QAAQC,GAAG,CAAC,CAAC,kBAAkB,CAAC,EAAEF;YACpC;YACAV,YAAY;QACd;QACA,MAAMI;IACR,GAAG;QAACN;KAAU;IAEd,MAAMe,SAAS5B,YAAY;QACzBe,YAAY;QACZ,IAAI;YACF,uCAAuC;YACvC,8BAA8B;YAC9B,KAAK;YACL,6CAA6C;YAC7C,cAAc;YACd,oBAAoB;YACpB,yBAAyB;YACzB,KAAK;YACL,oCAAoC;YACpC,MAAMc,iBAAiB,MAAMR,MAAM,eAAe;gBAChDC,QAAQ;YACV;YAEA,gDAAgD;YAEhD,IAAIO,eAAeN,EAAE,EAAE;gBACrBX,cAAc;gBACdK,eAAe;YACjB;QACF,EAAE,OAAOQ,OAAgB;YACvBC,QAAQC,GAAG,CAAC,CAAC,oBAAoB,CAAC,EAAEF;QACtC;QACAV,YAAY;IACd,GAAG,EAAE;IAELd,UAAU;QACR,KAAKiB;IACP,GAAG;QAACA;KAAkB;IAEtB,mEAAmE;IACnE,MAAMY,eAAsC1B,QAC1C,IAAO,CAAA;YACLU;YACAc;YACAZ;YACAE;YACAP;QACF,CAAA,GACA;QAACG;QAAUc;QAAQZ;QAAaE;QAAmBP;KAAW;IAGhE,qBAAO,KAACJ,kBAAkBwB,QAAQ;QAACC,OAAOF;kBAAepB;;AAC3D;AAEA;;;;;CAKC,GACD,OAAO,SAASuB;IACd,MAAMC,UAAU/B,WAAWI;IAC3B,IAAI2B,YAAY1B,WAAW;QACzB,MAAM,IAAI2B,MAAM;IAClB;IACA,OAAOD;AACT"}
1
+ {"version":3,"sources":["../../src/contexts/SubscriberProvider.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ReactNode, useCallback, useEffect } from 'react'\nimport { createContext, useContext, useMemo, useState } from 'react'\n\nimport type { Config, OptInChannel, Subscriber } from '../copied/payload-types.js'\n\nimport { useServerUrl } from '../react-hooks/useServerUrl.js'\n\n/** Value provided by SubscriberProvider: current subscriber, auth state, and actions. */\nexport type SubscriberContextType = {\n isLoaded: boolean\n logOut: () => void\n permissions: any\n refreshSubscriber: () => void\n subscriber: ({ optIns?: null | OptInChannel[] } & Omit<Subscriber, 'optIns'>) | null\n}\n\nconst SubscriberContext = createContext<SubscriberContextType | undefined>(undefined)\n\n/** Props for SubscriberProvider. */\ninterface ProviderProps {\n children?: ReactNode\n}\n\n/**\n * Provider that fetches and holds the current subscriber auth state (via POST /api/subscriberAuth).\n * Exposes subscriber, permissions, refreshSubscriber, and logOut to descendants. Must wrap any\n * component that uses useSubscriber().\n *\n * @param props.children - React tree to wrap\n * @returns SubscriberContext.Provider with current auth state and actions\n */\nexport function SubscriberProvider({ children }: ProviderProps) {\n // eslint-disable-next-line\n const [subscriber, setSubscriber] = useState<null | (Subscriber & { optIns: OptInChannel[] })>(\n null,\n )\n\n const { serverURL } = useServerUrl()\n\n // Keep track of if the selection content is loaded yet\n const [isLoaded, setIsLoaded] = useState(false)\n\n const [permissions, setPermissions] = useState<any>()\n\n const refreshSubscriber = useCallback(async () => {\n const initSubscriber = async () => {\n setIsLoaded(false)\n try {\n const authResponse = await fetch('/api/subscriberAuth', {\n // body: JSON.stringify({}),\n method: 'POST',\n })\n\n if (authResponse.ok) {\n // Call the server function to get the user data\n const authResponseJson = await authResponse.json()\n // console.log('authResponseJson', JSON.stringify(authResponseJson, undefined, 2))\n const { permissions, subscriber } = authResponseJson\n // console.log(`subscriber = `, subscriber)\n // console.log(`permissions = `, permissions)\n setPermissions(permissions)\n setSubscriber(subscriber)\n } else {\n setPermissions(null)\n setSubscriber(null)\n }\n } catch (error: unknown) {\n console.log(`authResponse error`, error)\n }\n setIsLoaded(true)\n }\n await initSubscriber()\n }, [serverURL])\n\n const logOut = useCallback(async () => {\n setIsLoaded(false)\n try {\n // const sdk = new PayloadSDK<Config>({\n // baseURL: serverURL || '',\n // })\n // const logoutResponse = await sdk.request({\n // json: {},\n // method: 'POST',\n // path: '/api/logout',\n // })\n // Unsure why sdk isn't working here\n const logoutResponse = await fetch('/api/logout', {\n method: 'POST',\n })\n\n // console.log(`logoutResponse`, logoutResponse)\n\n if (logoutResponse.ok) {\n setSubscriber(null)\n setPermissions(null)\n }\n } catch (error: unknown) {\n console.log(`logoutResponse error`, error)\n }\n setIsLoaded(true)\n }, [])\n\n useEffect(() => {\n void refreshSubscriber()\n }, [refreshSubscriber])\n\n // Memoize the value to prevent unnecessary re-renders in consumers\n const contextValue: SubscriberContextType = useMemo(\n () => ({\n isLoaded,\n logOut,\n permissions,\n refreshSubscriber,\n subscriber,\n }),\n [isLoaded, logOut, permissions, refreshSubscriber, subscriber],\n )\n\n return <SubscriberContext.Provider value={contextValue}>{children}</SubscriberContext.Provider>\n}\n\n/**\n * Consumes SubscriberContext. Use only inside a SubscriberProvider.\n *\n * @returns Current subscriber (or null), permissions, isLoaded, refreshSubscriber, and logOut\n * @throws Error if used outside SubscriberProvider\n */\nexport function useSubscriber() {\n const context = useContext(SubscriberContext)\n if (context === undefined) {\n throw new Error('useSubscriber must be used within a SubscriberProvider')\n }\n return context\n}\n"],"names":["useCallback","useEffect","createContext","useContext","useMemo","useState","useServerUrl","SubscriberContext","undefined","SubscriberProvider","children","subscriber","setSubscriber","serverURL","isLoaded","setIsLoaded","permissions","setPermissions","refreshSubscriber","initSubscriber","authResponse","fetch","method","ok","authResponseJson","json","error","console","log","logOut","logoutResponse","contextValue","Provider","value","useSubscriber","context","Error"],"mappings":"AAAA;;AAGA,SAAyBA,WAAW,EAAEC,SAAS,QAAQ,QAAO;AAC9D,SAASC,aAAa,EAAEC,UAAU,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAIpE,SAASC,YAAY,QAAQ,iCAAgC;AAW7D,MAAMC,kCAAoBL,cAAiDM;AAO3E;;;;;;;CAOC,GACD,OAAO,SAASC,mBAAmB,EAAEC,QAAQ,EAAiB;IAC5D,2BAA2B;IAC3B,MAAM,CAACC,YAAYC,cAAc,GAAGP,SAClC;IAGF,MAAM,EAAEQ,SAAS,EAAE,GAAGP;IAEtB,uDAAuD;IACvD,MAAM,CAACQ,UAAUC,YAAY,GAAGV,SAAS;IAEzC,MAAM,CAACW,aAAaC,eAAe,GAAGZ;IAEtC,MAAMa,oBAAoBlB,YAAY;QACpC,MAAMmB,iBAAiB;YACrBJ,YAAY;YACZ,IAAI;gBACF,MAAMK,eAAe,MAAMC,MAAM,uBAAuB;oBACtD,4BAA4B;oBAC5BC,QAAQ;gBACV;gBAEA,IAAIF,aAAaG,EAAE,EAAE;oBACnB,gDAAgD;oBAChD,MAAMC,mBAAmB,MAAMJ,aAAaK,IAAI;oBAChD,kFAAkF;oBAClF,MAAM,EAAET,WAAW,EAAEL,UAAU,EAAE,GAAGa;oBACpC,2CAA2C;oBAC3C,6CAA6C;oBAC7CP,eAAeD;oBACfJ,cAAcD;gBAChB,OAAO;oBACLM,eAAe;oBACfL,cAAc;gBAChB;YACF,EAAE,OAAOc,OAAgB;gBACvBC,QAAQC,GAAG,CAAC,CAAC,kBAAkB,CAAC,EAAEF;YACpC;YACAX,YAAY;QACd;QACA,MAAMI;IACR,GAAG;QAACN;KAAU;IAEd,MAAMgB,SAAS7B,YAAY;QACzBe,YAAY;QACZ,IAAI;YACF,uCAAuC;YACvC,8BAA8B;YAC9B,KAAK;YACL,6CAA6C;YAC7C,cAAc;YACd,oBAAoB;YACpB,yBAAyB;YACzB,KAAK;YACL,oCAAoC;YACpC,MAAMe,iBAAiB,MAAMT,MAAM,eAAe;gBAChDC,QAAQ;YACV;YAEA,gDAAgD;YAEhD,IAAIQ,eAAeP,EAAE,EAAE;gBACrBX,cAAc;gBACdK,eAAe;YACjB;QACF,EAAE,OAAOS,OAAgB;YACvBC,QAAQC,GAAG,CAAC,CAAC,oBAAoB,CAAC,EAAEF;QACtC;QACAX,YAAY;IACd,GAAG,EAAE;IAELd,UAAU;QACR,KAAKiB;IACP,GAAG;QAACA;KAAkB;IAEtB,mEAAmE;IACnE,MAAMa,eAAsC3B,QAC1C,IAAO,CAAA;YACLU;YACAe;YACAb;YACAE;YACAP;QACF,CAAA,GACA;QAACG;QAAUe;QAAQb;QAAaE;QAAmBP;KAAW;IAGhE,qBAAO,KAACJ,kBAAkByB,QAAQ;QAACC,OAAOF;kBAAerB;;AAC3D;AAEA;;;;;CAKC,GACD,OAAO,SAASwB;IACd,MAAMC,UAAUhC,WAAWI;IAC3B,IAAI4B,YAAY3B,WAAW;QACzB,MAAM,IAAI4B,MAAM;IAClB;IACA,OAAOD;AACT"}
@@ -1,5 +1,5 @@
1
- import type { OptInChannel } from '../copied/payload-types.js';
2
1
  import type { Endpoint, PayloadHandler } from 'payload';
2
+ import type { OptInChannel } from '../copied/payload-types.js';
3
3
  export type GetOptInChannelsResponse = {
4
4
  error: string;
5
5
  now: string;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoints/getOptInChannels.ts"],"sourcesContent":["import type { OptInChannel } from '../copied/payload-types.js'\nimport type { CollectionSlug, Endpoint, PayloadHandler } from 'payload'\n\nimport { OptInChannels as OptInChannelCollection } from '../collections/OptInChannels.js'\n\nexport type GetOptInChannelsResponse =\n | {\n error: string\n now: string\n }\n | {\n now: string\n optInChannels: OptInChannel[]\n }\n\n/**\n * Payload handler for GET /optinchannels. Returns all active opt-in channels\n * for subscription preferences.\n *\n * @param req - Payload request object\n * @returns Response with `optInChannels` array on success, or `error` and `now` on failure (400)\n */\nexport const getOptInChannelsHandler: PayloadHandler = async (req) => {\n const findResults = await req.payload.find({\n collection: OptInChannelCollection.slug as CollectionSlug,\n depth: 2,\n where: {\n active: { equals: true },\n },\n })\n // .catch((error) => {\n // return Response.json({ error, now: new Date().toISOString() } as GetOptInChannelsResponse, {\n // status: 400,\n // })\n // })\n\n if (!findResults) {\n return Response.json(\n { error: 'Unknown find result', now: new Date().toISOString() } as GetOptInChannelsResponse,\n { status: 400 },\n )\n }\n\n return Response.json({\n now: new Date().toISOString(),\n optInChannels: findResults.docs,\n } as GetOptInChannelsResponse)\n}\n\n/**\n * Endpoint config for listing active opt-in channels. Mount as GET /optinchannels.\n * Used by the subscribe UI to fetch available subscription channels.\n */\nconst getOptInChannelsEndpoint: Endpoint = {\n handler: getOptInChannelsHandler,\n method: 'get',\n path: '/optinchannels',\n}\n\nexport default getOptInChannelsEndpoint\n"],"names":["OptInChannels","OptInChannelCollection","getOptInChannelsHandler","req","findResults","payload","find","collection","slug","depth","where","active","equals","Response","json","error","now","Date","toISOString","status","optInChannels","docs","getOptInChannelsEndpoint","handler","method","path"],"mappings":"AAGA,SAASA,iBAAiBC,sBAAsB,QAAQ,kCAAiC;AAYzF;;;;;;CAMC,GACD,OAAO,MAAMC,0BAA0C,OAAOC;IAC5D,MAAMC,cAAc,MAAMD,IAAIE,OAAO,CAACC,IAAI,CAAC;QACzCC,YAAYN,uBAAuBO,IAAI;QACvCC,OAAO;QACPC,OAAO;YACLC,QAAQ;gBAAEC,QAAQ;YAAK;QACzB;IACF;IACA,sBAAsB;IACtB,iGAAiG;IACjG,mBAAmB;IACnB,OAAO;IACP,KAAK;IAEL,IAAI,CAACR,aAAa;QAChB,OAAOS,SAASC,IAAI,CAClB;YAAEC,OAAO;YAAuBC,KAAK,IAAIC,OAAOC,WAAW;QAAG,GAC9D;YAAEC,QAAQ;QAAI;IAElB;IAEA,OAAON,SAASC,IAAI,CAAC;QACnBE,KAAK,IAAIC,OAAOC,WAAW;QAC3BE,eAAehB,YAAYiB,IAAI;IACjC;AACF,EAAC;AAED;;;CAGC,GACD,MAAMC,2BAAqC;IACzCC,SAASrB;IACTsB,QAAQ;IACRC,MAAM;AACR;AAEA,eAAeH,yBAAwB"}
1
+ {"version":3,"sources":["../../src/endpoints/getOptInChannels.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadHandler } from 'payload'\n\nimport type { OptInChannel } from '../copied/payload-types.js'\n\nimport { OptInChannels as OptInChannelCollection } from '../collections/OptInChannels.js'\n\nexport type GetOptInChannelsResponse =\n | {\n error: string\n now: string\n }\n | {\n now: string\n optInChannels: OptInChannel[]\n }\n\n/**\n * Payload handler for GET /optinchannels. Returns all active opt-in channels\n * for subscription preferences.\n *\n * @param req - Payload request object\n * @returns Response with `optInChannels` array on success, or `error` and `now` on failure (400)\n */\nexport const getOptInChannelsHandler: PayloadHandler = async (req) => {\n const findResults = await req.payload.find({\n collection: OptInChannelCollection.slug as CollectionSlug,\n depth: 2,\n where: {\n active: { equals: true },\n },\n })\n // .catch((error) => {\n // return Response.json({ error, now: new Date().toISOString() } as GetOptInChannelsResponse, {\n // status: 400,\n // })\n // })\n\n if (!findResults) {\n return Response.json(\n { error: 'Unknown find result', now: new Date().toISOString() } as GetOptInChannelsResponse,\n { status: 400 },\n )\n }\n\n return Response.json({\n now: new Date().toISOString(),\n optInChannels: findResults.docs,\n } as GetOptInChannelsResponse)\n}\n\n/**\n * Endpoint config for listing active opt-in channels. Mount as GET /optinchannels.\n * Used by the subscribe UI to fetch available subscription channels.\n */\nconst getOptInChannelsEndpoint: Endpoint = {\n handler: getOptInChannelsHandler,\n method: 'get',\n path: '/optinchannels',\n}\n\nexport default getOptInChannelsEndpoint\n"],"names":["OptInChannels","OptInChannelCollection","getOptInChannelsHandler","req","findResults","payload","find","collection","slug","depth","where","active","equals","Response","json","error","now","Date","toISOString","status","optInChannels","docs","getOptInChannelsEndpoint","handler","method","path"],"mappings":"AAIA,SAASA,iBAAiBC,sBAAsB,QAAQ,kCAAiC;AAYzF;;;;;;CAMC,GACD,OAAO,MAAMC,0BAA0C,OAAOC;IAC5D,MAAMC,cAAc,MAAMD,IAAIE,OAAO,CAACC,IAAI,CAAC;QACzCC,YAAYN,uBAAuBO,IAAI;QACvCC,OAAO;QACPC,OAAO;YACLC,QAAQ;gBAAEC,QAAQ;YAAK;QACzB;IACF;IACA,sBAAsB;IACtB,iGAAiG;IACjG,mBAAmB;IACnB,OAAO;IACP,KAAK;IAEL,IAAI,CAACR,aAAa;QAChB,OAAOS,SAASC,IAAI,CAClB;YAAEC,OAAO;YAAuBC,KAAK,IAAIC,OAAOC,WAAW;QAAG,GAC9D;YAAEC,QAAQ;QAAI;IAElB;IAEA,OAAON,SAASC,IAAI,CAAC;QACnBE,KAAK,IAAIC,OAAOC,WAAW;QAC3BE,eAAehB,YAAYiB,IAAI;IACjC;AACF,EAAC;AAED;;;CAGC,GACD,MAAMC,2BAAqC;IACzCC,SAASrB;IACTsB,QAAQ;IACRC,MAAM;AACR;AAEA,eAAeH,yBAAwB"}
@@ -1,4 +1,5 @@
1
1
  import { headers as nextHeaders } from 'next/headers.js';
2
+ import { OptInChannels as OptInChannelCollection } from '../collections/OptInChannels.js';
2
3
  import { defaultCollectionSlug } from '../collections/Subscribers.js';
3
4
  /**
4
5
  * Factory that creates the subscriber-auth endpoint config and handler.
@@ -27,7 +28,26 @@ import { defaultCollectionSlug } from '../collections/Subscribers.js';
27
28
  if (user && user.collection == subscribersCollectionSlug) {
28
29
  const subscriber = user;
29
30
  if (subscriber.optIns) {
30
- subscriber.optIns = subscriber.optIns.map((channel)=>typeof channel == 'string' ? channel : channel.id);
31
+ // subscriber.optIns = subscriber.optIns.map((channel) =>
32
+ // typeof channel == 'string' ? channel : channel.id,
33
+ // )
34
+ const channelsToGet = subscriber.optIns.map((channel)=>typeof channel == 'string' ? channel : channel.id);
35
+ const findResults = await req.payload.find({
36
+ collection: OptInChannelCollection.slug,
37
+ depth: 2,
38
+ where: {
39
+ id: {
40
+ in: channelsToGet
41
+ }
42
+ }
43
+ });
44
+ if (!findResults) {
45
+ req.payload.logger.info(`Error getting optIns data: ${JSON.stringify({
46
+ error: 'Unknown find result'
47
+ })}`);
48
+ } else {
49
+ subscriber.optIns = findResults.docs.map((c)=>c);
50
+ }
31
51
  }
32
52
  return Response.json({
33
53
  now: new Date().toISOString(),
@@ -43,7 +63,7 @@ import { defaultCollectionSlug } from '../collections/Subscribers.js';
43
63
  subscriber: null
44
64
  }, {
45
65
  headers,
46
- status: 400
66
+ status: 200
47
67
  });
48
68
  } catch (error) {
49
69
  // req.payload.logger.info(`subscriberAuth error: ${JSON.stringify(error)}`)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoints/subscriberAuth.ts"],"sourcesContent":["import { headers as nextHeaders } from 'next/headers.js'\n\nimport type { Subscriber } from '../copied/payload-types.js'\n\n// If you're using Next.js, you'll have to import headers from next/headers, like so:\nimport type { CollectionSlug, Endpoint, PayloadHandler, Permissions } from 'payload'\n\nimport { defaultCollectionSlug } from '../collections/Subscribers.js'\n\nexport type SubscriberAuthResponse =\n | {\n error: string\n now: string\n }\n | {\n now: string\n permissions: Permissions\n subscriber: null | Subscriber\n }\n\n/**\n * Factory that creates the subscriber-auth endpoint config and handler.\n * Authenticates the current request via Payload auth and returns the subscriber and permissions if from the subscribers collection.\n *\n * @param options - Config options for the endpoint\n * @param options.subscribersCollectionSlug - Collection slug for subscribers (default from Subscribers collection)\n * @returns Payload Endpoint config for POST /subscriberAuth\n */\nfunction createEndpointSubscriberAuth({\n subscribersCollectionSlug = defaultCollectionSlug,\n}: {\n subscribersCollectionSlug: CollectionSlug\n}): Endpoint {\n /**\n * Handler for POST /subscriberAuth. Uses Payload auth (e.g. cookies) to resolve the current user;\n * if the user belongs to the subscribers collection, returns subscriber and permissions.\n *\n * @param req - Payload request (auth via headers)\n * @returns 200 with `subscriber`, `permissions`, `now` when a subscriber is authed; 400 with `subscriber: null` or `error` otherwise\n */\n const subscriberAuthHandler: PayloadHandler = async (req) => {\n // req.payload.logger.info('subscriberAuthHandler')\n // Log the user in via Payload headers\n const headers = await nextHeaders()\n\n try {\n const { permissions, user } = await req.payload.auth({\n headers,\n })\n\n // req.payload.logger.info(`user = ${JSON.stringify(user)}`)\n // req.payload.logger.info(`permissions = ${JSON.stringify(permissions)}`)\n\n if (user && user.collection == subscribersCollectionSlug) {\n const subscriber: Subscriber = user as Subscriber\n if (subscriber.optIns) {\n subscriber.optIns = subscriber.optIns.map((channel) =>\n typeof channel == 'string' ? channel : channel.id,\n )\n }\n return Response.json({\n now: new Date().toISOString(),\n permissions,\n subscriber,\n } as SubscriberAuthResponse)\n }\n\n // req.payload.logger.info('subscriberAuthHandler: No subscriber authed')\n return Response.json(\n {\n // error: 'No subscriber authed',\n now: new Date().toISOString(),\n permissions,\n subscriber: null,\n } as SubscriberAuthResponse,\n { headers, status: 400 },\n )\n } catch (error: unknown) {\n // req.payload.logger.info(`subscriberAuth error: ${JSON.stringify(error)}`)\n return Response.json(\n {\n error,\n now: new Date().toISOString(),\n } as SubscriberAuthResponse,\n { headers, status: 400 },\n )\n }\n }\n\n /** Endpoint config for checking current subscriber auth. Mount as POST /subscriberAuth. */\n const subscriberAuthEndpoint: Endpoint = {\n handler: subscriberAuthHandler,\n method: 'post',\n path: '/subscriberAuth',\n }\n return subscriberAuthEndpoint\n}\n\nexport default createEndpointSubscriberAuth\n"],"names":["headers","nextHeaders","defaultCollectionSlug","createEndpointSubscriberAuth","subscribersCollectionSlug","subscriberAuthHandler","req","permissions","user","payload","auth","collection","subscriber","optIns","map","channel","id","Response","json","now","Date","toISOString","status","error","subscriberAuthEndpoint","handler","method","path"],"mappings":"AAAA,SAASA,WAAWC,WAAW,QAAQ,kBAAiB;AAOxD,SAASC,qBAAqB,QAAQ,gCAA+B;AAarE;;;;;;;CAOC,GACD,SAASC,6BAA6B,EACpCC,4BAA4BF,qBAAqB,EAGlD;IACC;;;;;;GAMC,GACD,MAAMG,wBAAwC,OAAOC;QACnD,mDAAmD;QACnD,sCAAsC;QACtC,MAAMN,UAAU,MAAMC;QAEtB,IAAI;YACF,MAAM,EAAEM,WAAW,EAAEC,IAAI,EAAE,GAAG,MAAMF,IAAIG,OAAO,CAACC,IAAI,CAAC;gBACnDV;YACF;YAEA,4DAA4D;YAC5D,0EAA0E;YAE1E,IAAIQ,QAAQA,KAAKG,UAAU,IAAIP,2BAA2B;gBACxD,MAAMQ,aAAyBJ;gBAC/B,IAAII,WAAWC,MAAM,EAAE;oBACrBD,WAAWC,MAAM,GAAGD,WAAWC,MAAM,CAACC,GAAG,CAAC,CAACC,UACzC,OAAOA,WAAW,WAAWA,UAAUA,QAAQC,EAAE;gBAErD;gBACA,OAAOC,SAASC,IAAI,CAAC;oBACnBC,KAAK,IAAIC,OAAOC,WAAW;oBAC3Bd;oBACAK;gBACF;YACF;YAEA,yEAAyE;YACzE,OAAOK,SAASC,IAAI,CAClB;gBACE,iCAAiC;gBACjCC,KAAK,IAAIC,OAAOC,WAAW;gBAC3Bd;gBACAK,YAAY;YACd,GACA;gBAAEZ;gBAASsB,QAAQ;YAAI;QAE3B,EAAE,OAAOC,OAAgB;YACvB,4EAA4E;YAC5E,OAAON,SAASC,IAAI,CAClB;gBACEK;gBACAJ,KAAK,IAAIC,OAAOC,WAAW;YAC7B,GACA;gBAAErB;gBAASsB,QAAQ;YAAI;QAE3B;IACF;IAEA,yFAAyF,GACzF,MAAME,yBAAmC;QACvCC,SAASpB;QACTqB,QAAQ;QACRC,MAAM;IACR;IACA,OAAOH;AACT;AAEA,eAAerB,6BAA4B"}
1
+ {"version":3,"sources":["../../src/endpoints/subscriberAuth.ts"],"sourcesContent":["import { headers as nextHeaders } from 'next/headers.js'\n\nimport type { OptInChannel, Subscriber } from '../copied/payload-types.js'\n\nimport { OptInChannels as OptInChannelCollection } from '../collections/OptInChannels.js'\n\n// If you're using Next.js, you'll have to import headers from next/headers, like so:\nimport type { CollectionSlug, Endpoint, PayloadHandler, Permissions } from 'payload'\n\nimport type { GetOptInChannelsResponse } from './getOptInChannels.js'\n\nimport { defaultCollectionSlug } from '../collections/Subscribers.js'\n\nexport type SubscriberAuthResponse =\n | {\n error: string\n now: string\n }\n | {\n now: string\n permissions: Permissions\n subscriber: null | Subscriber\n }\n\n/**\n * Factory that creates the subscriber-auth endpoint config and handler.\n * Authenticates the current request via Payload auth and returns the subscriber and permissions if from the subscribers collection.\n *\n * @param options - Config options for the endpoint\n * @param options.subscribersCollectionSlug - Collection slug for subscribers (default from Subscribers collection)\n * @returns Payload Endpoint config for POST /subscriberAuth\n */\nfunction createEndpointSubscriberAuth({\n subscribersCollectionSlug = defaultCollectionSlug,\n}: {\n subscribersCollectionSlug: CollectionSlug\n}): Endpoint {\n /**\n * Handler for POST /subscriberAuth. Uses Payload auth (e.g. cookies) to resolve the current user;\n * if the user belongs to the subscribers collection, returns subscriber and permissions.\n *\n * @param req - Payload request (auth via headers)\n * @returns 200 with `subscriber`, `permissions`, `now` when a subscriber is authed; 400 with `subscriber: null` or `error` otherwise\n */\n const subscriberAuthHandler: PayloadHandler = async (req) => {\n // req.payload.logger.info('subscriberAuthHandler')\n // Log the user in via Payload headers\n const headers = await nextHeaders()\n\n try {\n const { permissions, user } = await req.payload.auth({\n headers,\n })\n\n // req.payload.logger.info(`user = ${JSON.stringify(user)}`)\n // req.payload.logger.info(`permissions = ${JSON.stringify(permissions)}`)\n\n if (user && user.collection == subscribersCollectionSlug) {\n const subscriber: Subscriber = user as Subscriber\n if (subscriber.optIns) {\n // subscriber.optIns = subscriber.optIns.map((channel) =>\n // typeof channel == 'string' ? channel : channel.id,\n // )\n const channelsToGet = subscriber.optIns.map((channel) =>\n typeof channel == 'string' ? channel : channel.id,\n )\n const findResults = await req.payload.find({\n collection: OptInChannelCollection.slug as CollectionSlug,\n depth: 2,\n where: {\n id: { in: channelsToGet },\n },\n })\n\n if (!findResults) {\n req.payload.logger.info(\n `Error getting optIns data: ${JSON.stringify({\n error: 'Unknown find result',\n // now: new Date().toISOString(),\n } as GetOptInChannelsResponse)}`,\n )\n } else {\n subscriber.optIns = findResults.docs.map((c) => c as OptInChannel)\n }\n }\n return Response.json({\n now: new Date().toISOString(),\n permissions,\n subscriber,\n } as SubscriberAuthResponse)\n }\n\n // req.payload.logger.info('subscriberAuthHandler: No subscriber authed')\n return Response.json(\n {\n // error: 'No subscriber authed',\n now: new Date().toISOString(),\n permissions,\n subscriber: null,\n } as SubscriberAuthResponse,\n { headers, status: 200 },\n )\n } catch (error: unknown) {\n // req.payload.logger.info(`subscriberAuth error: ${JSON.stringify(error)}`)\n return Response.json(\n {\n error,\n now: new Date().toISOString(),\n } as SubscriberAuthResponse,\n { headers, status: 400 },\n )\n }\n }\n\n /** Endpoint config for checking current subscriber auth. Mount as POST /subscriberAuth. */\n const subscriberAuthEndpoint: Endpoint = {\n handler: subscriberAuthHandler,\n method: 'post',\n path: '/subscriberAuth',\n }\n return subscriberAuthEndpoint\n}\n\nexport default createEndpointSubscriberAuth\n"],"names":["headers","nextHeaders","OptInChannels","OptInChannelCollection","defaultCollectionSlug","createEndpointSubscriberAuth","subscribersCollectionSlug","subscriberAuthHandler","req","permissions","user","payload","auth","collection","subscriber","optIns","channelsToGet","map","channel","id","findResults","find","slug","depth","where","in","logger","info","JSON","stringify","error","docs","c","Response","json","now","Date","toISOString","status","subscriberAuthEndpoint","handler","method","path"],"mappings":"AAAA,SAASA,WAAWC,WAAW,QAAQ,kBAAiB;AAIxD,SAASC,iBAAiBC,sBAAsB,QAAQ,kCAAiC;AAOzF,SAASC,qBAAqB,QAAQ,gCAA+B;AAarE;;;;;;;CAOC,GACD,SAASC,6BAA6B,EACpCC,4BAA4BF,qBAAqB,EAGlD;IACC;;;;;;GAMC,GACD,MAAMG,wBAAwC,OAAOC;QACnD,mDAAmD;QACnD,sCAAsC;QACtC,MAAMR,UAAU,MAAMC;QAEtB,IAAI;YACF,MAAM,EAAEQ,WAAW,EAAEC,IAAI,EAAE,GAAG,MAAMF,IAAIG,OAAO,CAACC,IAAI,CAAC;gBACnDZ;YACF;YAEA,4DAA4D;YAC5D,0EAA0E;YAE1E,IAAIU,QAAQA,KAAKG,UAAU,IAAIP,2BAA2B;gBACxD,MAAMQ,aAAyBJ;gBAC/B,IAAII,WAAWC,MAAM,EAAE;oBACrB,yDAAyD;oBACzD,uDAAuD;oBACvD,IAAI;oBACJ,MAAMC,gBAAgBF,WAAWC,MAAM,CAACE,GAAG,CAAC,CAACC,UAC3C,OAAOA,WAAW,WAAWA,UAAUA,QAAQC,EAAE;oBAEnD,MAAMC,cAAc,MAAMZ,IAAIG,OAAO,CAACU,IAAI,CAAC;wBACzCR,YAAYV,uBAAuBmB,IAAI;wBACvCC,OAAO;wBACPC,OAAO;4BACLL,IAAI;gCAAEM,IAAIT;4BAAc;wBAC1B;oBACF;oBAEA,IAAI,CAACI,aAAa;wBAChBZ,IAAIG,OAAO,CAACe,MAAM,CAACC,IAAI,CACrB,CAAC,2BAA2B,EAAEC,KAAKC,SAAS,CAAC;4BAC3CC,OAAO;wBAET,IAAgC;oBAEpC,OAAO;wBACLhB,WAAWC,MAAM,GAAGK,YAAYW,IAAI,CAACd,GAAG,CAAC,CAACe,IAAMA;oBAClD;gBACF;gBACA,OAAOC,SAASC,IAAI,CAAC;oBACnBC,KAAK,IAAIC,OAAOC,WAAW;oBAC3B5B;oBACAK;gBACF;YACF;YAEA,yEAAyE;YACzE,OAAOmB,SAASC,IAAI,CAClB;gBACE,iCAAiC;gBACjCC,KAAK,IAAIC,OAAOC,WAAW;gBAC3B5B;gBACAK,YAAY;YACd,GACA;gBAAEd;gBAASsC,QAAQ;YAAI;QAE3B,EAAE,OAAOR,OAAgB;YACvB,4EAA4E;YAC5E,OAAOG,SAASC,IAAI,CAClB;gBACEJ;gBACAK,KAAK,IAAIC,OAAOC,WAAW;YAC7B,GACA;gBAAErC;gBAASsC,QAAQ;YAAI;QAE3B;IACF;IAEA,yFAAyF,GACzF,MAAMC,yBAAmC;QACvCC,SAASjC;QACTkC,QAAQ;QACRC,MAAM;IACR;IACA,OAAOH;AACT;AAEA,eAAelC,6BAA4B"}
@@ -15,3 +15,4 @@ export { useSubscribe } from '../hooks/useSubscribe.js';
15
15
  export { useUnsubscribe } from '../hooks/useUnsubscribe.js';
16
16
  export { useVerifyMagicLink } from '../hooks/useVerifyMagicLink.js';
17
17
  export { getServerUrl } from '../server-functions/serverUrl.js';
18
+ export type { OptInChannel } from 'src/copied/payload-types.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/exports/ui.ts"],"sourcesContent":["export type { RequestMagicLinkResponse } from '../components/app/RequestMagicLink.js'\nexport { RequestMagicLink } from '../components/app/RequestMagicLink.js'\n\nexport { RequestOrSubscribe } from '../components/app/RequestOrSubscribe.js'\n\nexport type { SubscribeResponse } from '../components/app/Subscribe.js'\nexport { Subscribe } from '../components/app/Subscribe.js'\n\nexport { SubscriberMenu } from '../components/app/SubscriberMenu.js'\n\nexport type { UnsubscribeResponse } from '../components/app/Unsubscribe.js'\nexport { Unsubscribe } from '../components/app/Unsubscribe.js'\n\nexport type { VerifyMagicLinkResponse } from '../components/app/VerifyMagicLink.js'\nexport { VerifyMagicLink } from '../components/app/VerifyMagicLink.js'\n\nexport type { SubscriberContextType } from '../contexts/SubscriberProvider.js'\nexport { SubscriberProvider, useSubscriber } from '../contexts/SubscriberProvider.js'\n\nexport { useRequestMagicLink } from '../hooks/useRequestMagicLink.js'\nexport { useSubscribe } from '../hooks/useSubscribe.js'\nexport { useUnsubscribe } from '../hooks/useUnsubscribe.js'\nexport { useVerifyMagicLink } from '../hooks/useVerifyMagicLink.js'\n\nexport { getServerUrl } from '../server-functions/serverUrl.js'\n"],"names":["RequestMagicLink","RequestOrSubscribe","Subscribe","SubscriberMenu","Unsubscribe","VerifyMagicLink","SubscriberProvider","useSubscriber","useRequestMagicLink","useSubscribe","useUnsubscribe","useVerifyMagicLink","getServerUrl"],"mappings":"AACA,SAASA,gBAAgB,QAAQ,wCAAuC;AAExE,SAASC,kBAAkB,QAAQ,0CAAyC;AAG5E,SAASC,SAAS,QAAQ,iCAAgC;AAE1D,SAASC,cAAc,QAAQ,sCAAqC;AAGpE,SAASC,WAAW,QAAQ,mCAAkC;AAG9D,SAASC,eAAe,QAAQ,uCAAsC;AAGtE,SAASC,kBAAkB,EAAEC,aAAa,QAAQ,oCAAmC;AAErF,SAASC,mBAAmB,QAAQ,kCAAiC;AACrE,SAASC,YAAY,QAAQ,2BAA0B;AACvD,SAASC,cAAc,QAAQ,6BAA4B;AAC3D,SAASC,kBAAkB,QAAQ,iCAAgC;AAEnE,SAASC,YAAY,QAAQ,mCAAkC"}
1
+ {"version":3,"sources":["../../src/exports/ui.ts"],"sourcesContent":["export type { RequestMagicLinkResponse } from '../components/app/RequestMagicLink.js'\nexport { RequestMagicLink } from '../components/app/RequestMagicLink.js'\n\nexport { RequestOrSubscribe } from '../components/app/RequestOrSubscribe.js'\n\nexport type { SubscribeResponse } from '../components/app/Subscribe.js'\nexport { Subscribe } from '../components/app/Subscribe.js'\n\nexport { SubscriberMenu } from '../components/app/SubscriberMenu.js'\n\nexport type { UnsubscribeResponse } from '../components/app/Unsubscribe.js'\nexport { Unsubscribe } from '../components/app/Unsubscribe.js'\n\nexport type { VerifyMagicLinkResponse } from '../components/app/VerifyMagicLink.js'\nexport { VerifyMagicLink } from '../components/app/VerifyMagicLink.js'\n\nexport type { SubscriberContextType } from '../contexts/SubscriberProvider.js'\nexport { SubscriberProvider, useSubscriber } from '../contexts/SubscriberProvider.js'\n\nexport { useRequestMagicLink } from '../hooks/useRequestMagicLink.js'\nexport { useSubscribe } from '../hooks/useSubscribe.js'\nexport { useUnsubscribe } from '../hooks/useUnsubscribe.js'\nexport { useVerifyMagicLink } from '../hooks/useVerifyMagicLink.js'\n\nexport { getServerUrl } from '../server-functions/serverUrl.js'\n\nexport type { OptInChannel } from 'src/copied/payload-types.js'\n"],"names":["RequestMagicLink","RequestOrSubscribe","Subscribe","SubscriberMenu","Unsubscribe","VerifyMagicLink","SubscriberProvider","useSubscriber","useRequestMagicLink","useSubscribe","useUnsubscribe","useVerifyMagicLink","getServerUrl"],"mappings":"AACA,SAASA,gBAAgB,QAAQ,wCAAuC;AAExE,SAASC,kBAAkB,QAAQ,0CAAyC;AAG5E,SAASC,SAAS,QAAQ,iCAAgC;AAE1D,SAASC,cAAc,QAAQ,sCAAqC;AAGpE,SAASC,WAAW,QAAQ,mCAAkC;AAG9D,SAASC,eAAe,QAAQ,uCAAsC;AAGtE,SAASC,kBAAkB,EAAEC,aAAa,QAAQ,oCAAmC;AAErF,SAASC,mBAAmB,QAAQ,kCAAiC;AACrE,SAASC,YAAY,QAAQ,2BAA0B;AACvD,SAASC,cAAc,QAAQ,6BAA4B;AAC3D,SAASC,kBAAkB,QAAQ,iCAAgC;AAEnE,SAASC,YAAY,QAAQ,mCAAkC"}
@@ -1,4 +1,4 @@
1
- import type { Subscriber } from '../copied/payload-types.js';
1
+ import type { OptInChannel, Subscriber } from '../copied/payload-types.js';
2
2
  import type { SubscribeResponse } from '../endpoints/subscribe.js';
3
3
  export { SubscribeResponse };
4
4
  /**
@@ -20,9 +20,12 @@ export interface IUseSubscribeOptions {
20
20
  * @property updateSubscriptions - Updates opt-in channels for the current subscriber
21
21
  */
22
22
  export interface IUseSubscribe {
23
+ optInChannels: OptInChannel[];
23
24
  result?: string;
24
25
  status?: UpdateSubscriptionStatusValue;
25
- subscriber: null | Subscriber;
26
+ subscriber: ({
27
+ optIns?: null | OptInChannel[];
28
+ } & Omit<Subscriber, 'optIns'>) | null;
26
29
  updateSubscriptions: (selectedChannelIDs: string[]) => Promise<void>;
27
30
  }
28
31
  export type UpdateSubscriptionStatusValue = 'default' | 'error' | 'sent' | 'updated' | 'updating';
@@ -1,6 +1,7 @@
1
1
  'use client';
2
- import { useState } from 'react';
2
+ import { useEffect, useState } from 'react';
3
3
  import { useSubscriber } from '../contexts/SubscriberProvider.js';
4
+ import { useServerUrl } from '../react-hooks/useServerUrl.js';
4
5
  /**
5
6
  * Hook to update subscriber opt-in channels. Calls POST /api/subscribe, refreshes subscriber
6
7
  * from context on success, and optionally invokes handleSubscribe.
@@ -11,6 +12,30 @@ import { useSubscriber } from '../contexts/SubscriberProvider.js';
11
12
  * @returns updateSubscriptions, subscriber, result message, and status (see IUseSubscribe)
12
13
  */ export const useSubscribe = ({ handleSubscribe, verifyData })=>{
13
14
  const { refreshSubscriber, subscriber } = useSubscriber();
15
+ const { serverURL } = useServerUrl();
16
+ const [optInChannels, setOptInChannels] = useState([]);
17
+ useEffect(()=>{
18
+ async function getOptInChannels() {
19
+ const result = await fetch(`${serverURL ? serverURL : ''}/api/optinchannels`, {
20
+ method: 'GET'
21
+ });
22
+ if (result.ok) {
23
+ const resultJson = await result.json();
24
+ // @ts-expect-error OR type union not recognized
25
+ setOptInChannels(resultJson?.optInChannels);
26
+ } else {
27
+ const resultText = await result.text();
28
+ console.log('Error getting opt-in channels: ', [
29
+ {
30
+ resultText
31
+ }
32
+ ]);
33
+ }
34
+ }
35
+ void getOptInChannels();
36
+ }, [
37
+ serverURL
38
+ ]);
14
39
  const [status, setStatus] = useState('default');
15
40
  const [result, setResult] = useState();
16
41
  const updateSubscriptions = async (selectedChannelIDs)=>{
@@ -52,6 +77,7 @@ import { useSubscriber } from '../contexts/SubscriberProvider.js';
52
77
  }
53
78
  };
54
79
  return {
80
+ optInChannels,
55
81
  result,
56
82
  status,
57
83
  subscriber,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/useSubscribe.tsx"],"sourcesContent":["'use client'\n\nimport { useState } from 'react'\n\nimport type { Subscriber } from '../copied/payload-types.js'\nimport type { SubscribeResponse } from '../endpoints/subscribe.js'\n\nexport { SubscribeResponse }\n\nimport { useSubscriber } from '../contexts/SubscriberProvider.js'\n\n/**\n * Options for the useSubscribe hook.\n *\n * @property handleSubscribe - Callback when subscription is updated or magic link is sent\n * @property verifyData - Optional data sent with subscribe requests (e.g. for verification)\n */\nexport interface IUseSubscribeOptions {\n handleSubscribe?: (result: SubscribeResponse) => void\n verifyData?: string\n}\n\n/**\n * Return value of useSubscribe.\n *\n * @property result - Success or error message from the last update\n * @property status - Current status: 'default' | 'updating' | 'updated' | 'sent' | 'error'\n * @property subscriber - Current subscriber from context, or null\n * @property updateSubscriptions - Updates opt-in channels for the current subscriber\n */\nexport interface IUseSubscribe {\n result?: string\n status?: UpdateSubscriptionStatusValue\n subscriber: null | Subscriber\n updateSubscriptions: (selectedChannelIDs: string[]) => Promise<void>\n}\n\nexport type UpdateSubscriptionStatusValue = 'default' | 'error' | 'sent' | 'updated' | 'updating'\n\n/**\n * Hook to update subscriber opt-in channels. Calls POST /api/subscribe, refreshes subscriber\n * from context on success, and optionally invokes handleSubscribe.\n *\n * @param options - Hook options (see IUseSubscribeOptions)\n * @param options.handleSubscribe - Callback when subscription is updated or magic link is sent\n * @param options.verifyData - Optional data sent with subscribe requests (e.g. for verification)\n * @returns updateSubscriptions, subscriber, result message, and status (see IUseSubscribe)\n */\nexport const useSubscribe = ({\n handleSubscribe,\n verifyData,\n}: IUseSubscribeOptions): IUseSubscribe => {\n const { refreshSubscriber, subscriber } = useSubscriber()\n\n const [status, setStatus] = useState<UpdateSubscriptionStatusValue>('default')\n const [result, setResult] = useState<string>()\n\n const updateSubscriptions = async (selectedChannelIDs: string[]) => {\n setStatus('updating')\n setResult(`Updating...`)\n const subscribeResult = await fetch('/api/subscribe', {\n body: JSON.stringify({\n email: subscriber?.email,\n optIns: selectedChannelIDs,\n verifyData,\n }),\n method: 'POST',\n })\n if (subscribeResult.ok) {\n const resultJson: SubscribeResponse = await subscribeResult.json()\n // @ts-expect-error Silly type confusion\n const { emailResult, error } = resultJson\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 if (subscriber) {\n setStatus('updated')\n setResult(`You're subscriptions have been updated.`)\n } else {\n setStatus('error')\n setResult(`An error occured. Please try again. \\nResult unknown`)\n }\n\n refreshSubscriber()\n\n if (handleSubscribe) {\n handleSubscribe(resultJson)\n }\n } else {\n // const resultText = await subscribeResult.text()\n setStatus('error')\n setResult(`An error occured. Please try again. \\nResult unknown`)\n }\n }\n\n return {\n result,\n status,\n subscriber,\n updateSubscriptions,\n }\n}\n"],"names":["useState","useSubscriber","useSubscribe","handleSubscribe","verifyData","refreshSubscriber","subscriber","status","setStatus","result","setResult","updateSubscriptions","selectedChannelIDs","subscribeResult","fetch","body","JSON","stringify","email","optIns","method","ok","resultJson","json","emailResult","error"],"mappings":"AAAA;AAEA,SAASA,QAAQ,QAAQ,QAAO;AAOhC,SAASC,aAAa,QAAQ,oCAAmC;AA8BjE;;;;;;;;CAQC,GACD,OAAO,MAAMC,eAAe,CAAC,EAC3BC,eAAe,EACfC,UAAU,EACW;IACrB,MAAM,EAAEC,iBAAiB,EAAEC,UAAU,EAAE,GAAGL;IAE1C,MAAM,CAACM,QAAQC,UAAU,GAAGR,SAAwC;IACpE,MAAM,CAACS,QAAQC,UAAU,GAAGV;IAE5B,MAAMW,sBAAsB,OAAOC;QACjCJ,UAAU;QACVE,UAAU,CAAC,WAAW,CAAC;QACvB,MAAMG,kBAAkB,MAAMC,MAAM,kBAAkB;YACpDC,MAAMC,KAAKC,SAAS,CAAC;gBACnBC,OAAOZ,YAAYY;gBACnBC,QAAQP;gBACRR;YACF;YACAgB,QAAQ;QACV;QACA,IAAIP,gBAAgBQ,EAAE,EAAE;YACtB,MAAMC,aAAgC,MAAMT,gBAAgBU,IAAI;YAChE,wCAAwC;YACxC,MAAM,EAAEC,WAAW,EAAEC,KAAK,EAAE,GAAGH;YAC/B,IAAIG,OAAO;gBACTjB,UAAU;gBACVE,UAAU,CAAC,uCAAuC,EAAEe,OAAO;YAC7D,OAAO,IAAID,aAAa;gBACtBhB,UAAU;gBACVE,UAAU;YACZ,OAAO,IAAIJ,YAAY;gBACrBE,UAAU;gBACVE,UAAU,CAAC,uCAAuC,CAAC;YACrD,OAAO;gBACLF,UAAU;gBACVE,UAAU,CAAC,oDAAoD,CAAC;YAClE;YAEAL;YAEA,IAAIF,iBAAiB;gBACnBA,gBAAgBmB;YAClB;QACF,OAAO;YACL,kDAAkD;YAClDd,UAAU;YACVE,UAAU,CAAC,oDAAoD,CAAC;QAClE;IACF;IAEA,OAAO;QACLD;QACAF;QACAD;QACAK;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/hooks/useSubscribe.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\n\nimport type { OptInChannel, Subscriber } from '../copied/payload-types.js'\nimport type { SubscribeResponse } from '../endpoints/subscribe.js'\n\nexport { SubscribeResponse }\n\nimport type { GetOptInChannelsResponse } from '../endpoints/getOptInChannels.js'\n\nimport { useSubscriber } from '../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../react-hooks/useServerUrl.js'\n\n/**\n * Options for the useSubscribe hook.\n *\n * @property handleSubscribe - Callback when subscription is updated or magic link is sent\n * @property verifyData - Optional data sent with subscribe requests (e.g. for verification)\n */\nexport interface IUseSubscribeOptions {\n handleSubscribe?: (result: SubscribeResponse) => void\n verifyData?: string\n}\n\n/**\n * Return value of useSubscribe.\n *\n * @property result - Success or error message from the last update\n * @property status - Current status: 'default' | 'updating' | 'updated' | 'sent' | 'error'\n * @property subscriber - Current subscriber from context, or null\n * @property updateSubscriptions - Updates opt-in channels for the current subscriber\n */\nexport interface IUseSubscribe {\n optInChannels: OptInChannel[]\n result?: string\n status?: UpdateSubscriptionStatusValue\n subscriber: ({ optIns?: null | OptInChannel[] } & Omit<Subscriber, 'optIns'>) | null\n updateSubscriptions: (selectedChannelIDs: string[]) => Promise<void>\n}\n\nexport type UpdateSubscriptionStatusValue = 'default' | 'error' | 'sent' | 'updated' | 'updating'\n\n/**\n * Hook to update subscriber opt-in channels. Calls POST /api/subscribe, refreshes subscriber\n * from context on success, and optionally invokes handleSubscribe.\n *\n * @param options - Hook options (see IUseSubscribeOptions)\n * @param options.handleSubscribe - Callback when subscription is updated or magic link is sent\n * @param options.verifyData - Optional data sent with subscribe requests (e.g. for verification)\n * @returns updateSubscriptions, subscriber, result message, and status (see IUseSubscribe)\n */\nexport const useSubscribe = ({\n handleSubscribe,\n verifyData,\n}: IUseSubscribeOptions): IUseSubscribe => {\n const { refreshSubscriber, subscriber } = useSubscriber()\n\n const { serverURL } = useServerUrl()\n const [optInChannels, setOptInChannels] = useState<OptInChannel[]>([])\n\n useEffect(() => {\n async function getOptInChannels() {\n const result = await fetch(`${serverURL ? serverURL : ''}/api/optinchannels`, {\n method: 'GET',\n })\n if (result.ok) {\n const resultJson: GetOptInChannelsResponse = await result.json()\n // @ts-expect-error OR type union not recognized\n setOptInChannels(resultJson?.optInChannels)\n } else {\n const resultText = await result.text()\n console.log('Error getting opt-in channels: ', [{ resultText }])\n }\n }\n void getOptInChannels()\n }, [serverURL])\n\n const [status, setStatus] = useState<UpdateSubscriptionStatusValue>('default')\n const [result, setResult] = useState<string>()\n\n const updateSubscriptions = async (selectedChannelIDs: string[]) => {\n setStatus('updating')\n setResult(`Updating...`)\n const subscribeResult = await fetch('/api/subscribe', {\n body: JSON.stringify({\n email: subscriber?.email,\n optIns: selectedChannelIDs,\n verifyData,\n }),\n method: 'POST',\n })\n if (subscribeResult.ok) {\n const resultJson: SubscribeResponse = await subscribeResult.json()\n // @ts-expect-error Silly type confusion\n const { emailResult, error } = resultJson\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 if (subscriber) {\n setStatus('updated')\n setResult(`You're subscriptions have been updated.`)\n } else {\n setStatus('error')\n setResult(`An error occured. Please try again. \\nResult unknown`)\n }\n\n refreshSubscriber()\n\n if (handleSubscribe) {\n handleSubscribe(resultJson)\n }\n } else {\n // const resultText = await subscribeResult.text()\n setStatus('error')\n setResult(`An error occured. Please try again. \\nResult unknown`)\n }\n }\n\n return {\n optInChannels,\n result,\n status,\n subscriber,\n updateSubscriptions,\n }\n}\n"],"names":["useEffect","useState","useSubscriber","useServerUrl","useSubscribe","handleSubscribe","verifyData","refreshSubscriber","subscriber","serverURL","optInChannels","setOptInChannels","getOptInChannels","result","fetch","method","ok","resultJson","json","resultText","text","console","log","status","setStatus","setResult","updateSubscriptions","selectedChannelIDs","subscribeResult","body","JSON","stringify","email","optIns","emailResult","error"],"mappings":"AAAA;AAEA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAS3C,SAASC,aAAa,QAAQ,oCAAmC;AACjE,SAASC,YAAY,QAAQ,iCAAgC;AA+B7D;;;;;;;;CAQC,GACD,OAAO,MAAMC,eAAe,CAAC,EAC3BC,eAAe,EACfC,UAAU,EACW;IACrB,MAAM,EAAEC,iBAAiB,EAAEC,UAAU,EAAE,GAAGN;IAE1C,MAAM,EAAEO,SAAS,EAAE,GAAGN;IACtB,MAAM,CAACO,eAAeC,iBAAiB,GAAGV,SAAyB,EAAE;IAErED,UAAU;QACR,eAAeY;YACb,MAAMC,SAAS,MAAMC,MAAM,GAAGL,YAAYA,YAAY,GAAG,kBAAkB,CAAC,EAAE;gBAC5EM,QAAQ;YACV;YACA,IAAIF,OAAOG,EAAE,EAAE;gBACb,MAAMC,aAAuC,MAAMJ,OAAOK,IAAI;gBAC9D,gDAAgD;gBAChDP,iBAAiBM,YAAYP;YAC/B,OAAO;gBACL,MAAMS,aAAa,MAAMN,OAAOO,IAAI;gBACpCC,QAAQC,GAAG,CAAC,mCAAmC;oBAAC;wBAAEH;oBAAW;iBAAE;YACjE;QACF;QACA,KAAKP;IACP,GAAG;QAACH;KAAU;IAEd,MAAM,CAACc,QAAQC,UAAU,GAAGvB,SAAwC;IACpE,MAAM,CAACY,QAAQY,UAAU,GAAGxB;IAE5B,MAAMyB,sBAAsB,OAAOC;QACjCH,UAAU;QACVC,UAAU,CAAC,WAAW,CAAC;QACvB,MAAMG,kBAAkB,MAAMd,MAAM,kBAAkB;YACpDe,MAAMC,KAAKC,SAAS,CAAC;gBACnBC,OAAOxB,YAAYwB;gBACnBC,QAAQN;gBACRrB;YACF;YACAS,QAAQ;QACV;QACA,IAAIa,gBAAgBZ,EAAE,EAAE;YACtB,MAAMC,aAAgC,MAAMW,gBAAgBV,IAAI;YAChE,wCAAwC;YACxC,MAAM,EAAEgB,WAAW,EAAEC,KAAK,EAAE,GAAGlB;YAC/B,IAAIkB,OAAO;gBACTX,UAAU;gBACVC,UAAU,CAAC,uCAAuC,EAAEU,OAAO;YAC7D,OAAO,IAAID,aAAa;gBACtBV,UAAU;gBACVC,UAAU;YACZ,OAAO,IAAIjB,YAAY;gBACrBgB,UAAU;gBACVC,UAAU,CAAC,uCAAuC,CAAC;YACrD,OAAO;gBACLD,UAAU;gBACVC,UAAU,CAAC,oDAAoD,CAAC;YAClE;YAEAlB;YAEA,IAAIF,iBAAiB;gBACnBA,gBAAgBY;YAClB;QACF,OAAO;YACL,kDAAkD;YAClDO,UAAU;YACVC,UAAU,CAAC,oDAAoD,CAAC;QAClE;IACF;IAEA,OAAO;QACLf;QACAG;QACAU;QACAf;QACAkB;IACF;AACF,EAAC"}
@@ -11,7 +11,7 @@ import { useServerUrl } from '../react-hooks/useServerUrl.js';
11
11
  * @returns unsubscribe function plus isLoading, isError, and result (see IUseUnsubscribe)
12
12
  */ export const useUnsubscribe = ({ handleUnsubscribe })=>{
13
13
  const { serverURL } = useServerUrl();
14
- const { subscriber } = useSubscriber();
14
+ const { refreshSubscriber, subscriber } = useSubscriber();
15
15
  const [result, setResult] = useState('');
16
16
  const [isError, setIsError] = useState(false);
17
17
  const [isLoading, setIsLoading] = useState(false);
@@ -67,6 +67,7 @@ import { useServerUrl } from '../react-hooks/useServerUrl.js';
67
67
  setResult(message || `An error occured. Please try again. (${error})`);
68
68
  setIsError(error && !message);
69
69
  setIsLoading(false);
70
+ refreshSubscriber();
70
71
  if (handleUnsubscribe) {
71
72
  handleUnsubscribe(resultJson);
72
73
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/useUnsubscribe.tsx"],"sourcesContent":["'use client'\n\nimport { useCallback, useState } from 'react'\n\nimport type { UnsubscribeResponse } from '../endpoints/unsubscribe.js'\n\nexport { UnsubscribeResponse }\nimport { useSubscriber } from '../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../react-hooks/useServerUrl.js'\n\n/**\n * Options for the useUnsubscribe hook.\n *\n * @property handleUnsubscribe - Callback when unsubscribe is attempted (success or error)\n */\nexport interface IUseUnsubscribeOptions {\n handleUnsubscribe?: (result: UnsubscribeResponse) => void\n}\n\n/**\n * Arguments for the unsubscribe function when calling it with email/hash explicitly.\n *\n * @property email - Subscriber email\n * @property hash - Unsubscribe token (from email link)\n */\nexport interface IUnsubscribeProps {\n email: string\n hash: string\n}\n\n/**\n * Return value of useUnsubscribe.\n *\n * @property isError - True if the last unsubscribe attempt failed\n * @property isLoading - True while an unsubscribe request is in progress\n * @property result - Result message from the last attempt\n * @property unsubscribe - Calls POST /api/unsubscribe; optional props or uses subscriber from context\n */\nexport interface IUseUnsubscribe {\n isError: boolean\n isLoading: boolean\n result: string\n unsubscribe: (props?: IUnsubscribeProps) => Promise<void>\n}\n\n/**\n * Hook to perform unsubscribe. Calls POST /api/unsubscribe with email and token (from args or\n * subscriber context). For use with unsubscribe URLs in emails, etc.\n *\n * @param options - Hook options (see IUseUnsubscribeOptions)\n * @param options.handleUnsubscribe - Callback when unsubscribe is attempted (success or error)\n * @returns unsubscribe function plus isLoading, isError, and result (see IUseUnsubscribe)\n */\nexport const useUnsubscribe = ({ handleUnsubscribe }: IUseUnsubscribeOptions): IUseUnsubscribe => {\n const { serverURL } = useServerUrl()\n const { subscriber } = useSubscriber()\n\n const [result, setResult] = useState<string>('')\n const [isError, setIsError] = useState<boolean>(false)\n const [isLoading, setIsLoading] = useState<boolean>(false)\n\n const unsubscribe = useCallback(\n async (props?: IUnsubscribeProps) => {\n let email: string | undefined\n let hash: string | undefined\n let resultJson: UnsubscribeResponse\n\n if (!props) {\n if (subscriber?.email) {\n email = subscriber?.email\n }\n } else {\n email = props.email\n hash = props.hash\n }\n if (!email || !hash) {\n resultJson = { error: 'Invalid input', now: new Date().toISOString() }\n }\n setIsLoading(true)\n\n try {\n const unsubscribeEndpointResult = await fetch(\n `${serverURL ? serverURL : ''}/api/unsubscribe`,\n {\n body: JSON.stringify({\n email,\n unsubscribeToken: hash,\n }),\n method: 'POST',\n },\n )\n\n if (unsubscribeEndpointResult && unsubscribeEndpointResult.json) {\n resultJson = await unsubscribeEndpointResult.json()\n } else if (unsubscribeEndpointResult && unsubscribeEndpointResult.text) {\n const resultText = await unsubscribeEndpointResult.text()\n resultJson = { error: resultText, now: new Date().toISOString() }\n } else {\n resultJson = {\n error: `${unsubscribeEndpointResult.status}`,\n now: new Date().toISOString(),\n }\n }\n } catch (error: any) {\n resultJson = { error, now: new Date().toISOString() }\n }\n\n // @ts-expect-error Linter doesn't recognize the OR typing\n const { error, message } = resultJson\n setResult(message || `An error occured. Please try again. (${error})`)\n setIsError(error && !message)\n setIsLoading(false)\n\n if (handleUnsubscribe) {\n handleUnsubscribe(resultJson)\n }\n },\n [serverURL, handleUnsubscribe, subscriber],\n )\n\n return { isError, isLoading, result, unsubscribe }\n}\n"],"names":["useCallback","useState","useSubscriber","useServerUrl","useUnsubscribe","handleUnsubscribe","serverURL","subscriber","result","setResult","isError","setIsError","isLoading","setIsLoading","unsubscribe","props","email","hash","resultJson","error","now","Date","toISOString","unsubscribeEndpointResult","fetch","body","JSON","stringify","unsubscribeToken","method","json","text","resultText","status","message"],"mappings":"AAAA;AAEA,SAASA,WAAW,EAAEC,QAAQ,QAAQ,QAAO;AAK7C,SAASC,aAAa,QAAQ,oCAAmC;AACjE,SAASC,YAAY,QAAQ,iCAAgC;AAqC7D;;;;;;;CAOC,GACD,OAAO,MAAMC,iBAAiB,CAAC,EAAEC,iBAAiB,EAA0B;IAC1E,MAAM,EAAEC,SAAS,EAAE,GAAGH;IACtB,MAAM,EAAEI,UAAU,EAAE,GAAGL;IAEvB,MAAM,CAACM,QAAQC,UAAU,GAAGR,SAAiB;IAC7C,MAAM,CAACS,SAASC,WAAW,GAAGV,SAAkB;IAChD,MAAM,CAACW,WAAWC,aAAa,GAAGZ,SAAkB;IAEpD,MAAMa,cAAcd,YAClB,OAAOe;QACL,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QAEJ,IAAI,CAACH,OAAO;YACV,IAAIR,YAAYS,OAAO;gBACrBA,QAAQT,YAAYS;YACtB;QACF,OAAO;YACLA,QAAQD,MAAMC,KAAK;YACnBC,OAAOF,MAAME,IAAI;QACnB;QACA,IAAI,CAACD,SAAS,CAACC,MAAM;YACnBC,aAAa;gBAAEC,OAAO;gBAAiBC,KAAK,IAAIC,OAAOC,WAAW;YAAG;QACvE;QACAT,aAAa;QAEb,IAAI;YACF,MAAMU,4BAA4B,MAAMC,MACtC,GAAGlB,YAAYA,YAAY,GAAG,gBAAgB,CAAC,EAC/C;gBACEmB,MAAMC,KAAKC,SAAS,CAAC;oBACnBX;oBACAY,kBAAkBX;gBACpB;gBACAY,QAAQ;YACV;YAGF,IAAIN,6BAA6BA,0BAA0BO,IAAI,EAAE;gBAC/DZ,aAAa,MAAMK,0BAA0BO,IAAI;YACnD,OAAO,IAAIP,6BAA6BA,0BAA0BQ,IAAI,EAAE;gBACtE,MAAMC,aAAa,MAAMT,0BAA0BQ,IAAI;gBACvDb,aAAa;oBAAEC,OAAOa;oBAAYZ,KAAK,IAAIC,OAAOC,WAAW;gBAAG;YAClE,OAAO;gBACLJ,aAAa;oBACXC,OAAO,GAAGI,0BAA0BU,MAAM,EAAE;oBAC5Cb,KAAK,IAAIC,OAAOC,WAAW;gBAC7B;YACF;QACF,EAAE,OAAOH,OAAY;YACnBD,aAAa;gBAAEC;gBAAOC,KAAK,IAAIC,OAAOC,WAAW;YAAG;QACtD;QAEA,0DAA0D;QAC1D,MAAM,EAAEH,KAAK,EAAEe,OAAO,EAAE,GAAGhB;QAC3BT,UAAUyB,WAAW,CAAC,qCAAqC,EAAEf,MAAM,CAAC,CAAC;QACrER,WAAWQ,SAAS,CAACe;QACrBrB,aAAa;QAEb,IAAIR,mBAAmB;YACrBA,kBAAkBa;QACpB;IACF,GACA;QAACZ;QAAWD;QAAmBE;KAAW;IAG5C,OAAO;QAAEG;QAASE;QAAWJ;QAAQM;IAAY;AACnD,EAAC"}
1
+ {"version":3,"sources":["../../src/hooks/useUnsubscribe.tsx"],"sourcesContent":["'use client'\n\nimport { useCallback, useState } from 'react'\n\nimport type { UnsubscribeResponse } from '../endpoints/unsubscribe.js'\n\nexport { UnsubscribeResponse }\nimport { useSubscriber } from '../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../react-hooks/useServerUrl.js'\n\n/**\n * Options for the useUnsubscribe hook.\n *\n * @property handleUnsubscribe - Callback when unsubscribe is attempted (success or error)\n */\nexport interface IUseUnsubscribeOptions {\n handleUnsubscribe?: (result: UnsubscribeResponse) => void\n}\n\n/**\n * Arguments for the unsubscribe function when calling it with email/hash explicitly.\n *\n * @property email - Subscriber email\n * @property hash - Unsubscribe token (from email link)\n */\nexport interface IUnsubscribeProps {\n email: string\n hash: string\n}\n\n/**\n * Return value of useUnsubscribe.\n *\n * @property isError - True if the last unsubscribe attempt failed\n * @property isLoading - True while an unsubscribe request is in progress\n * @property result - Result message from the last attempt\n * @property unsubscribe - Calls POST /api/unsubscribe; optional props or uses subscriber from context\n */\nexport interface IUseUnsubscribe {\n isError: boolean\n isLoading: boolean\n result: string\n unsubscribe: (props?: IUnsubscribeProps) => Promise<void>\n}\n\n/**\n * Hook to perform unsubscribe. Calls POST /api/unsubscribe with email and token (from args or\n * subscriber context). For use with unsubscribe URLs in emails, etc.\n *\n * @param options - Hook options (see IUseUnsubscribeOptions)\n * @param options.handleUnsubscribe - Callback when unsubscribe is attempted (success or error)\n * @returns unsubscribe function plus isLoading, isError, and result (see IUseUnsubscribe)\n */\nexport const useUnsubscribe = ({ handleUnsubscribe }: IUseUnsubscribeOptions): IUseUnsubscribe => {\n const { serverURL } = useServerUrl()\n const { refreshSubscriber, subscriber } = useSubscriber()\n\n const [result, setResult] = useState<string>('')\n const [isError, setIsError] = useState<boolean>(false)\n const [isLoading, setIsLoading] = useState<boolean>(false)\n\n const unsubscribe = useCallback(\n async (props?: IUnsubscribeProps) => {\n let email: string | undefined\n let hash: string | undefined\n let resultJson: UnsubscribeResponse\n\n if (!props) {\n if (subscriber?.email) {\n email = subscriber?.email\n }\n } else {\n email = props.email\n hash = props.hash\n }\n if (!email || !hash) {\n resultJson = { error: 'Invalid input', now: new Date().toISOString() }\n }\n setIsLoading(true)\n\n try {\n const unsubscribeEndpointResult = await fetch(\n `${serverURL ? serverURL : ''}/api/unsubscribe`,\n {\n body: JSON.stringify({\n email,\n unsubscribeToken: hash,\n }),\n method: 'POST',\n },\n )\n\n if (unsubscribeEndpointResult && unsubscribeEndpointResult.json) {\n resultJson = await unsubscribeEndpointResult.json()\n } else if (unsubscribeEndpointResult && unsubscribeEndpointResult.text) {\n const resultText = await unsubscribeEndpointResult.text()\n resultJson = { error: resultText, now: new Date().toISOString() }\n } else {\n resultJson = {\n error: `${unsubscribeEndpointResult.status}`,\n now: new Date().toISOString(),\n }\n }\n } catch (error: any) {\n resultJson = { error, now: new Date().toISOString() }\n }\n\n // @ts-expect-error Linter doesn't recognize the OR typing\n const { error, message } = resultJson\n setResult(message || `An error occured. Please try again. (${error})`)\n setIsError(error && !message)\n setIsLoading(false)\n\n refreshSubscriber()\n\n if (handleUnsubscribe) {\n handleUnsubscribe(resultJson)\n }\n },\n [serverURL, handleUnsubscribe, subscriber],\n )\n\n return { isError, isLoading, result, unsubscribe }\n}\n"],"names":["useCallback","useState","useSubscriber","useServerUrl","useUnsubscribe","handleUnsubscribe","serverURL","refreshSubscriber","subscriber","result","setResult","isError","setIsError","isLoading","setIsLoading","unsubscribe","props","email","hash","resultJson","error","now","Date","toISOString","unsubscribeEndpointResult","fetch","body","JSON","stringify","unsubscribeToken","method","json","text","resultText","status","message"],"mappings":"AAAA;AAEA,SAASA,WAAW,EAAEC,QAAQ,QAAQ,QAAO;AAK7C,SAASC,aAAa,QAAQ,oCAAmC;AACjE,SAASC,YAAY,QAAQ,iCAAgC;AAqC7D;;;;;;;CAOC,GACD,OAAO,MAAMC,iBAAiB,CAAC,EAAEC,iBAAiB,EAA0B;IAC1E,MAAM,EAAEC,SAAS,EAAE,GAAGH;IACtB,MAAM,EAAEI,iBAAiB,EAAEC,UAAU,EAAE,GAAGN;IAE1C,MAAM,CAACO,QAAQC,UAAU,GAAGT,SAAiB;IAC7C,MAAM,CAACU,SAASC,WAAW,GAAGX,SAAkB;IAChD,MAAM,CAACY,WAAWC,aAAa,GAAGb,SAAkB;IAEpD,MAAMc,cAAcf,YAClB,OAAOgB;QACL,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QAEJ,IAAI,CAACH,OAAO;YACV,IAAIR,YAAYS,OAAO;gBACrBA,QAAQT,YAAYS;YACtB;QACF,OAAO;YACLA,QAAQD,MAAMC,KAAK;YACnBC,OAAOF,MAAME,IAAI;QACnB;QACA,IAAI,CAACD,SAAS,CAACC,MAAM;YACnBC,aAAa;gBAAEC,OAAO;gBAAiBC,KAAK,IAAIC,OAAOC,WAAW;YAAG;QACvE;QACAT,aAAa;QAEb,IAAI;YACF,MAAMU,4BAA4B,MAAMC,MACtC,GAAGnB,YAAYA,YAAY,GAAG,gBAAgB,CAAC,EAC/C;gBACEoB,MAAMC,KAAKC,SAAS,CAAC;oBACnBX;oBACAY,kBAAkBX;gBACpB;gBACAY,QAAQ;YACV;YAGF,IAAIN,6BAA6BA,0BAA0BO,IAAI,EAAE;gBAC/DZ,aAAa,MAAMK,0BAA0BO,IAAI;YACnD,OAAO,IAAIP,6BAA6BA,0BAA0BQ,IAAI,EAAE;gBACtE,MAAMC,aAAa,MAAMT,0BAA0BQ,IAAI;gBACvDb,aAAa;oBAAEC,OAAOa;oBAAYZ,KAAK,IAAIC,OAAOC,WAAW;gBAAG;YAClE,OAAO;gBACLJ,aAAa;oBACXC,OAAO,GAAGI,0BAA0BU,MAAM,EAAE;oBAC5Cb,KAAK,IAAIC,OAAOC,WAAW;gBAC7B;YACF;QACF,EAAE,OAAOH,OAAY;YACnBD,aAAa;gBAAEC;gBAAOC,KAAK,IAAIC,OAAOC,WAAW;YAAG;QACtD;QAEA,0DAA0D;QAC1D,MAAM,EAAEH,KAAK,EAAEe,OAAO,EAAE,GAAGhB;QAC3BT,UAAUyB,WAAW,CAAC,qCAAqC,EAAEf,MAAM,CAAC,CAAC;QACrER,WAAWQ,SAAS,CAACe;QACrBrB,aAAa;QAEbP;QAEA,IAAIF,mBAAmB;YACrBA,kBAAkBc;QACpB;IACF,GACA;QAACb;QAAWD;QAAmBG;KAAW;IAG5C,OAAO;QAAEG;QAASE;QAAWJ;QAAQM;IAAY;AACnD,EAAC"}
package/dist/index.d.ts CHANGED
@@ -32,4 +32,16 @@ export type PayloadSubscribersConfig = {
32
32
  */
33
33
  verifyURL?: string;
34
34
  };
35
+ /**
36
+ * Adds the payload-subscribers-plugin to your payload config
37
+ *
38
+ * @param pluginOptions - Plugin options
39
+ * @param pluginOptions.collections - (optional) An array of existing collection slugs to add an optIns relationship field to
40
+ * @param pluginOptions.disabled - (optional) A convenience option to disable the plugin
41
+ * @param pluginOptions.subscribersCollectionSlug - (optional) The slug of an existing collection to use for subscribers. If omitted, the plugin will create the 'subscribers' collection
42
+ * @param pluginOptions.tokenExpiration - (optional) The expiration time for a token, in milliseconds. Defaults to 30 minutes
43
+ * @param pluginOptions.unsubscribeURL - (optional) The route or full URL for unsubscribe links
44
+ * @param pluginOptions.verifyURL - (optional) The route or full URL for verify links
45
+ * @returns Payload config modified to include the plugin
46
+ */
35
47
  export declare const payloadSubscribersPlugin: (pluginOptions: PayloadSubscribersConfig) => (config: Config) => Config;
package/dist/index.js CHANGED
@@ -11,7 +11,18 @@ import createEndpointVerifyMagicLink from './endpoints/verifyMagicLink.js';
11
11
  import { getTestEmail } from './helpers/testData.js';
12
12
  import { getTokenAndHash } from './helpers/token.js';
13
13
  import { isAbsoluteURL } from './helpers/utilities.js';
14
- export const payloadSubscribersPlugin = (pluginOptions)=>(config)=>{
14
+ /**
15
+ * Adds the payload-subscribers-plugin to your payload config
16
+ *
17
+ * @param pluginOptions - Plugin options
18
+ * @param pluginOptions.collections - (optional) An array of existing collection slugs to add an optIns relationship field to
19
+ * @param pluginOptions.disabled - (optional) A convenience option to disable the plugin
20
+ * @param pluginOptions.subscribersCollectionSlug - (optional) The slug of an existing collection to use for subscribers. If omitted, the plugin will create the 'subscribers' collection
21
+ * @param pluginOptions.tokenExpiration - (optional) The expiration time for a token, in milliseconds. Defaults to 30 minutes
22
+ * @param pluginOptions.unsubscribeURL - (optional) The route or full URL for unsubscribe links
23
+ * @param pluginOptions.verifyURL - (optional) The route or full URL for verify links
24
+ * @returns Payload config modified to include the plugin
25
+ */ export const payloadSubscribersPlugin = (pluginOptions)=>(config)=>{
15
26
  if (!config.serverURL && !(pluginOptions.unsubscribeURL && pluginOptions.verifyURL)) {
16
27
  throw new Error('payloadSubscribersPlugin requires config.serverURL OR valid values for all URL options: unsubscribeURL, verifyURL');
17
28
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { BasePayload, CollectionSlug, Config } from 'payload'\n\nimport { OptedInChannels } from './collections/fields/OptedInChannels.js'\nimport OptInChannels from './collections/OptInChannels.js'\nimport {\n defaultTokenExpiration,\n SubscribersCollectionFactory,\n subscribersCollectionFields,\n} from './collections/Subscribers.js'\nimport getOptInChannelsEndpoint from './endpoints/getOptInChannels.js'\nimport createEndpointLogout from './endpoints/logout.js'\nimport createEndpointRequestMagicLink from './endpoints/requestMagicLink.js'\nimport createEndpointSubscribe from './endpoints/subscribe.js'\nimport createEndpointSubscriberAuth from './endpoints/subscriberAuth.js'\nimport createEndpointUnsubscribe from './endpoints/unsubscribe.js'\nimport createEndpointVerifyMagicLink from './endpoints/verifyMagicLink.js'\nimport { getTestEmail } from './helpers/testData.js'\nimport { getTokenAndHash } from './helpers/token.js'\nimport { isAbsoluteURL } from './helpers/utilities.js'\n\nexport type PayloadSubscribersConfig = {\n /**\n * List of collections to add a custom field\n */\n collections?: Partial<Record<CollectionSlug, true>>\n /**\n * Defaults to false-y. When true:\n * - Database schema changes are still made and seeded\n * - APIs return null or undefined success\n * - Admin components are not added\n * - App components return nothing\n */\n disabled?: boolean\n /**\n * The collection to use as the subscribers collection\n * - Optional. If not specified, the plugin will add a 'subscribers' collection.\n * - Sets the collection auth if not already.\n * - Adds (or overrides) fields: email, firstName, status, optIns, verificationToken, verificationTokenExpires.\n */\n subscribersCollectionSlug?: CollectionSlug\n /**\n * Defaults to 30 minutes\n */\n tokenExpiration?: number\n /**\n * The route or full URL for unsubscribe links\n */\n unsubscribeURL?: string\n /**\n * The route or full URL for verify links\n */\n verifyURL?: string\n}\n\nexport const payloadSubscribersPlugin =\n (pluginOptions: PayloadSubscribersConfig) =>\n (config: Config): Config => {\n if (!config.serverURL && !(pluginOptions.unsubscribeURL && pluginOptions.verifyURL)) {\n throw new Error(\n 'payloadSubscribersPlugin requires config.serverURL OR valid values for all URL options: unsubscribeURL, verifyURL',\n )\n }\n\n if (!config.collections) {\n config.collections = []\n }\n\n config.collections.push(OptInChannels)\n\n const unsubscribeURL = !pluginOptions.unsubscribeURL\n ? new URL('/unsubscribe', config.serverURL)\n : isAbsoluteURL(pluginOptions.unsubscribeURL)\n ? new URL(pluginOptions.unsubscribeURL)\n : new URL(pluginOptions.unsubscribeURL, config.serverURL)\n\n // Get a URL object from the verifyURL option\n const verifyURL = !pluginOptions.verifyURL\n ? new URL('/verify', config.serverURL)\n : isAbsoluteURL(pluginOptions.verifyURL)\n ? new URL(pluginOptions.verifyURL)\n : new URL(pluginOptions.verifyURL, config.serverURL)\n\n let subscribersCollection = pluginOptions.subscribersCollectionSlug\n ? config.collections.find(\n (collection) => collection.slug == pluginOptions.subscribersCollectionSlug,\n )\n : undefined\n\n if (subscribersCollection) {\n // Configure the input collection to be the subscribers collection\n config.collections = config.collections.filter(\n (collection) => collection.slug != subscribersCollection?.slug,\n )\n subscribersCollection.fields.push(...subscribersCollectionFields)\n if (!subscribersCollection.auth) {\n subscribersCollection = {\n ...subscribersCollection,\n auth: { tokenExpiration: defaultTokenExpiration },\n }\n }\n if (!subscribersCollection.admin?.useAsTitle) {\n if (!subscribersCollection.admin) {\n subscribersCollection.admin = { useAsTitle: 'email' }\n } else {\n // Throw error? Or override?\n subscribersCollection.admin.useAsTitle = 'email'\n }\n }\n config.collections.push(subscribersCollection)\n } else {\n // Configure the default built-in subscribers collection\n subscribersCollection = SubscribersCollectionFactory({\n slug: pluginOptions.subscribersCollectionSlug,\n tokenExpiration: pluginOptions.tokenExpiration,\n })\n config.collections.push(subscribersCollection)\n }\n\n if (pluginOptions.collections) {\n for (const collectionSlug in pluginOptions.collections) {\n const collection = config.collections.find(\n (collection) => collection.slug === collectionSlug,\n )\n\n if (collection) {\n collection.fields.push(OptedInChannels)\n }\n }\n }\n\n /**\n * If the plugin is disabled, we still want to keep added collections/fields so the database schema is consistent which is important for migrations.\n * If your plugin heavily modifies the database schema, you may want to remove this property.\n */\n if (pluginOptions.disabled) {\n return config\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.beforeDashboard) {\n config.admin.components.beforeDashboard = []\n }\n\n if (!config.endpoints) {\n config.endpoints = []\n }\n\n config.endpoints.push(\n getOptInChannelsEndpoint,\n createEndpointLogout({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointRequestMagicLink({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n unsubscribeURL,\n verifyURL,\n }),\n createEndpointSubscribe({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n unsubscribeURL,\n verifyURL,\n }),\n createEndpointSubscriberAuth({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointUnsubscribe({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointVerifyMagicLink({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n )\n\n const incomingOnInit = config.onInit\n\n const genInit = (testData: { testEmail: string }) => async (payload: BasePayload) => {\n // Ensure we are executing any existing onInit functions before running our own.\n if (incomingOnInit) {\n await incomingOnInit(payload)\n }\n\n // console.log('Object.keys(payload.collections)', Object.keys(payload.collections))\n const { totalDocs: totalOptIns } = await payload.count({\n collection: 'opt-in-channels',\n where: {\n title: {\n equals: 'seeded-by-plugin',\n },\n },\n })\n\n if (totalOptIns === 0) {\n await payload.create({\n collection: 'opt-in-channels',\n data: {\n active: true,\n title: 'seeded-by-plugin',\n },\n })\n }\n\n // const { seededChannel } = await payload.find({\n // collection: 'opt-in-channels',\n // where: {\n // title: {\n // equals: 'seeded-by-plugin',\n // },\n // },\n // })\n\n const { totalDocs: totalSubscribers } = await payload.count({\n collection: subscribersCollection.slug as CollectionSlug,\n where: {\n email: {\n equals: testData.testEmail,\n },\n },\n })\n\n const { tokenHash } = getTokenAndHash() // Unknowable\n // payload.logger.info(`testData.testEmail == '${testData.testEmail}'`)\n if (totalSubscribers === 0) {\n await payload.create({\n collection: subscribersCollection.slug as CollectionSlug,\n data: {\n email: testData.testEmail,\n password: tokenHash,\n status: 'pending',\n },\n })\n }\n }\n\n // console.log(`getTestEmail == '${getTestEmail()}'`)\n config.onInit = genInit({ testEmail: getTestEmail() })\n\n return config\n }\n"],"names":["OptedInChannels","OptInChannels","defaultTokenExpiration","SubscribersCollectionFactory","subscribersCollectionFields","getOptInChannelsEndpoint","createEndpointLogout","createEndpointRequestMagicLink","createEndpointSubscribe","createEndpointSubscriberAuth","createEndpointUnsubscribe","createEndpointVerifyMagicLink","getTestEmail","getTokenAndHash","isAbsoluteURL","payloadSubscribersPlugin","pluginOptions","config","serverURL","unsubscribeURL","verifyURL","Error","collections","push","URL","subscribersCollection","subscribersCollectionSlug","find","collection","slug","undefined","filter","fields","auth","tokenExpiration","admin","useAsTitle","collectionSlug","disabled","components","beforeDashboard","endpoints","incomingOnInit","onInit","genInit","testData","payload","totalDocs","totalOptIns","count","where","title","equals","create","data","active","totalSubscribers","email","testEmail","tokenHash","password","status"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { BasePayload, CollectionSlug, Config } from 'payload'\n\nimport { OptedInChannels } from './collections/fields/OptedInChannels.js'\nimport OptInChannels from './collections/OptInChannels.js'\nimport {\n defaultTokenExpiration,\n SubscribersCollectionFactory,\n subscribersCollectionFields,\n} from './collections/Subscribers.js'\nimport getOptInChannelsEndpoint from './endpoints/getOptInChannels.js'\nimport createEndpointLogout from './endpoints/logout.js'\nimport createEndpointRequestMagicLink from './endpoints/requestMagicLink.js'\nimport createEndpointSubscribe from './endpoints/subscribe.js'\nimport createEndpointSubscriberAuth from './endpoints/subscriberAuth.js'\nimport createEndpointUnsubscribe from './endpoints/unsubscribe.js'\nimport createEndpointVerifyMagicLink from './endpoints/verifyMagicLink.js'\nimport { getTestEmail } from './helpers/testData.js'\nimport { getTokenAndHash } from './helpers/token.js'\nimport { isAbsoluteURL } from './helpers/utilities.js'\n\nexport type PayloadSubscribersConfig = {\n /**\n * List of collections to add a custom field\n */\n collections?: Partial<Record<CollectionSlug, true>>\n /**\n * Defaults to false-y. When true:\n * - Database schema changes are still made and seeded\n * - APIs return null or undefined success\n * - Admin components are not added\n * - App components return nothing\n */\n disabled?: boolean\n /**\n * The collection to use as the subscribers collection\n * - Optional. If not specified, the plugin will add a 'subscribers' collection.\n * - Sets the collection auth if not already.\n * - Adds (or overrides) fields: email, firstName, status, optIns, verificationToken, verificationTokenExpires.\n */\n subscribersCollectionSlug?: CollectionSlug\n /**\n * Defaults to 30 minutes\n */\n tokenExpiration?: number\n /**\n * The route or full URL for unsubscribe links\n */\n unsubscribeURL?: string\n /**\n * The route or full URL for verify links\n */\n verifyURL?: string\n}\n\n/**\n * Adds the payload-subscribers-plugin to your payload config\n *\n * @param pluginOptions - Plugin options\n * @param pluginOptions.collections - (optional) An array of existing collection slugs to add an optIns relationship field to\n * @param pluginOptions.disabled - (optional) A convenience option to disable the plugin\n * @param pluginOptions.subscribersCollectionSlug - (optional) The slug of an existing collection to use for subscribers. If omitted, the plugin will create the 'subscribers' collection\n * @param pluginOptions.tokenExpiration - (optional) The expiration time for a token, in milliseconds. Defaults to 30 minutes\n * @param pluginOptions.unsubscribeURL - (optional) The route or full URL for unsubscribe links\n * @param pluginOptions.verifyURL - (optional) The route or full URL for verify links\n * @returns Payload config modified to include the plugin\n */\nexport const payloadSubscribersPlugin =\n (pluginOptions: PayloadSubscribersConfig) =>\n (config: Config): Config => {\n if (!config.serverURL && !(pluginOptions.unsubscribeURL && pluginOptions.verifyURL)) {\n throw new Error(\n 'payloadSubscribersPlugin requires config.serverURL OR valid values for all URL options: unsubscribeURL, verifyURL',\n )\n }\n\n if (!config.collections) {\n config.collections = []\n }\n\n config.collections.push(OptInChannels)\n\n const unsubscribeURL = !pluginOptions.unsubscribeURL\n ? new URL('/unsubscribe', config.serverURL)\n : isAbsoluteURL(pluginOptions.unsubscribeURL)\n ? new URL(pluginOptions.unsubscribeURL)\n : new URL(pluginOptions.unsubscribeURL, config.serverURL)\n\n // Get a URL object from the verifyURL option\n const verifyURL = !pluginOptions.verifyURL\n ? new URL('/verify', config.serverURL)\n : isAbsoluteURL(pluginOptions.verifyURL)\n ? new URL(pluginOptions.verifyURL)\n : new URL(pluginOptions.verifyURL, config.serverURL)\n\n let subscribersCollection = pluginOptions.subscribersCollectionSlug\n ? config.collections.find(\n (collection) => collection.slug == pluginOptions.subscribersCollectionSlug,\n )\n : undefined\n\n if (subscribersCollection) {\n // Configure the input collection to be the subscribers collection\n config.collections = config.collections.filter(\n (collection) => collection.slug != subscribersCollection?.slug,\n )\n subscribersCollection.fields.push(...subscribersCollectionFields)\n if (!subscribersCollection.auth) {\n subscribersCollection = {\n ...subscribersCollection,\n auth: { tokenExpiration: defaultTokenExpiration },\n }\n }\n if (!subscribersCollection.admin?.useAsTitle) {\n if (!subscribersCollection.admin) {\n subscribersCollection.admin = { useAsTitle: 'email' }\n } else {\n // Throw error? Or override?\n subscribersCollection.admin.useAsTitle = 'email'\n }\n }\n config.collections.push(subscribersCollection)\n } else {\n // Configure the default built-in subscribers collection\n subscribersCollection = SubscribersCollectionFactory({\n slug: pluginOptions.subscribersCollectionSlug,\n tokenExpiration: pluginOptions.tokenExpiration,\n })\n config.collections.push(subscribersCollection)\n }\n\n if (pluginOptions.collections) {\n for (const collectionSlug in pluginOptions.collections) {\n const collection = config.collections.find(\n (collection) => collection.slug === collectionSlug,\n )\n\n if (collection) {\n collection.fields.push(OptedInChannels)\n }\n }\n }\n\n /**\n * If the plugin is disabled, we still want to keep added collections/fields so the database schema is consistent which is important for migrations.\n * If your plugin heavily modifies the database schema, you may want to remove this property.\n */\n if (pluginOptions.disabled) {\n return config\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.beforeDashboard) {\n config.admin.components.beforeDashboard = []\n }\n\n if (!config.endpoints) {\n config.endpoints = []\n }\n\n config.endpoints.push(\n getOptInChannelsEndpoint,\n createEndpointLogout({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointRequestMagicLink({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n unsubscribeURL,\n verifyURL,\n }),\n createEndpointSubscribe({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n unsubscribeURL,\n verifyURL,\n }),\n createEndpointSubscriberAuth({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointUnsubscribe({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointVerifyMagicLink({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n )\n\n const incomingOnInit = config.onInit\n\n const genInit = (testData: { testEmail: string }) => async (payload: BasePayload) => {\n // Ensure we are executing any existing onInit functions before running our own.\n if (incomingOnInit) {\n await incomingOnInit(payload)\n }\n\n // console.log('Object.keys(payload.collections)', Object.keys(payload.collections))\n const { totalDocs: totalOptIns } = await payload.count({\n collection: 'opt-in-channels',\n where: {\n title: {\n equals: 'seeded-by-plugin',\n },\n },\n })\n\n if (totalOptIns === 0) {\n await payload.create({\n collection: 'opt-in-channels',\n data: {\n active: true,\n title: 'seeded-by-plugin',\n },\n })\n }\n\n // const { seededChannel } = await payload.find({\n // collection: 'opt-in-channels',\n // where: {\n // title: {\n // equals: 'seeded-by-plugin',\n // },\n // },\n // })\n\n const { totalDocs: totalSubscribers } = await payload.count({\n collection: subscribersCollection.slug as CollectionSlug,\n where: {\n email: {\n equals: testData.testEmail,\n },\n },\n })\n\n const { tokenHash } = getTokenAndHash() // Unknowable\n // payload.logger.info(`testData.testEmail == '${testData.testEmail}'`)\n if (totalSubscribers === 0) {\n await payload.create({\n collection: subscribersCollection.slug as CollectionSlug,\n data: {\n email: testData.testEmail,\n password: tokenHash,\n status: 'pending',\n },\n })\n }\n }\n\n // console.log(`getTestEmail == '${getTestEmail()}'`)\n config.onInit = genInit({ testEmail: getTestEmail() })\n\n return config\n }\n"],"names":["OptedInChannels","OptInChannels","defaultTokenExpiration","SubscribersCollectionFactory","subscribersCollectionFields","getOptInChannelsEndpoint","createEndpointLogout","createEndpointRequestMagicLink","createEndpointSubscribe","createEndpointSubscriberAuth","createEndpointUnsubscribe","createEndpointVerifyMagicLink","getTestEmail","getTokenAndHash","isAbsoluteURL","payloadSubscribersPlugin","pluginOptions","config","serverURL","unsubscribeURL","verifyURL","Error","collections","push","URL","subscribersCollection","subscribersCollectionSlug","find","collection","slug","undefined","filter","fields","auth","tokenExpiration","admin","useAsTitle","collectionSlug","disabled","components","beforeDashboard","endpoints","incomingOnInit","onInit","genInit","testData","payload","totalDocs","totalOptIns","count","where","title","equals","create","data","active","totalSubscribers","email","testEmail","tokenHash","password","status"],"mappings":"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"}
package/package.json CHANGED
@@ -69,7 +69,7 @@
69
69
  },
70
70
  "registry": "https://registry.npmjs.org/",
71
71
  "dependencies": {},
72
- "version": "0.0.11",
72
+ "version": "0.0.13",
73
73
  "scripts": {
74
74
  "build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
75
75
  "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",