Send email on paid subscription

This commit is contained in:
Joe Au-Yeung 2022-10-31 16:30:52 -04:00
parent 2a52e7693c
commit 20f1306be2
6 changed files with 113 additions and 45 deletions

View File

@ -76,7 +76,11 @@ const CreateNewTeamPage = () => {
const currentStepIndex = steps.indexOf(currentStep);
const purchaseTeamMutation = trpc.useMutation(["viewer.teams.purchaseTeamSubscription"]);
const purchaseTeamMutation = trpc.useMutation(["viewer.teams.purchaseTeamSubscription"], {
onSuccess: (data) => {
router.push(data.url);
},
});
return (
<div

View File

@ -6,6 +6,7 @@ import Stripe from "stripe";
import stripe from "@calcom/app-store/stripepayment/lib/server";
import EventManager from "@calcom/core/EventManager";
import { sendScheduledEmails } from "@calcom/emails";
import { sendTeamInvite } from "@calcom/features/ee/teams/lib/inviteMember";
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
import { getErrorFromUnknown } from "@calcom/lib/errors";
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
@ -169,18 +170,56 @@ async function handleTeamSubscriptionSuccess(event: Stripe.Event) {
// Update team record with Stripe ids
if (checkoutSession.payment_status === "paid") {
await prisma.team.update({
const team = await prisma.team.update({
where: {
id: parseInt(checkoutSession.metadata.teamId),
},
data: {
subscriptionStatus: "ACTIVE",
metadata: {
stripeCustomerId: checkoutSession.customer as string,
stripeSubscriptionId: checkoutSession.subscription as string,
subscriptionStatus: "active",
},
},
});
const members = await prisma.membership.findMany({
where: {
teamId: parseInt(checkoutSession.metadata.teamId),
},
select: {
role: true,
user: {
select: {
email: true,
name: true,
username: true,
locale: true,
},
},
},
});
console.log("🚀 ~ file: webhook.ts ~ line 199 ~ handleTeamSubscriptionSuccess ~ members", members);
const teamOwner = members.find((member) => member.role === "OWNER");
console.log("🚀 ~ file: webhook.ts ~ line 204 ~ handleTeamSubscriptionSuccess ~ teamOwner", teamOwner);
console.log("🚀 ~ file: webhook.ts ~ line 184 ~ handleTeamSubscriptionSuccess ~ team", team);
await Promise.all(
members.map(
(member) =>
new Promise((resolve, reject) => {
sendTeamInvite({
member: member.user,
inviter: teamOwner.user.name,
teamOwnerLocale: teamOwner.user.locale,
teamId: team.id,
teamName: team.name,
});
})
)
);
} else {
throw new HttpCode({
statusCode: 200,

View File

@ -8,7 +8,7 @@ import { prisma } from "@calcom/prisma";
import { PendingMember } from "./types";
const inviteMember = async ({
export const createMember = async ({
teamId,
teamName,
inviter,
@ -22,7 +22,6 @@ const inviteMember = async ({
language: string;
teamSubscriptionActive?: boolean;
} => {
const translation = await getTranslation(language ?? "en", "common");
if (pendingMember.username) {
await prisma.membership.create({
data: {
@ -43,7 +42,6 @@ const inviteMember = async ({
id: true,
},
});
console.log("🚀 ~ file: inviteMember.ts ~ line 31 ~ user", user);
if (user) {
await prisma.user.update({
where: {
@ -73,26 +71,42 @@ const inviteMember = async ({
},
});
}
if (teamSubscriptionActive) {
const token: string = randomBytes(32).toString("hex");
await prisma.verificationToken.create({
data: {
identifier: pendingMember.email,
token,
expires: new Date(new Date().setHours(168)), // +1 week
},
});
await sendTeamInviteEmail({
language: translation,
from: inviter,
to: pendingMember.email,
teamName: teamName,
joinLink: `${WEBAPP_URL}/signup?token=${token}&callbackUrl=/settings/teams`,
});
}
}
};
export default inviteMember;
export const sendTeamInvite = async ({ member, inviter, teamOwnerLocale, teamId, teamName }) => {
if (member.role === "OWNER") return;
const translation = await getTranslation(member.locale || teamOwnerLocale || "en", "common");
if (member.username) {
await sendTeamInviteEmail({
language: translation,
from: inviter,
to: member.email,
teamName,
joinLink: WEBAPP_URL + `/settings/teams/${teamId}/members`,
});
// Send an invite with a signup link if not a user
} else {
const token: string = randomBytes(32).toString("hex");
await prisma.verificationToken.create({
data: {
identifier: pendingMember.email,
token,
expires: new Date(new Date().setHours(168)), // +1 week
},
});
await sendTeamInviteEmail({
language: translation,
from: inviter,
to: member.email,
teamName: teamName,
joinLink: `${WEBAPP_URL}/signup?token=${token}&callbackUrl=/settings/teams`,
});
}
console.log("🚀 ~ file: inviteMember.ts ~ line 100 ~ sendTeamInvite ~ member", member);
};

View File

@ -56,6 +56,11 @@ const ProfileView = () => {
router.push("/settings");
},
onSuccess: (team) => {
console.log(
"🚀 ~ file: team-profile-view.tsx ~ line 59 ~ const{data:team,isLoading}=trpc.useQuery ~ team",
team
);
if (team) {
form.setValue("name", team.name || "");
form.setValue("url", team.slug || "");

View File

@ -10,7 +10,7 @@ import {
} from "@calcom/app-store/stripepayment/lib/team-billing";
import { getUserAvailability } from "@calcom/core/getUserAvailability";
import { sendTeamInviteEmail } from "@calcom/emails";
import inviteMember from "@calcom/features/ee/teams/lib/inviteMember";
import { createMember } from "@calcom/features/ee/teams/lib/inviteMember";
import { deleteTeamFromStripe, purchaseTeamSubscription } from "@calcom/features/ee/teams/lib/payments";
import { HOSTED_CAL_FEATURES, IS_STRIPE_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
import { getTranslation } from "@calcom/lib/server/i18n";
@ -501,7 +501,6 @@ export const viewerTeamsRouter = createProtectedRouter()
async resolve({ ctx, input }) {
const { slug, name, logo, members } = input;
const { prisma } = ctx;
console.log("🚀 ~ file: teams.tsx ~ line 499 ~ resolve ~ input", input);
// Tentatively create the team in the DB
const createTeam = await prisma.team.create({
@ -509,29 +508,35 @@ export const viewerTeamsRouter = createProtectedRouter()
name,
slug,
logo,
// members: {
// create: {
// userId: ctx.user.id,
// role: MembershipRole.OWNER,
// accepted: true,
// },
// },
members: {
create: {
userId: ctx.user.id,
accepted: true,
role: "OWNER",
},
},
subscriptionStatus: "PENDING",
},
});
// Tentatively create members on team
for (const member of members) {
inviteMember({
teamId: createTeam.id,
teamName: name,
inviter: ctx.user.name,
pendingMember: member,
});
if (member.userId !== ctx.user.id)
createMember({
teamId: createTeam.id,
teamName: name,
inviter: ctx.user.name,
pendingMember: member,
});
}
if (!IS_STRIPE_ENABLED)
throw new TRPCError({ code: "FORBIDDEN", message: "Team billing is not enabled" });
return await purchaseTeamSubscription({ ...input, email: ctx.user.email });
return await purchaseTeamSubscription({
teamId: createTeam.id,
seats: members.length,
email: ctx.user.email,
});
return true;
},
})

View File

@ -169,8 +169,9 @@ const SettingsSidebarContainer = ({ className = "" }) => {
teamMenuState &&
teams.map((team, index: number) => {
if (
teamMenuState.some((teamState) => teamState.teamId === team.id) &&
team.subscriptionStatus !== "PENDING"
teamMenuState.some((teamState) => teamState.teamId === team.id)
// &&
// team.subscriptionStatus !== "PENDING"
)
return (
<Collapsible