feat: add trial onboarding emails

This commit is contained in:
Marc Seitz
2024-09-06 14:24:06 +02:00
parent 6faaf6eddb
commit 59716cacf1
10 changed files with 1873 additions and 52 deletions

View File

@@ -40,6 +40,9 @@ NEXT_PUBLIC_HANKO_TENANT_ID=add-your-hanko-tenent-id
TRIGGER_API_KEY=
TRIGGER_API_URL=https://api.trigger.dev
NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY=
# Trigger v3
TRIGGER_SECRET_KEY=
TRIGGER_API_URL=https://api.trigger.dev
# [[STORAGE]]
# Defines the storage transport to use. Available options: vercel (default) | s3

3
.gitignore vendored
View File

@@ -55,3 +55,6 @@ lib/emails/marketing
# vscode configs
.vscode
# trigger.dev
.trigger

View File

@@ -36,11 +36,10 @@ const Onboarding3Email = () => {
<li>Share data rooms with one link</li>
<li>Upload unlimited files</li>
<li>Create unlimited folders and subfolders</li>
<li>Invite unlimited team members</li>
<li>
Connect your <strong>custom domain 💫</strong>{" "}
</li>
<li>Create fully branded expereince </li>
<li>Create fully branded experience </li>
<li>Use advanced link settings</li>
<li>Create full whitelabeling</li>
<li>Build self-hosted expereince</li>
@@ -60,14 +59,14 @@ const Onboarding3Email = () => {
<Section className="mb-[32px] mt-[32px] text-center">
<Button
className="rounded bg-black text-center text-xs font-semibold text-white no-underline"
href={`https://app.papermark.io/documents?utm_source=onboarding&utm_medium=email&utm_campaign=20240723&utm_content=upload_documents`}
href={`https://app.papermark.io/datarooms?utm_source=dataroom-info&utm_medium=email&utm_campaign=20240723&utm_content=upload_documents`}
style={{ padding: "12px 20px" }}
>
Create new data room
</Button>
</Section>
<Text className="text-sm">
If you want to sel-host Papermark, and build fully customizable
If you want to self-host Papermark, and build fully customizable
experience{" "}
<a
href="https://cal.com/marcseitz/papermark"
@@ -90,7 +89,7 @@ const Onboarding3Email = () => {
</a>
</Text>
<Text className="text-xs">
This is a last onboaridng email. If you have any feedback or
This is a last onboarding email. If you have any feedback or
questions about this email, simply reply to it. I&apos;d love to
hear from you!{" "}
</Text>

View File

@@ -0,0 +1,26 @@
import Onboarding5Email from "@/components/emails/onboarding-5";
import { sendEmail } from "@/lib/resend";
import { CreateUserEmailProps } from "../types";
export const sendDataroomInfoEmail = async (params: CreateUserEmailProps) => {
const { email } = params.user;
let emailTemplate;
let subject;
emailTemplate = Onboarding5Email();
subject = "Virtual Data Rooms";
try {
await sendEmail({
to: email as string,
subject,
react: emailTemplate,
test: process.env.NODE_ENV === "development",
});
} catch (e) {
console.error(e);
}
};

View File

@@ -0,0 +1,57 @@
import { logger, task } from "@trigger.dev/sdk/v3";
import { sendDataroomInfoEmail } from "@/lib/emails/send-dataroom-info";
import prisma from "@/lib/prisma";
export const sendDataroomTrialInfoEmailTask = task({
id: "send-dataroom-trial-info-email",
retry: { maxAttempts: 3 },
run: async (payload: { to: string }) => {
await sendDataroomInfoEmail({ user: { email: payload.to, name: "Marc" } });
logger.info("Email sent", { to: payload.to });
},
});
export const sendDataroomTrialExpiredEmailTask = task({
id: "send-dataroom-trial-expired-email",
retry: { maxAttempts: 3 },
run: async (payload: { to: string; teamId: string }) => {
const team = await prisma.team.findUnique({
where: {
id: payload.teamId,
},
select: {
plan: true,
},
});
if (!team) {
logger.error("Team not found", { teamId: payload.teamId });
return;
}
if (team.plan.includes("drtrial")) {
await sendDataroomInfoEmail({
user: { email: payload.to, name: "Marc" },
});
logger.info("Email sent", { to: payload.to, teamId: payload.teamId });
await prisma.team.update({
where: {
id: payload.teamId,
},
data: {
plan: team.plan.replace("+drtrial", ""),
},
});
logger.info("Trial removed", { teamId: payload.teamId });
return;
}
logger.info("Team upgraded - no further action", {
teamId: payload.teamId,
plan: team.plan,
});
return;
},
});

1769
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,7 @@
"@next-auth/prisma-adapter": "^1.0.7",
"@pdf-lib/fontkit": "^1.1.1",
"@prisma/client": "^5.19.1",
"@prisma/instrumentation": "^5.19.1",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-checkbox": "^1.1.1",
@@ -54,9 +55,9 @@
"@tailwindcss/typography": "^0.5.15",
"@teamhanko/passkeys-next-auth-provider": "^0.2.7",
"@tremor/react": "^3.18.0",
"@trigger.dev/nextjs": "^2.3.19",
"@trigger.dev/react": "^2.3.19",
"@trigger.dev/sdk": "^2.3.19",
"@trigger.dev/nextjs": "3.0.0-beta.56",
"@trigger.dev/react": "3.0.0-beta.56",
"@trigger.dev/sdk": "3.0.0-beta.56",
"@tus/s3-store": "^1.5.0",
"@tus/server": "^1.7.0",
"@tus/utils": "^0.3.0",

View File

@@ -7,6 +7,11 @@ import { getServerSession } from "next-auth/next";
import { sendDataroomTrialWelcome } from "@/lib/emails/send-dataroom-trial";
import { newId } from "@/lib/id-helper";
import prisma from "@/lib/prisma";
import {
sendDataroomTrialExpiredEmailTask,
sendDataroomTrialInfoEmailTask,
sendScheduledEmailTask,
} from "@/lib/trigger/send-scheduled-email";
import { CustomUser } from "@/lib/types";
import { log } from "@/lib/utils";
@@ -96,6 +101,18 @@ export default async function handle(
};
waitUntil(sendDataroomTrialWelcome({ fullName, to: email! }));
waitUntil(
sendDataroomTrialInfoEmailTask.trigger(
{ to: email! },
{ delay: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000) },
),
);
waitUntil(
sendDataroomTrialExpiredEmailTask.trigger(
{ to: email!, teamId: teamId },
{ delay: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) },
),
);
res.status(201).json(dataroomWithCount);
} catch (error) {

22
trigger.config.ts Normal file
View File

@@ -0,0 +1,22 @@
import { PrismaInstrumentation } from "@prisma/instrumentation";
import type { TriggerConfig } from "@trigger.dev/sdk/v3";
export const config: TriggerConfig = {
project: "proj_plmsfqvqunboixacjjus",
triggerDirectories: ["./lib/trigger"],
instrumentations: [new PrismaInstrumentation()],
retries: {
enabledInDev: false,
default: {
maxAttempts: 3,
minTimeoutInMs: 1000,
maxTimeoutInMs: 10000,
factor: 2,
randomize: true,
},
},
dependenciesToBundle: ["nanoid"],
additionalFiles: ["./prisma/schema.prisma"],
additionalPackages: ["prisma@5.11.0"],
postInstall: "npm exec --package prisma -- prisma generate",
};

View File

@@ -24,6 +24,12 @@
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"trigger.config.ts"
],
"exclude": ["node_modules"]
}