@vrplatform/email 1.0.2-stage.37478928158 → 1.0.2-stage.37579320177

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.
@@ -1,9 +1,14 @@
1
- import { type ActionEmailData, type ActionEmailTemplateProps } from '../components/ActionEmailTemplate';
1
+ import type { ActionEmailData, ActionEmailTemplateProps } from '../components/ActionEmailTemplate';
2
2
  export declare const getDefaultOwnerStatementEmailData: (mode: "tag" | "text", args: {
3
3
  appName: string;
4
4
  ownerStatementHref: string;
5
5
  listingName: string;
6
6
  userName: string;
7
7
  month: string;
8
+ /** The owner opens the statement through an emailed link, without a login. */
9
+ noLogin?: boolean;
8
10
  }) => ActionEmailData;
9
- export declare const OwnerStatementEmailTemplate: (props: ActionEmailTemplateProps) => import("react").JSX.Element;
11
+ export declare const OwnerStatementEmailTemplate: ({ data, tenant, themeColors, mode, user, listing, month, unsubscribeHref, renewHref, }: ActionEmailTemplateProps & {
12
+ /** Requests a new no-login link once the emailed one has expired. */
13
+ renewHref?: string;
14
+ }) => import("react").JSX.Element;
@@ -2,13 +2,28 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OwnerStatementEmailTemplate = exports.getDefaultOwnerStatementEmailData = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const heading_1 = require("@react-email/heading");
6
+ const text_1 = require("@react-email/text");
5
7
  const extensions_1 = require("../extensions");
6
- const ActionEmailTemplate_1 = require("../components/ActionEmailTemplate");
8
+ const Button_1 = require("../components/Button");
9
+ const EmailContainer_1 = require("../components/EmailContainer");
10
+ const utils_1 = require("../components/utils");
7
11
  const getDefaultOwnerStatementEmailData = (mode, args) => {
8
12
  const ownerStatementHref = mode === 'tag' ? extensions_1.EMAIL_ACTION_LINK_COMPONENT : args.ownerStatementHref;
9
13
  const listingName = mode === 'tag' ? extensions_1.EMAIL_LISTING_COMPONENT : args.listingName;
10
14
  const month = mode === 'tag' ? extensions_1.EMAIL_DATE_COMPONENT : args.month;
11
15
  const userName = mode === 'tag' ? extensions_1.EMAIL_USER_NAME_COMPONENT : args.userName;
16
+ if (args.noLogin) {
17
+ return {
18
+ subject: `Your ${args.month} owner statement for ${args.listingName}`,
19
+ shortDescription: `Your ${args.month} statement for ${args.listingName} is ready. Open it with one click, no login needed.`,
20
+ header: 'Your owner statement is ready',
21
+ bodyOne: `<p>Hi ${userName},</p><p>${args.appName} published your ${month} owner statement for ${listingName}. Open it with the button below. You don't need a login.</p>`,
22
+ buttonText: 'View statement',
23
+ bodyTwo: `<p style="color:#737373;font-size:13px">If the button doesn't work, copy this link into your browser: ${ownerStatementHref}</p>`,
24
+ href: args.ownerStatementHref,
25
+ };
26
+ }
12
27
  return {
13
28
  subject: 'Owner statement was published',
14
29
  shortDescription: `An owner statement is ready for you. Log in to ${args.appName} now to view it.`,
@@ -20,8 +35,69 @@ const getDefaultOwnerStatementEmailData = (mode, args) => {
20
35
  };
21
36
  };
22
37
  exports.getDefaultOwnerStatementEmailData = getDefaultOwnerStatementEmailData;
23
- const OwnerStatementEmailTemplate = (props) => {
24
- return (0, jsx_runtime_1.jsx)(ActionEmailTemplate_1.ActionEmailTemplate, { ...props });
38
+ const mutedColor = '#737373';
39
+ const borderColor = '#e5e7eb';
40
+ const OwnerStatementEmailTemplate = ({ data, tenant, themeColors, mode, user, listing, month, unsubscribeHref, renewHref, }) => {
41
+ const parse = (html) => (0, utils_1.parseEmailHtml)(html, {
42
+ href: data.href,
43
+ userName: user.firstName || '',
44
+ date: month || '',
45
+ listingName: listing || '',
46
+ });
47
+ return ((0, jsx_runtime_1.jsxs)(EmailContainer_1.EmailContainer, { title: data.subject, shortDescription: data.shortDescription, tenant: tenant, mode: mode, unsubscribeHref: unsubscribeHref, children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: {
48
+ color: themeColors[8],
49
+ fontSize: 12,
50
+ fontWeight: 600,
51
+ letterSpacing: '0.08em',
52
+ textTransform: 'uppercase',
53
+ margin: '0 0 8px',
54
+ }, children: "Owner statement" }), (0, jsx_runtime_1.jsx)(heading_1.Heading, { style: {
55
+ fontSize: 26,
56
+ fontWeight: 600,
57
+ lineHeight: '34px',
58
+ margin: '0 0 32px',
59
+ }, children: data.header?.trim() || 'Your owner statement is ready' }), data.banner?.trim() && ((0, jsx_runtime_1.jsx)(text_1.Text, { style: {
60
+ padding: '16px 20px',
61
+ backgroundColor: '#f8f9fa',
62
+ borderLeft: `3px solid ${themeColors[8]}`,
63
+ borderRadius: '4px',
64
+ margin: '0 0 32px',
65
+ whiteSpace: 'pre-line',
66
+ }, children: data.banner.trim() })), (0, jsx_runtime_1.jsx)("div", {
67
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml
68
+ dangerouslySetInnerHTML: { __html: parse(data.bodyOne) } }), (listing || month) && ((0, jsx_runtime_1.jsx)("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, width: "100%", style: {
69
+ border: `1px solid ${borderColor}`,
70
+ borderRadius: '8px',
71
+ borderCollapse: 'separate',
72
+ margin: '24px 0 0',
73
+ }, children: (0, jsx_runtime_1.jsx)("tbody", { children: [
74
+ ['Property', listing],
75
+ ['Statement', month],
76
+ ].map(([label, value], index) => value ? ((0, jsx_runtime_1.jsxs)("tr", { children: [(0, jsx_runtime_1.jsx)("td", { style: {
77
+ padding: '14px 20px',
78
+ color: mutedColor,
79
+ fontSize: 14,
80
+ borderTop: index ? `1px solid ${borderColor}` : 'none',
81
+ }, children: label }), (0, jsx_runtime_1.jsx)("td", { style: {
82
+ padding: '14px 20px',
83
+ fontSize: 14,
84
+ fontWeight: 600,
85
+ textAlign: 'right',
86
+ borderTop: index ? `1px solid ${borderColor}` : 'none',
87
+ }, children: value })] }, label)) : null) }) })), (0, jsx_runtime_1.jsx)(Button_1.Button, { href: data.href, mode: mode, "data-testid": "view-owner-statement-button", label: data.buttonText?.trim() || 'View statement', themeColors: themeColors, style: { marginTop: '24px', marginBottom: '32px' } }), renewHref && ((0, jsx_runtime_1.jsxs)("div", { style: {
88
+ padding: '20px',
89
+ backgroundColor: '#f8f9fa',
90
+ borderRadius: '8px',
91
+ marginBottom: '32px',
92
+ }, children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: { fontWeight: 600, margin: '0 0 4px' }, children: "Link expired?" }), (0, jsx_runtime_1.jsx)(text_1.Text, { style: { color: mutedColor, fontSize: 14, margin: 0 }, children: "For your security, this link opens only this statement and works for 7 days. After that, request a new one and we'll email it to this address." }), (0, jsx_runtime_1.jsx)(Button_1.Button, { href: renewHref, mode: mode, "data-testid": "renew-owner-statement-link-button", label: "Send me a new link", themeColors: themeColors, style: {
93
+ background: '#ffffff',
94
+ border: `1px solid ${themeColors[8]}`,
95
+ color: themeColors[8],
96
+ marginTop: '16px',
97
+ marginBottom: 0,
98
+ } })] })), (0, jsx_runtime_1.jsx)("div", {
99
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml
100
+ dangerouslySetInnerHTML: { __html: parse(data.bodyTwo) } })] }));
25
101
  };
