mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-08-02 19:31:19 -04:00
Redesign message notification email: add avatar, profile link, and metadata; refine translations and layout for better engagement.
This commit is contained in:
@@ -17,9 +17,11 @@ export type PartialProfile = Pick<
|
||||
> &
|
||||
Partial<ProfileRow>
|
||||
|
||||
const avatarUrl =
|
||||
'https://firebasestorage.googleapis.com/v0/b/compass-130ba.firebasestorage.app/o/user-images%2FMartin%2Flove-images%2FeD09lRtuRF.jpg?alt=media&token=db41b5f2-b1c0-4df9-aa9c-11d44c970947'
|
||||
export const mockUser: User = {
|
||||
createdTime: 0,
|
||||
avatarUrl: 'https://martinbraquet.com/wp-content/uploads/BDo_Tbzj.jpeg',
|
||||
avatarUrl: avatarUrl,
|
||||
id: '0k1suGSJKVUnHbCPEhHNpgZPkUP2',
|
||||
username: 'Martin',
|
||||
name: 'Martin',
|
||||
@@ -27,7 +29,7 @@ export const mockUser: User = {
|
||||
|
||||
export const jamesUser: User = {
|
||||
createdTime: 0,
|
||||
avatarUrl: 'https://martinbraquet.com/wp-content/uploads/BDo_Tbzj.jpeg',
|
||||
avatarUrl: avatarUrl,
|
||||
id: '5LZ4LgYuySdL1huCWe7bti02ghx2',
|
||||
username: 'James',
|
||||
name: 'James',
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
Container,
|
||||
Head,
|
||||
Html,
|
||||
Img,
|
||||
Link,
|
||||
Preview,
|
||||
Section,
|
||||
@@ -13,7 +14,7 @@ import {ANDROID_APP_URL} from 'common/constants'
|
||||
import {DOMAIN} from 'common/envs/constants'
|
||||
import {type ProfileRow} from 'common/profiles/profile'
|
||||
import {type User} from 'common/user'
|
||||
import {container, content, Footer, main} from 'email/utils'
|
||||
import {container, content, DARK_MODE_CSS, Footer, main} from 'email/utils'
|
||||
import React from 'react'
|
||||
import {createT} from 'shared/locale'
|
||||
|
||||
@@ -31,7 +32,7 @@ interface NewMessageEmailProps {
|
||||
|
||||
export const NewMessageEmail = ({
|
||||
fromUser,
|
||||
// fromUserProfile,
|
||||
fromUserProfile,
|
||||
toUser,
|
||||
channelId,
|
||||
unsubscribeUrl,
|
||||
@@ -41,16 +42,25 @@ export const NewMessageEmail = ({
|
||||
const name = toUser.name.split(' ')[0]
|
||||
const creatorName = fromUser.name
|
||||
const messagesUrl = `https://${DOMAIN}/messages/${channelId}`
|
||||
// const userImgSrc = getOgImageUrl(fromUser, fromUserProfile)
|
||||
const profileUrl = `https://${DOMAIN}/${fromUser.username}`
|
||||
// Every client renders <img> reliably, none of them render a CSS-generated placeholder — so an absent
|
||||
// avatar falls back to the same asset the web app uses rather than to a broken image icon.
|
||||
const avatarUrl = fromUser.avatarUrl
|
||||
const t = createT(locale)
|
||||
|
||||
// Age and city are the two facts a reader can act on at a glance; anything more turns the card into a
|
||||
// profile page and competes with the one button this email has.
|
||||
const meta = [fromUserProfile?.age, fromUserProfile?.city].filter(Boolean).join(' · ')
|
||||
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<Head>
|
||||
<style>{DARK_MODE_CSS}</style>
|
||||
</Head>
|
||||
<Preview>
|
||||
{t('email.new_message.preview', 'New message from {creatorName}', {creatorName})}
|
||||
</Preview>
|
||||
<Body style={main}>
|
||||
<Body style={main} className="cm-body">
|
||||
<Container style={container}>
|
||||
{/*<Section style={logoContainer}>*/}
|
||||
{/* <Img*/}
|
||||
@@ -61,52 +71,155 @@ export const NewMessageEmail = ({
|
||||
{/* />*/}
|
||||
{/*</Section>*/}
|
||||
|
||||
<Section style={content}>
|
||||
<Section style={content} className="cm-surface">
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
marginBottom: '32px',
|
||||
marginBottom: '28px',
|
||||
}}
|
||||
>
|
||||
{/* A pill rather than a headline: it names the event in one glance, above the fold and above
|
||||
the greeting, which is what the reader is scanning for when the subject line already
|
||||
said someone wrote to them. */}
|
||||
<span
|
||||
className="cm-chip"
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
backgroundColor: '#faf3e9',
|
||||
border: '1px solid #e8c99e',
|
||||
borderRadius: '9999px',
|
||||
padding: '6px 14px',
|
||||
fontFamily: "'DM Sans', sans-serif",
|
||||
fontSize: '11px',
|
||||
fontWeight: '600',
|
||||
letterSpacing: '0.12em',
|
||||
textTransform: 'uppercase',
|
||||
color: '#a6682e',
|
||||
lineHeight: '1.2',
|
||||
}}
|
||||
>
|
||||
{t('email.new_message.badge', 'New message')}
|
||||
</span>
|
||||
|
||||
<Text
|
||||
style={{
|
||||
fontSize: '28px',
|
||||
fontFamily: "'Cormorant Garamond', serif",
|
||||
fontWeight: '500',
|
||||
color: '#1e1a14',
|
||||
marginBottom: '8px',
|
||||
margin: '18px 0 0 0',
|
||||
letterSpacing: '-0.01em',
|
||||
lineHeight: '1.1',
|
||||
}}
|
||||
className="cm-name"
|
||||
>
|
||||
{t('email.new_message.greeting', 'Hi {name},', {name})}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="cm-card"
|
||||
style={{
|
||||
backgroundColor: '#f7f4ef',
|
||||
border: '1px solid #dee5b2',
|
||||
borderRadius: '14px',
|
||||
padding: '24px',
|
||||
borderRadius: '18px',
|
||||
padding: '28px 24px 26px 24px',
|
||||
margin: '24px 0',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{/* The avatar is the whole point of the redesign: a face converts where a name does not.
|
||||
The ring is a padded round div rather than a box-shadow, which Gmail strips. */}
|
||||
{avatarUrl && (
|
||||
<Link href={profileUrl} style={{textDecoration: 'none'}}>
|
||||
<span
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
padding: '4px',
|
||||
backgroundColor: '#e8c99e',
|
||||
borderRadius: '9999px',
|
||||
lineHeight: '0',
|
||||
}}
|
||||
>
|
||||
<Img
|
||||
src={avatarUrl}
|
||||
alt={creatorName}
|
||||
width={96}
|
||||
height={96}
|
||||
style={{
|
||||
width: '96px',
|
||||
height: '96px',
|
||||
borderRadius: '9999px',
|
||||
objectFit: 'cover',
|
||||
display: 'block',
|
||||
border: '3px solid #ffffff',
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<Text
|
||||
className="cm-name"
|
||||
style={{
|
||||
fontSize: '18px',
|
||||
fontSize: '22px',
|
||||
fontFamily: "'Cormorant Garamond', serif",
|
||||
fontWeight: '500',
|
||||
fontWeight: '600',
|
||||
color: '#1e1a14',
|
||||
marginBottom: '20px',
|
||||
margin: '16px 0 0 0',
|
||||
lineHeight: '1.2',
|
||||
letterSpacing: '0.01em',
|
||||
}}
|
||||
>
|
||||
{creatorName}
|
||||
</Text>
|
||||
|
||||
<Text
|
||||
className="cm-accent"
|
||||
style={{
|
||||
fontSize: '13px',
|
||||
fontFamily: "'DM Sans', sans-serif",
|
||||
color: '#c17f3e',
|
||||
margin: '4px 0 0 0',
|
||||
lineHeight: '1.3',
|
||||
}}
|
||||
>
|
||||
{t('email.new_message.message', '{creatorName} just messaged you!', {creatorName})}
|
||||
@{fromUser.username}
|
||||
{meta ? ` · ${meta}` : ''}
|
||||
</Text>
|
||||
|
||||
{/* A chat bubble, not a paragraph: the asymmetric corner reads as a message in every client
|
||||
without needing a CSS triangle that Outlook would drop. */}
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: '#ffffff',
|
||||
border: '1px solid #e8c99e',
|
||||
borderRadius: '18px 18px 18px 4px',
|
||||
padding: '18px 20px',
|
||||
margin: '22px 0 0 0',
|
||||
textAlign: 'left',
|
||||
}}
|
||||
className="cm-chip"
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: '18px',
|
||||
fontFamily: "'Cormorant Garamond', serif",
|
||||
fontStyle: 'italic',
|
||||
fontWeight: '500',
|
||||
color: '#1e1a14',
|
||||
margin: '0',
|
||||
letterSpacing: '0.01em',
|
||||
lineHeight: '1.4',
|
||||
}}
|
||||
className="cm-name"
|
||||
>
|
||||
{t('email.new_message.message', '{creatorName} just messaged you!', {
|
||||
creatorName,
|
||||
})}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
href={messagesUrl}
|
||||
style={{
|
||||
@@ -119,22 +232,69 @@ export const NewMessageEmail = ({
|
||||
textDecoration: 'none',
|
||||
textAlign: 'center' as const,
|
||||
display: 'inline-block',
|
||||
padding: '14px 32px',
|
||||
margin: '0',
|
||||
padding: '14px 36px',
|
||||
margin: '24px 0 0 0',
|
||||
border: '1px solid #a6682e',
|
||||
transition: 'all 0.12s ease',
|
||||
}}
|
||||
>
|
||||
{t('email.new_message.viewButton', 'View message')}
|
||||
{t('email.new_message.viewButton', 'Read & reply')}
|
||||
</Button>
|
||||
|
||||
<Text
|
||||
className="cm-muted"
|
||||
style={{
|
||||
fontSize: '12px',
|
||||
fontFamily: "'DM Sans', sans-serif",
|
||||
color: '#8c8070',
|
||||
margin: '14px 0 0 0',
|
||||
lineHeight: '1.5',
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
href={profileUrl}
|
||||
style={{color: '#c17f3e', textDecoration: 'none', fontWeight: '500'}}
|
||||
>
|
||||
{t('email.new_message.view_profile', 'View profile')}
|
||||
</Link>
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
{/* The nudge sits outside the card so the card stays a single, clean unit — and because the
|
||||
reader who is going to reply has already clicked by the time they reach this line. */}
|
||||
<Text
|
||||
className="cm-muted"
|
||||
style={{
|
||||
fontSize: '14px',
|
||||
fontFamily: "'Cormorant Garamond', serif",
|
||||
fontStyle: 'italic',
|
||||
lineHeight: '1.6',
|
||||
color: '#8c8070',
|
||||
marginTop: '24px',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{t(
|
||||
'email.new_message.nudge',
|
||||
'One sentence back is usually all it takes to start something real.',
|
||||
)}
|
||||
</Text>
|
||||
|
||||
<hr
|
||||
style={{
|
||||
border: 'none',
|
||||
borderTop: '1px solid #ece7de',
|
||||
margin: '28px 0 0 0',
|
||||
}}
|
||||
/>
|
||||
|
||||
<Text
|
||||
className="cm-muted"
|
||||
style={{
|
||||
fontSize: '13px',
|
||||
lineHeight: '1.75',
|
||||
color: '#8c8070',
|
||||
marginTop: '32px',
|
||||
marginTop: '20px',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -314,7 +314,7 @@
|
||||
"email.new_message.message": "{creatorName} hat Ihnen gerade eine Nachricht geschickt!",
|
||||
"email.new_message.preview": "Neue Nachricht von {creatorName}",
|
||||
"email.new_message.subject": "{creatorName} hat Ihnen eine Nachricht geschickt!",
|
||||
"email.new_message.viewButton": "Nachricht anzeigen",
|
||||
"email.new_message.viewButton": "Lesen und antworten",
|
||||
"email.search_alerts.callToAction": "Wenn jemand zu Ihnen passt, treten Sie in Kontakt. Ein einfaches Hallo kann der Beginn einer bedeutungsvollen Freundschaft, Zusammenarbeit oder Beziehung sein.",
|
||||
"email.search_alerts.communityNote": "Compass wird von der Community aufgebaut und erhalten — keine Werbung, keine versteckten Algorithmen, keine Abonnements. Ihre Präsenz und Teilnahme machen es möglich.",
|
||||
"email.search_alerts.greeting": "Hallo {name},",
|
||||
@@ -1749,6 +1749,9 @@
|
||||
"email.new_message.daily_limit": "Um deine Inbox nicht zu überladen, erhältst du höchstens eine E-Mail pro Tag pro Konversation. Wenn {creatorName} heute weitere Nachrichten sendet, wirst du erst morgen wieder per E-Mail benachrichtigt.",
|
||||
"email.new_message.app_prompt": "Willst du Echtzeit-Benachrichtigungen? Lade die Compass App für Android herunter:",
|
||||
"email.new_message.app_link": "App herunterladen",
|
||||
"email.new_message.badge": "Neue Nachricht",
|
||||
"email.new_message.view_profile": "Profil ansehen",
|
||||
"email.new_message.nudge": "Ein einziger Satz zurück reicht oft, damit etwas Echtes entsteht.",
|
||||
"faq.empty.cta": "Frage stellen →",
|
||||
"faq.empty.text": "Versuche ein allgemeineres Wort — oder frag uns direkt, wir beantworten jede Nachricht.",
|
||||
"faq.empty.title": "Dazu passt hier nichts.",
|
||||
|
||||
@@ -314,7 +314,7 @@
|
||||
"email.new_message.message": "{creatorName} vient de vous envoyer un message !",
|
||||
"email.new_message.preview": "Nouveau message de {creatorName}",
|
||||
"email.new_message.subject": "{creatorName} vous a envoyé un message !",
|
||||
"email.new_message.viewButton": "Voir le message",
|
||||
"email.new_message.viewButton": "Lire et répondre",
|
||||
"email.search_alerts.callToAction": "Si quelqu'un vous parle, contactez-les. Un simple bonjour peut être le début d'une amitié, d'une collaboration ou d'une relation significative.",
|
||||
"email.search_alerts.communityNote": "Compass est construit et soutenu par la communauté — pas de publicité, pas d'algorithmes cachés, pas d'abonnements. Votre présence et votre participation le rendent possible.",
|
||||
"email.search_alerts.greeting": "Bonjour {name},",
|
||||
@@ -1748,6 +1748,9 @@
|
||||
"email.new_message.daily_limit": "Pour éviter de surcharger votre boîte de réception, vous recevrez au plus un e-mail par jour par conversation. Si {creatorName} envoie d'autres messages aujourd'hui, vous ne serez pas notifié par e-mail.",
|
||||
"email.new_message.app_prompt": "Vous voulez des notifications en temps réel ? Téléchargez l'application Compass pour Android :",
|
||||
"email.new_message.app_link": "Obtenir l'app",
|
||||
"email.new_message.badge": "Nouveau message",
|
||||
"email.new_message.view_profile": "Voir le profil",
|
||||
"email.new_message.nudge": "Une seule phrase en retour suffit souvent à faire naître quelque chose de vrai.",
|
||||
"faq.empty.cta": "Poser une question →",
|
||||
"faq.empty.text": "Essayez un mot plus général — ou posez-nous directement la question, nous répondons à chaque message.",
|
||||
"faq.empty.title": "Aucun résultat pour cette recherche.",
|
||||
|
||||
Reference in New Issue
Block a user