diff --git a/.env.example b/.env.example index 1aa4a763..2ab98736 100644 --- a/.env.example +++ b/.env.example @@ -3,7 +3,6 @@ # ----------------------------------------------------------------------------- NEXT_PUBLIC_APP_URL=http://localhost:3000 NEXTJS_URL=http://localhost:3000 -CRON_SECRET=csec_ # Clerk NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_" @@ -22,11 +21,10 @@ DATABASE_HOST=eu-west.connect.psdb. DATABASE_NAME=YOUR_DB_NAME # ----------------------------------------------------------------------------- -# Email (Resend) +# Stripe # ----------------------------------------------------------------------------- -RESEND_API_KEY=re_ -# Stripe +USE_STRIPE=false STRIPE_API_KEY="sk_test_" STRIPE_WEBHOOK_SECRET="whsec_" NEXT_PUBLIC_STRIPE_STD_PRODUCT_ID="prod_" diff --git a/README.md b/README.md index 952ab0bc..fdee8f2e 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,7 @@ cp .env.example .env.local 1. Create [Clerk](https://clerk.com) Account 2. Create [Planet Scale](https://planetscale.com/) Account - 3. Create [Resend](https://resend.com) Account - 4. Create [Stripe](https://stripe.com) Account and download [Stripe CLI](https://docs.stripe.com/stripe-cli) - 5. Secure [CRON](https://dev.to/chrisnowicki/how-to-secure-vercel-cron-job-routes-in-nextjs-13-9g8) jobs + 3. Create [Stripe](https://stripe.com) Account and download [Stripe CLI](https://docs.stripe.com/stripe-cli) 5. Start the development server from either yarn or turbo: @@ -121,14 +119,6 @@ You can also use `docker-compose` to have a Mysql database locally, instead of r 2. run `docker-compose --env-file .env.local up` to start the DB. 3. run `pnpm run db:push`. -## Email provider - -This project uses [Resend](https://resend.com/) to handle transactional emails. You need to add create an account and get an api key needed for authentication. - -Please be aware that the Resend is designed to send test emails exclusively to the email address registered with the account, or to `delivered@resend.dev`, where they are logged on their dashboard. - -The default setting for `TEST_EMAIL_ADDRESS` is `delivered@resend.dev` but you have the option to change it to the email address that is associated with your Resend account. - ## Roadmap - [x] ~Initial setup~ diff --git a/apps/www/actions/generate-user-stripe.ts b/apps/www/actions/generate-user-stripe.ts index 56cd3add..907b2378 100644 --- a/apps/www/actions/generate-user-stripe.ts +++ b/apps/www/actions/generate-user-stripe.ts @@ -4,7 +4,7 @@ import { redirect } from "next/navigation"; import { api } from "@/trpc/server"; import { currentUser } from "@clerk/nextjs"; -import { stripe } from "@projectx/stripe"; +import { withStripe } from "@projectx/stripe"; import { absoluteUrl } from "@/lib/utils"; @@ -18,10 +18,10 @@ const billingUrl = absoluteUrl("/pricing"); export async function generateUserStripe( priceId: string, -): Promise { - let redirectUrl: string = ""; +): Promise { + return withStripe(async (stripe) => { + let redirectUrl = ""; - try { const user = await currentUser(); if (!user || !user.emailAddresses) { @@ -60,10 +60,8 @@ export async function generateUserStripe( redirectUrl = stripeSession.url as string; } - } catch (error) { - throw new Error("Failed to generate user stripe session"); - } - // no revalidatePath because redirect - redirect(redirectUrl); + // no revalidatePath because redirect + redirect(redirectUrl); + }); } diff --git a/apps/www/app/(dashboard)/_components/workspace-switcher.tsx b/apps/www/app/(dashboard)/_components/workspace-switcher.tsx index 9b4595c4..3b6b361d 100644 --- a/apps/www/app/(dashboard)/_components/workspace-switcher.tsx +++ b/apps/www/app/(dashboard)/_components/workspace-switcher.tsx @@ -8,6 +8,8 @@ import { useOrganization, useOrganizationList, useUser } from "@clerk/nextjs"; import { toDecimal } from "dinero.js"; import { Check, ChevronDown, ChevronsUpDown, PlusCircle } from "lucide-react"; +import { env } from "@projectx/stripe/env"; +import type { ExtendedPlanInfo, PlansResponse } from "@projectx/stripe/plans"; import type { PurchaseOrg } from "@projectx/validators"; import { purchaseOrgSchema } from "@projectx/validators"; @@ -244,7 +246,12 @@ export function WorkspaceSwitcher({ isCollapsed }: WorkspaceSwitcherProps) { } function NewOrganizationDialog(props: { closeDialog: () => void }) { - const plans = React.use(api.stripe.plans.query()); + const useStripe = env.USE_STRIPE === "true"; + + let plans: any | null = null; + if (useStripe) { + plans = api.stripe.plans.query(); + } const form = useZodForm({ schema: purchaseOrgSchema }); @@ -255,7 +262,7 @@ function NewOrganizationDialog(props: { closeDialog: () => void }) { .mutate(data) .catch(() => ({ success: false as const })); - if (response.success) window.location.href = response.url; + if (response?.success) window.location.href = response.url as string; else toaster.toast({ title: "Error", @@ -293,49 +300,51 @@ function NewOrganizationDialog(props: { closeDialog: () => void }) { )} /> - ( - -
- Subscription plan * - ( + +
+ Subscription plan * + + What's included in each plan? + +
+ - - - - - - - {plans.map((plan) => ( - - {plan.name} -{" "} - - {toDecimal( - plan.price, - ({ value, currency }) => - `${currencySymbol(currency.code)}${value}`, - )}{" "} - per month - - - ))} - - - -
- )} - /> + + + + + + + {plans?.map((plan: ExtendedPlanInfo) => ( + + {plan.name} -{" "} + + {toDecimal( + plan.price, + ({ value, currency }) => + `${currencySymbol(currency.code)}${value}`, + )}{" "} + per month + + + ))} + + + + + )} + /> + )}