26
102
  exports.OwnerStatementEmailTemplate = OwnerStatementEmailTemplate;
27
103
  //# sourceMappingURL=OwnerStatementEmailTemplate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OwnerStatementEmailTemplate.js","sourceRoot":"src/","sources":["templates/OwnerStatementEmailTemplate.tsx"],"names":[],"mappings":";;;;AAAA,8CAKuB;AACvB,2EAI2C;AAEpC,MAAM,iCAAiC,GAAG,CAC/C,IAAoB,EACpB,IAMC,EACgB,EAAE;IACnB,MAAM,kBAAkB,GACtB,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,wCAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;IAEzE,MAAM,WAAW,GACf,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,oCAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;IAC9D,MAAM,KAAK,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,iCAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;IACjE,MAAM,QAAQ,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,sCAAyB,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IAE5E,OAAO;QACL,OAAO,EAAE,+BAA+B;QACxC,gBAAgB,EAAE,kDAAkD,IAAI,CAAC,OAAO,kBAAkB;QAClG,MAAM,EAAE,+BAA+B;QACvC,OAAO,EAAE,SAAS,QAAQ,YAAY,KAAK,iCAAiC,WAAW,gCAAgC,IAAI,CAAC,OAAO,sEAAsE;QACzM,UAAU,EAAE,sBAAsB;QAClC,OAAO,EAAE,wGAAwG,kBAAkB,MAAM;QACzI,IAAI,EAAE,IAAI,CAAC,kBAAkB;KAC9B,CAAC;AACJ,CAAC,CAAC;AA3BW,QAAA,iCAAiC,qCA2B5C;AAEK,MAAM,2BAA2B,GAAG,CACzC,KAA+B,EAC/B,EAAE;IACF,OAAO,uBAAC,yCAAmB,OAAK,KAAK,GAAI,CAAC;AAC5C,CAAC,CAAC;AAJW,QAAA,2BAA2B,+BAItC","sourcesContent":["import {\n EMAIL_ACTION_LINK_COMPONENT,\n EMAIL_DATE_COMPONENT,\n EMAIL_LISTING_COMPONENT,\n EMAIL_USER_NAME_COMPONENT,\n} from '../extensions';\nimport {\n type ActionEmailData,\n ActionEmailTemplate,\n type ActionEmailTemplateProps,\n} from '../components/ActionEmailTemplate';\n\nexport const getDefaultOwnerStatementEmailData = (\n mode: 'tag' | 'text',\n args: {\n appName: string;\n ownerStatementHref: string;\n listingName: string;\n userName: string;\n month: string;\n }\n): ActionEmailData => {\n const ownerStatementHref =\n mode === 'tag' ? EMAIL_ACTION_LINK_COMPONENT : args.ownerStatementHref;\n\n const listingName =\n mode === 'tag' ? EMAIL_LISTING_COMPONENT : args.listingName;\n const month = mode === 'tag' ? EMAIL_DATE_COMPONENT : args.month;\n const userName = mode === 'tag' ? EMAIL_USER_NAME_COMPONENT : args.userName;\n\n return {\n subject: 'Owner statement was published',\n shortDescription: `An owner statement is ready for you. Log in to ${args.appName} now to view it.`,\n header: 'Owner statement was published',\n bodyOne: `<p>Hi ${userName},<p>Your ${month} owner statement for property ${listingName} is ready for your review on ${args.appName}.</p><p>To access your statement, please click the button below:</p>`,\n buttonText: 'View Owner statement',\n bodyTwo: `<p>If you have any trouble with the button, you can copy and paste the link below into your browser: ${ownerStatementHref}</p>`,\n href: args.ownerStatementHref,\n };\n};\n\nexport const OwnerStatementEmailTemplate = (\n props: ActionEmailTemplateProps\n) => {\n return <ActionEmailTemplate {...props} />;\n};\n"]}
