payload-subscribers-plugin 0.0.8 → 0.0.9
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 +4 -1
- package/dist/components/app/RequestMagicLink.js +45 -32
- package/dist/components/app/RequestMagicLink.js.map +1 -1
- package/dist/components/app/Subscribe.js +23 -8
- package/dist/components/app/Subscribe.js.map +1 -1
- package/dist/components/app/Unsubscribe.d.ts +31 -0
- package/dist/components/app/Unsubscribe.js +155 -0
- package/dist/components/app/Unsubscribe.js.map +1 -0
- package/dist/components/app/VerifyMagicLink.js +2 -6
- package/dist/components/app/VerifyMagicLink.js.map +1 -1
- package/dist/endpoints/requestMagicLink.d.ts +3 -1
- package/dist/endpoints/requestMagicLink.js +13 -10
- package/dist/endpoints/requestMagicLink.js.map +1 -1
- package/dist/endpoints/subscribe.js +22 -8
- package/dist/endpoints/subscribe.js.map +1 -1
- package/dist/endpoints/unsubscribe.d.ts +21 -0
- package/dist/endpoints/unsubscribe.js +118 -0
- package/dist/endpoints/unsubscribe.js.map +1 -0
- package/dist/endpoints/verifyMagicLink.js +3 -2
- package/dist/endpoints/verifyMagicLink.js.map +1 -1
- package/dist/exports/ui.d.ts +2 -0
- package/dist/exports/ui.js +1 -0
- package/dist/exports/ui.js.map +1 -1
- package/dist/helpers/token.d.ts +3 -0
- package/dist/helpers/token.js +12 -2
- package/dist/helpers/token.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,9 @@ export default buildConfig({
|
|
|
50
50
|
|
|
51
51
|
// Provide a custom expiration for magic link tokens. The default is 30 minutes.
|
|
52
52
|
tokenExpiration: 60 * 60,
|
|
53
|
+
|
|
54
|
+
// Provide your unsubscribe route. This route should include the Unsubscribe component.
|
|
55
|
+
unsubscribeUrl?: string
|
|
53
56
|
}),
|
|
54
57
|
],
|
|
55
58
|
})
|
|
@@ -94,7 +97,7 @@ const Page = () => {
|
|
|
94
97
|
}
|
|
95
98
|
```
|
|
96
99
|
|
|
97
|
-
**
|
|
100
|
+
**_IMPORTANT:_** Be sure to create a /verify route
|
|
98
101
|
|
|
99
102
|
```typescript
|
|
100
103
|
// verify/page.tsx
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { PayloadSDK } from '@payloadcms/sdk';
|
|
4
3
|
import { useEffect, useState } from 'react';
|
|
5
4
|
import { useSubscriber } from '../../contexts/SubscriberProvider.js';
|
|
6
5
|
import { useServerUrl } from '../../react-hooks/useServerUrl.js';
|
|
@@ -20,15 +19,17 @@ import styles from './shared.module.css';
|
|
|
20
19
|
form: '',
|
|
21
20
|
message: ''
|
|
22
21
|
}, handleMagicLinkRequested, verifyUrl })=>{
|
|
22
|
+
const { subscriber } = useSubscriber();
|
|
23
|
+
const { serverURL } = useServerUrl();
|
|
24
|
+
if (!verifyUrl && serverURL) {
|
|
25
|
+
console.log('verifyUrl DEFAULT');
|
|
26
|
+
verifyUrl = `${serverURL ? serverURL : ''}/verify`;
|
|
27
|
+
}
|
|
23
28
|
if (typeof verifyUrl == 'string') {
|
|
29
|
+
console.log('verifyUrl STRING: ', verifyUrl);
|
|
24
30
|
verifyUrl = new URL(verifyUrl);
|
|
25
31
|
}
|
|
26
|
-
const { subscriber } = useSubscriber();
|
|
27
|
-
const { serverURL } = useServerUrl();
|
|
28
32
|
const [status, setStatus] = useState('default');
|
|
29
|
-
const sdk = new PayloadSDK({
|
|
30
|
-
baseURL: serverURL || ''
|
|
31
|
-
});
|
|
32
33
|
const [result, setResult] = useState();
|
|
33
34
|
const [email, setEmail] = useState(subscriber?.email || '');
|
|
34
35
|
useEffect(()=>{
|
|
@@ -38,35 +39,47 @@ import styles from './shared.module.css';
|
|
|
38
39
|
]);
|
|
39
40
|
const handleSubmit = async (e)=>{
|
|
40
41
|
e.preventDefault();
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
42
|
+
if (!verifyUrl) {
|
|
43
|
+
setStatus('error');
|
|
44
|
+
setResult(`An error occured. Please try again. \n(No verify URL available.)`);
|
|
45
|
+
} else {
|
|
46
|
+
// const emailTokenResponse = await sdk.request({
|
|
47
|
+
// json: {
|
|
48
|
+
// email,
|
|
49
|
+
// verifyUrl: verifyUrl?.href,
|
|
50
|
+
// },
|
|
51
|
+
// method: 'POST',
|
|
52
|
+
// path: '/api/emailToken',
|
|
53
|
+
// })
|
|
54
|
+
const emailTokenResponse = await fetch(`${serverURL ? serverURL : ''}/api/emailToken`, {
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
email,
|
|
57
|
+
verifyUrl: verifyUrl?.href
|
|
58
|
+
}),
|
|
59
|
+
method: 'POST'
|
|
60
|
+
});
|
|
61
|
+
if (emailTokenResponse.ok) {
|
|
62
|
+
const emailTokenResponseJson = await emailTokenResponse.json();
|
|
63
|
+
if (handleMagicLinkRequested) {
|
|
64
|
+
handleMagicLinkRequested(emailTokenResponseJson);
|
|
65
|
+
}
|
|
66
|
+
// @ts-expect-error One or the other exists
|
|
67
|
+
const { emailResult, error } = emailTokenResponseJson;
|
|
68
|
+
if (error) {
|
|
69
|
+
setStatus('error');
|
|
70
|
+
setResult(`An error occured. Please try again. \n ${error}`);
|
|
71
|
+
} else if (emailResult) {
|
|
72
|
+
setStatus('sent');
|
|
73
|
+
setResult('An email has been sent containing your magic link.');
|
|
74
|
+
} else {
|
|
75
|
+
setStatus('error');
|
|
76
|
+
setResult(`An error occured. Please try again. \nResult unknown`);
|
|
77
|
+
}
|
|
62
78
|
} else {
|
|
79
|
+
const emailTokenResponseText = await emailTokenResponse.text();
|
|
63
80
|
setStatus('error');
|
|
64
|
-
setResult(`An error occured. Please try again. \
|
|
81
|
+
setResult(`An error occured. Please try again. \n${emailTokenResponseText}`);
|
|
65
82
|
}
|
|
66
|
-
} else {
|
|
67
|
-
const emailTokenResponseText = await emailTokenResponse.text();
|
|
68
|
-
setStatus('error');
|
|
69
|
-
setResult(`An error occured. Please try again. \n${emailTokenResponseText}`);
|
|
70
83
|
}
|
|
71
84
|
};
|
|
72
85
|
return /*#__PURE__*/ _jsxs("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/app/RequestMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ChangeEvent, type SubmitEvent, useEffect, useState } from 'react'\n\nimport type { Config } from '../../copied/payload-types.js'\nimport type { RequestMagicLinkResponse } from '../../endpoints/requestMagicLink.js'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../../react-hooks/useServerUrl.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\nexport { RequestMagicLinkResponse }\n\n/**\n * Props for the RequestMagicLink component.\n */\nexport interface IRequestMagicLink {\n classNames?: RequestMagicLinkClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n props?: any\n verifyUrl?: string | URL\n}\n\n/** Optional CSS class overrides for RequestMagicLink elements. */\nexport type RequestMagicLinkClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n message?: string\n}\n\ntype statusValues = 'default' | 'error' | 'sent'\n\n/**\n * Form component that lets users request a magic-login link by email. Submits to POST /api/emailToken\n * and shows success or error message. Uses SubscriberProvider for pre-filling email when available.\n *\n * @param props - See IRequestMagicLink\n * @returns Form UI with email input and \"Request magic link\" button\n */\nexport const RequestMagicLink = ({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n message: '',\n },\n handleMagicLinkRequested,\n verifyUrl,\n}: IRequestMagicLink) => {\n
|
|
1
|
+
{"version":3,"sources":["../../../src/components/app/RequestMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ChangeEvent, type SubmitEvent, useEffect, useState } from 'react'\n\nimport type { Config } from '../../copied/payload-types.js'\nimport type { RequestMagicLinkResponse } from '../../endpoints/requestMagicLink.js'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../../react-hooks/useServerUrl.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\nexport { RequestMagicLinkResponse }\n\n/**\n * Props for the RequestMagicLink component.\n */\nexport interface IRequestMagicLink {\n classNames?: RequestMagicLinkClasses\n handleMagicLinkRequested?: (result: RequestMagicLinkResponse) => void\n props?: any\n verifyUrl?: string | URL\n}\n\n/** Optional CSS class overrides for RequestMagicLink elements. */\nexport type RequestMagicLinkClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n message?: string\n}\n\ntype statusValues = 'default' | 'error' | 'sent'\n\n/**\n * Form component that lets users request a magic-login link by email. Submits to POST /api/emailToken\n * and shows success or error message. Uses SubscriberProvider for pre-filling email when available.\n *\n * @param props - See IRequestMagicLink\n * @returns Form UI with email input and \"Request magic link\" button\n */\nexport const RequestMagicLink = ({\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n message: '',\n },\n handleMagicLinkRequested,\n verifyUrl,\n}: IRequestMagicLink) => {\n const { subscriber } = useSubscriber()\n const { serverURL } = useServerUrl()\n\n if (!verifyUrl && serverURL) {\n console.log('verifyUrl DEFAULT')\n verifyUrl = `${serverURL ? serverURL : ''}/verify`\n }\n if (typeof verifyUrl == 'string') {\n console.log('verifyUrl STRING: ', verifyUrl)\n verifyUrl = new URL(verifyUrl)\n }\n\n const [status, setStatus] = useState<statusValues>('default')\n\n const [result, setResult] = useState<string>()\n const [email, setEmail] = useState(subscriber?.email || '')\n\n useEffect(() => {\n setEmail(subscriber?.email || '')\n }, [subscriber])\n\n const handleSubmit = async (e: SubmitEvent<HTMLFormElement>) => {\n e.preventDefault()\n if (!verifyUrl) {\n setStatus('error')\n setResult(`An error occured. Please try again. \\n(No verify URL available.)`)\n } else {\n // const emailTokenResponse = await sdk.request({\n // json: {\n // email,\n // verifyUrl: verifyUrl?.href,\n // },\n // method: 'POST',\n // path: '/api/emailToken',\n // })\n const emailTokenResponse = await fetch(`${serverURL ? serverURL : ''}/api/emailToken`, {\n body: JSON.stringify({\n email,\n verifyUrl: verifyUrl?.href,\n }),\n method: 'POST',\n })\n if (emailTokenResponse.ok) {\n const emailTokenResponseJson: RequestMagicLinkResponse = await emailTokenResponse.json()\n if (handleMagicLinkRequested) {\n handleMagicLinkRequested(emailTokenResponseJson)\n }\n // @ts-expect-error One or the other exists\n const { emailResult, error } = emailTokenResponseJson\n if (error) {\n setStatus('error')\n setResult(`An error occured. Please try again. \\n ${error}`)\n } else if (emailResult) {\n setStatus('sent')\n setResult('An email has been sent containing your magic link.')\n } else {\n setStatus('error')\n setResult(`An error occured. Please try again. \\nResult unknown`)\n }\n } else {\n const emailTokenResponseText = await emailTokenResponse.text()\n setStatus('error')\n setResult(`An error occured. Please try again. \\n${emailTokenResponseText}`)\n }\n }\n }\n return (\n <div\n className={mergeClassNames([\n 'subscribers-request subscribers-container',\n styles.container,\n classNames.container,\n ])}\n >\n {result ? (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n status == 'error' ? ['subscribers-error', styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n ) : (\n <></>\n )}\n <form\n className={mergeClassNames(['subscribers-form', styles.form, classNames.form])}\n method=\"POST\"\n onSubmit={handleSubmit}\n >\n <input\n aria-label=\"enter your email\"\n className={mergeClassNames([\n 'subscribers-emailInput',\n styles.emailInput,\n classNames.emailInput,\n ])}\n onChange={(e: ChangeEvent<HTMLInputElement>) => setEmail(e.target.value)}\n placeholder=\"enter your email\"\n type=\"email\"\n value={email}\n />\n <button\n className={mergeClassNames(['subscribers-button', styles.button, classNames.button])}\n type=\"submit\"\n >\n Request magic link\n </button>\n </form>\n </div>\n )\n}\n"],"names":["useEffect","useState","useSubscriber","useServerUrl","mergeClassNames","styles","RequestMagicLink","classNames","button","container","emailInput","error","form","message","handleMagicLinkRequested","verifyUrl","subscriber","serverURL","console","log","URL","status","setStatus","result","setResult","email","setEmail","handleSubmit","e","preventDefault","emailTokenResponse","fetch","body","JSON","stringify","href","method","ok","emailTokenResponseJson","json","emailResult","emailTokenResponseText","text","div","className","p","onSubmit","input","aria-label","onChange","target","value","placeholder","type"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { PayloadSDK } from '@payloadcms/sdk';
|
|
4
4
|
import { useEffect, useState } from 'react';
|
|
5
5
|
import { useSubscriber } from '../../contexts/SubscriberProvider.js';
|
|
@@ -114,16 +114,21 @@ import styles from './shared.module.css';
|
|
|
114
114
|
/*#__PURE__*/ _jsx("h2", {
|
|
115
115
|
children: "Subscribe"
|
|
116
116
|
}),
|
|
117
|
-
/*#__PURE__*/
|
|
117
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
118
118
|
className: mergeClassNames([
|
|
119
119
|
'subscribers-section',
|
|
120
120
|
styles.section,
|
|
121
121
|
classNames.section
|
|
122
122
|
]),
|
|
123
|
-
children:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
children: [
|
|
124
|
+
subscriber?.status == 'unsubscribed' && /*#__PURE__*/ _jsx("p", {
|
|
125
|
+
children: "You are unsubscribed"
|
|
126
|
+
}),
|
|
127
|
+
/*#__PURE__*/ _jsx(SelectOptInChannels, {
|
|
128
|
+
handleOptInChannelsSelected: handleOptInChannelsSelected,
|
|
129
|
+
selectedOptInChannelIDs: selectedChannelIDs
|
|
130
|
+
})
|
|
131
|
+
]
|
|
127
132
|
}),
|
|
128
133
|
/*#__PURE__*/ _jsx("form", {
|
|
129
134
|
className: mergeClassNames([
|
|
@@ -155,14 +160,24 @@ import styles from './shared.module.css';
|
|
|
155
160
|
type: "email",
|
|
156
161
|
value: email
|
|
157
162
|
}),
|
|
158
|
-
/*#__PURE__*/
|
|
163
|
+
/*#__PURE__*/ _jsxs("button", {
|
|
159
164
|
className: mergeClassNames([
|
|
160
165
|
'subscribers-button',
|
|
161
166
|
styles.button,
|
|
162
167
|
classNames.button
|
|
163
168
|
]),
|
|
164
169
|
type: "submit",
|
|
165
|
-
children:
|
|
170
|
+
children: [
|
|
171
|
+
!subscriber && /*#__PURE__*/ _jsx(_Fragment, {
|
|
172
|
+
children: "Subscribe"
|
|
173
|
+
}),
|
|
174
|
+
subscriber && subscriber?.status != 'unsubscribed' && /*#__PURE__*/ _jsx(_Fragment, {
|
|
175
|
+
children: "Save choices"
|
|
176
|
+
}),
|
|
177
|
+
subscriber?.status == 'unsubscribed' && /*#__PURE__*/ _jsx(_Fragment, {
|
|
178
|
+
children: "Subscribe and save choices"
|
|
179
|
+
})
|
|
180
|
+
]
|
|
166
181
|
})
|
|
167
182
|
]
|
|
168
183
|
})
|
|
@@ -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/** Props for the Subscribe component. */\nexport interface ISubscribe {\n classNames?: SubscribeClasses\n handleSubscribe?: (result: SubscribeResponse) => void\n props?: any\n verifyUrl?: string | URL\n}\n\n/** Optional CSS class overrides for Subscribe elements. */\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\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 - See ISubscribe\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 verifyUrl,\n}: ISubscribe) => {\n if (typeof verifyUrl == 'string') {\n verifyUrl = new URL(verifyUrl)\n }\n\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\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 <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 await handleSubmit()\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 Save choices\n </button>\n </div>\n </form>\n {!!result && (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n status == 'error' ? ['subscribers-error', styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n )}\n </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","URL","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":"AAAA;;AAEA,SAASA,UAAU,QAAQ,kBAAiB;AAC5C,SAA2BC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAO7D,SAASC,aAAa,QAAQ,uCAAsC;AACpE,SAASC,YAAY,QAAQ,oCAAmC;AAChE,SAASC,eAAe,QAAQ,eAAc;AAC9C,SAASC,mBAAmB,QAAQ,2BAA0B;AAC9D,OAAOC,YAAY,sBAAqB;AAwBxC;;;;;;;CAOC,GACD,OAAO,MAAMC,YAAY,CAAC,EACxBC,aAAa;IACXC,QAAQ;IACRC,WAAW;IACXC,YAAY;IACZC,OAAO;IACPC,MAAM;IACNC,SAAS;IACTC,SAAS;IACTC,SAAS;AACX,CAAC,EACDC,eAAe,EACfC,SAAS,EACE;IACX,IAAI,OAAOA,aAAa,UAAU;QAChCA,YAAY,IAAIC,IAAID;IACtB;IAEA,MAAM,EAAEE,iBAAiB,EAAEC,UAAU,EAAE,GAAGnB;IAE1C,MAAM,EAAEoB,SAAS,EAAE,GAAGnB;IAEtB,MAAMoB,MAAM,IAAIxB,WAAmB;QACjCyB,SAASF,aAAa;IACxB;IAEA,MAAMG,kBAAkB,CAACC;QACvB,IAAI,CAACA,UAAU;YACb,OAAO,EAAE;QACX;QACA,OAAOA,SAASC,GAAG,CAAC,CAACC,UACnB,OAAOA,WAAW,WAAWA,UAAUA,QAAQC,EAAE;IAErD;IAEA,MAAM,CAACC,QAAQC,UAAU,GAAG9B,SAAuB;IACnD,MAAM,CAAC+B,QAAQC,UAAU,GAAGhC;IAC5B,MAAM,CAACiC,OAAOC,SAAS,GAAGlC,SAASoB,aAAaA,WAAWa,KAAK,GAAG;IACnE,MAAM,CAACE,oBAAoBC,sBAAsB,GAAGpC,SAAmB,IACrEwB,gBAAgBJ,YAAYiB;IAG9BtC,UAAU;QACRmC,SAASd,YAAYa,SAAS;QAC9BG,sBAAsBZ,gBAAgBJ,YAAYiB;IACpD,GAAG;QAACjB;KAAW;IAEf,MAAMkB,8BAA8B,CAACP;QACnCK,sBAAsBL,OAAOL,GAAG,CAAC,CAACC,UAAYA,QAAQC,EAAE;IAC1D;IAEA,MAAMW,eAAe;QACnB,MAAMC,kBAAkB,MAAMlB,IAAImB,OAAO,CAAC;YACxCC,MAAM;gBACJT;gBACAI,QAAQF;gBACRlB,WAAWA,WAAW0B;YACxB;YACAC,QAAQ;YACRC,MAAM;QACR;QACA,IAAIL,gBAAgBM,EAAE,EAAE;YACtB,MAAMC,aAAgC,MAAMP,gBAAgBE,IAAI;YAChE,2CAA2C;YAC3C,MAAM;YACN,oBAAoB;YACpB,kBAAkB;YAClB,uBAAuB;YACvB,MAAM;YACN,sCAAsC;YACtC,MAAM;YACN,uBAAuB;YACvB,kBAAkB;YAClB,MAAM;YACN,8BAA8B;YAC9B,MAAM;YACN,oBAAoB;YACpB,kBAAkB;YAClB,MAAM;YACN,wCAAwC;YACxC,MAAM,EAAEM,WAAW,EAAErC,KAAK,EAAE,GAAGoC;YAC/B,IAAIpC,OAAO;gBACTmB,UAAU;gBACVE,UAAU,CAAC,uCAAuC,EAAErB,OAAO;YAC7D,OAAO,IAAIqC,aAAa;gBACtBlB,UAAU;gBACVE,UAAU;YACZ,OAAO,IAAIC,OAAO;gBAChBH,UAAU;gBACVE,UAAU,CAAC,uCAAuC,CAAC;YACrD,OAAO;gBACLF,UAAU;gBACVE,UAAU,CAAC,oDAAoD,CAAC;YAClE;YAEAb;YAEA,IAAIH,iBAAiB;gBACnBA,gBAAgB+B;YAClB;QACF,OAAO;YACL,kDAAkD;YAClDjB,UAAU;YACVE,UAAU,CAAC,oDAAoD,CAAC;QAClE;IACF;IAEA,qBACE,MAACiB;QACCC,WAAW/C,gBAAgB;YACzB;YACAE,OAAOI,SAAS;YAChBF,WAAWE,SAAS;SACrB;;0BAED,KAAC0C;0BAAG;;0BACJ,KAACF;gBAAIC,WAAW/C,gBAAgB;oBAAC;oBAAuBE,OAAOU,OAAO;oBAAER,WAAWQ,OAAO;iBAAC;0BACzF,cAAA,KAACX;oBACCkC,6BAA6BA;oBAC7Bc,yBAAyBjB;;;0BAG7B,KAACvB;gBACCsC,WAAW/C,gBAAgB;oBAAC;oBAAoBE,OAAOO,IAAI;oBAAEL,WAAWK,IAAI;iBAAC;gBAC7EgC,QAAO;gBACPS,UAAU,OAAOC;oBACfA,EAAEC,cAAc;oBAChB,MAAMhB;gBACR;0BAEA,cAAA,MAACU;oBACCC,WAAW/C,gBAAgB;wBAAC;wBAAuBE,OAAOU,OAAO;wBAAER,WAAWQ,OAAO;qBAAC;;wBAErF,CAACK,4BACA,KAACoC;4BACCC,cAAW;4BACXP,WAAW/C,gBAAgB;gCACzB;gCACAE,OAAOK,UAAU;gCACjBH,WAAWG,UAAU;6BACtB;4BACDgD,UAAU,CAACJ,IAAqCpB,SAASoB,EAAEK,MAAM,CAACC,KAAK;4BACvEC,aAAY;4BACZC,MAAK;4BACLF,OAAO3B;;sCAGX,KAACzB;4BACC0C,WAAW/C,gBAAgB;gCAAC;gCAAsBE,OAAOG,MAAM;gCAAED,WAAWC,MAAM;6BAAC;4BACnFsD,MAAK;sCACN;;;;;YAKJ,CAAC,CAAC/B,wBACD,KAACgC;gBACCb,WAAW/C,gBAAgB;oBACzB;oBACAE,OAAOS,OAAO;oBACdP,WAAWO,OAAO;oBAClBe,UAAU,UAAU;wBAAC;wBAAqBxB,OAAOM,KAAK;wBAAEJ,WAAWI,KAAK;qBAAC,GAAG,EAAE;iBAC/E;0BAEAoB;;;;AAKX,EAAC"}
|
|
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/** Props for the Subscribe component. */\nexport interface ISubscribe {\n classNames?: SubscribeClasses\n handleSubscribe?: (result: SubscribeResponse) => void\n props?: any\n verifyUrl?: string | URL\n}\n\n/** Optional CSS class overrides for Subscribe elements. */\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\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 - See ISubscribe\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 verifyUrl,\n}: ISubscribe) => {\n if (typeof verifyUrl == 'string') {\n verifyUrl = new URL(verifyUrl)\n }\n\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\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 await handleSubmit()\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 </div>\n </form>\n {!!result && (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n status == 'error' ? ['subscribers-error', styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n )}\n </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","URL","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","p","selectedOptInChannelIDs","onSubmit","e","preventDefault","input","aria-label","onChange","target","value","placeholder","type"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { UnsubscribeResponse } from '../../endpoints/unsubscribe.js';
|
|
2
|
+
export { UnsubscribeResponse };
|
|
3
|
+
/** Props for the Unsubscribe component. */
|
|
4
|
+
export interface IUnsubscribe {
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
classNames?: UnsubscribeClasses;
|
|
7
|
+
handleUnsubscribe?: (result: UnsubscribeResponse) => void;
|
|
8
|
+
renderButton?: (props: {
|
|
9
|
+
name?: string;
|
|
10
|
+
onClick?: () => any;
|
|
11
|
+
text?: string;
|
|
12
|
+
}) => React.ReactNode;
|
|
13
|
+
}
|
|
14
|
+
/** Optional CSS class overrides for Unsubscribe elements. */
|
|
15
|
+
export type UnsubscribeClasses = {
|
|
16
|
+
button?: string;
|
|
17
|
+
container?: string;
|
|
18
|
+
emailInput?: string;
|
|
19
|
+
error?: string;
|
|
20
|
+
form?: string;
|
|
21
|
+
loading?: string;
|
|
22
|
+
message?: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Handles the verify step of magic-link flow. When URL has email and hash query params, calls
|
|
26
|
+
* POST /api/unsubscribe to complete the unsubscribe. Displays children provided after unsubscribe is attempted.
|
|
27
|
+
*
|
|
28
|
+
* @param props - See IUnsubscribe
|
|
29
|
+
* @returns Result message, and optional button/children
|
|
30
|
+
*/
|
|
31
|
+
export declare const Unsubscribe: ({ children, classNames, handleUnsubscribe, renderButton, }: IUnsubscribe) => import("react").JSX.Element;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useSearchParams } from 'next/navigation.js';
|
|
4
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
5
|
+
import { useSubscriber } from '../../exports/ui.js';
|
|
6
|
+
import { useServerUrl } from '../../react-hooks/useServerUrl.js';
|
|
7
|
+
import { mergeClassNames } from './helpers.js';
|
|
8
|
+
import styles from './shared.module.css';
|
|
9
|
+
/**
|
|
10
|
+
* Handles the verify step of magic-link flow. When URL has email and hash query params, calls
|
|
11
|
+
* POST /api/unsubscribe to complete the unsubscribe. Displays children provided after unsubscribe is attempted.
|
|
12
|
+
*
|
|
13
|
+
* @param props - See IUnsubscribe
|
|
14
|
+
* @returns Result message, and optional button/children
|
|
15
|
+
*/ export const Unsubscribe = ({ children, classNames = {
|
|
16
|
+
button: '',
|
|
17
|
+
container: '',
|
|
18
|
+
emailInput: '',
|
|
19
|
+
error: '',
|
|
20
|
+
form: '',
|
|
21
|
+
loading: '',
|
|
22
|
+
message: ''
|
|
23
|
+
}, handleUnsubscribe, renderButton = ({ name, onClick, text })=>/*#__PURE__*/ _jsx("button", {
|
|
24
|
+
className: mergeClassNames([
|
|
25
|
+
'subscribers-button',
|
|
26
|
+
styles.button,
|
|
27
|
+
classNames.button
|
|
28
|
+
]),
|
|
29
|
+
name: name,
|
|
30
|
+
onClick: onClick,
|
|
31
|
+
type: "button",
|
|
32
|
+
children: text
|
|
33
|
+
}) })=>{
|
|
34
|
+
const { serverURL } = useServerUrl();
|
|
35
|
+
const { // refreshSubscriber,
|
|
36
|
+
subscriber } = useSubscriber();
|
|
37
|
+
const searchParams = useSearchParams();
|
|
38
|
+
const email = searchParams.get('email');
|
|
39
|
+
const hash = searchParams.get('hash');
|
|
40
|
+
const [result, setResult] = useState();
|
|
41
|
+
const [isError, setIsError] = useState(false);
|
|
42
|
+
// const [email, setEmail] = useState('')
|
|
43
|
+
const { refreshSubscriber } = useSubscriber();
|
|
44
|
+
const callUnsubscribe = useCallback(async ()=>{
|
|
45
|
+
if (!email || !hash) {
|
|
46
|
+
return {
|
|
47
|
+
error: 'Invalid input'
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
let resultJson;
|
|
51
|
+
try {
|
|
52
|
+
const unsubscribeEndpointResult = await fetch(`${serverURL ? serverURL : ''}/api/unsubscribe`, {
|
|
53
|
+
body: JSON.stringify({
|
|
54
|
+
email,
|
|
55
|
+
unsubscribeToken: hash
|
|
56
|
+
}),
|
|
57
|
+
method: 'POST'
|
|
58
|
+
});
|
|
59
|
+
// return unsubscribeEndpointResult
|
|
60
|
+
if (unsubscribeEndpointResult && unsubscribeEndpointResult.json) {
|
|
61
|
+
resultJson = await unsubscribeEndpointResult.json();
|
|
62
|
+
resultJson = {
|
|
63
|
+
error: resultJson.error,
|
|
64
|
+
message: resultJson.message,
|
|
65
|
+
now: resultJson.now
|
|
66
|
+
};
|
|
67
|
+
} else if (unsubscribeEndpointResult && unsubscribeEndpointResult.text) {
|
|
68
|
+
const resultText = await unsubscribeEndpointResult.text();
|
|
69
|
+
resultJson = {
|
|
70
|
+
error: resultText,
|
|
71
|
+
now: new Date().toISOString()
|
|
72
|
+
};
|
|
73
|
+
} else {
|
|
74
|
+
resultJson = {
|
|
75
|
+
error: unsubscribeEndpointResult.status,
|
|
76
|
+
now: new Date().toISOString()
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
resultJson = {
|
|
81
|
+
error,
|
|
82
|
+
now: new Date().toISOString()
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (handleUnsubscribe) {
|
|
86
|
+
handleUnsubscribe(resultJson);
|
|
87
|
+
}
|
|
88
|
+
return resultJson;
|
|
89
|
+
}, [
|
|
90
|
+
email,
|
|
91
|
+
serverURL,
|
|
92
|
+
hash
|
|
93
|
+
]);
|
|
94
|
+
useEffect(()=>{
|
|
95
|
+
async function verify() {
|
|
96
|
+
const { error, message } = await callUnsubscribe();
|
|
97
|
+
console.log(`Unknown error: (${error})`);
|
|
98
|
+
setResult(message || `An error occured. Please try again. (${error})`);
|
|
99
|
+
setIsError(error && !message);
|
|
100
|
+
// console.info('callUnsubscribe not okay', { error, message })
|
|
101
|
+
}
|
|
102
|
+
if (!subscriber) {
|
|
103
|
+
void verify();
|
|
104
|
+
}
|
|
105
|
+
}, [
|
|
106
|
+
callUnsubscribe,
|
|
107
|
+
serverURL,
|
|
108
|
+
email,
|
|
109
|
+
refreshSubscriber,
|
|
110
|
+
subscriber,
|
|
111
|
+
hash
|
|
112
|
+
]);
|
|
113
|
+
return /*#__PURE__*/ _jsx(_Fragment, {
|
|
114
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
115
|
+
className: mergeClassNames([
|
|
116
|
+
'subscribers-verify subscribers-container',
|
|
117
|
+
styles.container,
|
|
118
|
+
classNames.container
|
|
119
|
+
]),
|
|
120
|
+
children: [
|
|
121
|
+
!result && /*#__PURE__*/ _jsx("p", {
|
|
122
|
+
className: mergeClassNames([
|
|
123
|
+
'subscribers-loading',
|
|
124
|
+
styles.loading,
|
|
125
|
+
classNames.loading
|
|
126
|
+
]),
|
|
127
|
+
children: "unsubscribing..."
|
|
128
|
+
}),
|
|
129
|
+
result && /*#__PURE__*/ _jsx("p", {
|
|
130
|
+
className: mergeClassNames([
|
|
131
|
+
'subscribers-message',
|
|
132
|
+
styles.message,
|
|
133
|
+
classNames.message,
|
|
134
|
+
isError ? [
|
|
135
|
+
'subscribers-error',
|
|
136
|
+
styles.error,
|
|
137
|
+
classNames.error
|
|
138
|
+
] : []
|
|
139
|
+
]),
|
|
140
|
+
children: result
|
|
141
|
+
}),
|
|
142
|
+
/*#__PURE__*/ _jsx("div", {
|
|
143
|
+
className: mergeClassNames([
|
|
144
|
+
'subscribers-form',
|
|
145
|
+
styles.form,
|
|
146
|
+
classNames.form
|
|
147
|
+
]),
|
|
148
|
+
children: result && children
|
|
149
|
+
})
|
|
150
|
+
]
|
|
151
|
+
})
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
//# sourceMappingURL=Unsubscribe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/app/Unsubscribe.tsx"],"sourcesContent":["'use client'\n\nimport { useSearchParams } from 'next/navigation.js'\nimport { useCallback, useEffect, useState } from 'react'\n\nimport type { UnsubscribeResponse } from '../../endpoints/unsubscribe.js'\n\nexport { UnsubscribeResponse }\nimport { 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/** Props for the Unsubscribe component. */\nexport interface IUnsubscribe {\n children?: React.ReactNode\n classNames?: UnsubscribeClasses\n handleUnsubscribe?: (result: UnsubscribeResponse) => void\n renderButton?: (props: { name?: string; onClick?: () => any; text?: string }) => React.ReactNode\n}\n\n/** Optional CSS class overrides for Unsubscribe elements. */\nexport type UnsubscribeClasses = {\n button?: string\n container?: string\n emailInput?: string\n error?: string\n form?: string\n loading?: string\n message?: string\n}\n\n/**\n * Handles the verify step of magic-link flow. When URL has email and hash query params, calls\n * POST /api/unsubscribe to complete the unsubscribe. Displays children provided after unsubscribe is attempted.\n *\n * @param props - See IUnsubscribe\n * @returns Result message, and optional button/children\n */\nexport const Unsubscribe = ({\n children,\n classNames = {\n button: '',\n container: '',\n emailInput: '',\n error: '',\n form: '',\n loading: '',\n message: '',\n },\n handleUnsubscribe,\n renderButton = ({ name, onClick, text }) => (\n <button\n className={mergeClassNames(['subscribers-button', styles.button, classNames.button])}\n name={name}\n onClick={onClick}\n type=\"button\"\n >\n {text}\n </button>\n ),\n}: IUnsubscribe) => {\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 hash = searchParams.get('hash')\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 callUnsubscribe = useCallback(async () => {\n if (!email || !hash) {\n return { error: 'Invalid input' }\n }\n let resultJson\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 // return unsubscribeEndpointResult\n if (unsubscribeEndpointResult && unsubscribeEndpointResult.json) {\n resultJson = await unsubscribeEndpointResult.json()\n resultJson = { error: resultJson.error, message: resultJson.message, now: resultJson.now }\n } else if (unsubscribeEndpointResult && unsubscribeEndpointResult.text) {\n const resultText = await unsubscribeEndpointResult.text()\n resultJson = { error: resultText, now: new Date().toISOString() }\n } else {\n resultJson = { error: unsubscribeEndpointResult.status, now: new Date().toISOString() }\n }\n } catch (error: any) {\n resultJson = { error, now: new Date().toISOString() }\n }\n if (handleUnsubscribe) {\n handleUnsubscribe(resultJson)\n }\n return resultJson\n }, [email, serverURL, hash])\n\n useEffect(() => {\n async function verify() {\n const { error, message } = await callUnsubscribe()\n console.log(`Unknown error: (${error})`)\n setResult(message || `An error occured. Please try again. (${error})`)\n setIsError(error && !message)\n // console.info('callUnsubscribe not okay', { error, message })\n }\n if (!subscriber) {\n void verify()\n }\n }, [callUnsubscribe, serverURL, email, refreshSubscriber, subscriber, hash])\n\n return (\n <>\n <div\n className={mergeClassNames([\n 'subscribers-verify subscribers-container',\n styles.container,\n classNames.container,\n ])}\n >\n {!result && (\n <p\n className={mergeClassNames(['subscribers-loading', styles.loading, classNames.loading])}\n >\n unsubscribing...\n </p>\n )}\n {result && (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n isError ? ['subscribers-error', styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n )}\n <div className={mergeClassNames(['subscribers-form', 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"],"names":["useSearchParams","useCallback","useEffect","useState","useSubscriber","useServerUrl","mergeClassNames","styles","Unsubscribe","children","classNames","button","container","emailInput","error","form","loading","message","handleUnsubscribe","renderButton","name","onClick","text","className","type","serverURL","subscriber","searchParams","email","get","hash","result","setResult","isError","setIsError","refreshSubscriber","callUnsubscribe","resultJson","unsubscribeEndpointResult","fetch","body","JSON","stringify","unsubscribeToken","method","json","now","resultText","Date","toISOString","status","verify","console","log","div","p"],"mappings":"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"}
|
|
@@ -48,7 +48,6 @@ import styles from './shared.module.css';
|
|
|
48
48
|
const { refreshSubscriber } = useSubscriber();
|
|
49
49
|
const callVerify = useCallback(async ()=>{
|
|
50
50
|
if (!email || !token) {
|
|
51
|
-
console.info('Invalid input');
|
|
52
51
|
return {
|
|
53
52
|
error: 'Invalid input'
|
|
54
53
|
};
|
|
@@ -58,7 +57,7 @@ import styles from './shared.module.css';
|
|
|
58
57
|
// returns a not-okay status, PayloadSDK.request returns its
|
|
59
58
|
// own "Bad request" error, and doesn't share the endpoint
|
|
60
59
|
// result data.
|
|
61
|
-
const verifyEndpointResult = await fetch(serverURL
|
|
60
|
+
const verifyEndpointResult = await fetch(`${serverURL ? serverURL : ''}/api/verifyToken`, {
|
|
62
61
|
body: JSON.stringify({
|
|
63
62
|
email,
|
|
64
63
|
token
|
|
@@ -67,26 +66,22 @@ import styles from './shared.module.css';
|
|
|
67
66
|
});
|
|
68
67
|
// return verifyEndpointResult
|
|
69
68
|
if (verifyEndpointResult && verifyEndpointResult.json) {
|
|
70
|
-
console.log(1);
|
|
71
69
|
const resultJson = await verifyEndpointResult.json();
|
|
72
70
|
return {
|
|
73
71
|
error: resultJson.error,
|
|
74
72
|
message: resultJson.message
|
|
75
73
|
};
|
|
76
74
|
} else if (verifyEndpointResult && verifyEndpointResult.text) {
|
|
77
|
-
console.log(2);
|
|
78
75
|
const resultText = await verifyEndpointResult.text();
|
|
79
76
|
return {
|
|
80
77
|
error: resultText
|
|
81
78
|
};
|
|
82
79
|
} else {
|
|
83
|
-
console.log(3);
|
|
84
80
|
return {
|
|
85
81
|
error: verifyEndpointResult.status
|
|
86
82
|
};
|
|
87
83
|
}
|
|
88
84
|
} catch (error) {
|
|
89
|
-
console.log('catch');
|
|
90
85
|
return {
|
|
91
86
|
error
|
|
92
87
|
};
|
|
@@ -99,6 +94,7 @@ import styles from './shared.module.css';
|
|
|
99
94
|
useEffect(()=>{
|
|
100
95
|
async function verify() {
|
|
101
96
|
const { error, message } = await callVerify();
|
|
97
|
+
console.log(`Unknown error: (${error})`);
|
|
102
98
|
setResult(message || `An error occured. Please try again. (${error})`);
|
|
103
99
|
setIsError(error && !message);
|
|
104
100
|
// console.info('callVerify not okay', { error, message })
|
|
@@ -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/** Props for the VerifyMagicLink component. */\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?: string | URL\n}\n\n/** Optional CSS class overrides for VerifyMagicLink elements. */\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\n/**\n * Handles the verify step of magic-link flow. When URL has email and token query params, calls\n * POST /api/verifyToken to verify and log in; otherwise shows RequestMagicLink. Supports\n * \"Request another magic link\" via renderButton and optional callbacks.\n *\n * @param props - See IVerifyMagicLink\n * @returns RequestMagicLink when no token/email; otherwise verifying state, result message, and optional button/children\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(['subscribers-button', styles.button, classNames.button])}\n name={name}\n onClick={onClick}\n type=\"button\"\n >\n {text}\n </button>\n ),\n verifyUrl,\n}: IVerifyMagicLink) => {\n if (typeof verifyUrl == 'string') {\n verifyUrl = new URL(verifyUrl)\n }\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\n className={mergeClassNames([\n 'subscribers-verify subscribers-container',\n styles.container,\n classNames.container,\n ])}\n >\n {!result && (\n <p\n className={mergeClassNames([\n 'subscribers-loading',\n styles.loading,\n classNames.loading,\n ])}\n >\n verifying...\n </p>\n )}\n {result && (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n isError ? ['subscribers-error', styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n )}\n <div className={mergeClassNames(['subscribers-form', 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","URL","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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"}
|
|
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/** Props for the VerifyMagicLink component. */\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?: string | URL\n}\n\n/** Optional CSS class overrides for VerifyMagicLink elements. */\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\n/**\n * Handles the verify step of magic-link flow. When URL has email and token query params, calls\n * POST /api/verifyToken to verify and log in; otherwise shows RequestMagicLink. Supports\n * \"Request another magic link\" via renderButton and optional callbacks.\n *\n * @param props - See IVerifyMagicLink\n * @returns RequestMagicLink when no token/email; otherwise verifying state, result message, and optional button/children\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(['subscribers-button', styles.button, classNames.button])}\n name={name}\n onClick={onClick}\n type=\"button\"\n >\n {text}\n </button>\n ),\n verifyUrl,\n}: IVerifyMagicLink) => {\n if (typeof verifyUrl == 'string') {\n verifyUrl = new URL(verifyUrl)\n }\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 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 ? 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 const resultJson = await verifyEndpointResult.json()\n return { error: resultJson.error, message: resultJson.message }\n } else if (verifyEndpointResult && verifyEndpointResult.text) {\n const resultText = await verifyEndpointResult.text()\n return { error: resultText }\n } else {\n return { error: verifyEndpointResult.status }\n }\n } catch (error: unknown) {\n return { error }\n }\n }, [email, serverURL, token])\n\n useEffect(() => {\n async function verify() {\n const { error, message } = await callVerify()\n console.log(`Unknown error: (${error})`)\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\n className={mergeClassNames([\n 'subscribers-verify subscribers-container',\n styles.container,\n classNames.container,\n ])}\n >\n {!result && (\n <p\n className={mergeClassNames([\n 'subscribers-loading',\n styles.loading,\n classNames.loading,\n ])}\n >\n verifying...\n </p>\n )}\n {result && (\n <p\n className={mergeClassNames([\n 'subscribers-message',\n styles.message,\n classNames.message,\n isError ? ['subscribers-error', styles.error, classNames.error] : [],\n ])}\n >\n {result}\n </p>\n )}\n <div className={mergeClassNames(['subscribers-form', 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","URL","serverURL","subscriber","searchParams","email","get","token","result","setResult","isError","setIsError","refreshSubscriber","callVerify","verifyEndpointResult","fetch","body","JSON","stringify","method","json","resultJson","resultText","status","verify","console","log","handleRequestAnother","sdk","baseURL","emailResult","request","href","path","ok","div","p"],"mappings":"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"}
|
|
@@ -12,9 +12,11 @@ export type RequestMagicLinkResponse = {
|
|
|
12
12
|
*
|
|
13
13
|
* @param options - Config options for the endpoint
|
|
14
14
|
* @param options.subscribersCollectionSlug - Collection slug for subscribers (default from Subscribers collection)
|
|
15
|
+
* @param options.unsubscribeUrl - The URL to use for unsubscribe links
|
|
15
16
|
* @returns Payload Endpoint config for POST /emailToken
|
|
16
17
|
*/
|
|
17
|
-
declare function createEndpointRequestMagicLink({ subscribersCollectionSlug, }: {
|
|
18
|
+
declare function createEndpointRequestMagicLink({ subscribersCollectionSlug, unsubscribeUrl, }: {
|
|
18
19
|
subscribersCollectionSlug: CollectionSlug;
|
|
20
|
+
unsubscribeUrl?: URL;
|
|
19
21
|
}): Endpoint;
|
|
20
22
|
export default createEndpointRequestMagicLink;
|