diff --git a/apps/www/src/actions/generate-user-stripe.ts b/apps/www/src/actions/generate-user-stripe.ts new file mode 100644 index 00000000..ecd56886 --- /dev/null +++ b/apps/www/src/actions/generate-user-stripe.ts @@ -0,0 +1,68 @@ +"use server"; + +import { redirect } from "next/navigation"; +import { authOptions } from "@/lib/auth"; +import { stripe } from "@/lib/stripe"; +import { getUserSubscriptionPlan } from "@/lib/subscription"; +import { absoluteUrl } from "@/lib/utils"; +import { getServerSession } from "next-auth"; + +export interface responseAction { + status: "success" | "error"; + stripeUrl?: string; +} + +// const billingUrl = absoluteUrl("/dashboard/billing") +const billingUrl = absoluteUrl("/pricing"); + +export async function generateUserStripe( + priceId: string +): Promise { + let redirectUrl = ""; + + try { + const session = await getServerSession(authOptions); + + if (!session?.user || !session.user.email) { + throw new Error("Unauthorized"); + } + + const subscriptionPlan = await getUserSubscriptionPlan(session.user.id); + + if (subscriptionPlan.isPaid && subscriptionPlan.stripeCustomerId) { + // User on Paid Plan - Create a portal session to manage subscription. + const stripeSession = await stripe.billingPortal.sessions.create({ + customer: subscriptionPlan.stripeCustomerId, + return_url: billingUrl, + }); + + redirectUrl = stripeSession.url; + } else { + // User on Free Plan - Create a checkout session to upgrade. + const stripeSession = await stripe.checkout.sessions.create({ + success_url: billingUrl, + cancel_url: billingUrl, + payment_method_types: ["card"], + mode: "subscription", + billing_address_collection: "auto", + customer_email: session.user.email, + line_items: [ + { + price: priceId, + quantity: 1, + }, + ], + metadata: { + userId: session.user.id, + }, + }); + + redirectUrl = stripeSession.url!; + } + } catch (error) { + throw new Error("Failed to generate user stripe session"); + } + + // no revalidatePath because redirect + redirect(redirectUrl); +} diff --git a/apps/www/src/actions/update-user-name.ts b/apps/www/src/actions/update-user-name.ts new file mode 100644 index 00000000..804a63c9 --- /dev/null +++ b/apps/www/src/actions/update-user-name.ts @@ -0,0 +1,40 @@ +"use server" + +import { revalidatePath } from "next/cache" +import { getServerSession } from "next-auth" + +import { authOptions } from "@/lib/auth" +import { prisma } from "@/lib/db" +import { userNameSchema } from "@/lib/validations/user" + +export interface FormData { + name: string +} + +export async function updateUserName(userId: string, data: FormData) { + try { + const session = await getServerSession(authOptions) + + if (!session?.user || session.user.id !== userId) { + throw new Error("Unauthorized") + } + + const { name } = userNameSchema.parse(data) + + // Update the user name. + await prisma.user.update({ + where: { + id: userId, + }, + data: { + name: name, + }, + }) + + revalidatePath("/dashboard/settings") + return { status: "success" } + } catch (error) { + console.log(error) + return { status: "error" } + } +} diff --git a/apps/www/src/app/(dashboard)/dashboard/settings/page.tsx b/apps/www/src/app/(dashboard)/dashboard/settings/page.tsx index 2c7eb855..128e61e0 100644 --- a/apps/www/src/app/(dashboard)/dashboard/settings/page.tsx +++ b/apps/www/src/app/(dashboard)/dashboard/settings/page.tsx @@ -1,5 +1,4 @@ import { redirect } from "next/navigation"; -import { getMetricsForUser } from "@/actions/get-metrics-user"; import { Card, @@ -30,8 +29,6 @@ export default async function SettingsPage() { redirect(authOptions.pages?.signIn || "/login"); } - const metrics = await getMetricsForUser(); - const formatNumber = (number) => { return new Intl.NumberFormat("en-US").format(number); }; @@ -47,11 +44,7 @@ export default async function SettingsPage() { Logs - - {metrics - ? `${formatNumber(metrics.logsUsed)} / ${formatNumber(metrics.logsLimit)}` - : "N/A"} - + @@ -61,9 +54,7 @@ export default async function SettingsPage() { Seats - - {metrics ? `${formatNumber(metrics.seatsUsed)} / 1` : "N/A"} - + @@ -73,9 +64,7 @@ export default async function SettingsPage() { Projects - - {metrics ? `${formatNumber(metrics.projectsUsed)} / ∞` : "N/A"} - + diff --git a/apps/www/src/app/(onboarding)/onboarding/layout.tsx b/apps/www/src/app/(onboarding)/onboarding/layout.tsx deleted file mode 100644 index 21096150..00000000 --- a/apps/www/src/app/(onboarding)/onboarding/layout.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { notFound } from "next/navigation"; -import { getUserChannels } from "@/actions/get-channels"; - -import { dashboardConfig } from "@/config/dashboard"; -import { getCurrentUser } from "@/lib/session"; -import { DashboardNav } from "@/components/layout/nav"; -import { NavBar } from "@/components/layout/navbar"; -import { SiteFooter } from "@/components/layout/site-footer"; - -interface OnBoardingLayoutProps { - children?: React.ReactNode; -} - -export default async function OnBoardingLayout({ - children, -}: OnBoardingLayoutProps) { - const user = await getCurrentUser(); - - if (!user) { - return notFound(); - } - - const userChannels = await getUserChannels(); - - const sidebarNavItems = [ - ...dashboardConfig.sidebarNav, - ...userChannels.map((channel) => ({ - title: channel.name, - href: `/dashboard/channels/${channel.id}`, // Use ID instead of name - })), - ]; - - return ( -
- - -
- -
- {children} -
-
- -
- ); -} diff --git a/apps/www/src/app/(onboarding)/onboarding/page.tsx b/apps/www/src/app/(onboarding)/onboarding/page.tsx deleted file mode 100644 index 5889b207..00000000 --- a/apps/www/src/app/(onboarding)/onboarding/page.tsx +++ /dev/null @@ -1,93 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { useSession } from "next-auth/react"; - -import type { StepItem } from "@dingify/ui/components/stepper/index"; -import { Step, Stepper } from "@dingify/ui/components/stepper/index"; - -import { cn } from "@/lib/utils"; -import { ChannelForm } from "@/components/onboarding/channel-form"; -import { EventForm } from "@/components/onboarding/event-form"; -import ExploreMore from "@/components/onboarding/explore-more"; -import GenerateApiKey from "@/components/onboarding/GenerateApiKey"; - -import { useRouter } from "next/navigation"; - -export default function OnBoardingPage() { - - const {data: session} = useSession() - const router = useRouter() - - if(session === null) { - router.push("/login") - } - - const steps = [ - { label: "step 1", description: "step 1" }, - { label: "step 2", description: "step 2" }, - { label: "step 3", description: "step 3" }, - { label: "step 4", description: "step 4" }, - ] as StepItem[]; - - const [apiKey, setApiKey] = useState(""); - const [channelName, setChannelName] = useState(""); - - return ( -
-
-
-

- Create your first event -

-

- Follow the steps to create your first event -

-
-
- - - - - - - - - - - - - - -
- ); -} - -function CircleIcon(props) { - return ( - - - - ); -}