1
+ {"version":3,"file":"OwnerStatementEmailTemplate.js","sourceRoot":"src/","sources":["templates/OwnerStatementEmailTemplate.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Heading } from '@react-email/heading';\nimport { Text } from '@react-email/text';\nimport {\n EMAIL_ACTION_LINK_COMPONENT,\n EMAIL_DATE_COMPONENT,\n EMAIL_LISTING_COMPONENT,\n EMAIL_USER_NAME_COMPONENT,\n} from '../extensions';\nimport type {\n ActionEmailData,\n ActionEmailTemplateProps,\n} from '../components/ActionEmailTemplate';\nimport { Button } from '../components/Button';\nimport { EmailContainer } from '../components/EmailContainer';\nimport { parseEmailHtml } from '../components/utils';\n\nexport const getDefaultOwnerStatementEmailData = (\n mode: 'tag' | 'text',\n args: {\n appName: string;\n ownerStatementHref: string;\n listingName: string;\n userName: string;\n month: string;\n /** The owner opens the statement through an emailed link, without a login. */\n noLogin?: boolean;\n }\n): ActionEmailData => {\n const ownerStatementHref =\n mode === 'tag' ? EMAIL_ACTION_LINK_COMPONENT : args.ownerStatementHref;\n\n const listingName =\n mode === 'tag' ? EMAIL_LISTING_COMPONENT : args.listingName;\n const month = mode === 'tag' ? EMAIL_DATE_COMPONENT : args.month;\n const userName = mode === 'tag' ? EMAIL_USER_NAME_COMPONENT : args.userName;\n\n if (args.noLogin) {\n return {\n subject: `Your ${args.month} owner statement for ${args.listingName}`,\n shortDescription: `Your ${args.month} statement for ${args.listingName} is ready. Open it with one click, no login needed.`,\n header: 'Your owner statement is ready',\n bodyOne: `<p>Hi ${userName},</p><p>${args.appName} published your ${month} owner statement for ${listingName}. Open it with the button below. You don't need a login.</p>`,\n buttonText: 'View statement',\n bodyTwo: `<p style=\"color:#737373;font-size:13px\">If the button doesn't work, copy this link into your browser: ${ownerStatementHref}</p>`,\n href: args.ownerStatementHref,\n };\n }\n\n return {\n subject: 'Owner statement was published',\n shortDescription: `An owner statement is ready for you. Log in to ${args.appName} now to view it.`,\n header: 'Owner statement was published',\n bodyOne: `<p>Hi ${userName},<p>Your ${month} owner statement for property ${listingName} is ready for your review on ${args.appName}.</p><p>To access your statement, please click the button below:</p>`,\n buttonText: 'View Owner statement',\n bodyTwo: `<p>If you have any trouble with the button, you can copy and paste the link below into your browser: ${ownerStatementHref}</p>`,\n href: args.ownerStatementHref,\n };\n};\n\nconst mutedColor = '#737373';\nconst borderColor = '#e5e7eb';\n\nexport const OwnerStatementEmailTemplate = ({\n data,\n tenant,\n themeColors,\n mode,\n user,\n listing,\n month,\n unsubscribeHref,\n renewHref,\n}: ActionEmailTemplateProps & {\n /** Requests a new no-login link once the emailed one has expired. */\n renewHref?: string;\n}) => {\n const parse = (html: string) =>\n parseEmailHtml(html, {\n href: data.href,\n userName: user.firstName || '',\n date: month || '',\n listingName: listing || '',\n });\n\n return (\n <EmailContainer\n title={data.subject}\n shortDescription={data.shortDescription}\n tenant={tenant}\n mode={mode}\n unsubscribeHref={unsubscribeHref}\n >\n <Text\n style={{\n color: themeColors[8],\n fontSize: 12,\n fontWeight: 600,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n margin: '0 0 8px',\n }}\n >\n Owner statement\n </Text>\n <Heading\n style={{\n fontSize: 26,\n fontWeight: 600,\n lineHeight: '34px',\n margin: '0 0 32px',\n }}\n >\n {data.header?.trim() || 'Your owner statement is ready'}\n </Heading>\n\n {data.banner?.trim() && (\n <Text\n style={{\n padding: '16px 20px',\n backgroundColor: '#f8f9fa',\n borderLeft: `3px solid ${themeColors[8]}`,\n borderRadius: '4px',\n margin: '0 0 32px',\n whiteSpace: 'pre-line',\n }}\n >\n {data.banner.trim()}\n </Text>\n )}\n\n <div\n // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml\n dangerouslySetInnerHTML={{ __html: parse(data.bodyOne) }}\n />\n\n {(listing || month) && (\n <table\n role=\"presentation\"\n cellPadding={0}\n cellSpacing={0}\n width=\"100%\"\n style={{\n border: `1px solid ${borderColor}`,\n borderRadius: '8px',\n borderCollapse: 'separate',\n margin: '24px 0 0',\n }}\n >\n <tbody>\n {[\n ['Property', listing],\n ['Statement', month],\n ].map(([label, value], index) =>\n value ? (\n <tr key={label}>\n <td\n style={{\n padding: '14px 20px',\n color: mutedColor,\n fontSize: 14,\n borderTop: index ? `1px solid ${borderColor}` : 'none',\n }}\n >\n {label}\n </td>\n <td\n style={{\n padding: '14px 20px',\n fontSize: 14,\n fontWeight: 600,\n textAlign: 'right',\n borderTop: index ? `1px solid ${borderColor}` : 'none',\n }}\n >\n {value}\n </td>\n </tr>\n ) : null\n )}\n </tbody>\n </table>\n )}\n\n <Button\n href={data.href}\n mode={mode}\n data-testid=\"view-owner-statement-button\"\n label={data.buttonText?.trim() || 'View statement'}\n themeColors={themeColors}\n style={{ marginTop: '24px', marginBottom: '32px' }}\n />\n\n {renewHref && (\n <div\n style={{\n padding: '20px',\n backgroundColor: '#f8f9fa',\n borderRadius: '8px',\n marginBottom: '32px',\n }}\n >\n <Text style={{ fontWeight: 600, margin: '0 0 4px' }}>\n Link expired?\n </Text>\n <Text style={{ color: mutedColor, fontSize: 14, margin: 0 }}>\n For your security, this link opens only this statement and works for\n 7 days. After that, request a new one and we'll email it to this\n address.\n </Text>\n <Button\n href={renewHref}\n mode={mode}\n data-testid=\"renew-owner-statement-link-button\"\n label=\"Send me a new link\"\n themeColors={themeColors}\n style={{\n background: '#ffffff',\n border: `1px solid ${themeColors[8]}`,\n color: themeColors[8],\n marginTop: '16px',\n marginBottom: 0,\n }}\n />\n </div>\n )}\n\n <div\n // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml\n dangerouslySetInnerHTML={{ __html: parse(data.bodyTwo) }}\n />\n </EmailContainer>\n );\n};\n"]}
@@ -1,9 +1,14 @@
1
- import { type ActionEmailData, type ActionEmailTemplateProps } from '../components/ActionEmailTemplate';
1
+ import type { ActionEmailData, ActionEmailTemplateProps } from '../components/ActionEmailTemplate';
2
2
  export declare const getDefaultOwnerStatementEmailData: (mode: "tag" | "text", args: {
3
3
  appName: string;
4
4
  ownerStatementHref: string;
5
5
  listingName: string;
6
6
  userName: string;
7
7
  month: string;
8
+ /** The owner opens the statement through an emailed link, without a login. */
9
+ noLogin?: boolean;
8
10
  }) => ActionEmailData;
