payload-subscribers-plugin 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -17
- package/dist/components/app/RequestMagicLink.d.ts +2 -1
- package/dist/components/app/RequestMagicLink.js +2 -3
- package/dist/components/app/RequestMagicLink.js.map +1 -1
- package/dist/components/app/RequestOrSubscribe.d.ts +2 -1
- package/dist/components/app/RequestOrSubscribe.js +5 -3
- package/dist/components/app/RequestOrSubscribe.js.map +1 -1
- package/dist/components/app/Subscribe.d.ts +2 -1
- package/dist/components/app/Subscribe.js +3 -3
- package/dist/components/app/Subscribe.js.map +1 -1
- package/dist/components/app/VerifyMagicLink.d.ts +4 -2
- package/dist/components/app/VerifyMagicLink.js +7 -22
- package/dist/components/app/VerifyMagicLink.js.map +1 -1
- package/dist/endpoints/requestMagicLink.js +4 -5
- package/dist/endpoints/requestMagicLink.js.map +1 -1
- package/dist/endpoints/subscribe.js +9 -10
- package/dist/endpoints/subscribe.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
A plugin to manage subscribers and the "channels" they can subscribe to.
|
|
4
4
|
|
|
5
5
|
This includes ways to allow your subscribers to:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
|
|
7
|
+
- Sign up or sign in by requesting a magic link email
|
|
8
|
+
- Verify the magic link to authenticate
|
|
9
|
+
- Opt in or out of "opt-in channels"
|
|
9
10
|
|
|
10
11
|
You manage the opt-in channels via the Payload admin.
|
|
11
12
|
|
|
12
13
|
The plugin relies on your email adapter configured in your payload config to send emails.
|
|
13
14
|
|
|
14
|
-
That is all this plugin does currently. Potential features might include email authoring and send scheduler or simple CRM features.
|
|
15
|
-
|
|
15
|
+
That is all this plugin does currently. Potential features might include email authoring and send scheduler or simple CRM features.
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
@@ -44,7 +44,7 @@ export default buildConfig({
|
|
|
44
44
|
// Specify the collection to use as the subscribers collection
|
|
45
45
|
// - Optional. If not specified, the plugin will add a 'subscribers' collection.
|
|
46
46
|
// - Sets auth if not already
|
|
47
|
-
// - Adds (or overrides) fields: email, firstName, status, optIns,
|
|
47
|
+
// - Adds (or overrides) fields: email, firstName, status, optIns,
|
|
48
48
|
// verificationToken, verificationTokenExpires, and source
|
|
49
49
|
subscribersCollectionSlug?: CollectionSlug
|
|
50
50
|
|
|
@@ -202,7 +202,9 @@ Shows the [Subscribe](#subscribe) component to authenticated subscribers, otherw
|
|
|
202
202
|
</div> -->
|
|
203
203
|
|
|
204
204
|
```typescript
|
|
205
|
-
<
|
|
205
|
+
<RequestOrSubscribe
|
|
206
|
+
// Provide the URL the user should go to after clicking the link in the email and having it verified
|
|
207
|
+
afterVerifyUrl={new URL(window.href)}
|
|
206
208
|
// Provide your own global class names to add to the component elements. Optional
|
|
207
209
|
classNames={{
|
|
208
210
|
button: 'customCssClassNames',
|
|
@@ -224,6 +226,8 @@ Shows the [Subscribe](#subscribe) component to authenticated subscribers, otherw
|
|
|
224
226
|
{text}
|
|
225
227
|
</button>
|
|
226
228
|
}
|
|
229
|
+
// Provide the URL to your route that has the VerifyMagicLink component on it.
|
|
230
|
+
verifyUrl={verifyUrl}
|
|
227
231
|
/>
|
|
228
232
|
```
|
|
229
233
|
|
|
@@ -235,6 +239,8 @@ Form to input email address and get a magic link email sent.
|
|
|
235
239
|
|
|
236
240
|
```typescript
|
|
237
241
|
<RequestMagicLink
|
|
242
|
+
// Provide the URL the user should go to after clicking the link in the email and having it verified
|
|
243
|
+
afterVerifyUrl={new URL(window.href)}
|
|
238
244
|
// Provide your own global class names to add to the component elements. Optional
|
|
239
245
|
classNames={{
|
|
240
246
|
button: 'customCssClassNames',
|
|
@@ -252,6 +258,8 @@ Form to input email address and get a magic link email sent.
|
|
|
252
258
|
{text}
|
|
253
259
|
</button>
|
|
254
260
|
}
|
|
261
|
+
// Provide the URL to your route that has the VerifyMagicLink component on it.
|
|
262
|
+
verifyUrl={verifyUrl}
|
|
255
263
|
/>
|
|
256
264
|
```
|
|
257
265
|
|
|
@@ -277,20 +285,25 @@ Component that verifies a magic link using expected url parameters.
|
|
|
277
285
|
// Called after a magic link has been verified. Optional
|
|
278
286
|
handleMagicLinkVerified={async (result: RequestMagicLinkResponse) => {}}
|
|
279
287
|
// Provided your own button component. Optional
|
|
280
|
-
renderButton={({ name,
|
|
281
|
-
forwardUrl ? (
|
|
282
|
-
<a href={forwardUrl}>
|
|
283
|
-
<button name={name} type="button">
|
|
284
|
-
{text}
|
|
285
|
-
</button>
|
|
286
|
-
</a>
|
|
287
|
-
) : (
|
|
288
|
+
renderButton={({ name, onClick, text }) =>
|
|
288
289
|
<button name={name} onClick={onClick} type="button">
|
|
289
290
|
{text}
|
|
290
291
|
</button>
|
|
291
|
-
)
|
|
292
292
|
}
|
|
293
|
-
|
|
293
|
+
// Provide the URL to your route that has the VerifyMagicLink component on it.
|
|
294
|
+
// Used when this VerifyMagicLink component provides an option to request another link
|
|
295
|
+
// when verifying the current one fails.
|
|
296
|
+
verifyUrl={verifyUrl}
|
|
297
|
+
>
|
|
298
|
+
// Provide children to render after link is verified. Optional
|
|
299
|
+
// Since you provide the verifyUrl to any of the plugin components, you can include a forwardUrl
|
|
300
|
+
// as a search param, which your route can then use here.
|
|
301
|
+
<a href={forwardUrl}>
|
|
302
|
+
<button className={'customCss'} name={'continue'} type="button">
|
|
303
|
+
Continue
|
|
304
|
+
</button>
|
|
305
|
+
</a>
|
|
306
|
+
</VerifyMagicLink>
|
|
294
307
|
```
|
|
295
308
|
|
|
296
309
|
#### **Subscribe**
|
|
@@ -301,6 +314,8 @@ Allows a subscriber to select from among all active optInChannels.
|
|
|
301
314
|
|
|
302
315
|
```typescript
|
|
303
316
|
<Subscribe
|
|
317
|
+
// Provide the URL the user should go to after clicking the link in the email and having it verified
|
|
318
|
+
afterVerifyUrl={new URL(window.href)}
|
|
304
319
|
// Provide your own global class names to add to the component elements. Optional
|
|
305
320
|
classNames={{
|
|
306
321
|
button: 'customCssClassNames',
|
|
@@ -320,6 +335,8 @@ Allows a subscriber to select from among all active optInChannels.
|
|
|
320
335
|
{text}
|
|
321
336
|
</button>
|
|
322
337
|
}
|
|
338
|
+
// Provide the URL to your route that has the VerifyMagicLink component on it.
|
|
339
|
+
verifyUrl={verifyUrl}
|
|
323
340
|
/>
|
|
324
341
|
```
|
|
325
342
|
|
|
@@ -4,6 +4,7 @@ export interface IRequestMagicLink {
|
|
|
4
4
|
classNames?: RequestMagicLinkClasses;
|
|
5
5
|
handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void;
|
|
6
6
|
props?: any;
|
|
7
|
+
verifyUrl?: URL;
|
|
7
8
|
}
|
|
8
9
|
export type RequestMagicLinkClasses = {
|
|
9
10
|
button?: string;
|
|
@@ -13,4 +14,4 @@ export type RequestMagicLinkClasses = {
|
|
|
13
14
|
form?: string;
|
|
14
15
|
message?: string;
|
|
15
16
|
};
|
|
16
|
-
export declare const RequestMagicLink: ({ classNames, handleMagicLinkRequested, }: IRequestMagicLink) => import("react").JSX.Element;
|
|
17
|
+
export declare const RequestMagicLink: ({ classNames, handleMagicLinkRequested, verifyUrl, }: IRequestMagicLink) => import("react").JSX.Element;
|
|
@@ -13,7 +13,7 @@ export const RequestMagicLink = ({ classNames = {
|
|
|
13
13
|
error: '',
|
|
14
14
|
form: '',
|
|
15
15
|
message: ''
|
|
16
|
-
}, handleMagicLinkRequested })=>{
|
|
16
|
+
}, handleMagicLinkRequested, verifyUrl })=>{
|
|
17
17
|
const { subscriber } = useSubscriber();
|
|
18
18
|
const { serverURL } = useServerUrl();
|
|
19
19
|
const [status, setStatus] = useState('default');
|
|
@@ -29,11 +29,10 @@ export const RequestMagicLink = ({ classNames = {
|
|
|
29
29
|
]);
|
|
30
30
|
const handleSubmit = async (e)=>{
|
|
31
31
|
e.preventDefault();
|
|
32
|
-
const forwardUrl = window.location.pathname + '?now=' + new Date().toISOString();
|
|
33
32
|
const emailTokenResponse = await sdk.request({
|
|
34
33
|
json: {
|
|
35
34
|
email,
|
|
36
|
-
|
|
35
|
+
verifyUrl: verifyUrl?.href
|
|
37
36
|
},
|
|
38
37
|
method: 'POST',
|
|
39
38
|
path: '/api/emailToken'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/app/RequestMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ChangeEvent, type SubmitEvent, useEffect, useState } from 'react'\n\nimport type { Config } from '../../copied/payload-types.js'\nimport type { RequestMagicLinkResponse } from '../../endpoints/requestMagicLink.js'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../../react-hooks/useServerUrl.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\nexport { RequestMagicLinkResponse }\n\nexport interface IRequestMagicLink {\n classNames?: RequestMagicLinkClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n props?: any\n}\n\nexport type RequestMagicLinkClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n message?: string\n}\n\ntype statusValues = 'default' | 'error' | 'sent'\n\nexport const RequestMagicLink = ({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n message: '',\n },\n handleMagicLinkRequested,\n}: IRequestMagicLink) => {\n const { subscriber } = useSubscriber()\n const { serverURL } = useServerUrl()\n
|
|
1
|
+
{"version":3,"sources":["../../../src/components/app/RequestMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ChangeEvent, type SubmitEvent, useEffect, useState } from 'react'\n\nimport type { Config } from '../../copied/payload-types.js'\nimport type { RequestMagicLinkResponse } from '../../endpoints/requestMagicLink.js'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../../react-hooks/useServerUrl.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\nexport { RequestMagicLinkResponse }\n\nexport interface IRequestMagicLink {\n classNames?: RequestMagicLinkClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n props?: any\n verifyUrl?: URL\n}\n\nexport type RequestMagicLinkClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n message?: string\n}\n\ntype statusValues = 'default' | 'error' | 'sent'\n\nexport const RequestMagicLink = ({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n message: '',\n },\n handleMagicLinkRequested,\n verifyUrl,\n}: IRequestMagicLink) => {\n const { subscriber } = useSubscriber()\n const { serverURL } = useServerUrl()\n const [status, setStatus] = useState<statusValues>('default')\n\n const sdk = new PayloadSDK<Config>({\n baseURL: serverURL || '',\n })\n\n const [result, setResult] = useState<string>()\n const [email, setEmail] = useState(subscriber?.email || '')\n\n useEffect(() => {\n setEmail(subscriber?.email || '')\n }, [subscriber])\n\n const handleSubmit = async (e: SubmitEvent<HTMLFormElement>) => {\n e.preventDefault()\n const emailTokenResponse = await sdk.request({\n json: {\n email,\n verifyUrl: verifyUrl?.href,\n },\n method: 'POST',\n path: '/api/emailToken',\n })\n if (emailTokenResponse.ok) {\n const emailTokenResponseJson: RequestMagicLinkResponse = await emailTokenResponse.json()\n if (handleMagicLinkRequested) {\n handleMagicLinkRequested(emailTokenResponseJson)\n }\n // @ts-expect-error One or the other exists\n const { emailResult, error } = emailTokenResponseJson\n if (error) {\n setStatus('error')\n setResult(`An error occured. Please try again. \\n ${error}`)\n } else if (emailResult) {\n setStatus('sent')\n setResult('An email has been sent containing your magic link.')\n } else {\n setStatus('error')\n setResult(`An error occured. Please try again. \\nResult unknown`)\n }\n } else {\n const emailTokenResponseText = await emailTokenResponse.text()\n setStatus('error')\n setResult(`An error occured. Please try again. \\n${emailTokenResponseText}`)\n }\n }\n\n return (\n <div className={mergeClassNames([styles.container, classNames.container])}>\n {result ? (\n <p\n className={mergeClassNames([\n styles.message,\n classNames.message,\n status == 'error' ? [styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n ) : (\n <></>\n )}\n <form\n className={mergeClassNames([styles.form, classNames.form])}\n method=\"POST\"\n onSubmit={handleSubmit}\n >\n <input\n aria-label=\"enter your email\"\n className={mergeClassNames([styles.emailInput, classNames.emailInput])}\n onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}\n placeholder=\"enter your email\"\n type=\"email\"\n value={email}\n />\n <button className={mergeClassNames([styles.button, classNames.button])} type=\"submit\">\n Request magic link\n </button>\n </form>\n </div>\n )\n}\n"],"names":["PayloadSDK","useEffect","useState","useSubscriber","useServerUrl","mergeClassNames","styles","RequestMagicLink","classNames","button","container","emailInput","error","form","message","handleMagicLinkRequested","verifyUrl","subscriber","serverURL","status","setStatus","sdk","baseURL","result","setResult","email","setEmail","handleSubmit","e","preventDefault","emailTokenResponse","request","json","href","method","path","ok","emailTokenResponseJson","emailResult","emailTokenResponseText","text","div","className","p","onSubmit","input","aria-label","onChange","target","value","placeholder","type"],"mappings":"AAAA;;AAEA,SAASA,UAAU,QAAQ,kBAAiB;AAC5C,SAA6CC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAK/E,SAASC,aAAa,QAAQ,uCAAsC;AACpE,SAASC,YAAY,QAAQ,oCAAmC;AAChE,SAASC,eAAe,QAAQ,eAAc;AAC9C,OAAOC,YAAY,sBAAqB;AAsBxC,OAAO,MAAMC,mBAAmB,CAAC,EAC/BC,aAAa;IACXC,QAAQ;IACRC,WAAW;IACXC,YAAY;IACZC,OAAO;IACPC,MAAM;IACNC,SAAS;AACX,CAAC,EACDC,wBAAwB,EACxBC,SAAS,EACS;IAClB,MAAM,EAAEC,UAAU,EAAE,GAAGd;IACvB,MAAM,EAAEe,SAAS,EAAE,GAAGd;IACtB,MAAM,CAACe,QAAQC,UAAU,GAAGlB,SAAuB;IAEnD,MAAMmB,MAAM,IAAIrB,WAAmB;QACjCsB,SAASJ,aAAa;IACxB;IAEA,MAAM,CAACK,QAAQC,UAAU,GAAGtB;IAC5B,MAAM,CAACuB,OAAOC,SAAS,GAAGxB,SAASe,YAAYQ,SAAS;IAExDxB,UAAU;QACRyB,SAAST,YAAYQ,SAAS;IAChC,GAAG;QAACR;KAAW;IAEf,MAAMU,eAAe,OAAOC;QAC1BA,EAAEC,cAAc;QAChB,MAAMC,qBAAqB,MAAMT,IAAIU,OAAO,CAAC;YAC3CC,MAAM;gBACJP;gBACAT,WAAWA,WAAWiB;YACxB;YACAC,QAAQ;YACRC,MAAM;QACR;QACA,IAAIL,mBAAmBM,EAAE,EAAE;YACzB,MAAMC,yBAAmD,MAAMP,mBAAmBE,IAAI;YACtF,IAAIjB,0BAA0B;gBAC5BA,yBAAyBsB;YAC3B;YACA,2CAA2C;YAC3C,MAAM,EAAEC,WAAW,EAAE1B,KAAK,EAAE,GAAGyB;YAC/B,IAAIzB,OAAO;gBACTQ,UAAU;gBACVI,UAAU,CAAC,uCAAuC,EAAEZ,OAAO;YAC7D,OAAO,IAAI0B,aAAa;gBACtBlB,UAAU;gBACVI,UAAU;YACZ,OAAO;gBACLJ,UAAU;gBACVI,UAAU,CAAC,oDAAoD,CAAC;YAClE;QACF,OAAO;YACL,MAAMe,yBAAyB,MAAMT,mBAAmBU,IAAI;YAC5DpB,UAAU;YACVI,UAAU,CAAC,sCAAsC,EAAEe,wBAAwB;QAC7E;IACF;IAEA,qBACE,MAACE;QAAIC,WAAWrC,gBAAgB;YAACC,OAAOI,SAAS;YAAEF,WAAWE,SAAS;SAAC;;YACrEa,uBACC,KAACoB;gBACCD,WAAWrC,gBAAgB;oBACzBC,OAAOQ,OAAO;oBACdN,WAAWM,OAAO;oBAClBK,UAAU,UAAU;wBAACb,OAAOM,KAAK;wBAAEJ,WAAWI,KAAK;qBAAC,GAAG,EAAE;iBAC1D;0BAEAW;+BAGH;0BAEF,MAACV;gBACC6B,WAAWrC,gBAAgB;oBAACC,OAAOO,IAAI;oBAAEL,WAAWK,IAAI;iBAAC;gBACzDqB,QAAO;gBACPU,UAAUjB;;kCAEV,KAACkB;wBACCC,cAAW;wBACXJ,WAAWrC,gBAAgB;4BAACC,OAAOK,UAAU;4BAAEH,WAAWG,UAAU;yBAAC;wBACrEoC,UAAU,CAACnB,IAAqCF,SAASE,EAAEoB,MAAM,CAACC,KAAK;wBACvEC,aAAY;wBACZC,MAAK;wBACLF,OAAOxB;;kCAET,KAAChB;wBAAOiC,WAAWrC,gBAAgB;4BAACC,OAAOG,MAAM;4BAAED,WAAWC,MAAM;yBAAC;wBAAG0C,MAAK;kCAAS;;;;;;AAM9F,EAAC"}
|
|
@@ -10,8 +10,9 @@ export type RequestOrSubscribeClasses = {
|
|
|
10
10
|
message?: string;
|
|
11
11
|
section?: string;
|
|
12
12
|
};
|
|
13
|
-
export declare function RequestOrSubscribe({ classNames, handleMagicLinkRequested, handleSubscribe, }: {
|
|
13
|
+
export declare function RequestOrSubscribe({ classNames, handleMagicLinkRequested, handleSubscribe, verifyUrl, }: {
|
|
14
14
|
classNames?: RequestOrSubscribeClasses;
|
|
15
15
|
handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void;
|
|
16
16
|
handleSubscribe?: (result: SubscribeResponse) => void;
|
|
17
|
+
verifyUrl?: URL;
|
|
17
18
|
}): import("react").JSX.Element;
|
|
@@ -11,16 +11,18 @@ export function RequestOrSubscribe({ classNames = {
|
|
|
11
11
|
loading: '',
|
|
12
12
|
message: '',
|
|
13
13
|
section: ''
|
|
14
|
-
}, handleMagicLinkRequested, handleSubscribe }) {
|
|
14
|
+
}, handleMagicLinkRequested, handleSubscribe, verifyUrl }) {
|
|
15
15
|
const { subscriber } = useSubscriber();
|
|
16
16
|
// Example: Conditionally render something or pass the state to children
|
|
17
17
|
return /*#__PURE__*/ _jsx(_Fragment, {
|
|
18
18
|
children: subscriber ? /*#__PURE__*/ _jsx(Subscribe, {
|
|
19
19
|
classNames: classNames,
|
|
20
|
-
handleSubscribe: handleSubscribe
|
|
20
|
+
handleSubscribe: handleSubscribe,
|
|
21
|
+
verifyUrl: verifyUrl
|
|
21
22
|
}) : /*#__PURE__*/ _jsx(RequestMagicLink, {
|
|
22
23
|
classNames: classNames,
|
|
23
|
-
handleMagicLinkRequested: handleMagicLinkRequested
|
|
24
|
+
handleMagicLinkRequested: handleMagicLinkRequested,
|
|
25
|
+
verifyUrl: verifyUrl
|
|
24
26
|
})
|
|
25
27
|
});
|
|
26
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/app/RequestOrSubscribe.tsx"],"sourcesContent":["'use client'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport {\n RequestMagicLink,\n type RequestMagicLinkResponse,\n Subscribe,\n type SubscribeResponse,\n} from '../../exports/ui.js'\n\nexport type { RequestMagicLinkResponse, SubscribeResponse }\n\nexport type RequestOrSubscribeClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n loading?: string\n message?: string\n section?: string\n}\n\nexport function RequestOrSubscribe({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n section: '',\n },\n handleMagicLinkRequested,\n handleSubscribe,\n}: {\n classNames?: RequestOrSubscribeClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n handleSubscribe?: (result: SubscribeResponse) => void\n}) {\n const { subscriber } = useSubscriber()\n\n // Example: Conditionally render something or pass the state to children\n return (\n <>\n {subscriber ? (\n <Subscribe
|
|
1
|
+
{"version":3,"sources":["../../../src/components/app/RequestOrSubscribe.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport {\n RequestMagicLink,\n type RequestMagicLinkResponse,\n Subscribe,\n type SubscribeResponse,\n} from '../../exports/ui.js'\n\nexport type { RequestMagicLinkResponse, SubscribeResponse }\n\nexport type RequestOrSubscribeClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n loading?: string\n message?: string\n section?: string\n}\n\nexport function RequestOrSubscribe({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n section: '',\n },\n handleMagicLinkRequested,\n handleSubscribe,\n verifyUrl,\n}: {\n classNames?: RequestOrSubscribeClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n handleSubscribe?: (result: SubscribeResponse) => void\n verifyUrl?: URL\n}) {\n const { subscriber } = useSubscriber()\n\n // Example: Conditionally render something or pass the state to children\n return (\n <>\n {subscriber ? (\n <Subscribe\n classNames={classNames}\n handleSubscribe={handleSubscribe}\n verifyUrl={verifyUrl}\n />\n ) : (\n <RequestMagicLink\n classNames={classNames}\n handleMagicLinkRequested={handleMagicLinkRequested}\n verifyUrl={verifyUrl}\n />\n )}\n {/* <div>subscriber = {JSON.stringify(subscriber)}</div> */}\n </>\n )\n}\n"],"names":["useSubscriber","RequestMagicLink","Subscribe","RequestOrSubscribe","classNames","button","container","emailInput","error","form","loading","message","section","handleMagicLinkRequested","handleSubscribe","verifyUrl","subscriber"],"mappings":"AAAA;;AAIA,SAASA,aAAa,QAAQ,uCAAsC;AACpE,SACEC,gBAAgB,EAEhBC,SAAS,QAEJ,sBAAqB;AAe5B,OAAO,SAASC,mBAAmB,EACjCC,aAAa;IACXC,QAAQ;IACRC,WAAW;IACXC,YAAY;IACZC,OAAO;IACPC,MAAM;IACNC,SAAS;IACTC,SAAS;IACTC,SAAS;AACX,CAAC,EACDC,wBAAwB,EACxBC,eAAe,EACfC,SAAS,EAMV;IACC,MAAM,EAAEC,UAAU,EAAE,GAAGhB;IAEvB,wEAAwE;IACxE,qBACE;kBACGgB,2BACC,KAACd;YACCE,YAAYA;YACZU,iBAAiBA;YACjBC,WAAWA;2BAGb,KAACd;YACCG,YAAYA;YACZS,0BAA0BA;YAC1BE,WAAWA;;;AAMrB"}
|
|
@@ -4,6 +4,7 @@ export interface ISubscribe {
|
|
|
4
4
|
classNames?: SubscribeClasses;
|
|
5
5
|
handleSubscribe?: (result: SubscribeResponse) => void;
|
|
6
6
|
props?: any;
|
|
7
|
+
verifyUrl?: URL;
|
|
7
8
|
}
|
|
8
9
|
export type SubscribeClasses = {
|
|
9
10
|
button?: string;
|
|
@@ -15,4 +16,4 @@ export type SubscribeClasses = {
|
|
|
15
16
|
message?: string;
|
|
16
17
|
section?: string;
|
|
17
18
|
};
|
|
18
|
-
export declare const Subscribe: ({ classNames, handleSubscribe, }: ISubscribe) => import("react").JSX.Element;
|
|
19
|
+
export declare const Subscribe: ({ classNames, handleSubscribe, verifyUrl, }: ISubscribe) => import("react").JSX.Element;
|
|
@@ -16,7 +16,7 @@ export const Subscribe = ({ classNames = {
|
|
|
16
16
|
loading: '',
|
|
17
17
|
message: '',
|
|
18
18
|
section: ''
|
|
19
|
-
}, handleSubscribe })=>{
|
|
19
|
+
}, handleSubscribe, verifyUrl })=>{
|
|
20
20
|
const { refreshSubscriber, subscriber } = useSubscriber();
|
|
21
21
|
const { serverURL } = useServerUrl();
|
|
22
22
|
const sdk = new PayloadSDK({
|
|
@@ -44,9 +44,9 @@ export const Subscribe = ({ classNames = {
|
|
|
44
44
|
const handleSubmit = async ()=>{
|
|
45
45
|
const subscribeResult = await sdk.request({
|
|
46
46
|
json: {
|
|
47
|
-
afterVerifyUrl: window.location.pathname + '?now=' + new Date().toISOString(),
|
|
48
47
|
email,
|
|
49
|
-
optIns: selectedChannelIDs
|
|
48
|
+
optIns: selectedChannelIDs,
|
|
49
|
+
verifyUrl: verifyUrl?.href
|
|
50
50
|
},
|
|
51
51
|
method: 'POST',
|
|
52
52
|
path: '/api/subscribe'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/app/Subscribe.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ChangeEvent, useEffect, useState } from 'react'\n\nimport type { Config, OptInChannel } from '../../copied/payload-types.js'\nimport type { SubscribeResponse } from '../../endpoints/subscribe.js'\n\nexport { SubscribeResponse }\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.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// const payload = await getPayload({\n// config: configPromise,\n// })\n\n// Pass your config from generated types as generic\n\nexport interface ISubscribe {\n classNames?: SubscribeClasses\n handleSubscribe?: (result: SubscribeResponse) => void\n props?: any\n}\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\ntype statusValues = 'default' | 'error' | 'sent' | 'updated'\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}: ISubscribe) => {\n const { refreshSubscriber, subscriber } = useSubscriber()\n\n const { serverURL } = useServerUrl()\n\n const sdk = new PayloadSDK<Config>({\n baseURL: serverURL || '',\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 [status, setStatus] = useState<statusValues>('default')\n const [result, setResult] = useState<string>()\n const [email, setEmail] = useState(subscriber ? subscriber.email : '')\n const [selectedChannelIDs, setSelectedChannelIDs] = useState<string[]>(() =>\n flattenChannels(subscriber?.optIns),\n )\n\n useEffect(() => {\n setEmail(subscriber?.email || '')\n setSelectedChannelIDs(flattenChannels(subscriber?.optIns))\n }, [subscriber])\n\n const handleOptInChannelsSelected = (result: OptInChannel[]) => {\n setSelectedChannelIDs(result.map((channel) => channel.id))\n }\n\n const handleSubmit = async () => {\n const subscribeResult = await sdk.request({\n json: {\n
|
|
1
|
+
{"version":3,"sources":["../../../src/components/app/Subscribe.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ChangeEvent, useEffect, useState } from 'react'\n\nimport type { Config, OptInChannel } from '../../copied/payload-types.js'\nimport type { SubscribeResponse } from '../../endpoints/subscribe.js'\n\nexport { SubscribeResponse }\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.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// const payload = await getPayload({\n// config: configPromise,\n// })\n\n// Pass your config from generated types as generic\n\nexport interface ISubscribe {\n classNames?: SubscribeClasses\n handleSubscribe?: (result: SubscribeResponse) => void\n props?: any\n verifyUrl?: URL\n}\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\ntype statusValues = 'default' | 'error' | 'sent' | 'updated'\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 verifyUrl,\n}: ISubscribe) => {\n const { refreshSubscriber, subscriber } = useSubscriber()\n\n const { serverURL } = useServerUrl()\n\n const sdk = new PayloadSDK<Config>({\n baseURL: serverURL || '',\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 [status, setStatus] = useState<statusValues>('default')\n const [result, setResult] = useState<string>()\n const [email, setEmail] = useState(subscriber ? subscriber.email : '')\n const [selectedChannelIDs, setSelectedChannelIDs] = useState<string[]>(() =>\n flattenChannels(subscriber?.optIns),\n )\n\n useEffect(() => {\n setEmail(subscriber?.email || '')\n setSelectedChannelIDs(flattenChannels(subscriber?.optIns))\n }, [subscriber])\n\n const handleOptInChannelsSelected = (result: OptInChannel[]) => {\n setSelectedChannelIDs(result.map((channel) => channel.id))\n }\n\n const handleSubmit = async () => {\n const subscribeResult = await sdk.request({\n json: {\n email,\n optIns: selectedChannelIDs,\n verifyUrl: verifyUrl?.href,\n },\n method: 'POST',\n path: '/api/subscribe',\n })\n if (subscribeResult.ok) {\n const resultJson: SubscribeResponse = await subscribeResult.json()\n // // When subscriber optIns are updated...\n // | {\n // email: string\n // now: string\n // optIns: string[]\n // }\n // // When a verify link is emailed...\n // | {\n // emailResult: any\n // now: string\n // }\n // // When any error occurs...\n // | {\n // error: string\n // now: string\n // }\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 (email) {\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 <div className={mergeClassNames([styles.container, classNames.container])}>\n <h2>Subscribe</h2>\n <div className={mergeClassNames([styles.section, classNames.section])}>\n <SelectOptInChannels\n handleOptInChannelsSelected={handleOptInChannelsSelected}\n selectedOptInChannelIDs={selectedChannelIDs}\n />\n </div>\n <form\n className={mergeClassNames([styles.form, classNames.form])}\n method=\"POST\"\n onSubmit={async (e) => {\n e.preventDefault()\n await handleSubmit()\n }}\n >\n <div className={mergeClassNames([styles.section, classNames.section])}>\n {!subscriber && (\n <input\n aria-label=\"enter your email\"\n className={mergeClassNames([styles.emailInput, classNames.emailInput])}\n onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}\n placeholder=\"enter your email\"\n type=\"email\"\n value={email}\n />\n )}\n <button className={mergeClassNames([styles.button, classNames.button])} type=\"submit\">\n Save choices\n </button>\n </div>\n </form>\n {!!result && (\n <p\n className={mergeClassNames([\n styles.message,\n classNames.message,\n status == 'error' ? [styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n )}\n </div>\n )\n}\n"],"names":["PayloadSDK","useEffect","useState","useSubscriber","useServerUrl","mergeClassNames","SelectOptInChannels","styles","Subscribe","classNames","button","container","emailInput","error","form","loading","message","section","handleSubscribe","verifyUrl","refreshSubscriber","subscriber","serverURL","sdk","baseURL","flattenChannels","channels","map","channel","id","status","setStatus","result","setResult","email","setEmail","selectedChannelIDs","setSelectedChannelIDs","optIns","handleOptInChannelsSelected","handleSubmit","subscribeResult","request","json","href","method","path","ok","resultJson","emailResult","div","className","h2","selectedOptInChannelIDs","onSubmit","e","preventDefault","input","aria-label","onChange","target","value","placeholder","type","p"],"mappings":"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"}
|
|
@@ -2,22 +2,24 @@ import type { RequestMagicLinkResponse } from '../..//endpoints/requestMagicLink
|
|
|
2
2
|
import type { VerifyMagicLinkResponse } from '../../endpoints/verifyMagicLink.js';
|
|
3
3
|
export { VerifyMagicLinkResponse };
|
|
4
4
|
export interface IVerifyMagicLink {
|
|
5
|
+
children?: React.ReactNode;
|
|
5
6
|
classNames?: VerifyMagicLinkClasses;
|
|
6
7
|
handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void;
|
|
7
8
|
handleMagicLinkVerified?: (result: VerifyMagicLinkResponse) => void;
|
|
8
9
|
renderButton?: (props: {
|
|
9
|
-
forwardUrl?: string;
|
|
10
10
|
name?: string;
|
|
11
11
|
onClick?: () => any;
|
|
12
12
|
text?: string;
|
|
13
13
|
}) => React.ReactNode;
|
|
14
|
+
verifyUrl?: URL;
|
|
14
15
|
}
|
|
15
16
|
export type VerifyMagicLinkClasses = {
|
|
16
17
|
button?: string;
|
|
17
18
|
container?: string;
|
|
19
|
+
emailInput?: string;
|
|
18
20
|
error?: string;
|
|
19
21
|
form?: string;
|
|
20
22
|
loading?: string;
|
|
21
23
|
message?: string;
|
|
22
24
|
};
|
|
23
|
-
export declare const VerifyMagicLink: ({ classNames, handleMagicLinkRequested, handleMagicLinkVerified, renderButton, }: IVerifyMagicLink) => import("react").JSX.Element;
|
|
25
|
+
export declare const VerifyMagicLink: ({ children, classNames, handleMagicLinkRequested, handleMagicLinkVerified, renderButton, verifyUrl, }: IVerifyMagicLink) => import("react").JSX.Element;
|
|
@@ -7,25 +7,15 @@ import { RequestMagicLink, useSubscriber } from '../../exports/ui.js';
|
|
|
7
7
|
import { useServerUrl } from '../../react-hooks/useServerUrl.js';
|
|
8
8
|
import { mergeClassNames } from './helpers.js';
|
|
9
9
|
import styles from './shared.module.css';
|
|
10
|
-
export const VerifyMagicLink = ({ classNames = {
|
|
10
|
+
export const VerifyMagicLink = ({ children, classNames = {
|
|
11
11
|
button: '',
|
|
12
12
|
container: '',
|
|
13
|
+
emailInput: '',
|
|
13
14
|
error: '',
|
|
14
15
|
form: '',
|
|
15
16
|
loading: '',
|
|
16
17
|
message: ''
|
|
17
|
-
}, handleMagicLinkRequested, handleMagicLinkVerified, renderButton = ({ name,
|
|
18
|
-
href: forwardUrl,
|
|
19
|
-
children: /*#__PURE__*/ _jsx("button", {
|
|
20
|
-
className: mergeClassNames([
|
|
21
|
-
styles.button,
|
|
22
|
-
classNames.button
|
|
23
|
-
]),
|
|
24
|
-
name: name,
|
|
25
|
-
type: "button",
|
|
26
|
-
children: text
|
|
27
|
-
})
|
|
28
|
-
}) : /*#__PURE__*/ _jsx("button", {
|
|
18
|
+
}, handleMagicLinkRequested, handleMagicLinkVerified, renderButton = ({ name, onClick, text })=>/*#__PURE__*/ _jsx("button", {
|
|
29
19
|
className: mergeClassNames([
|
|
30
20
|
styles.button,
|
|
31
21
|
classNames.button
|
|
@@ -34,13 +24,12 @@ export const VerifyMagicLink = ({ classNames = {
|
|
|
34
24
|
onClick: onClick,
|
|
35
25
|
type: "button",
|
|
36
26
|
children: text
|
|
37
|
-
}) })=>{
|
|
27
|
+
}), verifyUrl })=>{
|
|
38
28
|
const { serverURL } = useServerUrl();
|
|
39
29
|
const { // refreshSubscriber,
|
|
40
30
|
subscriber } = useSubscriber();
|
|
41
31
|
const searchParams = useSearchParams();
|
|
42
32
|
const email = searchParams.get('email');
|
|
43
|
-
const forwardUrl = searchParams.get('forwardUrl');
|
|
44
33
|
const token = searchParams.get('token');
|
|
45
34
|
const [result, setResult] = useState();
|
|
46
35
|
const [isError, setIsError] = useState(false);
|
|
@@ -122,7 +111,7 @@ export const VerifyMagicLink = ({ classNames = {
|
|
|
122
111
|
const emailResult = await sdk.request({
|
|
123
112
|
json: {
|
|
124
113
|
email,
|
|
125
|
-
|
|
114
|
+
verifyUrl: verifyUrl?.href
|
|
126
115
|
},
|
|
127
116
|
method: 'POST',
|
|
128
117
|
path: '/api/emailToken'
|
|
@@ -175,16 +164,12 @@ export const VerifyMagicLink = ({ classNames = {
|
|
|
175
164
|
classNames.form
|
|
176
165
|
]),
|
|
177
166
|
children: [
|
|
178
|
-
result && isError && renderButton({
|
|
167
|
+
result && isError && renderButton && renderButton({
|
|
179
168
|
name: 'request',
|
|
180
169
|
onClick: handleRequestAnother,
|
|
181
170
|
text: 'Request another magic link'
|
|
182
171
|
}),
|
|
183
|
-
result &&
|
|
184
|
-
name: 'continue',
|
|
185
|
-
forwardUrl,
|
|
186
|
-
text: 'Continue'
|
|
187
|
-
})
|
|
172
|
+
result && children
|
|
188
173
|
]
|
|
189
174
|
})
|
|
190
175
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/app/VerifyMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { useSearchParams } from 'next/navigation.js'\nimport { useCallback, useEffect, useState } from 'react'\n\nimport type { RequestMagicLinkResponse } from '../..//endpoints/requestMagicLink.js'\nimport type { Config } from '../../copied/payload-types.js'\nimport type { VerifyMagicLinkResponse } from '../../endpoints/verifyMagicLink.js'\n\nexport { VerifyMagicLinkResponse }\nimport { RequestMagicLink, useSubscriber } from '../../exports/ui.js'\nimport { useServerUrl } from '../../react-hooks/useServerUrl.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\n// const payload = await getPayload({\n// config: configPromise,\n// })\n\n// Pass your config from generated types as generic\n\nexport interface IVerifyMagicLink {\n classNames?: VerifyMagicLinkClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n handleMagicLinkVerified?: (result: VerifyMagicLinkResponse) => void\n renderButton?: (props: {\n forwardUrl?: string\n name?: string\n onClick?: () => any\n text?: string\n }) => React.ReactNode\n}\n\nexport type VerifyMagicLinkClasses = {\n button?: string\n container?: string\n error?: string\n form?: string\n loading?: string\n message?: string\n}\n\nexport const VerifyMagicLink = ({\n classNames = {\n button: '',\n container: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n },\n handleMagicLinkRequested,\n handleMagicLinkVerified,\n renderButton = ({ name, forwardUrl, onClick, text }) =>\n forwardUrl ? (\n <a href={forwardUrl}>\n <button\n className={mergeClassNames([styles.button, classNames.button])}\n name={name}\n type=\"button\"\n >\n {text}\n </button>\n </a>\n ) : (\n <button\n className={mergeClassNames([styles.button, classNames.button])}\n name={name}\n onClick={onClick}\n type=\"button\"\n >\n {text}\n </button>\n ),\n}: IVerifyMagicLink) => {\n const { serverURL } = useServerUrl()\n const {\n // refreshSubscriber,\n subscriber,\n } = useSubscriber()\n\n const searchParams = useSearchParams()\n const email = searchParams.get('email')\n const forwardUrl = searchParams.get('forwardUrl')\n const token = searchParams.get('token')\n\n const [result, setResult] = useState<string>()\n const [isError, setIsError] = useState<boolean>(false)\n // const [email, setEmail] = useState('')\n\n const { refreshSubscriber } = useSubscriber()\n\n const callVerify = useCallback(async () => {\n if (!email || !token) {\n console.info('Invalid input')\n return { error: 'Invalid input' }\n }\n try {\n // I tried using PayloadSDK.request, but when the endpoint\n // returns a not-okay status, PayloadSDK.request returns its\n // own \"Bad request\" error, and doesn't share the endpoint\n // result data.\n const verifyEndpointResult = await fetch(serverURL + '/api/verifyToken', {\n body: JSON.stringify({\n email,\n token,\n }),\n method: 'POST',\n })\n\n // return verifyEndpointResult\n if (verifyEndpointResult && verifyEndpointResult.json) {\n console.log(1)\n const resultJson = await verifyEndpointResult.json()\n return { error: resultJson.error, message: resultJson.message }\n } else if (verifyEndpointResult && verifyEndpointResult.text) {\n console.log(2)\n const resultText = await verifyEndpointResult.text()\n return { error: resultText }\n } else {\n console.log(3)\n return { error: verifyEndpointResult.status }\n }\n } catch (error: unknown) {\n console.log('catch')\n return { error }\n }\n }, [email, serverURL, token])\n\n useEffect(() => {\n async function verify() {\n const { error, message } = await callVerify()\n setResult(message || `An error occured. Please try again. (${error})`)\n setIsError(error && !message)\n // console.info('callVerify not okay', { error, message })\n }\n if (!subscriber) {\n void verify()\n }\n }, [callVerify, serverURL, email, handleMagicLinkVerified, refreshSubscriber, subscriber, token])\n\n const handleRequestAnother = async () => {\n const sdk = new PayloadSDK<Config>({\n baseURL: serverURL || '',\n })\n\n const emailResult = await sdk.request({\n json: {\n email,\n forwardUrl,\n },\n method: 'POST',\n path: '/api/emailToken',\n })\n if (emailResult.ok) {\n const resultJson = await emailResult.json()\n setResult('An email has been sent containing your magic link.')\n setIsError(false)\n if (handleMagicLinkRequested) {\n handleMagicLinkRequested(resultJson)\n }\n } else {\n // const resultText = await emailResult.text()\n setResult('An error occured. Please try again.')\n setIsError(true)\n }\n }\n\n return (\n <>\n {(!email || !token) && <RequestMagicLink classNames={classNames} />}\n {email && token && (\n <div className={mergeClassNames([styles.container, classNames.container])}>\n {!result && (\n <p className={mergeClassNames([styles.loading, classNames.loading])}>verifying...</p>\n )}\n {result && (\n <p\n className={mergeClassNames([\n styles.message,\n classNames.message,\n isError ? [styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n )}\n <div className={mergeClassNames([styles.form, classNames.form])}>\n {result &&\n isError &&\n renderButton({\n name: 'request',\n onClick: handleRequestAnother,\n text: 'Request another magic link',\n })}\n {result &&\n forwardUrl &&\n renderButton({\n name: 'continue',\n forwardUrl,\n text: 'Continue',\n })}\n </div>\n </div>\n )}\n </>\n )\n}\n"],"names":["PayloadSDK","useSearchParams","useCallback","useEffect","useState","RequestMagicLink","useSubscriber","useServerUrl","mergeClassNames","styles","VerifyMagicLink","classNames","button","container","error","form","loading","message","handleMagicLinkRequested","handleMagicLinkVerified","renderButton","name","forwardUrl","onClick","text","a","href","className","type","serverURL","subscriber","searchParams","email","get","token","result","setResult","isError","setIsError","refreshSubscriber","callVerify","console","info","verifyEndpointResult","fetch","body","JSON","stringify","method","json","log","resultJson","resultText","status","verify","handleRequestAnother","sdk","baseURL","emailResult","request","path","ok","div","p"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/app/VerifyMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { useSearchParams } from 'next/navigation.js'\nimport { useCallback, useEffect, useState } from 'react'\n\nimport type { RequestMagicLinkResponse } from '../..//endpoints/requestMagicLink.js'\nimport type { Config } from '../../copied/payload-types.js'\nimport type { VerifyMagicLinkResponse } from '../../endpoints/verifyMagicLink.js'\n\nexport { VerifyMagicLinkResponse }\nimport { RequestMagicLink, useSubscriber } from '../../exports/ui.js'\nimport { useServerUrl } from '../../react-hooks/useServerUrl.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\n// const payload = await getPayload({\n// config: configPromise,\n// })\n\n// Pass your config from generated types as generic\n\nexport interface IVerifyMagicLink {\n children?: React.ReactNode\n classNames?: VerifyMagicLinkClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n handleMagicLinkVerified?: (result: VerifyMagicLinkResponse) => void\n renderButton?: (props: { name?: string; onClick?: () => any; text?: string }) => React.ReactNode\n verifyUrl?: URL\n}\n\nexport type VerifyMagicLinkClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n loading?: string\n message?: string\n}\n\nexport const VerifyMagicLink = ({\n children,\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n },\n handleMagicLinkRequested,\n handleMagicLinkVerified,\n renderButton = ({ name, onClick, text }) => (\n <button\n className={mergeClassNames([styles.button, classNames.button])}\n name={name}\n onClick={onClick}\n type=\"button\"\n >\n {text}\n </button>\n ),\n verifyUrl,\n}: IVerifyMagicLink) => {\n const { serverURL } = useServerUrl()\n const {\n // refreshSubscriber,\n subscriber,\n } = useSubscriber()\n\n const searchParams = useSearchParams()\n const email = searchParams.get('email')\n const token = searchParams.get('token')\n\n const [result, setResult] = useState<string>()\n const [isError, setIsError] = useState<boolean>(false)\n // const [email, setEmail] = useState('')\n\n const { refreshSubscriber } = useSubscriber()\n\n const callVerify = useCallback(async () => {\n if (!email || !token) {\n console.info('Invalid input')\n return { error: 'Invalid input' }\n }\n try {\n // I tried using PayloadSDK.request, but when the endpoint\n // returns a not-okay status, PayloadSDK.request returns its\n // own \"Bad request\" error, and doesn't share the endpoint\n // result data.\n const verifyEndpointResult = await fetch(serverURL + '/api/verifyToken', {\n body: JSON.stringify({\n email,\n token,\n }),\n method: 'POST',\n })\n\n // return verifyEndpointResult\n if (verifyEndpointResult && verifyEndpointResult.json) {\n console.log(1)\n const resultJson = await verifyEndpointResult.json()\n return { error: resultJson.error, message: resultJson.message }\n } else if (verifyEndpointResult && verifyEndpointResult.text) {\n console.log(2)\n const resultText = await verifyEndpointResult.text()\n return { error: resultText }\n } else {\n console.log(3)\n return { error: verifyEndpointResult.status }\n }\n } catch (error: unknown) {\n console.log('catch')\n return { error }\n }\n }, [email, serverURL, token])\n\n useEffect(() => {\n async function verify() {\n const { error, message } = await callVerify()\n setResult(message || `An error occured. Please try again. (${error})`)\n setIsError(error && !message)\n // console.info('callVerify not okay', { error, message })\n }\n if (!subscriber) {\n void verify()\n }\n }, [callVerify, serverURL, email, handleMagicLinkVerified, refreshSubscriber, subscriber, token])\n\n const handleRequestAnother = async () => {\n const sdk = new PayloadSDK<Config>({\n baseURL: serverURL || '',\n })\n\n const emailResult = await sdk.request({\n json: {\n email,\n verifyUrl: verifyUrl?.href,\n },\n method: 'POST',\n path: '/api/emailToken',\n })\n if (emailResult.ok) {\n const resultJson = await emailResult.json()\n setResult('An email has been sent containing your magic link.')\n setIsError(false)\n if (handleMagicLinkRequested) {\n handleMagicLinkRequested(resultJson)\n }\n } else {\n // const resultText = await emailResult.text()\n setResult('An error occured. Please try again.')\n setIsError(true)\n }\n }\n\n return (\n <>\n {(!email || !token) && <RequestMagicLink classNames={classNames} />}\n {email && token && (\n <div className={mergeClassNames([styles.container, classNames.container])}>\n {!result && (\n <p className={mergeClassNames([styles.loading, classNames.loading])}>verifying...</p>\n )}\n {result && (\n <p\n className={mergeClassNames([\n styles.message,\n classNames.message,\n isError ? [styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n )}\n <div className={mergeClassNames([styles.form, classNames.form])}>\n {result &&\n isError &&\n renderButton &&\n renderButton({\n name: 'request',\n onClick: handleRequestAnother,\n text: 'Request another magic link',\n })}\n {result && children}\n </div>\n </div>\n )}\n </>\n )\n}\n"],"names":["PayloadSDK","useSearchParams","useCallback","useEffect","useState","RequestMagicLink","useSubscriber","useServerUrl","mergeClassNames","styles","VerifyMagicLink","children","classNames","button","container","emailInput","error","form","loading","message","handleMagicLinkRequested","handleMagicLinkVerified","renderButton","name","onClick","text","className","type","verifyUrl","serverURL","subscriber","searchParams","email","get","token","result","setResult","isError","setIsError","refreshSubscriber","callVerify","console","info","verifyEndpointResult","fetch","body","JSON","stringify","method","json","log","resultJson","resultText","status","verify","handleRequestAnother","sdk","baseURL","emailResult","request","href","path","ok","div","p"],"mappings":"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"}
|
|
@@ -12,15 +12,15 @@ import { getTokenAndHash } from '../helpers/token.js';
|
|
|
12
12
|
/**
|
|
13
13
|
* requestMagicLink Endpoint Handler
|
|
14
14
|
* @param req
|
|
15
|
-
* @data { email }
|
|
15
|
+
* @data { email, verifyUrl }
|
|
16
16
|
* @returns { status: 200, json: {message: string, now: date} }
|
|
17
17
|
* @returns { status: 400, json: {error: ('Bad data' | 'Unknown email result'), now: date} }
|
|
18
18
|
*/ const requestMagicLinkHandler = async (req)=>{
|
|
19
19
|
const data = req?.json ? await req.json() : {};
|
|
20
|
-
const { email,
|
|
20
|
+
const { email, verifyUrl } = data // if by POST data
|
|
21
21
|
;
|
|
22
22
|
// const { email } = req.routeParams // if by path
|
|
23
|
-
if (!email) {
|
|
23
|
+
if (!email || !verifyUrl) {
|
|
24
24
|
return Response.json({
|
|
25
25
|
error: 'Bad data',
|
|
26
26
|
now: new Date().toISOString()
|
|
@@ -80,8 +80,7 @@ import { getTokenAndHash } from '../helpers/token.js';
|
|
|
80
80
|
}
|
|
81
81
|
});
|
|
82
82
|
// Send email
|
|
83
|
-
const
|
|
84
|
-
const magicLink = `${req.payload.config.serverURL}/verify?token=${token}&email=${email}${forwardUrlParam}`;
|
|
83
|
+
const magicLink = `${verifyUrl}${verifyUrl.search ? '&' : '?'}token=${token}&email=${email}`;
|
|
85
84
|
const subject = data.subject || 'Your Magic Login Link';
|
|
86
85
|
const message = `
|
|
87
86
|
${data.message || '<p>Use this link to log in:</p>'}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/requestMagicLink.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadHandler, PayloadRequest, TypedUser } from 'payload'\n\nimport crypto from 'crypto'\nimport { defaultCollectionSlug } from '../collections/Subscribers.js'\
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/requestMagicLink.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadHandler, PayloadRequest, TypedUser } from 'payload'\n\nimport crypto from 'crypto'\n\nimport { defaultCollectionSlug } from '../collections/Subscribers.js'\nimport { getTokenAndHash } from '../helpers/token.js'\n\nexport type RequestMagicLinkResponse =\n | {\n emailResult: any\n now: string\n }\n | {\n error: string\n now: string\n }\n\n/**\n * createEndpointRequestMagicLink\n * @param options\n * @returns\n *\n * Factory to generate the endpoint config with handler based on input option for subscribersCollectionSlug\n *\n */\nfunction createEndpointRequestMagicLink({\n subscribersCollectionSlug = defaultCollectionSlug,\n}: {\n subscribersCollectionSlug: CollectionSlug\n}): Endpoint {\n /**\n * requestMagicLink Endpoint Handler\n * @param req\n * @data { email, verifyUrl }\n * @returns { status: 200, json: {message: string, now: date} }\n * @returns { status: 400, json: {error: ('Bad data' | 'Unknown email result'), now: date} }\n */\n const requestMagicLinkHandler: PayloadHandler = async (req: PayloadRequest) => {\n const data = req?.json ? await req.json() : {}\n const { email, verifyUrl } = data // if by POST data\n // const { email } = req.routeParams // if by path\n\n if (!email || !verifyUrl) {\n return Response.json(\n { error: 'Bad data', now: new Date().toISOString() } as RequestMagicLinkResponse,\n { status: 400 },\n )\n }\n\n const userResults = await req.payload.find({\n collection: subscribersCollectionSlug,\n where: {\n email: { equals: email },\n },\n })\n const user = userResults.docs[0] as TypedUser\n\n if (!user) {\n //\n // Create subscriber with status 'pending',\n // and an invisible unknowable password,\n //\n const { tokenHash: tokenHash2 } = getTokenAndHash() // Unknowable\n const createResult = await req.payload.create({\n collection: subscribersCollectionSlug,\n data: {\n email,\n password: tokenHash2,\n status: 'pending',\n },\n draft: false,\n })\n if (!createResult) {\n return Response.json(\n { error: 'Bad data', now: new Date().toISOString() } as RequestMagicLinkResponse,\n { status: 400 },\n )\n }\n }\n\n // Update user with verificationToken\n const token = crypto.randomBytes(32).toString('hex')\n const tokenHash = crypto.createHash('sha256').update(token).digest('hex')\n const expiresAt = new Date(Date.now() + 15 * 60 * 1000) // 15 mins\n await req.payload.update({\n collection: subscribersCollectionSlug,\n data: {\n verificationToken: tokenHash,\n verificationTokenExpires: expiresAt.toISOString(),\n },\n where: {\n email: { equals: user.email },\n },\n })\n\n // Send email\n const magicLink = `${verifyUrl}${verifyUrl.search ? '&' : '?'}token=${token}&email=${email}`\n const subject = data.subject || 'Your Magic Login Link'\n const message = `\n ${data.message || '<p>Use this link to log in:</p>'}\n <p><a href=\"${magicLink}\"><b>Login</b></a></p>\n `\n const emailResult = await req.payload.sendEmail({\n html: message,\n subject,\n to: user.email,\n })\n // req.payload.logger.info(`email result: ${JSON.stringify(emailResult)}`)\n // return data; // Return data to allow normal submission if needed\n if (!emailResult) {\n return Response.json(\n {\n error: 'Unknown email result',\n now: new Date().toISOString(),\n } as RequestMagicLinkResponse,\n { status: 400 },\n )\n }\n req.payload.logger.info(`requestMagicLinkHandler email sent \\n ${magicLink}`)\n return Response.json({\n emailResult,\n now: new Date().toISOString(),\n } as RequestMagicLinkResponse)\n }\n\n /**\n * requestMagicLink Endpoint Config\n */\n const requestMagicLinkEndpoint: Endpoint = {\n handler: requestMagicLinkHandler,\n method: 'post',\n path: '/emailToken',\n }\n\n return requestMagicLinkEndpoint\n}\n\nexport default createEndpointRequestMagicLink\n"],"names":["crypto","defaultCollectionSlug","getTokenAndHash","createEndpointRequestMagicLink","subscribersCollectionSlug","requestMagicLinkHandler","req","data","json","email","verifyUrl","Response","error","now","Date","toISOString","status","userResults","payload","find","collection","where","equals","user","docs","tokenHash","tokenHash2","createResult","create","password","draft","token","randomBytes","toString","createHash","update","digest","expiresAt","verificationToken","verificationTokenExpires","magicLink","search","subject","message","emailResult","sendEmail","html","to","logger","info","requestMagicLinkEndpoint","handler","method","path"],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ import { verifyOptIns } from '../helpers/verifyOptIns.js';
|
|
|
17
17
|
* @returns { status: 400, json: {error: ('Bad data' | 'Already subscribed' | 'Unknown email result'), now: date} }
|
|
18
18
|
*/ const subscribeHandler = async (req)=>{
|
|
19
19
|
const data = req?.json ? await req.json() : {};
|
|
20
|
-
const {
|
|
20
|
+
const { email, optIns, verifyUrl } = data // if by POST data
|
|
21
21
|
;
|
|
22
22
|
// const { email } = req.routeParams // if by path
|
|
23
23
|
//
|
|
@@ -54,9 +54,8 @@ import { verifyOptIns } from '../helpers/verifyOptIns.js';
|
|
|
54
54
|
});
|
|
55
55
|
return updateResults;
|
|
56
56
|
};
|
|
57
|
-
const sendVerifyEmail = async ({ email,
|
|
58
|
-
const
|
|
59
|
-
const magicLink = `${req.payload.config.serverURL}/verify?token=${token}&email=${email}${forwardUrlParam}`;
|
|
57
|
+
const sendVerifyEmail = async ({ email, linkText, message, subject, token, verifyUrl })=>{
|
|
58
|
+
const magicLink = `${verifyUrl}${verifyUrl?.search ? '&' : '?'}token=${token}&email=${email}`;
|
|
60
59
|
const html = message + `<p><a href="${magicLink}">${linkText}</a></p>`;
|
|
61
60
|
const emailResult = await req.payload.sendEmail({
|
|
62
61
|
html,
|
|
@@ -155,11 +154,11 @@ import { verifyOptIns } from '../helpers/verifyOptIns.js';
|
|
|
155
154
|
// Send email
|
|
156
155
|
const emailResult = await sendVerifyEmail({
|
|
157
156
|
email,
|
|
158
|
-
forwardUrl: afterVerifyUrl,
|
|
159
157
|
linkText: '<b>Verify</b>',
|
|
160
158
|
message: data.message || `<p>Click here to verify your subscription:</p>`,
|
|
161
159
|
subject: data.subject || 'Please verify your subscription',
|
|
162
|
-
token
|
|
160
|
+
token,
|
|
161
|
+
verifyUrl
|
|
163
162
|
});
|
|
164
163
|
if (!emailResult) {
|
|
165
164
|
req.payload.logger.error(JSON.stringify({
|
|
@@ -211,11 +210,11 @@ import { verifyOptIns } from '../helpers/verifyOptIns.js';
|
|
|
211
210
|
// Send email
|
|
212
211
|
const emailResult = await sendVerifyEmail({
|
|
213
212
|
email,
|
|
214
|
-
forwardUrl: afterVerifyUrl,
|
|
215
213
|
linkText: 'Verify',
|
|
216
214
|
message: data.message || `<h1>Click here to verify your subscription:</h1>`,
|
|
217
215
|
subject: data.subject || 'Please verify your subscription',
|
|
218
|
-
token
|
|
216
|
+
token,
|
|
217
|
+
verifyUrl
|
|
219
218
|
});
|
|
220
219
|
if (!emailResult) {
|
|
221
220
|
req.payload.logger.error(JSON.stringify({
|
|
@@ -264,11 +263,11 @@ import { verifyOptIns } from '../helpers/verifyOptIns.js';
|
|
|
264
263
|
}
|
|
265
264
|
const emailResult = await sendVerifyEmail({
|
|
266
265
|
email,
|
|
267
|
-
forwardUrl: afterVerifyUrl,
|
|
268
266
|
linkText: 'Verify',
|
|
269
267
|
message: data.message || `<h1>Click here to verify your email:</h1>`,
|
|
270
268
|
subject: data.subject || 'Please verify your subscription',
|
|
271
|
-
token
|
|
269
|
+
token,
|
|
270
|
+
verifyUrl
|
|
272
271
|
});
|
|
273
272
|
if (!emailResult) {
|
|
274
273
|
req.payload.logger.error(JSON.stringify({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/subscribe.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadHandler } from 'payload'\nimport type { Subscriber } from 'src/copied/payload-types.js'\n\nimport { defaultCollectionSlug } from '../collections/Subscribers.js'\n\nimport { getTokenAndHash } from '../helpers/token.js'\nimport { verifyOptIns } from '../helpers/verifyOptIns.js'\n\nexport type SubscribeResponse =\n // When subscriber optIns are updated...\n | {\n email: string\n now: string\n optIns: string[]\n }\n // When a verify link is emailed...\n | {\n emailResult: any\n now: string\n }\n // When any error occurs...\n | {\n error: string\n now: string\n }\n\n/**\n * createEndpointLogout\n * @param options\n * @returns\n *\n * Factory to generate the endpoint config with handler based on input option for subscribersCollectionSlug\n *\n */\nfunction createEndpointSubscribe({\n subscribersCollectionSlug = defaultCollectionSlug,\n}: {\n subscribersCollectionSlug: CollectionSlug\n}): Endpoint {\n /**\n * subscribe Endpoint Handler\n * @param req\n * @data { email }\n * @returns { status: 200, json: {message: string, now: date} }\n * @returns { status: 400, json: {error: ('Bad data' | 'Already subscribed' | 'Unknown email result'), now: date} }\n */\n const subscribeHandler: PayloadHandler = async (req) => {\n const data = req?.json ? await req.json() : {}\n const {\n afterVerifyUrl,\n email,\n optIns,\n }: { afterVerifyUrl: string; email: string; optIns: string[] } = data // if by POST data\n // const { email } = req.routeParams // if by path\n\n //\n // HELPERS\n // Some of these functions make use of the scope within handler,\n // and would have to be refactored if moved out.\n //\n const createSubscriber = async ({\n optIns,\n password,\n status,\n verificationToken,\n verificationTokenExpires,\n }: {\n email: string\n optIns?: string[]\n password?: string\n status?: 'pending' | 'subscribed' | 'unsubscribed'\n verificationToken?: string\n verificationTokenExpires?: Date\n }) => {\n await req.payload.create({\n collection: subscribersCollectionSlug,\n data: {\n email,\n optIns,\n password,\n status: status || 'pending',\n verificationToken,\n verificationTokenExpires: verificationTokenExpires?.toISOString(),\n },\n draft: false,\n })\n }\n const updateSubscriber = async ({\n id,\n optIns,\n password,\n status,\n verificationToken,\n verificationTokenExpires,\n }: {\n id: string\n optIns?: string[]\n password?: string\n status?: 'pending' | 'subscribed' | 'unsubscribed'\n verificationToken?: string\n verificationTokenExpires?: Date | null\n }) => {\n const updateResults = await req.payload.update({\n id,\n collection: subscribersCollectionSlug,\n data: {\n optIns,\n password,\n status,\n verificationToken,\n verificationTokenExpires: verificationTokenExpires?.toISOString() || null,\n },\n depth: 0,\n })\n return updateResults\n }\n const sendVerifyEmail = async ({\n email,\n forwardUrl,\n linkText,\n message,\n subject,\n token,\n }: {\n email: string\n forwardUrl?: string\n linkText: string\n message: string\n subject: string\n token: string\n }) => {\n const forwardUrlParam = forwardUrl ? `&forwardUrl=${encodeURI(forwardUrl)}` : ''\n const magicLink = `${req.payload.config.serverURL}/verify?token=${token}&email=${email}${forwardUrlParam}`\n const html = message + `<p><a href=\"${magicLink}\">${linkText}</a></p>`\n const emailResult = await req.payload.sendEmail({\n html,\n subject,\n to: email,\n })\n req.payload.logger.info(`subscribe email sent \\n ${magicLink}`)\n return emailResult\n }\n\n //\n // VALIDATE INPUT\n //\n // Require email\n if (!email) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Bad data', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Bad data', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n //\n // Validate OptInChannels\n const { invalidOptInsInput, verifiedOptInIDs } = await verifyOptIns(req.payload, optIns)\n\n if (invalidOptInsInput) {\n req.payload.logger.error(\n JSON.stringify(\n {\n error: 'Invalid input: ' + JSON.stringify(optIns),\n now: new Date().toISOString(),\n } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n {\n error: 'Invalid input: ' + JSON.stringify(optIns),\n now: new Date().toISOString(),\n } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n //\n // Verify subscriber exists\n const userResults = await req.payload.find({\n collection: subscribersCollectionSlug,\n where: {\n email: { equals: email },\n },\n })\n const subscriber = userResults.docs[0] as Subscriber\n\n //\n // Now we have a subscriber and validatedOptIns\n // Handle scenarios\n //\n // ********************************************************\n //\n if (req.user && req.user.email != email) {\n //\n // Error: Auth-ed user doesn't match subscriber email\n //\n req.payload.logger.error(\n JSON.stringify(\n {\n error: 'Unauthorized: ' + email,\n now: new Date().toISOString(),\n } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n {\n error: 'Unauthorized: ' + email,\n now: new Date().toISOString(),\n } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n //\n // ********************************************************\n //\n if (!subscriber) {\n //\n // Create subscriber with status 'pending',\n // and an invisible unknowable password,\n // and send a verify email\n // Pass all optIns through verify link\n //\n const { expiresAt, token, tokenHash } = getTokenAndHash(15 * 60 * 1000) // Use for magic link\n const { tokenHash: tokenHash2 } = getTokenAndHash() // Unknowable\n await createSubscriber({\n email,\n optIns,\n password: tokenHash2,\n status: 'pending',\n verificationToken: tokenHash,\n verificationTokenExpires: expiresAt,\n })\n\n //\n // Send email\n const emailResult = await sendVerifyEmail({\n email,\n forwardUrl: afterVerifyUrl,\n linkText: '<b>Verify</b>',\n message: data.message || `<p>Click here to verify your subscription:</p>`,\n subject: data.subject || 'Please verify your subscription',\n token,\n })\n if (!emailResult) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n return Response.json({ emailResult, now: new Date().toISOString() } as SubscribeResponse)\n //\n }\n //\n // ********************************************************\n //\n if (!req.user && subscriber) {\n //\n // Send magic link to log the user in\n // Pass all optIns through verify link\n //\n const { expiresAt, token, tokenHash } = getTokenAndHash(15 * 60 * 1000) // Use for magic link\n // Update subscriber with token for pending email\n const updateResults = await updateSubscriber({\n id: subscriber.id,\n verificationToken: tokenHash,\n verificationTokenExpires: expiresAt,\n })\n if (!updateResults) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n //\n // Send email\n const emailResult = await sendVerifyEmail({\n email,\n forwardUrl: afterVerifyUrl,\n linkText: 'Verify',\n message: data.message || `<h1>Click here to verify your subscription:</h1>`,\n subject: data.subject || 'Please verify your subscription',\n token,\n })\n if (!emailResult) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n return Response.json({ emailResult, now: new Date().toISOString() } as SubscribeResponse)\n }\n //\n // ********************************************************\n //\n if (req.user && subscriber && subscriber.status == 'pending') {\n //\n // Send magic link to verify the email and log the user in\n // Pass all optIns through verify link\n //\n const { expiresAt, token, tokenHash } = getTokenAndHash(15 * 60 * 1000) // Use for magic link\n // Create subscriber with token for pending email\n const updateResults = await updateSubscriber({\n id: subscriber.id,\n verificationToken: tokenHash,\n verificationTokenExpires: expiresAt,\n })\n if (!updateResults) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n const emailResult = await sendVerifyEmail({\n email,\n forwardUrl: afterVerifyUrl,\n linkText: 'Verify',\n message: data.message || `<h1>Click here to verify your email:</h1>`,\n subject: data.subject || 'Please verify your subscription',\n token,\n })\n if (!emailResult) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n return Response.json({ emailResult, now: new Date().toISOString() } as SubscribeResponse)\n }\n\n //\n // ********************************************************\n //\n if (req.user && subscriber && subscriber.status != 'pending') {\n //\n // Update subscriber with status 'subscribed',\n // an invisible unknowable password,\n // and if any optIns input exists, set subscriber optIns\n // to EXACTLY verifiedOptInIDs (potentially unsubscribing from any not in verifiedOptInIDs)\n //\n const { tokenHash } = getTokenAndHash() // Use for magic link\n // Update subscriber with optIns\n const updateResults = (await updateSubscriber({\n id: subscriber.id,\n optIns: verifiedOptInIDs,\n password: tokenHash,\n status: 'subscribed',\n verificationToken: '',\n verificationTokenExpires: null,\n })) as Subscriber\n\n // Return results, including the verified optIns\n return Response.json({\n email: updateResults.email,\n now: new Date().toISOString(),\n optIns: updateResults.optIns,\n } as SubscribeResponse)\n }\n //\n // Uncaught case\n //\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n /**\n * subscribe Endpoint Config\n */\n const subscribeEndpoint: Endpoint = {\n handler: subscribeHandler,\n method: 'post',\n path: '/subscribe',\n }\n\n return subscribeEndpoint\n}\n\nexport default createEndpointSubscribe\n"],"names":["defaultCollectionSlug","getTokenAndHash","verifyOptIns","createEndpointSubscribe","subscribersCollectionSlug","subscribeHandler","req","data","json","afterVerifyUrl","email","optIns","createSubscriber","password","status","verificationToken","verificationTokenExpires","payload","create","collection","toISOString","draft","updateSubscriber","id","updateResults","update","depth","sendVerifyEmail","forwardUrl","linkText","message","subject","token","forwardUrlParam","encodeURI","magicLink","config","serverURL","html","emailResult","sendEmail","to","logger","info","error","JSON","stringify","now","Date","undefined","Response","invalidOptInsInput","verifiedOptInIDs","userResults","find","where","equals","subscriber","docs","user","expiresAt","tokenHash","tokenHash2","subscribeEndpoint","handler","method","path"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/subscribe.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadHandler } from 'payload'\nimport type { Subscriber } from 'src/copied/payload-types.js'\n\nimport { defaultCollectionSlug } from '../collections/Subscribers.js'\nimport { getTokenAndHash } from '../helpers/token.js'\nimport { verifyOptIns } from '../helpers/verifyOptIns.js'\n\nexport type SubscribeResponse =\n // When subscriber optIns are updated...\n | {\n email: string\n now: string\n optIns: string[]\n }\n // When a verify link is emailed...\n | {\n emailResult: any\n now: string\n }\n // When any error occurs...\n | {\n error: string\n now: string\n }\n\n/**\n * createEndpointLogout\n * @param options\n * @returns\n *\n * Factory to generate the endpoint config with handler based on input option for subscribersCollectionSlug\n *\n */\nfunction createEndpointSubscribe({\n subscribersCollectionSlug = defaultCollectionSlug,\n}: {\n subscribersCollectionSlug: CollectionSlug\n}): Endpoint {\n /**\n * subscribe Endpoint Handler\n * @param req\n * @data { email }\n * @returns { status: 200, json: {message: string, now: date} }\n * @returns { status: 400, json: {error: ('Bad data' | 'Already subscribed' | 'Unknown email result'), now: date} }\n */\n const subscribeHandler: PayloadHandler = async (req) => {\n const data = req?.json ? await req.json() : {}\n const { email, optIns, verifyUrl }: { email: string; optIns: string[]; verifyUrl: string } =\n data // if by POST data\n // const { email } = req.routeParams // if by path\n\n //\n // HELPERS\n // Some of these functions make use of the scope within handler,\n // and would have to be refactored if moved out.\n //\n const createSubscriber = async ({\n optIns,\n password,\n status,\n verificationToken,\n verificationTokenExpires,\n }: {\n email: string\n optIns?: string[]\n password?: string\n status?: 'pending' | 'subscribed' | 'unsubscribed'\n verificationToken?: string\n verificationTokenExpires?: Date\n }) => {\n await req.payload.create({\n collection: subscribersCollectionSlug,\n data: {\n email,\n optIns,\n password,\n status: status || 'pending',\n verificationToken,\n verificationTokenExpires: verificationTokenExpires?.toISOString(),\n },\n draft: false,\n })\n }\n const updateSubscriber = async ({\n id,\n optIns,\n password,\n status,\n verificationToken,\n verificationTokenExpires,\n }: {\n id: string\n optIns?: string[]\n password?: string\n status?: 'pending' | 'subscribed' | 'unsubscribed'\n verificationToken?: string\n verificationTokenExpires?: Date | null\n }) => {\n const updateResults = await req.payload.update({\n id,\n collection: subscribersCollectionSlug,\n data: {\n optIns,\n password,\n status,\n verificationToken,\n verificationTokenExpires: verificationTokenExpires?.toISOString() || null,\n },\n depth: 0,\n })\n return updateResults\n }\n const sendVerifyEmail = async ({\n email,\n linkText,\n message,\n subject,\n token,\n verifyUrl,\n }: {\n email: string\n linkText: string\n message: string\n subject: string\n token: string\n verifyUrl?: string\n }) => {\n const magicLink = `${verifyUrl}${verifyUrl?.search ? '&' : '?'}token=${token}&email=${email}`\n const html = message + `<p><a href=\"${magicLink}\">${linkText}</a></p>`\n const emailResult = await req.payload.sendEmail({\n html,\n subject,\n to: email,\n })\n req.payload.logger.info(`subscribe email sent \\n ${magicLink}`)\n return emailResult\n }\n\n //\n // VALIDATE INPUT\n //\n // Require email\n if (!email) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Bad data', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Bad data', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n //\n // Validate OptInChannels\n const { invalidOptInsInput, verifiedOptInIDs } = await verifyOptIns(req.payload, optIns)\n\n if (invalidOptInsInput) {\n req.payload.logger.error(\n JSON.stringify(\n {\n error: 'Invalid input: ' + JSON.stringify(optIns),\n now: new Date().toISOString(),\n } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n {\n error: 'Invalid input: ' + JSON.stringify(optIns),\n now: new Date().toISOString(),\n } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n //\n // Verify subscriber exists\n const userResults = await req.payload.find({\n collection: subscribersCollectionSlug,\n where: {\n email: { equals: email },\n },\n })\n const subscriber = userResults.docs[0] as Subscriber\n\n //\n // Now we have a subscriber and validatedOptIns\n // Handle scenarios\n //\n // ********************************************************\n //\n if (req.user && req.user.email != email) {\n //\n // Error: Auth-ed user doesn't match subscriber email\n //\n req.payload.logger.error(\n JSON.stringify(\n {\n error: 'Unauthorized: ' + email,\n now: new Date().toISOString(),\n } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n {\n error: 'Unauthorized: ' + email,\n now: new Date().toISOString(),\n } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n //\n // ********************************************************\n //\n if (!subscriber) {\n //\n // Create subscriber with status 'pending',\n // and an invisible unknowable password,\n // and send a verify email\n // Pass all optIns through verify link\n //\n const { expiresAt, token, tokenHash } = getTokenAndHash(15 * 60 * 1000) // Use for magic link\n const { tokenHash: tokenHash2 } = getTokenAndHash() // Unknowable\n await createSubscriber({\n email,\n optIns,\n password: tokenHash2,\n status: 'pending',\n verificationToken: tokenHash,\n verificationTokenExpires: expiresAt,\n })\n\n //\n // Send email\n const emailResult = await sendVerifyEmail({\n email,\n linkText: '<b>Verify</b>',\n message: data.message || `<p>Click here to verify your subscription:</p>`,\n subject: data.subject || 'Please verify your subscription',\n token,\n verifyUrl,\n })\n if (!emailResult) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n return Response.json({ emailResult, now: new Date().toISOString() } as SubscribeResponse)\n //\n }\n //\n // ********************************************************\n //\n if (!req.user && subscriber) {\n //\n // Send magic link to log the user in\n // Pass all optIns through verify link\n //\n const { expiresAt, token, tokenHash } = getTokenAndHash(15 * 60 * 1000) // Use for magic link\n // Update subscriber with token for pending email\n const updateResults = await updateSubscriber({\n id: subscriber.id,\n verificationToken: tokenHash,\n verificationTokenExpires: expiresAt,\n })\n if (!updateResults) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n //\n // Send email\n const emailResult = await sendVerifyEmail({\n email,\n linkText: 'Verify',\n message: data.message || `<h1>Click here to verify your subscription:</h1>`,\n subject: data.subject || 'Please verify your subscription',\n token,\n verifyUrl,\n })\n if (!emailResult) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n return Response.json({ emailResult, now: new Date().toISOString() } as SubscribeResponse)\n }\n //\n // ********************************************************\n //\n if (req.user && subscriber && subscriber.status == 'pending') {\n //\n // Send magic link to verify the email and log the user in\n // Pass all optIns through verify link\n //\n const { expiresAt, token, tokenHash } = getTokenAndHash(15 * 60 * 1000) // Use for magic link\n // Create subscriber with token for pending email\n const updateResults = await updateSubscriber({\n id: subscriber.id,\n verificationToken: tokenHash,\n verificationTokenExpires: expiresAt,\n })\n if (!updateResults) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n const emailResult = await sendVerifyEmail({\n email,\n linkText: 'Verify',\n message: data.message || `<h1>Click here to verify your email:</h1>`,\n subject: data.subject || 'Please verify your subscription',\n token,\n verifyUrl,\n })\n if (!emailResult) {\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown email result', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n return Response.json({ emailResult, now: new Date().toISOString() } as SubscribeResponse)\n }\n\n //\n // ********************************************************\n //\n if (req.user && subscriber && subscriber.status != 'pending') {\n //\n // Update subscriber with status 'subscribed',\n // an invisible unknowable password,\n // and if any optIns input exists, set subscriber optIns\n // to EXACTLY verifiedOptInIDs (potentially unsubscribing from any not in verifiedOptInIDs)\n //\n const { tokenHash } = getTokenAndHash() // Use for magic link\n // Update subscriber with optIns\n const updateResults = (await updateSubscriber({\n id: subscriber.id,\n optIns: verifiedOptInIDs,\n password: tokenHash,\n status: 'subscribed',\n verificationToken: '',\n verificationTokenExpires: null,\n })) as Subscriber\n\n // Return results, including the verified optIns\n return Response.json({\n email: updateResults.email,\n now: new Date().toISOString(),\n optIns: updateResults.optIns,\n } as SubscribeResponse)\n }\n //\n // Uncaught case\n //\n req.payload.logger.error(\n JSON.stringify(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n undefined,\n 2,\n ),\n )\n return Response.json(\n { error: 'Unknown error', now: new Date().toISOString() } as SubscribeResponse,\n { status: 400 },\n )\n }\n\n /**\n * subscribe Endpoint Config\n */\n const subscribeEndpoint: Endpoint = {\n handler: subscribeHandler,\n method: 'post',\n path: '/subscribe',\n }\n\n return subscribeEndpoint\n}\n\nexport default createEndpointSubscribe\n"],"names":["defaultCollectionSlug","getTokenAndHash","verifyOptIns","createEndpointSubscribe","subscribersCollectionSlug","subscribeHandler","req","data","json","email","optIns","verifyUrl","createSubscriber","password","status","verificationToken","verificationTokenExpires","payload","create","collection","toISOString","draft","updateSubscriber","id","updateResults","update","depth","sendVerifyEmail","linkText","message","subject","token","magicLink","search","html","emailResult","sendEmail","to","logger","info","error","JSON","stringify","now","Date","undefined","Response","invalidOptInsInput","verifiedOptInIDs","userResults","find","where","equals","subscriber","docs","user","expiresAt","tokenHash","tokenHash2","subscribeEndpoint","handler","method","path"],"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.
|
|
72
|
+
"version": "0.0.7",
|
|
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",
|