wip
This commit is contained in:
@@ -4,6 +4,21 @@ import EmailResetPassword, {
|
||||
zEmailResetPassword,
|
||||
} from './email-reset-password';
|
||||
import TrailEndingSoon, { zTrailEndingSoon } from './trial-ending-soon';
|
||||
import OnboardingWelcome, {
|
||||
zOnboardingWelcome,
|
||||
} from './onboarding-welcome';
|
||||
import OnboardingWhatToTrack, {
|
||||
zOnboardingWhatToTrack,
|
||||
} from './onboarding-what-to-track';
|
||||
import OnboardingDashboards, {
|
||||
zOnboardingDashboards,
|
||||
} from './onboarding-dashboards';
|
||||
import OnboardingReplaceStack, {
|
||||
zOnboardingReplaceStack,
|
||||
} from './onboarding-replace-stack';
|
||||
import OnboardingTrialEnding, {
|
||||
zOnboardingTrialEnding,
|
||||
} from './onboarding-trial-ending';
|
||||
|
||||
export const templates = {
|
||||
invite: {
|
||||
@@ -24,6 +39,31 @@ export const templates = {
|
||||
Component: TrailEndingSoon,
|
||||
schema: zTrailEndingSoon,
|
||||
},
|
||||
'onboarding-welcome': {
|
||||
subject: () => "You're in",
|
||||
Component: OnboardingWelcome,
|
||||
schema: zOnboardingWelcome,
|
||||
},
|
||||
'onboarding-what-to-track': {
|
||||
subject: () => "What's actually worth tracking",
|
||||
Component: OnboardingWhatToTrack,
|
||||
schema: zOnboardingWhatToTrack,
|
||||
},
|
||||
'onboarding-dashboards': {
|
||||
subject: () => 'The part most people skip',
|
||||
Component: OnboardingDashboards,
|
||||
schema: zOnboardingDashboards,
|
||||
},
|
||||
'onboarding-replace-stack': {
|
||||
subject: () => 'One provider to rule them all',
|
||||
Component: OnboardingReplaceStack,
|
||||
schema: zOnboardingReplaceStack,
|
||||
},
|
||||
'onboarding-trial-ending': {
|
||||
subject: () => 'Your trial ends in a few days',
|
||||
Component: OnboardingTrialEnding,
|
||||
schema: zOnboardingTrialEnding,
|
||||
},
|
||||
} as const;
|
||||
|
||||
export type Templates = typeof templates;
|
||||
|
||||
49
packages/email/src/emails/onboarding-dashboards.tsx
Normal file
49
packages/email/src/emails/onboarding-dashboards.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Link, Text } from '@react-email/components';
|
||||
import React from 'react';
|
||||
import { z } from 'zod';
|
||||
import { Layout } from '../components/layout';
|
||||
|
||||
export const zOnboardingDashboards = z.object({
|
||||
firstName: z.string().optional(),
|
||||
dashboardUrl: z.string(),
|
||||
});
|
||||
|
||||
export type Props = z.infer<typeof zOnboardingDashboards>;
|
||||
export default OnboardingDashboards;
|
||||
export function OnboardingDashboards({
|
||||
firstName,
|
||||
dashboardUrl = 'https://dashboard.openpanel.dev',
|
||||
}: Props) {
|
||||
const newUrl = new URL(dashboardUrl);
|
||||
newUrl.searchParams.set('utm_source', 'email');
|
||||
newUrl.searchParams.set('utm_medium', 'email');
|
||||
newUrl.searchParams.set('utm_campaign', 'onboarding-dashboards');
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Text>Hi{firstName ? ` ${firstName}` : ''},</Text>
|
||||
<Text>
|
||||
Tracking events is the easy part. The value comes from actually looking
|
||||
at them.
|
||||
</Text>
|
||||
<Text>
|
||||
If you haven't yet, try building a simple dashboard. Pick one thing you
|
||||
care about and visualize it. Could be:
|
||||
</Text>
|
||||
<Text>
|
||||
- How many people sign up and then actually do something
|
||||
</Text>
|
||||
<Text>- Where users drop off in a flow (funnel)</Text>
|
||||
<Text>- Which pages lead to conversions (entry page → CTA)</Text>
|
||||
<Text>
|
||||
This is usually when people go from "I have analytics" to "I understand
|
||||
what's happening." It's a different feeling.
|
||||
</Text>
|
||||
<Text>Takes maybe 10 minutes to set up. Worth it.</Text>
|
||||
<Text>
|
||||
<Link href={newUrl.toString()}>Create your first dashboard</Link>
|
||||
</Text>
|
||||
<Text>Carl</Text>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
37
packages/email/src/emails/onboarding-replace-stack.tsx
Normal file
37
packages/email/src/emails/onboarding-replace-stack.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Text } from '@react-email/components';
|
||||
import React from 'react';
|
||||
import { z } from 'zod';
|
||||
import { Layout } from '../components/layout';
|
||||
|
||||
export const zOnboardingReplaceStack = z.object({
|
||||
firstName: z.string().optional(),
|
||||
});
|
||||
|
||||
export type Props = z.infer<typeof zOnboardingReplaceStack>;
|
||||
export default OnboardingReplaceStack;
|
||||
export function OnboardingReplaceStack({
|
||||
firstName,
|
||||
}: Props) {
|
||||
return (
|
||||
<Layout>
|
||||
<Text>Hi{firstName ? ` ${firstName}` : ''},</Text>
|
||||
<Text>
|
||||
A lot of people who sign up are using multiple tools: something for
|
||||
traffic, something for product analytics and something else for seeing
|
||||
raw events.
|
||||
</Text>
|
||||
<Text>OpenPanel can replace that whole setup.</Text>
|
||||
<Text>
|
||||
If you're still thinking of web analytics and product analytics as
|
||||
separate things, try combining them in a single dashboard. Traffic
|
||||
sources on top, user behavior below. That view tends to be more useful
|
||||
than either one alone.
|
||||
</Text>
|
||||
<Text>
|
||||
OpenPanel should be able to replace all of them, you can just reach out
|
||||
if you feel like something is missing.
|
||||
</Text>
|
||||
<Text>Carl</Text>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
66
packages/email/src/emails/onboarding-trial-ending.tsx
Normal file
66
packages/email/src/emails/onboarding-trial-ending.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Button, Link, Text } from '@react-email/components';
|
||||
import React from 'react';
|
||||
import { z } from 'zod';
|
||||
import { Layout } from '../components/layout';
|
||||
|
||||
export const zOnboardingTrialEnding = z.object({
|
||||
firstName: z.string().optional(),
|
||||
organizationName: z.string(),
|
||||
billingUrl: z.string(),
|
||||
recommendedPlan: z.string().optional(),
|
||||
});
|
||||
|
||||
export type Props = z.infer<typeof zOnboardingTrialEnding>;
|
||||
export default OnboardingTrialEnding;
|
||||
export function OnboardingTrialEnding({
|
||||
firstName,
|
||||
organizationName = 'your organization',
|
||||
billingUrl = 'https://dashboard.openpanel.dev',
|
||||
recommendedPlan,
|
||||
}: Props) {
|
||||
const newUrl = new URL(billingUrl);
|
||||
newUrl.searchParams.set('utm_source', 'email');
|
||||
newUrl.searchParams.set('utm_medium', 'email');
|
||||
newUrl.searchParams.set('utm_campaign', 'onboarding-trial-ending');
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Text>Hi{firstName ? ` ${firstName}` : ''},</Text>
|
||||
<Text>Quick heads up: your OpenPanel trial ends soon.</Text>
|
||||
<Text>
|
||||
Your tracking will keep working, but you won't be able to see new data
|
||||
until you upgrade. Everything you've built so far (dashboards, reports,
|
||||
event history) stays intact.
|
||||
</Text>
|
||||
<Text>
|
||||
If OpenPanel has been useful, upgrading just keeps it going. Plans
|
||||
start at $2.50/month
|
||||
{recommendedPlan ? ` and based on your usage we recommend ${recommendedPlan}` : ''}
|
||||
.
|
||||
</Text>
|
||||
<Text>
|
||||
If something's holding you back, I'd like to hear about it. Just
|
||||
reply.
|
||||
</Text>
|
||||
<Text>
|
||||
Your project will recieve events for the next 30 days, if you haven't
|
||||
upgraded by then we'll remove your workspace and projects.
|
||||
</Text>
|
||||
<Text>
|
||||
<Button
|
||||
href={newUrl.toString()}
|
||||
style={{
|
||||
backgroundColor: '#0070f3',
|
||||
color: 'white',
|
||||
padding: '12px 20px',
|
||||
borderRadius: '5px',
|
||||
textDecoration: 'none',
|
||||
}}
|
||||
>
|
||||
Upgrade Now
|
||||
</Button>
|
||||
</Text>
|
||||
<Text>Carl</Text>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
43
packages/email/src/emails/onboarding-welcome.tsx
Normal file
43
packages/email/src/emails/onboarding-welcome.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Link, Text } from '@react-email/components';
|
||||
import React from 'react';
|
||||
import { z } from 'zod';
|
||||
import { Layout } from '../components/layout';
|
||||
|
||||
export const zOnboardingWelcome = z.object({
|
||||
firstName: z.string().optional(),
|
||||
dashboardUrl: z.string(),
|
||||
});
|
||||
|
||||
export type Props = z.infer<typeof zOnboardingWelcome>;
|
||||
export default OnboardingWelcome;
|
||||
export function OnboardingWelcome({
|
||||
firstName,
|
||||
dashboardUrl = 'https://dashboard.openpanel.dev',
|
||||
}: Props) {
|
||||
const newUrl = new URL(dashboardUrl);
|
||||
newUrl.searchParams.set('utm_source', 'email');
|
||||
newUrl.searchParams.set('utm_medium', 'email');
|
||||
newUrl.searchParams.set('utm_campaign', 'onboarding-welcome');
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Text>Hi{firstName ? ` ${firstName}` : ''},</Text>
|
||||
<Text>Thanks for trying OpenPanel.</Text>
|
||||
<Text>
|
||||
We built OpenPanel because most analytics tools are either too expensive,
|
||||
too complicated, or both. OpenPanel is different.
|
||||
</Text>
|
||||
<Text>
|
||||
If you already have setup your tracking you should see your dashboard
|
||||
getting filled up. If you come from another provider and want to import
|
||||
your old events you can do that in our{' '}
|
||||
<Link href={newUrl.toString()}>project settings</Link>.
|
||||
</Text>
|
||||
<Text>
|
||||
If you can't find your provider just reach out and we'll help you out.
|
||||
</Text>
|
||||
<Text>Reach out if you have any questions. I answer all emails.</Text>
|
||||
<Text>Carl</Text>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
41
packages/email/src/emails/onboarding-what-to-track.tsx
Normal file
41
packages/email/src/emails/onboarding-what-to-track.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Text } from '@react-email/components';
|
||||
import React from 'react';
|
||||
import { z } from 'zod';
|
||||
import { Layout } from '../components/layout';
|
||||
|
||||
export const zOnboardingWhatToTrack = z.object({
|
||||
firstName: z.string().optional(),
|
||||
});
|
||||
|
||||
export type Props = z.infer<typeof zOnboardingWhatToTrack>;
|
||||
export default OnboardingWhatToTrack;
|
||||
export function OnboardingWhatToTrack({
|
||||
firstName,
|
||||
}: Props) {
|
||||
return (
|
||||
<Layout>
|
||||
<Text>Hi{firstName ? ` ${firstName}` : ''},</Text>
|
||||
<Text>
|
||||
Track the moments that tell you whether your product is working. Track
|
||||
things that matters to your product the most and then you can easily
|
||||
create funnels or conversions reports to understand what happening.
|
||||
</Text>
|
||||
<Text>For most products, that's something like:</Text>
|
||||
<Text>- Signups</Text>
|
||||
<Text>
|
||||
- The first meaningful action (create something, send something, buy
|
||||
something)
|
||||
</Text>
|
||||
<Text>- Return visits</Text>
|
||||
<Text>
|
||||
You don't need 50 events. Five good ones will tell you more than fifty
|
||||
random ones.
|
||||
</Text>
|
||||
<Text>
|
||||
If you're not sure whether something's worth tracking, just ask. I'm
|
||||
happy to look at your setup.
|
||||
</Text>
|
||||
<Text>Carl</Text>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user