9
- export declare const OwnerStatementEmailTemplate: (props: ActionEmailTemplateProps) => import("react").JSX.Element;
11
+ export declare const OwnerStatementEmailTemplate: ({ data, tenant, themeColors, mode, user, listing, month, unsubscribeHref, renewHref, }: ActionEmailTemplateProps & {
12
+ /** Requests a new no-login link once the emailed one has expired. */
13
+ renewHref?: string;
14
+ }) => import("react").JSX.Element;
@@ -1,11 +1,26 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Heading } from '@react-email/heading';
3
+ import { Text } from '@react-email/text';
2
4
  import { EMAIL_ACTION_LINK_COMPONENT, EMAIL_DATE_COMPONENT, EMAIL_LISTING_COMPONENT, EMAIL_USER_NAME_COMPONENT, } from '../extensions';
3
- import { ActionEmailTemplate, } from '../components/ActionEmailTemplate';
5
+ import { Button } from '../components/Button';
6
+ import { EmailContainer } from '../components/EmailContainer';
7
+ import { parseEmailHtml } from '../components/utils';
4
8
  export const getDefaultOwnerStatementEmailData = (mode, args) => {
5
9
  const ownerStatementHref = mode === 'tag' ? EMAIL_ACTION_LINK_COMPONENT : args.ownerStatementHref;
6
10
  const listingName = mode === 'tag' ? EMAIL_LISTING_COMPONENT : args.listingName;
7
11
  const month = mode === 'tag' ? EMAIL_DATE_COMPONENT : args.month;
8
12
  const userName = mode === 'tag' ? EMAIL_USER_NAME_COMPONENT : args.userName;
13
+ if (args.noLogin) {
14
+ return {
15
+ subject: `Your ${args.month} owner statement for ${args.listingName}`,
16
+ shortDescription: `Your ${args.month} statement for ${args.listingName} is ready. Open it with one click, no login needed.`,
17
+ header: 'Your owner statement is ready',
18
+ bodyOne: `<p>Hi ${userName},</p><p>${args.appName} published your ${month} owner statement for ${listingName}. Open it with the button below. You don't need a login.</p>`,
19
+ buttonText: 'View statement',
20
+ bodyTwo: `<p style="color:#737373;font-size:13px">If the button doesn't work, copy this link into your browser: ${ownerStatementHref}</p>`,
21
+ href: args.ownerStatementHref,
22
+ };
23
+ }
9
24
  return {
10
25
  subject: 'Owner statement was published',
11
26
  shortDescription: `An owner statement is ready for you. Log in to ${args.appName} now to view it.`,
@@ -16,7 +31,68 @@ export const getDefaultOwnerStatementEmailData = (mode, args) => {
16
31
  href: args.ownerStatementHref,
17
32
  };
18
33
  };
19
- export const OwnerStatementEmailTemplate = (props) => {
20
- return _jsx(ActionEmailTemplate, { ...props });
34
+ const mutedColor = '#737373';
35
+ const borderColor = '#e5e7eb';
36
+ export const OwnerStatementEmailTemplate = ({ data, tenant, themeColors, mode, user, listing, month, unsubscribeHref, renewHref, }) => {
37
+ const parse = (html) => parseEmailHtml(html, {
38
+ href: data.href,
39
+ userName: user.firstName || '',
40
+ date: month || '',
41
+ listingName: listing || '',
42
+ });
43
+ return (_jsxs(EmailContainer, { title: data.subject, shortDescription: data.shortDescription, tenant: tenant, mode: mode, unsubscribeHref: unsubscribeHref, children: [_jsx(Text, { style: {
44
+ color: themeColors[8],
45
+ fontSize: 12,
46
+ fontWeight: 600,
47
+ letterSpacing: '0.08em',
48
+ textTransform: 'uppercase',
49
+ margin: '0 0 8px',
50
+ }, children: "Owner statement" }), _jsx(Heading, { style: {
51
+ fontSize: 26,
52
+ fontWeight: 600,
53
+ lineHeight: '34px',
54
+ margin: '0 0 32px',
55
+ }, children: data.header?.trim() || 'Your owner statement is ready' }), data.banner?.trim() && (_jsx(Text, { style: {
56
+ padding: '16px 20px',
57
+ backgroundColor: '#f8f9fa',
58
+ borderLeft: `3px solid ${themeColors[8]}`,
59
+ borderRadius: '4px',
60
+ margin: '0 0 32px',
61
+ whiteSpace: 'pre-line',
62
+ }, children: data.banner.trim() })), _jsx("div", {
63
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml
64
+ dangerouslySetInnerHTML: { __html: parse(data.bodyOne) } }), (listing || month) && (_jsx("table", { role: "presentation", cellPadding: 0, cellSpacing: 0, width: "100%", style: {
65
+ border: `1px solid ${borderColor}`,
66
+ borderRadius: '8px',
67
+ borderCollapse: 'separate',
68
+ margin: '24px 0 0',
69
+ }, children: _jsx("tbody", { children: [
70
+ ['Property', listing],
71
+ ['Statement', month],
72
+ ].map(([label, value], index) => value ? (_jsxs("tr", { children: [_jsx("td", { style: {
73
+ padding: '14px 20px',
74
+ color: mutedColor,
75
+ fontSize: 14,
76
+ borderTop: index ? `1px solid ${borderColor}` : 'none',
77
+ }, children: label }), _jsx("td", { style: {
78
+ padding: '14px 20px',
79
+ fontSize: 14,
80
+ fontWeight: 600,
81
+ textAlign: 'right',
82
+ borderTop: index ? `1px solid ${borderColor}` : 'none',
83
+ }, children: value })] }, label)) : null) }) })), _jsx(Button, { href: data.href, mode: mode, "data-testid": "view-owner-statement-button", label: data.buttonText?.trim() || 'View statement', themeColors: themeColors, style: { marginTop: '24px', marginBottom: '32px' } }), renewHref && (_jsxs("div", { style: {
84
+ padding: '20px',
85
+ backgroundColor: '#f8f9fa',
86
+ borderRadius: '8px',
87
+ marginBottom: '32px',
88
+ }, children: [_jsx(Text, { style: { fontWeight: 600, margin: '0 0 4px' }, children: "Link expired?" }), _jsx(Text, { style: { color: mutedColor, fontSize: 14, margin: 0 }, children: "For your security, this link opens only this statement and works for 7 days. After that, request a new one and we'll email it to this address." }), _jsx(Button, { href: renewHref, mode: mode, "data-testid": "renew-owner-statement-link-button", label: "Send me a new link", themeColors: themeColors, style: {
89
+ background: '#ffffff',
90
+ border: `1px solid ${themeColors[8]}`,
91
+ color: themeColors[8],
92
+ marginTop: '16px',
93
+ marginBottom: 0,
94
+ } })] })), _jsx("div", {
95
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml
96
+ dangerouslySetInnerHTML: { __html: parse(data.bodyTwo) } })] }));
21
97
  };
22
98
  //# sourceMappingURL=OwnerStatementEmailTemplate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OwnerStatementEmailTemplate.js","sourceRoot":"src/","sources":["templates/OwnerStatementEmailTemplate.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,mBAAmB,GAEpB,MAAM,mCAAmC,CAAC;AAE3C,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAC/C,IAAoB,EACpB,IAMC,EACgB,EAAE;IACnB,MAAM,kBAAkB,GACtB,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;IAEzE,MAAM,WAAW,GACf,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;IAC9D,MAAM,KAAK,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;IACjE,MAAM,QAAQ,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IAE5E,OAAO;QACL,OAAO,EAAE,+BAA+B;QACxC,gBAAgB,EAAE,kDAAkD,IAAI,CAAC,OAAO,kBAAkB;QAClG,MAAM,EAAE,+BAA+B;QACvC,OAAO,EAAE,SAAS,QAAQ,YAAY,KAAK,iCAAiC,WAAW,gCAAgC,IAAI,CAAC,OAAO,sEAAsE;QACzM,UAAU,EAAE,sBAAsB;QAClC,OAAO,EAAE,wGAAwG,kBAAkB,MAAM;QACzI,IAAI,EAAE,IAAI,CAAC,kBAAkB;KAC9B,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG,CACzC,KAA+B,EAC/B,EAAE;IACF,OAAO,KAAC,mBAAmB,OAAK,KAAK,GAAI,CAAC;AAC5C,CAAC,CAAC","sourcesContent":["import {\n EMAIL_ACTION_LINK_COMPONENT,\n EMAIL_DATE_COMPONENT,\n EMAIL_LISTING_COMPONENT,\n EMAIL_USER_NAME_COMPONENT,\n} from '../extensions';\nimport {\n type ActionEmailData,\n ActionEmailTemplate,\n type ActionEmailTemplateProps,\n} from '../components/ActionEmailTemplate';\n\nexport const getDefaultOwnerStatementEmailData = (\n mode: 'tag' | 'text',\n args: {\n appName: string;\n ownerStatementHref: string;\n listingName: string;\n userName: string;\n month: string;\n }\n): ActionEmailData => {\n const ownerStatementHref =\n mode === 'tag' ? EMAIL_ACTION_LINK_COMPONENT : args.ownerStatementHref;\n\n const listingName =\n mode === 'tag' ? EMAIL_LISTING_COMPONENT : args.listingName;\n const month = mode === 'tag' ? EMAIL_DATE_COMPONENT : args.month;\n const userName = mode === 'tag' ? EMAIL_USER_NAME_COMPONENT : args.userName;\n\n return {\n subject: 'Owner statement was published',\n shortDescription: `An owner statement is ready for you. Log in to ${args.appName} now to view it.`,\n header: 'Owner statement was published',\n bodyOne: `<p>Hi ${userName},<p>Your ${month} owner statement for property ${listingName} is ready for your review on ${args.appName}.</p><p>To access your statement, please click the button below:</p>`,\n buttonText: 'View Owner statement',\n bodyTwo: `<p>If you have any trouble with the button, you can copy and paste the link below into your browser: ${ownerStatementHref}</p>`,\n href: args.ownerStatementHref,\n };\n};\n\nexport const OwnerStatementEmailTemplate = (\n props: ActionEmailTemplateProps\n) => {\n return <ActionEmailTemplate {...props} />;\n};\n"]}
1
+ {"version":3,"file":"OwnerStatementEmailTemplate.js","sourceRoot":"src/","sources":["templates/OwnerStatementEmailTemplate.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Heading } from '@react-email/heading';\nimport { Text } from '@react-email/text';\nimport {\n EMAIL_ACTION_LINK_COMPONENT,\n EMAIL_DATE_COMPONENT,\n EMAIL_LISTING_COMPONENT,\n EMAIL_USER_NAME_COMPONENT,\n} from '../extensions';\nimport type {\n ActionEmailData,\n ActionEmailTemplateProps,\n} from '../components/ActionEmailTemplate';\nimport { Button } from '../components/Button';\nimport { EmailContainer } from '../components/EmailContainer';\nimport { parseEmailHtml } from '../components/utils';\n\nexport const getDefaultOwnerStatementEmailData = (\n mode: 'tag' | 'text',\n args: {\n appName: string;\n ownerStatementHref: string;\n listingName: string;\n userName: string;\n month: string;\n /** The owner opens the statement through an emailed link, without a login. */\n noLogin?: boolean;\n }\n): ActionEmailData => {\n const ownerStatementHref =\n mode === 'tag' ? EMAIL_ACTION_LINK_COMPONENT : args.ownerStatementHref;\n\n const listingName =\n mode === 'tag' ? EMAIL_LISTING_COMPONENT : args.listingName;\n const month = mode === 'tag' ? EMAIL_DATE_COMPONENT : args.month;\n const userName = mode === 'tag' ? EMAIL_USER_NAME_COMPONENT : args.userName;\n\n if (args.noLogin) {\n return {\n subject: `Your ${args.month} owner statement for ${args.listingName}`,\n shortDescription: `Your ${args.month} statement for ${args.listingName} is ready. Open it with one click, no login needed.`,\n header: 'Your owner statement is ready',\n bodyOne: `<p>Hi ${userName},</p><p>${args.appName} published your ${month} owner statement for ${listingName}. Open it with the button below. You don't need a login.</p>`,\n buttonText: 'View statement',\n bodyTwo: `<p style=\"color:#737373;font-size:13px\">If the button doesn't work, copy this link into your browser: ${ownerStatementHref}</p>`,\n href: args.ownerStatementHref,\n };\n }\n\n return {\n subject: 'Owner statement was published',\n shortDescription: `An owner statement is ready for you. Log in to ${args.appName} now to view it.`,\n header: 'Owner statement was published',\n bodyOne: `<p>Hi ${userName},<p>Your ${month} owner statement for property ${listingName} is ready for your review on ${args.appName}.</p><p>To access your statement, please click the button below:</p>`,\n buttonText: 'View Owner statement',\n bodyTwo: `<p>If you have any trouble with the button, you can copy and paste the link below into your browser: ${ownerStatementHref}</p>`,\n href: args.ownerStatementHref,\n };\n};\n\nconst mutedColor = '#737373';\nconst borderColor = '#e5e7eb';\n\nexport const OwnerStatementEmailTemplate = ({\n data,\n tenant,\n themeColors,\n mode,\n user,\n listing,\n month,\n unsubscribeHref,\n renewHref,\n}: ActionEmailTemplateProps & {\n /** Requests a new no-login link once the emailed one has expired. */\n renewHref?: string;\n}) => {\n const parse = (html: string) =>\n parseEmailHtml(html, {\n href: data.href,\n userName: user.firstName || '',\n date: month || '',\n listingName: listing || '',\n });\n\n return (\n <EmailContainer\n title={data.subject}\n shortDescription={data.shortDescription}\n tenant={tenant}\n mode={mode}\n unsubscribeHref={unsubscribeHref}\n >\n <Text\n style={{\n color: themeColors[8],\n fontSize: 12,\n fontWeight: 600,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n margin: '0 0 8px',\n }}\n >\n Owner statement\n </Text>\n <Heading\n style={{\n fontSize: 26,\n fontWeight: 600,\n lineHeight: '34px',\n margin: '0 0 32px',\n }}\n >\n {data.header?.trim() || 'Your owner statement is ready'}\n </Heading>\n\n {data.banner?.trim() && (\n <Text\n style={{\n padding: '16px 20px',\n backgroundColor: '#f8f9fa',\n borderLeft: `3px solid ${themeColors[8]}`,\n borderRadius: '4px',\n margin: '0 0 32px',\n whiteSpace: 'pre-line',\n }}\n >\n {data.banner.trim()}\n </Text>\n )}\n\n <div\n // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml\n dangerouslySetInnerHTML={{ __html: parse(data.bodyOne) }}\n />\n\n {(listing || month) && (\n <table\n role=\"presentation\"\n cellPadding={0}\n cellSpacing={0}\n width=\"100%\"\n style={{\n border: `1px solid ${borderColor}`,\n borderRadius: '8px',\n borderCollapse: 'separate',\n margin: '24px 0 0',\n }}\n >\n <tbody>\n {[\n ['Property', listing],\n ['Statement', month],\n ].map(([label, value], index) =>\n value ? (\n <tr key={label}>\n <td\n style={{\n padding: '14px 20px',\n color: mutedColor,\n fontSize: 14,\n borderTop: index ? `1px solid ${borderColor}` : 'none',\n }}\n >\n {label}\n </td>\n <td\n style={{\n padding: '14px 20px',\n fontSize: 14,\n fontWeight: 600,\n textAlign: 'right',\n borderTop: index ? `1px solid ${borderColor}` : 'none',\n }}\n >\n {value}\n </td>\n </tr>\n ) : null\n )}\n </tbody>\n </table>\n )}\n\n <Button\n href={data.href}\n mode={mode}\n data-testid=\"view-owner-statement-button\"\n label={data.buttonText?.trim() || 'View statement'}\n themeColors={themeColors}\n style={{ marginTop: '24px', marginBottom: '32px' }}\n />\n\n {renewHref && (\n <div\n style={{\n padding: '20px',\n backgroundColor: '#f8f9fa',\n borderRadius: '8px',\n marginBottom: '32px',\n }}\n >\n <Text style={{ fontWeight: 600, margin: '0 0 4px' }}>\n Link expired?\n </Text>\n <Text style={{ color: mutedColor, fontSize: 14, margin: 0 }}>\n For your security, this link opens only this statement and works for\n 7 days. After that, request a new one and we'll email it to this\n address.\n </Text>\n <Button\n href={renewHref}\n mode={mode}\n data-testid=\"renew-owner-statement-link-button\"\n label=\"Send me a new link\"\n themeColors={themeColors}\n style={{\n background: '#ffffff',\n border: `1px solid ${themeColors[8]}`,\n color: themeColors[8],\n marginTop: '16px',\n marginBottom: 0,\n }}\n />\n </div>\n )}\n\n <div\n // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml\n dangerouslySetInnerHTML={{ __html: parse(data.bodyTwo) }}\n />\n </EmailContainer>\n );\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vrplatform/email",
3
- "version": "1.0.2-stage.37478928158",
3
+ "version": "1.0.2-stage.37579320177",
4
4
  "description": "VRTrust transactional email templates and Postmark transport",
5
5
  "license": "ISC",
6
6
  "main": "build/main/index.js",
@@ -1,14 +1,18 @@
1
+ import { Heading } from '@react-email/heading';
2
+ import { Text } from '@react-email/text';
1
3
  import {
2
4
  EMAIL_ACTION_LINK_COMPONENT,
3
5
  EMAIL_DATE_COMPONENT,
4
6
  EMAIL_LISTING_COMPONENT,
5
7
  EMAIL_USER_NAME_COMPONENT,
6
8
  } from '../extensions';
7
- import {
8
- type ActionEmailData,
9
- ActionEmailTemplate,
10
- type ActionEmailTemplateProps,
9
+ import type {
10
+ ActionEmailData,
11
+ ActionEmailTemplateProps,
11
12
  } from '../components/ActionEmailTemplate';
13
+ import { Button } from '../components/Button';
14
+ import { EmailContainer } from '../components/EmailContainer';
15
+ import { parseEmailHtml } from '../components/utils';
12
16
 
13
17
  export const getDefaultOwnerStatementEmailData = (
14
18
  mode: 'tag' | 'text',
@@ -18,6 +22,8 @@ export const getDefaultOwnerStatementEmailData = (
18
22
  listingName: string;
19
23
  userName: string;
20
24
  month: string;
25
+ /** The owner opens the statement through an emailed link, without a login. */
26
+ noLogin?: boolean;
21
27
  }
22
28
  ): ActionEmailData => {
23
29
  const ownerStatementHref =
@@ -28,6 +34,18 @@ export const getDefaultOwnerStatementEmailData = (
28
34
  const month = mode === 'tag' ? EMAIL_DATE_COMPONENT : args.month;
29
35
  const userName = mode === 'tag' ? EMAIL_USER_NAME_COMPONENT : args.userName;
30
36
 
37
+ if (args.noLogin) {
38
+ return {
39
+ subject: `Your ${args.month} owner statement for ${args.listingName}`,
40
+ shortDescription: `Your ${args.month} statement for ${args.listingName} is ready. Open it with one click, no login needed.`,
41
+ header: 'Your owner statement is ready',
42
+ bodyOne: `<p>Hi ${userName},</p><p>${args.appName} published your ${month} owner statement for ${listingName}. Open it with the button below. You don't need a login.</p>`,
43
+ buttonText: 'View statement',
44
+ bodyTwo: `<p style="color:#737373;font-size:13px">If the button doesn't work, copy this link into your browser: ${ownerStatementHref}</p>`,
45
+ href: args.ownerStatementHref,
46
+ };
47
+ }
48
+
31
49
  return {
32
50
  subject: 'Owner statement was published',
33
51
  shortDescription: `An owner statement is ready for you. Log in to ${args.appName} now to view it.`,
@@ -39,8 +57,177 @@ export const getDefaultOwnerStatementEmailData = (
39
57
  };
40
58
  };
41
59
 
42
- export const OwnerStatementEmailTemplate = (
43
- props: ActionEmailTemplateProps
44
- ) => {
45
- return <ActionEmailTemplate {...props} />;
60
+ const mutedColor = '#737373';
61
+ const borderColor = '#e5e7eb';
62
+
63
+ export const OwnerStatementEmailTemplate = ({
64
+ data,
65
+ tenant,
66
+ themeColors,
67
+ mode,
68
+ user,
69
+ listing,
70
+ month,
71
+ unsubscribeHref,
72
+ renewHref,
73
+ }: ActionEmailTemplateProps & {
74
+ /** Requests a new no-login link once the emailed one has expired. */
75
+ renewHref?: string;
76
+ }) => {
77
+ const parse = (html: string) =>
78
+ parseEmailHtml(html, {
79
+ href: data.href,
80
+ userName: user.firstName || '',
81
+ date: month || '',
82
+ listingName: listing || '',
83
+ });
84
+
85
+ return (
86
+ <EmailContainer
87
+ title={data.subject}
88
+ shortDescription={data.shortDescription}
89
+ tenant={tenant}
90
+ mode={mode}
91
+ unsubscribeHref={unsubscribeHref}
92
+ >
93
+ <Text
94
+ style={{
95
+ color: themeColors[8],
96
+ fontSize: 12,
97
+ fontWeight: 600,
98
+ letterSpacing: '0.08em',
99
+ textTransform: 'uppercase',
100
+ margin: '0 0 8px',
101
+ }}
102
+ >
103
+ Owner statement
104
+ </Text>
105
+ <Heading
106
+ style={{
107
+ fontSize: 26,
108
+ fontWeight: 600,
109
+ lineHeight: '34px',
110
+ margin: '0 0 32px',
111
+ }}
112
+ >
113
+ {data.header?.trim() || 'Your owner statement is ready'}
114
+ </Heading>
115
+
116
+ {data.banner?.trim() && (
117
+ <Text
118
+ style={{
119
+ padding: '16px 20px',
120
+ backgroundColor: '#f8f9fa',
121
+ borderLeft: `3px solid ${themeColors[8]}`,
122
+ borderRadius: '4px',
123
+ margin: '0 0 32px',
124
+ whiteSpace: 'pre-line',
125
+ }}
126
+ >
127
+ {data.banner.trim()}
128
+ </Text>
129
+ )}
130
+
131
+ <div
132
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml
133
+ dangerouslySetInnerHTML={{ __html: parse(data.bodyOne) }}
134
+ />
135
+
136
+ {(listing || month) && (
137
+ <table
138
+ role="presentation"
139
+ cellPadding={0}
140
+ cellSpacing={0}
141
+ width="100%"
142
+ style={{
143
+ border: `1px solid ${borderColor}`,
144
+ borderRadius: '8px',
145
+ borderCollapse: 'separate',
146
+ margin: '24px 0 0',
147
+ }}
148
+ >
149
+ <tbody>
150
+ {[
151
+ ['Property', listing],
152
+ ['Statement', month],
153
+ ].map(([label, value], index) =>
154
+ value ? (
155
+ <tr key={label}>
156
+ <td
157
+ style={{
158
+ padding: '14px 20px',
159
+ color: mutedColor,
160
+ fontSize: 14,
161
+ borderTop: index ? `1px solid ${borderColor}` : 'none',
162
+ }}
163
+ >
164
+ {label}
165
+ </td>
166
+ <td
167
+ style={{
168
+ padding: '14px 20px',
169
+ fontSize: 14,
170
+ fontWeight: 600,
171
+ textAlign: 'right',
172
+ borderTop: index ? `1px solid ${borderColor}` : 'none',
173
+ }}
174
+ >
175
+ {value}
176
+ </td>
177
+ </tr>
178
+ ) : null
179
+ )}
180
+ </tbody>
181
+ </table>
182
+ )}
183
+
184
+ <Button
185
+ href={data.href}
186
+ mode={mode}
187
+ data-testid="view-owner-statement-button"
188
+ label={data.buttonText?.trim() || 'View statement'}
189
+ themeColors={themeColors}
190
+ style={{ marginTop: '24px', marginBottom: '32px' }}
191
+ />
192
+
193
+ {renewHref && (
194
+ <div
195
+ style={{
196
+ padding: '20px',
197
+ backgroundColor: '#f8f9fa',
198
+ borderRadius: '8px',
199
+ marginBottom: '32px',
200
+ }}
201
+ >
202
+ <Text style={{ fontWeight: 600, margin: '0 0 4px' }}>
203
+ Link expired?
204
+ </Text>
205
+ <Text style={{ color: mutedColor, fontSize: 14, margin: 0 }}>
206
+ For your security, this link opens only this statement and works for
207
+ 7 days. After that, request a new one and we'll email it to this
208
+ address.
209
+ </Text>
210
+ <Button
211
+ href={renewHref}
212
+ mode={mode}
213
+ data-testid="renew-owner-statement-link-button"
214
+ label="Send me a new link"
215
+ themeColors={themeColors}
216
+ style={{
217
+ background: '#ffffff',
218
+ border: `1px solid ${themeColors[8]}`,
219
+ color: themeColors[8],
220
+ marginTop: '16px',
221
+ marginBottom: 0,
222
+ }}
223
+ />
224
+ </div>
225
+ )}
226
+
227
+ <div
228
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: values are escaped by parseEmailHtml
229
+ dangerouslySetInnerHTML={{ __html: parse(data.bodyTwo) }}
230
+ />
231
+ </EmailContainer>
232
+ );
46
233
  };