From 0151175c50088b7c60d955b01c26169a01936eb0 Mon Sep 17 00:00:00 2001 From: Ali Farooq Date: Thu, 2 May 2024 22:10:20 +0500 Subject: [PATCH] feat(saas): get subscription count from lemon --- .../src/app/(app)/admin/dashboard/page.tsx | 6 +- starterkits/saas/src/config/pricing.ts | 4 +- .../{testimonials.tsx => testimonials.ts} | 0 .../saas/src/server/actions/plans/query.ts | 113 +++++++++++++----- 4 files changed, 90 insertions(+), 33 deletions(-) rename starterkits/saas/src/config/{testimonials.tsx => testimonials.ts} (100%) diff --git a/starterkits/saas/src/app/(app)/admin/dashboard/page.tsx b/starterkits/saas/src/app/(app)/admin/dashboard/page.tsx index 2b5f4a1..62d59bf 100644 --- a/starterkits/saas/src/app/(app)/admin/dashboard/page.tsx +++ b/starterkits/saas/src/app/(app)/admin/dashboard/page.tsx @@ -5,15 +5,17 @@ import { adminDashConfig } from "@/app/(app)/admin/dashboard/_constants/page-con import { buttonVariants } from "@/components/ui/button"; import { siteUrls } from "@/config/urls"; import { cn } from "@/lib/utils"; +import { getSubscriptionsCount } from "@/server/actions/plans/query"; import { getUsersCount } from "@/server/actions/user/queries"; import { DollarSignIcon, Users2Icon } from "lucide-react"; import Link from "next/link"; export default async function AdminDashPage() { const usersCountData = await getUsersCount(); - const usersChartData = usersCountData.usersCountByMonth; + const subscriptionsCountData = await getSubscriptionsCount({}); + return ( diff --git a/starterkits/saas/src/config/pricing.ts b/starterkits/saas/src/config/pricing.ts index 8f02aeb..2655741 100644 --- a/starterkits/saas/src/config/pricing.ts +++ b/starterkits/saas/src/config/pricing.ts @@ -139,7 +139,7 @@ export const pricingPlans: PrincingPlan[] = [ monthly: 99, yearly: 999, }, - variantId: { monthly: 335144, yearly: 335149 }, + variantId: { monthly: 362869, yearly: 362870 }, currency: { code: "USD", symbol: "$", @@ -159,7 +159,7 @@ export const pricingPlans: PrincingPlan[] = [ monthly: 199, yearly: 1999, }, - variantId: { monthly: 335161, yearly: 335167 }, + variantId: { monthly: 362872, yearly: 362874 }, currency: { code: "USD", symbol: "$", diff --git a/starterkits/saas/src/config/testimonials.tsx b/starterkits/saas/src/config/testimonials.ts similarity index 100% rename from starterkits/saas/src/config/testimonials.tsx rename to starterkits/saas/src/config/testimonials.ts diff --git a/starterkits/saas/src/server/actions/plans/query.ts b/starterkits/saas/src/server/actions/plans/query.ts index c8a7945..a54d86e 100644 --- a/starterkits/saas/src/server/actions/plans/query.ts +++ b/starterkits/saas/src/server/actions/plans/query.ts @@ -10,9 +10,15 @@ import { db } from "@/server/db"; import { subscriptions } from "@/server/db/schema"; import { configureLemonSqueezy } from "@/server/lemonsqueezy"; import { protectedProcedure } from "@/server/procedures"; -import { createCheckout, getSubscription } from "@lemonsqueezy/lemonsqueezy.js"; +import { + createCheckout, + getSubscription, + listSubscriptions, + type Subscription, +} from "@lemonsqueezy/lemonsqueezy.js"; import { eq } from "drizzle-orm"; import { redirect } from "next/navigation"; +import { eachMonthOfInterval, format, startOfMonth, subMonths } from "date-fns"; export async function getCheckoutURL(variantId?: number, embed = false) { await protectedProcedure(); @@ -62,42 +68,91 @@ export async function getCheckoutURL(variantId?: number, embed = false) { } export async function getOrgSubscription() { - configureLemonSqueezy(); - await protectedProcedure(); + try { + await protectedProcedure(); + configureLemonSqueezy(); + + const { currentOrg } = await getOrganizations(); + + const orgSubscription = await db.query.subscriptions.findFirst({ + where: eq(subscriptions.orgId, currentOrg.id), + }); + + if (!orgSubscription) { + return null; + } + + const lemonSubscription = await getSubscription( + orgSubscription?.lemonSqueezyId, + ); + + if (!lemonSubscription.data?.data) { + return null; + } + + const customerPortalUrl = + lemonSubscription.data.data.attributes.urls.customer_portal; + + // add plan details to the subscription + const plan = pricingPlans.find( + (p) => + p.variantId?.monthly === orgSubscription?.variantId || + p.variantId?.yearly === orgSubscription?.variantId, + ); + + return { + ...lemonSubscription.data.data.attributes, + lemonSqueezyId: lemonSubscription.data.data.id, + customerPortalUrl, + id: orgSubscription.id, + plan, + }; + } catch (error) { + return null; + } +} - const { currentOrg } = await getOrganizations(); +type SubscriptionCountByMonth = { + status?: Subscription["data"]["attributes"]["status"]; +}; - const orgSubscription = await db.query.subscriptions.findFirst({ - where: eq(subscriptions.orgId, currentOrg.id), - }); +export async function getSubscriptionsCount({ + status, +}: SubscriptionCountByMonth) { + await protectedProcedure(); + configureLemonSqueezy(); - if (!orgSubscription) { - return null; - } + const dateBeforeMonths = subMonths(new Date(), 6); - const lemonSubscription = await getSubscription( - orgSubscription?.lemonSqueezyId, - ); + const startDateOfTheMonth = startOfMonth(dateBeforeMonths); - if (!lemonSubscription.data?.data) { - return null; - } + const subscriptions = await listSubscriptions({ + filter: { + storeId: env.LEMONSQUEEZY_STORE_ID, + status, + }, + }); - const customerPortalUrl = - lemonSubscription.data.data.attributes.urls.customer_portal; + const months = eachMonthOfInterval({ + start: startDateOfTheMonth, + end: new Date(), + }); - // add plan details to the subscription - const plan = pricingPlans.find( - (p) => - p.variantId?.monthly === orgSubscription?.variantId || - p.variantId?.yearly === orgSubscription?.variantId, - ); + const subscriptionsCountByMonth = months.map((month) => { + const monthStr = format(month, "MMM-yyy"); + const count = + subscriptions.data?.data.filter( + (subscription) => + format( + new Date(subscription.attributes.created_at), + "MMM-yyy", + ) === monthStr, + )?.length ?? 0; + return { Date: monthStr, Count: count }; + }); return { - ...lemonSubscription.data.data.attributes, - lemonSqueezyId: lemonSubscription.data.data.id, - customerPortalUrl, - id: orgSubscription.id, - plan, + totalCount: subscriptions.data?.data.length ?? 0, + subscriptionsCountByMonth, }; }