refactor: improve news and email handling, style, folder structure (#16)
This commit is contained in:
37
components/email/Confirmation.tsx
Normal file
37
components/email/Confirmation.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import Note from './components/Note';
|
||||
import Template from './Template';
|
||||
|
||||
export default function ConfirmationTemplate(code: string) {
|
||||
return {
|
||||
subject: 'Welcome!',
|
||||
template: (
|
||||
<Template
|
||||
title='Welcome!'
|
||||
body={
|
||||
<div style={{ fontSize: '1rem', color: '#4a5568' }}>
|
||||
<p>Dear subscriber,</p>
|
||||
<p style={{ marginTop: '0.5rem' }}>
|
||||
thank you for subscribing to our newsletter! Please click the link
|
||||
below to confirm your subscription.
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
margin: '2rem 0',
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<a href={`${process.env.HOME_URL}/confirmation?code=${code}`}>
|
||||
{'Confirm subscription'}
|
||||
</a>
|
||||
</div>
|
||||
<Note>
|
||||
If you didn't subscribe to our newsletter, please ignore this
|
||||
email.
|
||||
</Note>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)
|
||||
};
|
||||
}
|
||||
84
components/email/Newsletter.tsx
Normal file
84
components/email/Newsletter.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import { sayings } from '@utils/sayings';
|
||||
import { textTruncate } from '@utils/textTruncate';
|
||||
import { NewsType } from '@utils/validationSchemas';
|
||||
import Template from './Template';
|
||||
|
||||
export default function NewsletterTemplate(stories: NewsType[]) {
|
||||
return {
|
||||
subject: `What's new from the Hackernews forum?`,
|
||||
template: (
|
||||
<Template
|
||||
title={`Here is something
|
||||
${sayings[Math.floor(Math.random() * sayings.length)]}!`}
|
||||
body={
|
||||
<div>
|
||||
{stories.map(story => {
|
||||
return (
|
||||
<div
|
||||
key={story.id}
|
||||
style={{
|
||||
marginTop: '2rem',
|
||||
marginBottom: '2rem',
|
||||
borderRadius: '0.5rem',
|
||||
border: '1px solid #e5e7eb',
|
||||
backgroundColor: `white`,
|
||||
color: '#111827',
|
||||
boxShadow: '0 16px 32px 0 rgba(0, 0, 0, 0.05)'
|
||||
}}
|
||||
data-v0-t='card'
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '0.375rem',
|
||||
paddingTop: '1.5rem',
|
||||
paddingLeft: '1.5rem',
|
||||
paddingRight: '1.5rem'
|
||||
}}
|
||||
>
|
||||
<h3>{story.title}</h3>
|
||||
<p style={{ fontSize: '1rem', fontStyle: 'italic' }}>
|
||||
by {story.by}
|
||||
</p>
|
||||
</div>
|
||||
{story.text && (
|
||||
<div
|
||||
style={{
|
||||
paddingLeft: '1.5rem',
|
||||
fontSize: '1rem',
|
||||
paddingRight: '1.5rem'
|
||||
}}
|
||||
>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html:
|
||||
story.text.length > 500
|
||||
? textTruncate(story.text, 500) + '...'
|
||||
: story.text
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{story.url && (
|
||||
<div
|
||||
style={{
|
||||
paddingBottom: '1.5rem',
|
||||
paddingLeft: '1.5rem',
|
||||
paddingRight: '1.5rem',
|
||||
textAlign: 'right',
|
||||
fontWeight: 'bold'
|
||||
}}
|
||||
>
|
||||
<a href={story.url}>Read more</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)
|
||||
};
|
||||
}
|
||||
32
components/email/Template.tsx
Normal file
32
components/email/Template.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import Footer from './components/Footer';
|
||||
|
||||
interface TemplateProps {
|
||||
title: string;
|
||||
body: JSX.Element;
|
||||
}
|
||||
|
||||
export default function Template({ title, body }: TemplateProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
maxWidth: '720px',
|
||||
alignContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F9FBFB'
|
||||
}}
|
||||
>
|
||||
<h2
|
||||
style={{
|
||||
padding: '20px',
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
backgroundColor: `#8230CC`
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<div style={{ margin: '20px', padding: '20px' }}>{body}</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
41
components/email/Unsubscribe.tsx
Normal file
41
components/email/Unsubscribe.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import Note from './components/Note';
|
||||
import Template from './Template';
|
||||
|
||||
export default function UnsubscribeTemplate() {
|
||||
return {
|
||||
subject: 'Unsubscribe confirmation',
|
||||
template: (
|
||||
<Template
|
||||
title="We're sad to see you go :("
|
||||
body={
|
||||
<div style={{ fontSize: '1rem', color: '#4a5568' }}>
|
||||
<p style={{ marginTop: '0.5rem' }}>
|
||||
You have been successfully unsubscribed from our newsletter. You
|
||||
won't receive any further communications from us unless you
|
||||
explicitly opt-in again.
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
margin: '2rem 0',
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<a href={`${process.env.HOME_URL}/`}>{'Re-subscribe'}</a>
|
||||
</div>
|
||||
<Note>
|
||||
If you have any questions or concerns, please feel free to{' '}
|
||||
<a
|
||||
style={{ color: '#3b82f6', textDecoration: 'underline' }}
|
||||
href={`mailto:${process.env.NEXT_PUBLIC_BRAND_EMAIL}`}
|
||||
>
|
||||
contact us
|
||||
</a>
|
||||
.
|
||||
</Note>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)
|
||||
};
|
||||
}
|
||||
34
components/email/components/Footer.tsx
Normal file
34
components/email/components/Footer.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer
|
||||
style={{
|
||||
paddingTop: '1.5rem',
|
||||
backgroundColor: `#E6F2F2`,
|
||||
color: 'black'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
marginLeft: '2rem',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingBottom: '2rem'
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<h4 style={{ fontSize: '1.125rem', fontWeight: '600' }}>
|
||||
Contact Us
|
||||
</h4>
|
||||
<p>{process.env.NEXT_PUBLIC_BRAND_NAME}</p>
|
||||
<p>
|
||||
Email:{' '}
|
||||
<a href={`mailto:${process.env.NEXT_PUBLIC_BRAND_EMAIL}`}>
|
||||
{process.env.NEXT_PUBLIC_BRAND_EMAIL}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
18
components/email/components/Note.tsx
Normal file
18
components/email/components/Note.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
interface NoteProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function Note({ children }: NoteProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
marginTop: '2rem',
|
||||
padding: '1.5rem 1.5rem',
|
||||
backgroundColor: '#EBF1F5',
|
||||
color: '#718096'
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: '0.875rem' }}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user