From 2386c95edd5baa729d4bba3fdada3783b31b1f0c Mon Sep 17 00:00:00 2001 From: MussiM <mussish99@gmail.com> Date: Tue, 10 Sep 2024 20:59:03 +0300 Subject: [PATCH 1/4] new example for emails notifications - credit usage --- .../notifications/novu-credit-alert.tsx | 281 ++++++++++++++++++ content-samples/react/package-lock.json | 4 +- 2 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 content-samples/react/emails/notifications/novu-credit-alert.tsx diff --git a/content-samples/react/emails/notifications/novu-credit-alert.tsx b/content-samples/react/emails/notifications/novu-credit-alert.tsx new file mode 100644 index 0000000..39db903 --- /dev/null +++ b/content-samples/react/emails/notifications/novu-credit-alert.tsx @@ -0,0 +1,281 @@ +import React from 'react'; +import { + Body, + Container, + Head, + Heading, + Hr, + Html, + Img, + Link, + Preview, + Section, + Text +} from '@react-email/components'; + +interface NovuCreditUsageAlertEmailProps { + companyName: string, + logoImg: string; + address: string; + linkToPricing: string; + linkToUnsubscribe: string; + customerName: string, + usage: number, + amount: number, + packagesList: Array<{name: string; amount: string; price: string}> +}; + +const NovuCreditUsageAlertEmail = ({ + companyName, + logoImg, + address, + linkToPricing, + linkToUnsubscribe, + customerName, + usage, + amount, + packagesList +}: NovuCreditUsageAlertEmailProps) => { + const usagePrecent = Math.round(usage / amount * 100); + return ( + <Html> + <Head /> + <Preview>Credit Usage Alert - You've used {`${usagePrecent}`}% of your monthly credit</Preview> + <Body style={main}> + <Container style={container}> + <Section style={iconContainer}> + <svg style={icon} viewBox="0 0 24 24"> + <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path> + <line x1="12" y1="9" x2="12" y2="13"></line> + <line x1="12" y1="17" x2="12.01" y2="17"></line> + </svg> + </Section> + <Heading style={h1}>Credit Usage Alert</Heading> + + <Text style={text}>Hello {customerName},</Text> + + <Text style={text}> + Thank you for using our services. We want to inform you that you have used <strong style={highlight}>{usagePrecent}%</strong> of your monthly credit. + </Text> + + <Section style={infoBox}> + <Head> + <svg style={infoIcon} + width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" + > + <line x1="18" y1="20" x2="18" y2="10"></line> + <line x1="12" y1="20" x2="12" y2="4"></line> + <line x1="6" y1="20" x2="6" y2="14"></line> + </svg> + <strong style={h2}>Your Credit Status</strong> + </Head> + <div style={progressBar}> + <div style={{...progressFill, width: `${usagePrecent}%`}}></div> + </div> + <Text style={text}>Credit used: <strong>{usage}/{amount}</strong></Text> + </Section> + + <Text style={text}> + To ensure you can continue enjoying our service without interruption, we recommend considering purchasing an additional credit package. + </Text> + + <Section style={infoBox}> + <Head> + <svg style={infoIcon} width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <rect x="1" y="4" width="22" height="16" rx="2" ry="2"></rect> + <line x1="1" y1="10" x2="23" y2="10"></line> + </svg> + <strong style={h2}>Purchase Additional Credits</strong> + </Head> + <Text style={text}>Choose the package that suits you:</Text> + <ul style={list}> + { + packagesList.map(({name, amount, price}, indx) => + <li key={indx}> {name}: {amount} - {price} </li> + ) + } + </ul> + <Link + href={linkToPricing} + style={button} + > + Upgrade {companyName} Plan + </Link> + </Section> + + <Text style={text}> + If you have any questions or need further information, please don't hesitate to contact us. We're here to help! + </Text> + + <Text style={footer}> + Best regards,<br/>The {companyName} Support Team + </Text> + + <Hr style={hr} /> + + <section style={{display: 'flex', alignItems: 'center', gap: '10px'}}> + <Img + src={logoImg} + width="42" + height="42" + alt={companyName} + /> + <Text style={footer}> + {companyName}<br/>{address} + </Text> + </section> + + + <Text style={footer}> + If you don't want to receive these alerts in the future,{' '} + <Link href={linkToUnsubscribe} style={link}>click here</Link> + {' '}to change your notification settings. + </Text> + </Container> + </Body> + </Html> + ); +}; + +const main = { + backgroundColor: '#f3f4f6', + fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', +}; + +const container = { + backgroundColor: '#ffffff', + margin: '0 auto', + padding: '24px', + marginBottom: '24px', + maxWidth: '600px', + borderRadius: '8px', + boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)', +}; + +const iconContainer = { + textAlign: 'center' as const, +}; + +const h1 = { + color: '#1f2937', + fontSize: '24px', + fontWeight: 'bold', + textAlign: 'center' as const, + margin: '16px 0 24px', +}; + +const h2 = { + color: '#1f2937', + fontWeight: 'bold', + fontSize: '20px', + verticalAlign: 'middle' +}; + +const text = { + color: '#4b5563', + fontSize: '16px', + lineHeight: '24px', +}; + +const icon: React.CSSProperties | undefined = { + width: "48", + height: "48", + fill: "none", + stroke: "currentColor", + strokeWidth: "2", + strokeLinecap: "round", + strokeLinejoin: "round", + color: '#DA3688', + marginBottom: '16px', +}; + +const infoBox: React.CSSProperties | undefined = { + backgroundColor: '#FFF2FA', + border: '1px solid #FF968A', + borderRadius: '8px', + padding: '16px', + marginBottom: '24px', +}; + +const infoIcon = { + marginRight: '8px', + color: '#DA0685', + verticalAlign: 'middle' +}; + +const progressBar = { + width: '100%', + backgroundColor: '#e5e7eb', + borderRadius: '9999px', + height: '16px', + marginBottom: '8px', + marginTop: '8px' +}; + +const progressFill = { + backgroundColor: '#DA0685', + height: '16px', + borderRadius: '9999px', +}; + +const button = { + backgroundColor: '#3b82f6', + borderRadius: '4px', + color: '#ffffff', + fontSize: '16px', + fontWeight: 'bold', + textDecoration: 'none', + textAlign: 'center' as const, + display: 'block', + padding: '12px 16px', +}; + +const hr = { + borderColor: '#e5e7eb', + margin: '20px 0', +}; + +const footer = { + color: '#6b7280', + fontSize: '14px', + lineHeight: '24px', +}; + +const link = { + color: '#3b82f6', + textDecoration: 'none', +}; + +const list = { + ...text, + paddingLeft: '24px', + margin: '0 0 16px', +}; + +const highlight = { + color: '#DA3688', + fontWeight: 'bold', +}; + +NovuCreditUsageAlertEmail.PreviewProps = { + companyName: "Novu", + logoImg: `https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/dca73b36-cf39-4e28-9bc7-8a0d0cd8ac70/standalone-gradient2x_2/w=128,quality=90,fit=scale-down`, + address: '', + linkToPricing: "https://novu.co/pricing/?utm_campaign=docs_top_nav", + linkToUnsubscribe: "https://google.com", + customerName: "Mussi", + usage: 80, + amount: 130, + packagesList: [{ + name: 'BUSINESS', + amount: '250K events/month', + price: '$250' + }, + { + name: 'ENTERPRISE', + amount: '5M events/month', + price: `Let's Talk` + }] + } as NovuCreditUsageAlertEmailProps; + +export default NovuCreditUsageAlertEmail \ No newline at end of file diff --git a/content-samples/react/package-lock.json b/content-samples/react/package-lock.json index e205b7d..8e9b0bb 100644 --- a/content-samples/react/package-lock.json +++ b/content-samples/react/package-lock.json @@ -1,11 +1,11 @@ { - "name": "emails", + "name": "react-email-templates", "version": "0.0.19", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "emails", + "name": "react-email-templates", "version": "0.0.19", "dependencies": { "@react-email/components": "0.0.18", From 370ae8d0625a0e07b58fadf494af330ba9f921a5 Mon Sep 17 00:00:00 2001 From: MussiM <mussish99@gmail.com> Date: Tue, 10 Sep 2024 23:25:08 +0300 Subject: [PATCH 2/4] Changing section to Section and style corrections --- .../notifications/novu-credit-alert.tsx | 52 +++++++++++++------ 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/content-samples/react/emails/notifications/novu-credit-alert.tsx b/content-samples/react/emails/notifications/novu-credit-alert.tsx index 39db903..bf711ac 100644 --- a/content-samples/react/emails/notifications/novu-credit-alert.tsx +++ b/content-samples/react/emails/notifications/novu-credit-alert.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Body, + Column, Container, Head, Heading, @@ -9,8 +10,9 @@ import { Img, Link, Preview, + Row, Section, - Text + Text, } from '@react-email/components'; interface NovuCreditUsageAlertEmailProps { @@ -70,7 +72,7 @@ const NovuCreditUsageAlertEmail = ({ <strong style={h2}>Your Credit Status</strong> </Head> <div style={progressBar}> - <div style={{...progressFill, width: `${usagePrecent}%`}}></div> + <div style={progressFill(usagePrecent)}></div> </div> <Text style={text}>Credit used: <strong>{usage}/{amount}</strong></Text> </Section> @@ -113,17 +115,24 @@ const NovuCreditUsageAlertEmail = ({ <Hr style={hr} /> - <section style={{display: 'flex', alignItems: 'center', gap: '10px'}}> - <Img - src={logoImg} - width="42" - height="42" - alt={companyName} - /> - <Text style={footer}> - {companyName}<br/>{address} - </Text> - </section> + <Section> + <Row> + <Column style={logoColumn}> + <Img + src={logoImg} + width="42" + height="42" + alt={companyName} + /> + </Column> + <Column> + <Text style={companyDetails}> + {`${companyName} + ${address}`} + </Text> + </Column> + </Row> + </Section> <Text style={footer}> @@ -212,11 +221,12 @@ const progressBar = { marginTop: '8px' }; -const progressFill = { +const progressFill = (usagePrecent: number) => ({ backgroundColor: '#DA0685', height: '16px', borderRadius: '9999px', -}; + width: `${usagePrecent}%` +}); const button = { backgroundColor: '#3b82f6', @@ -241,6 +251,16 @@ const footer = { lineHeight: '24px', }; +const logoColumn = { + width: '42px', + paddingRight: '12px', +}; + +const companyDetails = { + ...footer, + whiteSpace: 'pre-line' +}; + const link = { color: '#3b82f6', textDecoration: 'none', @@ -260,7 +280,7 @@ const highlight = { NovuCreditUsageAlertEmail.PreviewProps = { companyName: "Novu", logoImg: `https://images.spr.so/cdn-cgi/imagedelivery/j42No7y-dcokJuNgXeA0ig/dca73b36-cf39-4e28-9bc7-8a0d0cd8ac70/standalone-gradient2x_2/w=128,quality=90,fit=scale-down`, - address: '', + address: 'Tel Aviv, Israel', linkToPricing: "https://novu.co/pricing/?utm_campaign=docs_top_nav", linkToUnsubscribe: "https://google.com", customerName: "Mussi", From 8995846c701d7db6e8ede27ef4cc7a4c46bb5649 Mon Sep 17 00:00:00 2001 From: MussiM <mussish99@gmail.com> Date: Wed, 11 Sep 2024 12:57:29 +0300 Subject: [PATCH 3/4] Division into subcomponents --- .../notifications/novu-credit-alert.tsx | 62 ++++++++++++------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/content-samples/react/emails/notifications/novu-credit-alert.tsx b/content-samples/react/emails/notifications/novu-credit-alert.tsx index bf711ac..bdd1fb0 100644 --- a/content-samples/react/emails/notifications/novu-credit-alert.tsx +++ b/content-samples/react/emails/notifications/novu-credit-alert.tsx @@ -38,7 +38,7 @@ const NovuCreditUsageAlertEmail = ({ amount, packagesList }: NovuCreditUsageAlertEmailProps) => { - const usagePrecent = Math.round(usage / amount * 100); + const usagePrecent: number = Math.round(usage / amount * 100); return ( <Html> <Head /> @@ -46,11 +46,7 @@ const NovuCreditUsageAlertEmail = ({ <Body style={main}> <Container style={container}> <Section style={iconContainer}> - <svg style={icon} viewBox="0 0 24 24"> - <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path> - <line x1="12" y1="9" x2="12" y2="13"></line> - <line x1="12" y1="17" x2="12.01" y2="17"></line> - </svg> + <AlertIcon/> </Section> <Heading style={h1}>Credit Usage Alert</Heading> @@ -62,18 +58,10 @@ const NovuCreditUsageAlertEmail = ({ <Section style={infoBox}> <Head> - <svg style={infoIcon} - width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" - > - <line x1="18" y1="20" x2="18" y2="10"></line> - <line x1="12" y1="20" x2="12" y2="4"></line> - <line x1="6" y1="20" x2="6" y2="14"></line> - </svg> + <LineChartIcon/> <strong style={h2}>Your Credit Status</strong> </Head> - <div style={progressBar}> - <div style={progressFill(usagePrecent)}></div> - </div> + <ProgressBar usagePrecent={usagePrecent}/> <Text style={text}>Credit used: <strong>{usage}/{amount}</strong></Text> </Section> @@ -83,18 +71,14 @@ const NovuCreditUsageAlertEmail = ({ <Section style={infoBox}> <Head> - <svg style={infoIcon} width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> - <rect x="1" y="4" width="22" height="16" rx="2" ry="2"></rect> - <line x1="1" y1="10" x2="23" y2="10"></line> - </svg> + <CreditCardIcon/> <strong style={h2}>Purchase Additional Credits</strong> </Head> <Text style={text}>Choose the package that suits you:</Text> <ul style={list}> { packagesList.map(({name, amount, price}, indx) => - <li key={indx}> {name}: {amount} - {price} </li> - ) + <li key={indx}> {name}: {amount} - {price} </li> ) } </ul> <Link @@ -146,6 +130,38 @@ const NovuCreditUsageAlertEmail = ({ ); }; +const AlertIcon = () => ( + <svg style={icon} viewBox="0 0 24 24"> + <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path> + <line x1="12" y1="9" x2="12" y2="13"></line> + <line x1="12" y1="17" x2="12.01" y2="17"></line> + </svg> +); + +const LineChartIcon = () => ( + <svg style={infoIcon} + width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" + > + <line x1="18" y1="20" x2="18" y2="10"></line> + <line x1="12" y1="20" x2="12" y2="4"></line> + <line x1="6" y1="20" x2="6" y2="14"></line> + </svg> +); + +const CreditCardIcon = () => ( + <svg style={infoIcon} width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <rect x="1" y="4" width="22" height="16" rx="2" ry="2"></rect> + <line x1="1" y1="10" x2="23" y2="10"></line> + </svg> +); + +const ProgressBar = ({usagePrecent}) => { +return ( + <div style={progressBar}> + <div style={progressFill(usagePrecent)}></div> + </div>); +}; + const main = { backgroundColor: '#f3f4f6', fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', @@ -298,4 +314,4 @@ NovuCreditUsageAlertEmail.PreviewProps = { }] } as NovuCreditUsageAlertEmailProps; -export default NovuCreditUsageAlertEmail \ No newline at end of file +export default NovuCreditUsageAlertEmail; From 60f4d9ffb28d6fcd9d2f056a3d468351e701d8e8 Mon Sep 17 00:00:00 2001 From: MussiM <mussish99@gmail.com> Date: Thu, 12 Sep 2024 10:08:55 +0300 Subject: [PATCH 4/4] Changing string to Text tag --- .../notifications/novu-credit-alert.tsx | 72 ++++++++++++------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/content-samples/react/emails/notifications/novu-credit-alert.tsx b/content-samples/react/emails/notifications/novu-credit-alert.tsx index bdd1fb0..c08390d 100644 --- a/content-samples/react/emails/notifications/novu-credit-alert.tsx +++ b/content-samples/react/emails/notifications/novu-credit-alert.tsx @@ -48,21 +48,33 @@ const NovuCreditUsageAlertEmail = ({ <Section style={iconContainer}> <AlertIcon/> </Section> + <Heading style={h1}>Credit Usage Alert</Heading> <Text style={text}>Hello {customerName},</Text> - <Text style={text}> - Thank you for using our services. We want to inform you that you have used <strong style={highlight}>{usagePrecent}%</strong> of your monthly credit. - </Text> + <Row style={{marginBottom: 10}}> + <Text style={{...text, display: 'inline'}}> + Thank you for using our services. We want to inform you that you have used + </Text> + <Text style={highlight}>{usagePrecent}%</Text> + <Text style={{...text, display: 'inline'}}>of your monthly credit.</Text> + </Row> <Section style={infoBox}> - <Head> - <LineChartIcon/> - <strong style={h2}>Your Credit Status</strong> - </Head> + <Row> + <Column width="24px"> + <LineChartIcon/> + </Column> + <Column> + <Text style={h2}>Your Credit Status</Text> + </Column> + </Row> <ProgressBar usagePrecent={usagePrecent}/> - <Text style={text}>Credit used: <strong>{usage}/{amount}</strong></Text> + <Row> + <Text style={{...text, display: 'inline'}}>Credit used:</Text> + <Text style={highlight}>{usage}/{amount}</Text> + </Row> </Section> <Text style={text}> @@ -70,10 +82,14 @@ const NovuCreditUsageAlertEmail = ({ </Text> <Section style={infoBox}> - <Head> - <CreditCardIcon/> - <strong style={h2}>Purchase Additional Credits</strong> - </Head> + <Row> + <Column width="24px"> + <CreditCardIcon/> + </Column> + <Column> + <Text style={h2}>Purchase Additional Credits</Text> + </Column> + </Row> <Text style={text}>Choose the package that suits you:</Text> <ul style={list}> { @@ -139,9 +155,7 @@ const AlertIcon = () => ( ); const LineChartIcon = () => ( - <svg style={infoIcon} - width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" - > + <svg style={infoIcon} viewBox="0 0 24 24"> <line x1="18" y1="20" x2="18" y2="10"></line> <line x1="12" y1="20" x2="12" y2="4"></line> <line x1="6" y1="20" x2="6" y2="14"></line> @@ -149,7 +163,7 @@ const LineChartIcon = () => ( ); const CreditCardIcon = () => ( - <svg style={infoIcon} width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <svg style={infoIcon} viewBox="0 0 24 24"> <rect x="1" y="4" width="22" height="16" rx="2" ry="2"></rect> <line x1="1" y1="10" x2="23" y2="10"></line> </svg> @@ -193,7 +207,8 @@ const h2 = { color: '#1f2937', fontWeight: 'bold', fontSize: '20px', - verticalAlign: 'middle' + verticalAlign: 'middle', + marginBottom: 0 }; const text = { @@ -218,14 +233,21 @@ const infoBox: React.CSSProperties | undefined = { backgroundColor: '#FFF2FA', border: '1px solid #FF968A', borderRadius: '8px', - padding: '16px', - marginBottom: '24px', + padding: '0 16px 16px 16px', + marginBottom: '0 auto', }; -const infoIcon = { +const infoIcon: React.CSSProperties | undefined = { marginRight: '8px', color: '#DA0685', - verticalAlign: 'middle' + verticalAlign: 'middle', + marginTop: "17px", + height: "24", + fill: "none", + stroke: "currentColor", + strokeWidth: "2", + strokeLinecap: "round", + strokeLinejoin: "round" }; const progressBar = { @@ -233,8 +255,7 @@ const progressBar = { backgroundColor: '#e5e7eb', borderRadius: '9999px', height: '16px', - marginBottom: '8px', - marginTop: '8px' + margin: '8px 0' }; const progressFill = (usagePrecent: number) => ({ @@ -250,7 +271,6 @@ const button = { color: '#ffffff', fontSize: '16px', fontWeight: 'bold', - textDecoration: 'none', textAlign: 'center' as const, display: 'block', padding: '12px 16px', @@ -279,7 +299,6 @@ const companyDetails = { const link = { color: '#3b82f6', - textDecoration: 'none', }; const list = { @@ -289,8 +308,11 @@ const list = { }; const highlight = { + ...text, color: '#DA3688', fontWeight: 'bold', + display: 'inline', + margin: "5px", }; NovuCreditUsageAlertEmail.PreviewProps = {