@ainsleydev/payload-helper 0.0.40 → 0.1.0
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 +76 -0
- package/dist/cli/bin.js +20 -0
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/preview-emails.d.ts +5 -0
- package/dist/cli/commands/preview-emails.js +123 -0
- package/dist/cli/commands/preview-emails.js.map +1 -0
- package/dist/email/ForgotPasswordEmail.d.ts +38 -0
- package/dist/email/ForgotPasswordEmail.js +61 -0
- package/dist/email/ForgotPasswordEmail.js.map +1 -0
- package/dist/email/ForgotPasswordEmail.test.d.ts +1 -0
- package/dist/email/ForgotPasswordEmail.test.js +202 -0
- package/dist/email/ForgotPasswordEmail.test.js.map +1 -0
- package/dist/email/VerifyAccountEmail.d.ts +38 -0
- package/dist/email/VerifyAccountEmail.js +61 -0
- package/dist/email/VerifyAccountEmail.js.map +1 -0
- package/dist/email/VerifyAccountEmail.test.d.ts +1 -0
- package/dist/email/VerifyAccountEmail.test.js +212 -0
- package/dist/email/VerifyAccountEmail.test.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/plugin/email.d.ts +10 -0
- package/dist/plugin/email.js +98 -0
- package/dist/plugin/email.js.map +1 -0
- package/dist/plugin/email.test.js +265 -0
- package/dist/plugin/email.test.js.map +1 -0
- package/dist/types.d.ts +134 -0
- package/dist/types.js +3 -1
- package/dist/types.js.map +1 -1
- package/package.json +27 -14
- package/dist/plugin/icon.d.ts +0 -6
- package/dist/plugin/icon.js +0 -26
- package/dist/plugin/icon.js.map +0 -1
- package/dist/plugin/logo.d.ts +0 -6
- package/dist/plugin/logo.js +0 -26
- package/dist/plugin/logo.js.map +0 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { BaseEmail, Button, Heading, Section, Text } from '@ainsleydev/email-templates';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Email template for account verification in Payload CMS.
|
|
6
|
+
*
|
|
7
|
+
* @param props - The component props
|
|
8
|
+
* @returns The rendered email component
|
|
9
|
+
*/ export const VerifyAccountEmail = ({ theme, user, verifyUrl, content })=>{
|
|
10
|
+
const userName = user.firstName || user.email || 'there';
|
|
11
|
+
const previewText = content?.previewText || 'Verify your email';
|
|
12
|
+
const heading = content?.heading || `Welcome, ${userName}!`;
|
|
13
|
+
const bodyText = content?.bodyText || 'Please verify your email by clicking the button below. If you did not request a password reset, you can safely ignore this email.';
|
|
14
|
+
const buttonText = content?.buttonText || 'Verify Email';
|
|
15
|
+
return /*#__PURE__*/ _jsxs(BaseEmail, {
|
|
16
|
+
theme: theme,
|
|
17
|
+
previewText: previewText,
|
|
18
|
+
children: [
|
|
19
|
+
/*#__PURE__*/ _jsx(Heading, {
|
|
20
|
+
style: {
|
|
21
|
+
color: theme.colours.text.heading,
|
|
22
|
+
fontSize: '24px',
|
|
23
|
+
fontWeight: 'bold',
|
|
24
|
+
marginBottom: '20px'
|
|
25
|
+
},
|
|
26
|
+
children: heading
|
|
27
|
+
}),
|
|
28
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
29
|
+
style: {
|
|
30
|
+
color: theme.colours.text.body,
|
|
31
|
+
fontSize: '16px',
|
|
32
|
+
lineHeight: '24px',
|
|
33
|
+
marginBottom: '30px'
|
|
34
|
+
},
|
|
35
|
+
children: bodyText
|
|
36
|
+
}),
|
|
37
|
+
/*#__PURE__*/ _jsx(Section, {
|
|
38
|
+
style: {
|
|
39
|
+
textAlign: 'center',
|
|
40
|
+
marginBottom: '30px'
|
|
41
|
+
},
|
|
42
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
43
|
+
href: verifyUrl,
|
|
44
|
+
style: {
|
|
45
|
+
backgroundColor: theme.colours.background.accent,
|
|
46
|
+
color: theme.colours.text.heading,
|
|
47
|
+
padding: '12px 32px',
|
|
48
|
+
borderRadius: '5px',
|
|
49
|
+
fontSize: '16px',
|
|
50
|
+
fontWeight: 'bold',
|
|
51
|
+
textDecoration: 'none',
|
|
52
|
+
display: 'inline-block'
|
|
53
|
+
},
|
|
54
|
+
children: buttonText
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=VerifyAccountEmail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/email/VerifyAccountEmail.tsx"],"sourcesContent":["import { BaseEmail, Button, Heading, Section, Text } from '@ainsleydev/email-templates';\nimport type { EmailTheme } from '@ainsleydev/email-templates';\nimport * as React from 'react';\n\n/**\n * Props for the VerifyAccountEmail component.\n */\nexport interface VerifyAccountEmailProps {\n\t/**\n\t * The email theme (required by renderEmail).\n\t */\n\ttheme: EmailTheme;\n\n\t/**\n\t * The user object containing user information.\n\t */\n\tuser: {\n\t\tfirstName?: string;\n\t\temail?: string;\n\t};\n\n\t/**\n\t * The URL for verifying the account.\n\t */\n\tverifyUrl: string;\n\n\t/**\n\t * Optional content overrides.\n\t */\n\tcontent?: {\n\t\tpreviewText?: string;\n\t\theading?: string;\n\t\tbodyText?: string;\n\t\tbuttonText?: string;\n\t};\n}\n\n/**\n * Email template for account verification in Payload CMS.\n *\n * @param props - The component props\n * @returns The rendered email component\n */\nexport const VerifyAccountEmail = ({\n\ttheme,\n\tuser,\n\tverifyUrl,\n\tcontent,\n}: VerifyAccountEmailProps) => {\n\tconst userName = user.firstName || user.email || 'there';\n\tconst previewText = content?.previewText || 'Verify your email';\n\tconst heading = content?.heading || `Welcome, ${userName}!`;\n\tconst bodyText =\n\t\tcontent?.bodyText ||\n\t\t'Please verify your email by clicking the button below. If you did not request a password reset, you can safely ignore this email.';\n\tconst buttonText = content?.buttonText || 'Verify Email';\n\n\treturn (\n\t\t<BaseEmail theme={theme} previewText={previewText}>\n\t\t\t<Heading\n\t\t\t\tstyle={{\n\t\t\t\t\tcolor: theme.colours.text.heading,\n\t\t\t\t\tfontSize: '24px',\n\t\t\t\t\tfontWeight: 'bold',\n\t\t\t\t\tmarginBottom: '20px',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{heading}\n\t\t\t</Heading>\n\t\t\t<Text\n\t\t\t\tstyle={{\n\t\t\t\t\tcolor: theme.colours.text.body,\n\t\t\t\t\tfontSize: '16px',\n\t\t\t\t\tlineHeight: '24px',\n\t\t\t\t\tmarginBottom: '30px',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{bodyText}\n\t\t\t</Text>\n\t\t\t<Section style={{ textAlign: 'center', marginBottom: '30px' }}>\n\t\t\t\t<Button\n\t\t\t\t\thref={verifyUrl}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tbackgroundColor: theme.colours.background.accent,\n\t\t\t\t\t\tcolor: theme.colours.text.heading,\n\t\t\t\t\t\tpadding: '12px 32px',\n\t\t\t\t\t\tborderRadius: '5px',\n\t\t\t\t\t\tfontSize: '16px',\n\t\t\t\t\t\tfontWeight: 'bold',\n\t\t\t\t\t\ttextDecoration: 'none',\n\t\t\t\t\t\tdisplay: 'inline-block',\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{buttonText}\n\t\t\t\t</Button>\n\t\t\t</Section>\n\t\t</BaseEmail>\n\t);\n};\n"],"names":["BaseEmail","Button","Heading","Section","Text","React","VerifyAccountEmail","theme","user","verifyUrl","content","userName","firstName","email","previewText","heading","bodyText","buttonText","style","color","colours","text","fontSize","fontWeight","marginBottom","body","lineHeight","textAlign","href","backgroundColor","background","accent","padding","borderRadius","textDecoration","display"],"mappings":";AAAA,SAASA,SAAS,EAAEC,MAAM,EAAEC,OAAO,EAAEC,OAAO,EAAEC,IAAI,QAAQ,8BAA8B;AAExF,YAAYC,WAAW,QAAQ;AAmC/B;;;;;CAKC,GACD,OAAO,MAAMC,qBAAqB,CAAC,EAClCC,KAAK,EACLC,IAAI,EACJC,SAAS,EACTC,OAAO,EACkB;IACzB,MAAMC,WAAWH,KAAKI,SAAS,IAAIJ,KAAKK,KAAK,IAAI;IACjD,MAAMC,cAAcJ,SAASI,eAAe;IAC5C,MAAMC,UAAUL,SAASK,WAAW,CAAC,SAAS,EAAEJ,SAAS,CAAC,CAAC;IAC3D,MAAMK,WACLN,SAASM,YACT;IACD,MAAMC,aAAaP,SAASO,cAAc;IAE1C,qBACC,MAACjB;QAAUO,OAAOA;QAAOO,aAAaA;;0BACrC,KAACZ;gBACAgB,OAAO;oBACNC,OAAOZ,MAAMa,OAAO,CAACC,IAAI,CAACN,OAAO;oBACjCO,UAAU;oBACVC,YAAY;oBACZC,cAAc;gBACf;0BAECT;;0BAEF,KAACX;gBACAc,OAAO;oBACNC,OAAOZ,MAAMa,OAAO,CAACC,IAAI,CAACI,IAAI;oBAC9BH,UAAU;oBACVI,YAAY;oBACZF,cAAc;gBACf;0BAECR;;0BAEF,KAACb;gBAAQe,OAAO;oBAAES,WAAW;oBAAUH,cAAc;gBAAO;0BAC3D,cAAA,KAACvB;oBACA2B,MAAMnB;oBACNS,OAAO;wBACNW,iBAAiBtB,MAAMa,OAAO,CAACU,UAAU,CAACC,MAAM;wBAChDZ,OAAOZ,MAAMa,OAAO,CAACC,IAAI,CAACN,OAAO;wBACjCiB,SAAS;wBACTC,cAAc;wBACdX,UAAU;wBACVC,YAAY;wBACZW,gBAAgB;wBAChBC,SAAS;oBACV;8BAEClB;;;;;AAKN,EAAE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
3
|
+
import { VerifyAccountEmail } from './VerifyAccountEmail.js';
|
|
4
|
+
// Mock the email templates module
|
|
5
|
+
vi.mock('@ainsleydev/email-templates', ()=>({
|
|
6
|
+
BaseEmail: ({ children })=>children,
|
|
7
|
+
Button: ({ children, href })=>/*#__PURE__*/ _jsx("a", {
|
|
8
|
+
href: href,
|
|
9
|
+
children: children
|
|
10
|
+
}),
|
|
11
|
+
Heading: ({ children })=>/*#__PURE__*/ _jsx("h1", {
|
|
12
|
+
children: children
|
|
13
|
+
}),
|
|
14
|
+
Section: ({ children })=>/*#__PURE__*/ _jsx("section", {
|
|
15
|
+
children: children
|
|
16
|
+
}),
|
|
17
|
+
Text: ({ children })=>/*#__PURE__*/ _jsx("p", {
|
|
18
|
+
children: children
|
|
19
|
+
})
|
|
20
|
+
}));
|
|
21
|
+
const mockTheme = {
|
|
22
|
+
colours: {
|
|
23
|
+
text: {
|
|
24
|
+
heading: '#000000',
|
|
25
|
+
body: '#333333',
|
|
26
|
+
action: '#007bff',
|
|
27
|
+
negative: '#ffffff'
|
|
28
|
+
},
|
|
29
|
+
background: {
|
|
30
|
+
white: '#ffffff',
|
|
31
|
+
dark: '#000000',
|
|
32
|
+
darker: '#0f0f0f',
|
|
33
|
+
highlight: '#f5f5f5',
|
|
34
|
+
accent: '#007bff'
|
|
35
|
+
},
|
|
36
|
+
border: {
|
|
37
|
+
light: '#e0e0e0',
|
|
38
|
+
medium: '#cccccc',
|
|
39
|
+
dark: '#000000',
|
|
40
|
+
inverse: '#ffffff'
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
branding: {
|
|
44
|
+
companyName: 'Test Company',
|
|
45
|
+
logoUrl: 'https://example.com/logo.png',
|
|
46
|
+
logoWidth: 120,
|
|
47
|
+
websiteUrl: 'https://example.com'
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
describe('VerifyAccountEmail', ()=>{
|
|
51
|
+
test('should render with default content when no overrides provided', ()=>{
|
|
52
|
+
const props = {
|
|
53
|
+
theme: mockTheme,
|
|
54
|
+
user: {
|
|
55
|
+
firstName: 'John',
|
|
56
|
+
email: 'john@example.com'
|
|
57
|
+
},
|
|
58
|
+
verifyUrl: 'https://example.com/verify/token123'
|
|
59
|
+
};
|
|
60
|
+
const result = VerifyAccountEmail(props);
|
|
61
|
+
// Component should render without errors
|
|
62
|
+
expect(result).toBeDefined();
|
|
63
|
+
});
|
|
64
|
+
test('should use firstName when available', ()=>{
|
|
65
|
+
const props = {
|
|
66
|
+
theme: mockTheme,
|
|
67
|
+
user: {
|
|
68
|
+
firstName: 'Jane',
|
|
69
|
+
email: 'jane@example.com'
|
|
70
|
+
},
|
|
71
|
+
verifyUrl: 'https://example.com/verify/token123'
|
|
72
|
+
};
|
|
73
|
+
const result = VerifyAccountEmail(props);
|
|
74
|
+
// The userName should be set to firstName
|
|
75
|
+
// This is tested through the default heading which uses userName
|
|
76
|
+
expect(result).toBeDefined();
|
|
77
|
+
});
|
|
78
|
+
test('should use email when firstName is not available', ()=>{
|
|
79
|
+
const props = {
|
|
80
|
+
theme: mockTheme,
|
|
81
|
+
user: {
|
|
82
|
+
email: 'john@example.com'
|
|
83
|
+
},
|
|
84
|
+
verifyUrl: 'https://example.com/verify/token123'
|
|
85
|
+
};
|
|
86
|
+
const result = VerifyAccountEmail(props);
|
|
87
|
+
// The userName should be set to email
|
|
88
|
+
expect(result).toBeDefined();
|
|
89
|
+
});
|
|
90
|
+
test('should use "there" when neither firstName nor email is available', ()=>{
|
|
91
|
+
const props = {
|
|
92
|
+
theme: mockTheme,
|
|
93
|
+
user: {},
|
|
94
|
+
verifyUrl: 'https://example.com/verify/token123'
|
|
95
|
+
};
|
|
96
|
+
const result = VerifyAccountEmail(props);
|
|
97
|
+
// The userName should default to "there"
|
|
98
|
+
expect(result).toBeDefined();
|
|
99
|
+
});
|
|
100
|
+
test('should use custom content overrides when provided', ()=>{
|
|
101
|
+
const props = {
|
|
102
|
+
theme: mockTheme,
|
|
103
|
+
user: {
|
|
104
|
+
firstName: 'John'
|
|
105
|
+
},
|
|
106
|
+
verifyUrl: 'https://example.com/verify/token123',
|
|
107
|
+
content: {
|
|
108
|
+
previewText: 'Custom preview text',
|
|
109
|
+
heading: 'Custom Welcome Heading',
|
|
110
|
+
bodyText: 'Custom verification message',
|
|
111
|
+
buttonText: 'Custom Verify Button'
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const result = VerifyAccountEmail(props);
|
|
115
|
+
// Component should use custom content
|
|
116
|
+
expect(result).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
test('should use partial content overrides with defaults', ()=>{
|
|
119
|
+
const props = {
|
|
120
|
+
theme: mockTheme,
|
|
121
|
+
user: {
|
|
122
|
+
firstName: 'John'
|
|
123
|
+
},
|
|
124
|
+
verifyUrl: 'https://example.com/verify/token123',
|
|
125
|
+
content: {
|
|
126
|
+
buttonText: 'Confirm Email'
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const result = VerifyAccountEmail(props);
|
|
130
|
+
// Component should use custom button text and defaults for others
|
|
131
|
+
expect(result).toBeDefined();
|
|
132
|
+
});
|
|
133
|
+
test('should pass verifyUrl to the button', ()=>{
|
|
134
|
+
const verifyUrl = 'https://example.com/verify/xyz789abc';
|
|
135
|
+
const props = {
|
|
136
|
+
theme: mockTheme,
|
|
137
|
+
user: {
|
|
138
|
+
firstName: 'John'
|
|
139
|
+
},
|
|
140
|
+
verifyUrl
|
|
141
|
+
};
|
|
142
|
+
const result = VerifyAccountEmail(props);
|
|
143
|
+
// The verifyUrl should be used in the button href
|
|
144
|
+
expect(result).toBeDefined();
|
|
145
|
+
});
|
|
146
|
+
test('should apply theme colors correctly', ()=>{
|
|
147
|
+
const customTheme = {
|
|
148
|
+
colours: {
|
|
149
|
+
text: {
|
|
150
|
+
heading: '#ff0000',
|
|
151
|
+
body: '#00ff00',
|
|
152
|
+
action: '#0000ff',
|
|
153
|
+
negative: '#ffffff'
|
|
154
|
+
},
|
|
155
|
+
background: {
|
|
156
|
+
white: '#ffffff',
|
|
157
|
+
dark: '#000000',
|
|
158
|
+
darker: '#0f0f0f',
|
|
159
|
+
highlight: '#f5f5f5',
|
|
160
|
+
accent: '#0000ff'
|
|
161
|
+
},
|
|
162
|
+
border: {
|
|
163
|
+
light: '#e0e0e0',
|
|
164
|
+
medium: '#cccccc',
|
|
165
|
+
dark: '#000000',
|
|
166
|
+
inverse: '#ffffff'
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
branding: {
|
|
170
|
+
companyName: 'Custom Company',
|
|
171
|
+
logoUrl: 'https://custom.com/logo.png',
|
|
172
|
+
logoWidth: 150,
|
|
173
|
+
websiteUrl: 'https://custom.com'
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const props = {
|
|
177
|
+
theme: customTheme,
|
|
178
|
+
user: {
|
|
179
|
+
firstName: 'John'
|
|
180
|
+
},
|
|
181
|
+
verifyUrl: 'https://example.com/verify/token123'
|
|
182
|
+
};
|
|
183
|
+
const result = VerifyAccountEmail(props);
|
|
184
|
+
// Component should use custom theme colors
|
|
185
|
+
expect(result).toBeDefined();
|
|
186
|
+
});
|
|
187
|
+
test('should handle empty content object', ()=>{
|
|
188
|
+
const props = {
|
|
189
|
+
theme: mockTheme,
|
|
190
|
+
user: {
|
|
191
|
+
firstName: 'John'
|
|
192
|
+
},
|
|
193
|
+
verifyUrl: 'https://example.com/verify/token123',
|
|
194
|
+
content: {}
|
|
195
|
+
};
|
|
196
|
+
const result = VerifyAccountEmail(props);
|
|
197
|
+
// Should use all defaults when content is empty object
|
|
198
|
+
expect(result).toBeDefined();
|
|
199
|
+
});
|
|
200
|
+
test('should render with minimal props', ()=>{
|
|
201
|
+
const props = {
|
|
202
|
+
theme: mockTheme,
|
|
203
|
+
user: {},
|
|
204
|
+
verifyUrl: 'https://example.com/verify/token123'
|
|
205
|
+
};
|
|
206
|
+
const result = VerifyAccountEmail(props);
|
|
207
|
+
// Should handle minimal props gracefully
|
|
208
|
+
expect(result).toBeDefined();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
//# sourceMappingURL=VerifyAccountEmail.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/email/VerifyAccountEmail.test.tsx"],"sourcesContent":["import type { EmailTheme } from '@ainsleydev/email-templates';\nimport { describe, expect, test, vi } from 'vitest';\nimport { VerifyAccountEmail } from './VerifyAccountEmail.js';\nimport type { VerifyAccountEmailProps } from './VerifyAccountEmail.js';\n\n// Mock the email templates module\nvi.mock('@ainsleydev/email-templates', () => ({\n\tBaseEmail: ({ children }: { children: React.ReactNode }) => children,\n\tButton: ({ children, href }: { children: React.ReactNode; href: string }) => (\n\t\t<a href={href}>{children}</a>\n\t),\n\tHeading: ({ children }: { children: React.ReactNode }) => <h1>{children}</h1>,\n\tSection: ({ children }: { children: React.ReactNode }) => <section>{children}</section>,\n\tText: ({ children }: { children: React.ReactNode }) => <p>{children}</p>,\n}));\n\nconst mockTheme: EmailTheme = {\n\tcolours: {\n\t\ttext: {\n\t\t\theading: '#000000',\n\t\t\tbody: '#333333',\n\t\t\taction: '#007bff',\n\t\t\tnegative: '#ffffff',\n\t\t},\n\t\tbackground: {\n\t\t\twhite: '#ffffff',\n\t\t\tdark: '#000000',\n\t\t\tdarker: '#0f0f0f',\n\t\t\thighlight: '#f5f5f5',\n\t\t\taccent: '#007bff',\n\t\t},\n\t\tborder: {\n\t\t\tlight: '#e0e0e0',\n\t\t\tmedium: '#cccccc',\n\t\t\tdark: '#000000',\n\t\t\tinverse: '#ffffff',\n\t\t},\n\t},\n\tbranding: {\n\t\tcompanyName: 'Test Company',\n\t\tlogoUrl: 'https://example.com/logo.png',\n\t\tlogoWidth: 120,\n\t\twebsiteUrl: 'https://example.com',\n\t},\n};\n\ndescribe('VerifyAccountEmail', () => {\n\ttest('should render with default content when no overrides provided', () => {\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: mockTheme,\n\t\t\tuser: {\n\t\t\t\tfirstName: 'John',\n\t\t\t\temail: 'john@example.com',\n\t\t\t},\n\t\t\tverifyUrl: 'https://example.com/verify/token123',\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// Component should render without errors\n\t\texpect(result).toBeDefined();\n\t});\n\n\ttest('should use firstName when available', () => {\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: mockTheme,\n\t\t\tuser: {\n\t\t\t\tfirstName: 'Jane',\n\t\t\t\temail: 'jane@example.com',\n\t\t\t},\n\t\t\tverifyUrl: 'https://example.com/verify/token123',\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// The userName should be set to firstName\n\t\t// This is tested through the default heading which uses userName\n\t\texpect(result).toBeDefined();\n\t});\n\n\ttest('should use email when firstName is not available', () => {\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: mockTheme,\n\t\t\tuser: {\n\t\t\t\temail: 'john@example.com',\n\t\t\t},\n\t\t\tverifyUrl: 'https://example.com/verify/token123',\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// The userName should be set to email\n\t\texpect(result).toBeDefined();\n\t});\n\n\ttest('should use \"there\" when neither firstName nor email is available', () => {\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: mockTheme,\n\t\t\tuser: {},\n\t\t\tverifyUrl: 'https://example.com/verify/token123',\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// The userName should default to \"there\"\n\t\texpect(result).toBeDefined();\n\t});\n\n\ttest('should use custom content overrides when provided', () => {\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: mockTheme,\n\t\t\tuser: {\n\t\t\t\tfirstName: 'John',\n\t\t\t},\n\t\t\tverifyUrl: 'https://example.com/verify/token123',\n\t\t\tcontent: {\n\t\t\t\tpreviewText: 'Custom preview text',\n\t\t\t\theading: 'Custom Welcome Heading',\n\t\t\t\tbodyText: 'Custom verification message',\n\t\t\t\tbuttonText: 'Custom Verify Button',\n\t\t\t},\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// Component should use custom content\n\t\texpect(result).toBeDefined();\n\t});\n\n\ttest('should use partial content overrides with defaults', () => {\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: mockTheme,\n\t\t\tuser: {\n\t\t\t\tfirstName: 'John',\n\t\t\t},\n\t\t\tverifyUrl: 'https://example.com/verify/token123',\n\t\t\tcontent: {\n\t\t\t\tbuttonText: 'Confirm Email',\n\t\t\t\t// Other fields should use defaults\n\t\t\t},\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// Component should use custom button text and defaults for others\n\t\texpect(result).toBeDefined();\n\t});\n\n\ttest('should pass verifyUrl to the button', () => {\n\t\tconst verifyUrl = 'https://example.com/verify/xyz789abc';\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: mockTheme,\n\t\t\tuser: {\n\t\t\t\tfirstName: 'John',\n\t\t\t},\n\t\t\tverifyUrl,\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// The verifyUrl should be used in the button href\n\t\texpect(result).toBeDefined();\n\t});\n\n\ttest('should apply theme colors correctly', () => {\n\t\tconst customTheme: EmailTheme = {\n\t\t\tcolours: {\n\t\t\t\ttext: {\n\t\t\t\t\theading: '#ff0000',\n\t\t\t\t\tbody: '#00ff00',\n\t\t\t\t\taction: '#0000ff',\n\t\t\t\t\tnegative: '#ffffff',\n\t\t\t\t},\n\t\t\t\tbackground: {\n\t\t\t\t\twhite: '#ffffff',\n\t\t\t\t\tdark: '#000000',\n\t\t\t\t\tdarker: '#0f0f0f',\n\t\t\t\t\thighlight: '#f5f5f5',\n\t\t\t\t\taccent: '#0000ff',\n\t\t\t\t},\n\t\t\t\tborder: {\n\t\t\t\t\tlight: '#e0e0e0',\n\t\t\t\t\tmedium: '#cccccc',\n\t\t\t\t\tdark: '#000000',\n\t\t\t\t\tinverse: '#ffffff',\n\t\t\t\t},\n\t\t\t},\n\t\t\tbranding: {\n\t\t\t\tcompanyName: 'Custom Company',\n\t\t\t\tlogoUrl: 'https://custom.com/logo.png',\n\t\t\t\tlogoWidth: 150,\n\t\t\t\twebsiteUrl: 'https://custom.com',\n\t\t\t},\n\t\t};\n\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: customTheme,\n\t\t\tuser: {\n\t\t\t\tfirstName: 'John',\n\t\t\t},\n\t\t\tverifyUrl: 'https://example.com/verify/token123',\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// Component should use custom theme colors\n\t\texpect(result).toBeDefined();\n\t});\n\n\ttest('should handle empty content object', () => {\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: mockTheme,\n\t\t\tuser: {\n\t\t\t\tfirstName: 'John',\n\t\t\t},\n\t\t\tverifyUrl: 'https://example.com/verify/token123',\n\t\t\tcontent: {},\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// Should use all defaults when content is empty object\n\t\texpect(result).toBeDefined();\n\t});\n\n\ttest('should render with minimal props', () => {\n\t\tconst props: VerifyAccountEmailProps = {\n\t\t\ttheme: mockTheme,\n\t\t\tuser: {},\n\t\t\tverifyUrl: 'https://example.com/verify/token123',\n\t\t};\n\n\t\tconst result = VerifyAccountEmail(props);\n\n\t\t// Should handle minimal props gracefully\n\t\texpect(result).toBeDefined();\n\t});\n});\n"],"names":["describe","expect","test","vi","VerifyAccountEmail","mock","BaseEmail","children","Button","href","a","Heading","h1","Section","section","Text","p","mockTheme","colours","text","heading","body","action","negative","background","white","dark","darker","highlight","accent","border","light","medium","inverse","branding","companyName","logoUrl","logoWidth","websiteUrl","props","theme","user","firstName","email","verifyUrl","result","toBeDefined","content","previewText","bodyText","buttonText","customTheme"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,4 +9,9 @@ import type { PayloadHelperPluginConfig } from './types.js';
|
|
|
9
9
|
export declare const payloadHelper: (pluginOptions: PayloadHelperPluginConfig) => (incomingConfig: Config) => Config;
|
|
10
10
|
export type { IconProps } from './admin/components/Icon.js';
|
|
11
11
|
export type { LogoProps } from './admin/components/Logo.js';
|
|
12
|
-
export
|
|
12
|
+
export { ForgotPasswordEmail } from './email/ForgotPasswordEmail.js';
|
|
13
|
+
export type { ForgotPasswordEmailProps } from './email/ForgotPasswordEmail.js';
|
|
14
|
+
export { VerifyAccountEmail } from './email/VerifyAccountEmail.js';
|
|
15
|
+
export type { VerifyAccountEmailProps } from './email/VerifyAccountEmail.js';
|
|
16
|
+
export { default as env } from './util/env.js';
|
|
17
|
+
export type { AdminConfig, AdminIconConfig, AdminLogoConfig, EmailConfig, EmailContentOverrides, PayloadHelperPluginConfig, } from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { injectAdminIcon, injectAdminLogo } from './plugin/admin.js';
|
|
2
|
+
import { injectEmailTemplates } from './plugin/email.js';
|
|
2
3
|
import { cacheHookCollections, cacheHookGlobals } from './plugin/hooks.js';
|
|
3
4
|
/**
|
|
4
5
|
* Payload Helper Plugin for websites at ainsley.dev
|
|
@@ -19,6 +20,10 @@ import { cacheHookCollections, cacheHookGlobals } from './plugin/hooks.js';
|
|
|
19
20
|
if (pluginOptions.admin?.icon) {
|
|
20
21
|
config = injectAdminIcon(config, pluginOptions.admin.icon, pluginOptions.siteName);
|
|
21
22
|
}
|
|
23
|
+
// Inject email templates for auth-enabled collections if email config is provided
|
|
24
|
+
if (pluginOptions.email) {
|
|
25
|
+
config = injectEmailTemplates(config, pluginOptions.email);
|
|
26
|
+
}
|
|
22
27
|
// Map collections & add hooks
|
|
23
28
|
config.collections = (config.collections || []).map((collection)=>{
|
|
24
29
|
if (collection.upload !== undefined && collection.upload !== true) {
|
|
@@ -62,7 +67,15 @@ import { cacheHookCollections, cacheHookGlobals } from './plugin/hooks.js';
|
|
|
62
67
|
hooks
|
|
63
68
|
};
|
|
64
69
|
});
|
|
70
|
+
// Store plugin options in config.custom for CLI access (e.g., preview-emails command)
|
|
71
|
+
config.custom = {
|
|
72
|
+
...config.custom,
|
|
73
|
+
payloadHelperOptions: pluginOptions
|
|
74
|
+
};
|
|
65
75
|
return config;
|
|
66
76
|
};
|
|
77
|
+
export { ForgotPasswordEmail } from './email/ForgotPasswordEmail.js';
|
|
78
|
+
export { VerifyAccountEmail } from './email/VerifyAccountEmail.js';
|
|
79
|
+
export { default as env } from './util/env.js';
|
|
67
80
|
|
|
68
81
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config } from 'payload';\nimport { injectAdminIcon, injectAdminLogo } from './plugin/admin.js';\nimport { cacheHookCollections, cacheHookGlobals } from './plugin/hooks.js';\nimport type { PayloadHelperPluginConfig } from './types.js';\n\n/**\n * Payload Helper Plugin for websites at ainsley.dev\n *\n * @constructor\n * @param pluginOptions\n */\nexport const payloadHelper =\n\t(pluginOptions: PayloadHelperPluginConfig) =>\n\t(incomingConfig: Config): Config => {\n\t\t// TODO: Validate Config\n\n\t\tlet config = incomingConfig;\n\n\t\t// Update typescript generation file\n\t\tconfig.typescript = config.typescript || {};\n\t\tconfig.typescript.outputFile = './src/types/payload.ts';\n\n\t\t// Inject admin Logo component if logo config is provided\n\t\tif (pluginOptions.admin?.logo) {\n\t\t\tconfig = injectAdminLogo(config, pluginOptions.admin.logo, pluginOptions.siteName);\n\t\t}\n\n\t\t// Inject admin Icon component if icon config is provided\n\t\tif (pluginOptions.admin?.icon) {\n\t\t\tconfig = injectAdminIcon(config, pluginOptions.admin.icon, pluginOptions.siteName);\n\t\t}\n\n\t\t// Map collections & add hooks\n\t\tconfig.collections = (config.collections || []).map((collection): CollectionConfig => {\n\t\t\tif (collection.upload !== undefined && collection.upload !== true) {\n\t\t\t\treturn collection;\n\t\t\t}\n\n\t\t\tconst hooks = collection.hooks || {};\n\n\t\t\t// Add afterChange hook only if webServer is defined\n\t\t\tif (pluginOptions.webServer) {\n\t\t\t\thooks.afterChange = [\n\t\t\t\t\t...(hooks.afterChange || []),\n\t\t\t\t\tcacheHookCollections({\n\t\t\t\t\t\tserver: pluginOptions.webServer,\n\t\t\t\t\t\tslug: collection.slug,\n\t\t\t\t\t\tfields: collection.fields,\n\t\t\t\t\t\tisCollection: true,\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...collection,\n\t\t\t\thooks,\n\t\t\t};\n\t\t});\n\n\t\t// Map globals & add hooks\n\t\tconfig.globals = (config.globals || []).map((global) => {\n\t\t\tconst hooks = global.hooks || {};\n\n\t\t\t// Add afterChange hook only if webServer is defined\n\t\t\tif (pluginOptions.webServer) {\n\t\t\t\thooks.afterChange = [\n\t\t\t\t\t...(hooks.afterChange || []),\n\t\t\t\t\tcacheHookGlobals({\n\t\t\t\t\t\tserver: pluginOptions.webServer,\n\t\t\t\t\t\tslug: global.slug,\n\t\t\t\t\t\tfields: global.fields,\n\t\t\t\t\t\tisCollection: true,\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...global,\n\t\t\t\thooks,\n\t\t\t};\n\t\t});\n\n\t\treturn config;\n\t};\n\nexport type { IconProps } from './admin/components/Icon.js';\nexport type { LogoProps } from './admin/components/Logo.js';\nexport type {\n\tAdminConfig,\n\tAdminIconConfig,\n\tAdminLogoConfig,\n\tPayloadHelperPluginConfig,\n} from './types.js';\n"],"names":["injectAdminIcon","injectAdminLogo","cacheHookCollections","cacheHookGlobals","payloadHelper","pluginOptions","incomingConfig","config","typescript","outputFile","admin","logo","siteName","icon","collections","map","collection","upload","undefined","hooks","webServer","afterChange","server","slug","fields","isCollection","globals","global"],"mappings":"AACA,SAASA,eAAe,EAAEC,eAAe,QAAQ,oBAAoB;AACrE,SAASC,oBAAoB,EAAEC,gBAAgB,QAAQ,oBAAoB;AAG3E;;;;;CAKC,GACD,OAAO,MAAMC,gBACZ,CAACC,gBACD,CAACC;QACA,wBAAwB;QAExB,IAAIC,SAASD;QAEb,oCAAoC;QACpCC,OAAOC,UAAU,GAAGD,OAAOC,UAAU,IAAI,CAAC;QAC1CD,OAAOC,UAAU,CAACC,UAAU,GAAG;QAE/B,yDAAyD;QACzD,IAAIJ,cAAcK,KAAK,EAAEC,MAAM;YAC9BJ,
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config } from 'payload';\nimport { injectAdminIcon, injectAdminLogo } from './plugin/admin.js';\nimport { injectEmailTemplates } from './plugin/email.js';\nimport { cacheHookCollections, cacheHookGlobals } from './plugin/hooks.js';\nimport type { PayloadHelperPluginConfig } from './types.js';\n\n/**\n * Payload Helper Plugin for websites at ainsley.dev\n *\n * @constructor\n * @param pluginOptions\n */\nexport const payloadHelper =\n\t(pluginOptions: PayloadHelperPluginConfig) =>\n\t(incomingConfig: Config): Config => {\n\t\t// TODO: Validate Config\n\n\t\tlet config = incomingConfig;\n\n\t\t// Update typescript generation file\n\t\tconfig.typescript = config.typescript || {};\n\t\tconfig.typescript.outputFile = './src/types/payload.ts';\n\n\t\t// Inject admin Logo component if logo config is provided\n\t\tif (pluginOptions.admin?.logo) {\n\t\t\tconfig = injectAdminLogo(config, pluginOptions.admin.logo, pluginOptions.siteName);\n\t\t}\n\n\t\t// Inject admin Icon component if icon config is provided\n\t\tif (pluginOptions.admin?.icon) {\n\t\t\tconfig = injectAdminIcon(config, pluginOptions.admin.icon, pluginOptions.siteName);\n\t\t}\n\n\t\t// Inject email templates for auth-enabled collections if email config is provided\n\t\tif (pluginOptions.email) {\n\t\t\tconfig = injectEmailTemplates(config, pluginOptions.email);\n\t\t}\n\n\t\t// Map collections & add hooks\n\t\tconfig.collections = (config.collections || []).map((collection): CollectionConfig => {\n\t\t\tif (collection.upload !== undefined && collection.upload !== true) {\n\t\t\t\treturn collection;\n\t\t\t}\n\n\t\t\tconst hooks = collection.hooks || {};\n\n\t\t\t// Add afterChange hook only if webServer is defined\n\t\t\tif (pluginOptions.webServer) {\n\t\t\t\thooks.afterChange = [\n\t\t\t\t\t...(hooks.afterChange || []),\n\t\t\t\t\tcacheHookCollections({\n\t\t\t\t\t\tserver: pluginOptions.webServer,\n\t\t\t\t\t\tslug: collection.slug,\n\t\t\t\t\t\tfields: collection.fields,\n\t\t\t\t\t\tisCollection: true,\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...collection,\n\t\t\t\thooks,\n\t\t\t};\n\t\t});\n\n\t\t// Map globals & add hooks\n\t\tconfig.globals = (config.globals || []).map((global) => {\n\t\t\tconst hooks = global.hooks || {};\n\n\t\t\t// Add afterChange hook only if webServer is defined\n\t\t\tif (pluginOptions.webServer) {\n\t\t\t\thooks.afterChange = [\n\t\t\t\t\t...(hooks.afterChange || []),\n\t\t\t\t\tcacheHookGlobals({\n\t\t\t\t\t\tserver: pluginOptions.webServer,\n\t\t\t\t\t\tslug: global.slug,\n\t\t\t\t\t\tfields: global.fields,\n\t\t\t\t\t\tisCollection: true,\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...global,\n\t\t\t\thooks,\n\t\t\t};\n\t\t});\n\n\t\t// Store plugin options in config.custom for CLI access (e.g., preview-emails command)\n\t\tconfig.custom = {\n\t\t\t...config.custom,\n\t\t\tpayloadHelperOptions: pluginOptions,\n\t\t};\n\n\t\treturn config;\n\t};\n\nexport type { IconProps } from './admin/components/Icon.js';\nexport type { LogoProps } from './admin/components/Logo.js';\nexport { ForgotPasswordEmail } from './email/ForgotPasswordEmail.js';\nexport type { ForgotPasswordEmailProps } from './email/ForgotPasswordEmail.js';\nexport { VerifyAccountEmail } from './email/VerifyAccountEmail.js';\nexport type { VerifyAccountEmailProps } from './email/VerifyAccountEmail.js';\nexport { default as env } from './util/env.js';\nexport type {\n\tAdminConfig,\n\tAdminIconConfig,\n\tAdminLogoConfig,\n\tEmailConfig,\n\tEmailContentOverrides,\n\tPayloadHelperPluginConfig,\n} from './types.js';\n"],"names":["injectAdminIcon","injectAdminLogo","injectEmailTemplates","cacheHookCollections","cacheHookGlobals","payloadHelper","pluginOptions","incomingConfig","config","typescript","outputFile","admin","logo","siteName","icon","email","collections","map","collection","upload","undefined","hooks","webServer","afterChange","server","slug","fields","isCollection","globals","global","custom","payloadHelperOptions","ForgotPasswordEmail","VerifyAccountEmail","default","env"],"mappings":"AACA,SAASA,eAAe,EAAEC,eAAe,QAAQ,oBAAoB;AACrE,SAASC,oBAAoB,QAAQ,oBAAoB;AACzD,SAASC,oBAAoB,EAAEC,gBAAgB,QAAQ,oBAAoB;AAG3E;;;;;CAKC,GACD,OAAO,MAAMC,gBACZ,CAACC,gBACD,CAACC;QACA,wBAAwB;QAExB,IAAIC,SAASD;QAEb,oCAAoC;QACpCC,OAAOC,UAAU,GAAGD,OAAOC,UAAU,IAAI,CAAC;QAC1CD,OAAOC,UAAU,CAACC,UAAU,GAAG;QAE/B,yDAAyD;QACzD,IAAIJ,cAAcK,KAAK,EAAEC,MAAM;YAC9BJ,SAASP,gBAAgBO,QAAQF,cAAcK,KAAK,CAACC,IAAI,EAAEN,cAAcO,QAAQ;QAClF;QAEA,yDAAyD;QACzD,IAAIP,cAAcK,KAAK,EAAEG,MAAM;YAC9BN,SAASR,gBAAgBQ,QAAQF,cAAcK,KAAK,CAACG,IAAI,EAAER,cAAcO,QAAQ;QAClF;QAEA,kFAAkF;QAClF,IAAIP,cAAcS,KAAK,EAAE;YACxBP,SAASN,qBAAqBM,QAAQF,cAAcS,KAAK;QAC1D;QAEA,8BAA8B;QAC9BP,OAAOQ,WAAW,GAAG,AAACR,CAAAA,OAAOQ,WAAW,IAAI,EAAE,AAAD,EAAGC,GAAG,CAAC,CAACC;YACpD,IAAIA,WAAWC,MAAM,KAAKC,aAAaF,WAAWC,MAAM,KAAK,MAAM;gBAClE,OAAOD;YACR;YAEA,MAAMG,QAAQH,WAAWG,KAAK,IAAI,CAAC;YAEnC,oDAAoD;YACpD,IAAIf,cAAcgB,SAAS,EAAE;gBAC5BD,MAAME,WAAW,GAAG;uBACfF,MAAME,WAAW,IAAI,EAAE;oBAC3BpB,qBAAqB;wBACpBqB,QAAQlB,cAAcgB,SAAS;wBAC/BG,MAAMP,WAAWO,IAAI;wBACrBC,QAAQR,WAAWQ,MAAM;wBACzBC,cAAc;oBACf;iBACA;YACF;YAEA,OAAO;gBACN,GAAGT,UAAU;gBACbG;YACD;QACD;QAEA,0BAA0B;QAC1Bb,OAAOoB,OAAO,GAAG,AAACpB,CAAAA,OAAOoB,OAAO,IAAI,EAAE,AAAD,EAAGX,GAAG,CAAC,CAACY;YAC5C,MAAMR,QAAQQ,OAAOR,KAAK,IAAI,CAAC;YAE/B,oDAAoD;YACpD,IAAIf,cAAcgB,SAAS,EAAE;gBAC5BD,MAAME,WAAW,GAAG;uBACfF,MAAME,WAAW,IAAI,EAAE;oBAC3BnB,iBAAiB;wBAChBoB,QAAQlB,cAAcgB,SAAS;wBAC/BG,MAAMI,OAAOJ,IAAI;wBACjBC,QAAQG,OAAOH,MAAM;wBACrBC,cAAc;oBACf;iBACA;YACF;YAEA,OAAO;gBACN,GAAGE,MAAM;gBACTR;YACD;QACD;QAEA,sFAAsF;QACtFb,OAAOsB,MAAM,GAAG;YACf,GAAGtB,OAAOsB,MAAM;YAChBC,sBAAsBzB;QACvB;QAEA,OAAOE;IACR,EAAE;AAIH,SAASwB,mBAAmB,QAAQ,iCAAiC;AAErE,SAASC,kBAAkB,QAAQ,gCAAgC;AAEnE,SAASC,WAAWC,GAAG,QAAQ,gBAAgB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Config } from 'payload';
|
|
2
|
+
import type { EmailConfig } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Injects email templates into all auth-enabled collections in the Payload config.
|
|
5
|
+
*
|
|
6
|
+
* @param config - The Payload configuration object
|
|
7
|
+
* @param emailConfig - The email configuration from plugin options
|
|
8
|
+
* @returns The modified Payload configuration with email templates injected
|
|
9
|
+
*/
|
|
10
|
+
export declare const injectEmailTemplates: (config: Config, emailConfig: EmailConfig) => Config;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { renderEmail } from '@ainsleydev/email-templates';
|
|
2
|
+
import { ForgotPasswordEmail } from '../email/ForgotPasswordEmail.js';
|
|
3
|
+
import { VerifyAccountEmail } from '../email/VerifyAccountEmail.js';
|
|
4
|
+
/**
|
|
5
|
+
* Injects email templates into all auth-enabled collections in the Payload config.
|
|
6
|
+
*
|
|
7
|
+
* @param config - The Payload configuration object
|
|
8
|
+
* @param emailConfig - The email configuration from plugin options
|
|
9
|
+
* @returns The modified Payload configuration with email templates injected
|
|
10
|
+
*/ export const injectEmailTemplates = (config, emailConfig)=>{
|
|
11
|
+
// Get the website URL for branding, defaulting to Payload's serverUrl
|
|
12
|
+
const websiteUrl = emailConfig.frontEndUrl || config.serverURL || '';
|
|
13
|
+
// Merge user theme with websiteUrl for branding
|
|
14
|
+
const themeOverride = {
|
|
15
|
+
...emailConfig.theme,
|
|
16
|
+
branding: {
|
|
17
|
+
...emailConfig.theme?.branding,
|
|
18
|
+
websiteUrl
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
// Find all collections with auth enabled
|
|
22
|
+
const collectionsWithAuth = config.collections?.filter((collection)=>collection.auth) || [];
|
|
23
|
+
// If no collections with auth, return config unchanged
|
|
24
|
+
if (collectionsWithAuth.length === 0) {
|
|
25
|
+
return config;
|
|
26
|
+
}
|
|
27
|
+
// Inject email templates into each auth-enabled collection
|
|
28
|
+
const updatedCollections = config.collections?.map((collection)=>{
|
|
29
|
+
// Skip collections without auth
|
|
30
|
+
if (!collection.auth) {
|
|
31
|
+
return collection;
|
|
32
|
+
}
|
|
33
|
+
// Clone the collection to avoid mutation
|
|
34
|
+
const updatedCollection = {
|
|
35
|
+
...collection
|
|
36
|
+
};
|
|
37
|
+
// Ensure auth is an object (it could be true or an object)
|
|
38
|
+
if (typeof updatedCollection.auth === 'boolean') {
|
|
39
|
+
updatedCollection.auth = {};
|
|
40
|
+
} else {
|
|
41
|
+
updatedCollection.auth = {
|
|
42
|
+
...updatedCollection.auth
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Inject forgotPassword email template
|
|
46
|
+
const currentForgotPassword = updatedCollection.auth.forgotPassword;
|
|
47
|
+
updatedCollection.auth.forgotPassword = {
|
|
48
|
+
...typeof currentForgotPassword === 'object' ? currentForgotPassword : {},
|
|
49
|
+
generateEmailHTML: async (args)=>{
|
|
50
|
+
const token = args?.token || '';
|
|
51
|
+
const user = args?.user || {};
|
|
52
|
+
const resetUrl = `${config.serverURL}/admin/reset/${token}`;
|
|
53
|
+
return renderEmail({
|
|
54
|
+
component: ForgotPasswordEmail,
|
|
55
|
+
props: {
|
|
56
|
+
user: {
|
|
57
|
+
firstName: user?.firstName,
|
|
58
|
+
email: user?.email
|
|
59
|
+
},
|
|
60
|
+
resetUrl,
|
|
61
|
+
content: emailConfig.forgotPassword
|
|
62
|
+
},
|
|
63
|
+
theme: themeOverride
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
// Inject verify email template
|
|
68
|
+
const currentVerify = updatedCollection.auth.verify;
|
|
69
|
+
updatedCollection.auth.verify = {
|
|
70
|
+
...typeof currentVerify === 'object' ? currentVerify : {},
|
|
71
|
+
generateEmailHTML: async (args)=>{
|
|
72
|
+
const token = args?.token || '';
|
|
73
|
+
const user = args?.user || {};
|
|
74
|
+
// For verify emails, the token is used in the verification URL
|
|
75
|
+
const verifyUrl = `${config.serverURL}/admin/${collection.slug}/verify/${token}`;
|
|
76
|
+
return renderEmail({
|
|
77
|
+
component: VerifyAccountEmail,
|
|
78
|
+
props: {
|
|
79
|
+
user: {
|
|
80
|
+
firstName: user?.firstName,
|
|
81
|
+
email: user?.email
|
|
82
|
+
},
|
|
83
|
+
verifyUrl,
|
|
84
|
+
content: emailConfig.verifyAccount
|
|
85
|
+
},
|
|
86
|
+
theme: themeOverride
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
return updatedCollection;
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
...config,
|
|
94
|
+
collections: updatedCollections
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
//# sourceMappingURL=email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugin/email.ts"],"sourcesContent":["import { renderEmail } from '@ainsleydev/email-templates';\nimport type { Config } from 'payload';\n\nimport { ForgotPasswordEmail } from '../email/ForgotPasswordEmail.js';\nimport { VerifyAccountEmail } from '../email/VerifyAccountEmail.js';\nimport type { EmailConfig } from '../types.js';\n\n/**\n * Injects email templates into all auth-enabled collections in the Payload config.\n *\n * @param config - The Payload configuration object\n * @param emailConfig - The email configuration from plugin options\n * @returns The modified Payload configuration with email templates injected\n */\nexport const injectEmailTemplates = (config: Config, emailConfig: EmailConfig): Config => {\n\t// Get the website URL for branding, defaulting to Payload's serverUrl\n\tconst websiteUrl = emailConfig.frontEndUrl || config.serverURL || '';\n\n\t// Merge user theme with websiteUrl for branding\n\tconst themeOverride = {\n\t\t...emailConfig.theme,\n\t\tbranding: {\n\t\t\t...emailConfig.theme?.branding,\n\t\t\twebsiteUrl,\n\t\t},\n\t};\n\n\t// Find all collections with auth enabled\n\tconst collectionsWithAuth = config.collections?.filter((collection) => collection.auth) || [];\n\n\t// If no collections with auth, return config unchanged\n\tif (collectionsWithAuth.length === 0) {\n\t\treturn config;\n\t}\n\n\t// Inject email templates into each auth-enabled collection\n\tconst updatedCollections = config.collections?.map((collection) => {\n\t\t// Skip collections without auth\n\t\tif (!collection.auth) {\n\t\t\treturn collection;\n\t\t}\n\n\t\t// Clone the collection to avoid mutation\n\t\tconst updatedCollection = { ...collection };\n\n\t\t// Ensure auth is an object (it could be true or an object)\n\t\tif (typeof updatedCollection.auth === 'boolean') {\n\t\t\tupdatedCollection.auth = {};\n\t\t} else {\n\t\t\tupdatedCollection.auth = { ...updatedCollection.auth };\n\t\t}\n\n\t\t// Inject forgotPassword email template\n\t\tconst currentForgotPassword = updatedCollection.auth.forgotPassword;\n\t\tupdatedCollection.auth.forgotPassword = {\n\t\t\t...(typeof currentForgotPassword === 'object' ? currentForgotPassword : {}),\n\t\t\tgenerateEmailHTML: async (args) => {\n\t\t\t\tconst token = args?.token || '';\n\t\t\t\tconst user = args?.user || {};\n\t\t\t\tconst resetUrl = `${config.serverURL}/admin/reset/${token}`;\n\n\t\t\t\treturn renderEmail({\n\t\t\t\t\tcomponent: ForgotPasswordEmail,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tfirstName: user?.firstName,\n\t\t\t\t\t\t\temail: user?.email,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tresetUrl,\n\t\t\t\t\t\tcontent: emailConfig.forgotPassword,\n\t\t\t\t\t},\n\t\t\t\t\ttheme: themeOverride,\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\n\t\t// Inject verify email template\n\t\tconst currentVerify = updatedCollection.auth.verify;\n\t\tupdatedCollection.auth.verify = {\n\t\t\t...(typeof currentVerify === 'object' ? currentVerify : {}),\n\t\t\tgenerateEmailHTML: async (args) => {\n\t\t\t\tconst token = args?.token || '';\n\t\t\t\tconst user = args?.user || {};\n\t\t\t\t// For verify emails, the token is used in the verification URL\n\t\t\t\tconst verifyUrl = `${config.serverURL}/admin/${collection.slug}/verify/${token}`;\n\n\t\t\t\treturn renderEmail({\n\t\t\t\t\tcomponent: VerifyAccountEmail,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tfirstName: user?.firstName,\n\t\t\t\t\t\t\temail: user?.email,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tverifyUrl,\n\t\t\t\t\t\tcontent: emailConfig.verifyAccount,\n\t\t\t\t\t},\n\t\t\t\t\ttheme: themeOverride,\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\n\t\treturn updatedCollection;\n\t});\n\n\treturn {\n\t\t...config,\n\t\tcollections: updatedCollections,\n\t};\n};\n"],"names":["renderEmail","ForgotPasswordEmail","VerifyAccountEmail","injectEmailTemplates","config","emailConfig","websiteUrl","frontEndUrl","serverURL","themeOverride","theme","branding","collectionsWithAuth","collections","filter","collection","auth","length","updatedCollections","map","updatedCollection","currentForgotPassword","forgotPassword","generateEmailHTML","args","token","user","resetUrl","component","props","firstName","email","content","currentVerify","verify","verifyUrl","slug","verifyAccount"],"mappings":"AAAA,SAASA,WAAW,QAAQ,8BAA8B;AAG1D,SAASC,mBAAmB,QAAQ,kCAAkC;AACtE,SAASC,kBAAkB,QAAQ,iCAAiC;AAGpE;;;;;;CAMC,GACD,OAAO,MAAMC,uBAAuB,CAACC,QAAgBC;IACpD,sEAAsE;IACtE,MAAMC,aAAaD,YAAYE,WAAW,IAAIH,OAAOI,SAAS,IAAI;IAElE,gDAAgD;IAChD,MAAMC,gBAAgB;QACrB,GAAGJ,YAAYK,KAAK;QACpBC,UAAU;YACT,GAAGN,YAAYK,KAAK,EAAEC,QAAQ;YAC9BL;QACD;IACD;IAEA,yCAAyC;IACzC,MAAMM,sBAAsBR,OAAOS,WAAW,EAAEC,OAAO,CAACC,aAAeA,WAAWC,IAAI,KAAK,EAAE;IAE7F,uDAAuD;IACvD,IAAIJ,oBAAoBK,MAAM,KAAK,GAAG;QACrC,OAAOb;IACR;IAEA,2DAA2D;IAC3D,MAAMc,qBAAqBd,OAAOS,WAAW,EAAEM,IAAI,CAACJ;QACnD,gCAAgC;QAChC,IAAI,CAACA,WAAWC,IAAI,EAAE;YACrB,OAAOD;QACR;QAEA,yCAAyC;QACzC,MAAMK,oBAAoB;YAAE,GAAGL,UAAU;QAAC;QAE1C,2DAA2D;QAC3D,IAAI,OAAOK,kBAAkBJ,IAAI,KAAK,WAAW;YAChDI,kBAAkBJ,IAAI,GAAG,CAAC;QAC3B,OAAO;YACNI,kBAAkBJ,IAAI,GAAG;gBAAE,GAAGI,kBAAkBJ,IAAI;YAAC;QACtD;QAEA,uCAAuC;QACvC,MAAMK,wBAAwBD,kBAAkBJ,IAAI,CAACM,cAAc;QACnEF,kBAAkBJ,IAAI,CAACM,cAAc,GAAG;YACvC,GAAI,OAAOD,0BAA0B,WAAWA,wBAAwB,CAAC,CAAC;YAC1EE,mBAAmB,OAAOC;gBACzB,MAAMC,QAAQD,MAAMC,SAAS;gBAC7B,MAAMC,OAAOF,MAAME,QAAQ,CAAC;gBAC5B,MAAMC,WAAW,GAAGvB,OAAOI,SAAS,CAAC,aAAa,EAAEiB,OAAO;gBAE3D,OAAOzB,YAAY;oBAClB4B,WAAW3B;oBACX4B,OAAO;wBACNH,MAAM;4BACLI,WAAWJ,MAAMI;4BACjBC,OAAOL,MAAMK;wBACd;wBACAJ;wBACAK,SAAS3B,YAAYiB,cAAc;oBACpC;oBACAZ,OAAOD;gBACR;YACD;QACD;QAEA,+BAA+B;QAC/B,MAAMwB,gBAAgBb,kBAAkBJ,IAAI,CAACkB,MAAM;QACnDd,kBAAkBJ,IAAI,CAACkB,MAAM,GAAG;YAC/B,GAAI,OAAOD,kBAAkB,WAAWA,gBAAgB,CAAC,CAAC;YAC1DV,mBAAmB,OAAOC;gBACzB,MAAMC,QAAQD,MAAMC,SAAS;gBAC7B,MAAMC,OAAOF,MAAME,QAAQ,CAAC;gBAC5B,+DAA+D;gBAC/D,MAAMS,YAAY,GAAG/B,OAAOI,SAAS,CAAC,OAAO,EAAEO,WAAWqB,IAAI,CAAC,QAAQ,EAAEX,OAAO;gBAEhF,OAAOzB,YAAY;oBAClB4B,WAAW1B;oBACX2B,OAAO;wBACNH,MAAM;4BACLI,WAAWJ,MAAMI;4BACjBC,OAAOL,MAAMK;wBACd;wBACAI;wBACAH,SAAS3B,YAAYgC,aAAa;oBACnC;oBACA3B,OAAOD;gBACR;YACD;QACD;QAEA,OAAOW;IACR;IAEA,OAAO;QACN,GAAGhB,MAAM;QACTS,aAAaK;IACd;AACD,EAAE"}
|