From 2d40b2dfe586ffa077ea374e0a35499f2783c8b4 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Fri, 18 Oct 2024 01:43:45 -0600 Subject: [PATCH] feat: add stripe integration --- .../components/layouts/settings-layout.tsx | 12 ++++ apps/dokploy/package.json | 1 + .../pages/dashboard/settings/billing.tsx | 66 +++++++++++++++++++ .../pages/dashboard/settings/cluster.tsx | 1 - apps/dokploy/server/api/root.ts | 2 + apps/dokploy/server/api/routers/stripe.ts | 22 +++++++ pnpm-lock.yaml | 12 ++++ 7 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 apps/dokploy/pages/dashboard/settings/billing.tsx create mode 100644 apps/dokploy/server/api/routers/stripe.ts diff --git a/apps/dokploy/components/layouts/settings-layout.tsx b/apps/dokploy/components/layouts/settings-layout.tsx index a44278d1..c6880446 100644 --- a/apps/dokploy/components/layouts/settings-layout.tsx +++ b/apps/dokploy/components/layouts/settings-layout.tsx @@ -80,6 +80,7 @@ export const SettingsLayout = ({ children }: Props) => { icon: ListMusic, href: "/dashboard/settings/registry", }, + ...(!isCloud ? [ { @@ -102,6 +103,16 @@ export const SettingsLayout = ({ children }: Props) => { icon: Server, href: "/dashboard/settings/servers", }, + ...(isCloud + ? [ + { + title: "Billing", + label: "", + icon: CreditCardIcon, + href: "/dashboard/settings/billing", + }, + ] + : []), ] : []), ...(user?.canAccessToSSHKeys @@ -137,6 +148,7 @@ import { Activity, Bell, BoxesIcon, + CreditCardIcon, Database, GitBranch, KeyIcon, diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 79da59e3..66dd76e1 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -34,6 +34,7 @@ "test": "vitest --config __test__/vitest.config.ts" }, "dependencies": { + "stripe": "17.2.0", "@dokploy/server": "workspace:*", "@codemirror/lang-json": "^6.0.1", "@codemirror/lang-yaml": "^6.1.1", diff --git a/apps/dokploy/pages/dashboard/settings/billing.tsx b/apps/dokploy/pages/dashboard/settings/billing.tsx new file mode 100644 index 00000000..45d1159b --- /dev/null +++ b/apps/dokploy/pages/dashboard/settings/billing.tsx @@ -0,0 +1,66 @@ +import { ShowNodes } from "@/components/dashboard/settings/cluster/nodes/show-nodes"; +import { DashboardLayout } from "@/components/layouts/dashboard-layout"; +import { SettingsLayout } from "@/components/layouts/settings-layout"; +import { api } from "@/utils/api"; +import { IS_CLOUD, validateRequest } from "@dokploy/server"; +import type { GetServerSidePropsContext } from "next"; +import React, { type ReactElement } from "react"; + +const Page = () => { + const { data } = api.stripe.getProducts.useQuery(); + console.log(data); + return ( +
+ {data?.map((product) => ( +
+

{product.name}

+ {product.description && ( +

{product.description}

+ )} +

+ Price: {product.default_price.unit_amount / 100}{" "} + {product.default_price.currency.toUpperCase()} +

+ {/* */} +
+ ))} +
+ ); +}; + +export default Page; + +Page.getLayout = (page: ReactElement) => { + return ( + + {page} + + ); +}; +export async function getServerSideProps( + ctx: GetServerSidePropsContext<{ serviceId: string }>, +) { + if (!IS_CLOUD) { + return { + redirect: { + permanent: true, + destination: "/dashboard/projects", + }, + }; + } + const { user, session } = await validateRequest(ctx.req, ctx.res); + if (!user || user.rol === "user") { + return { + redirect: { + permanent: true, + destination: "/", + }, + }; + } + + return { + props: {}, + }; +} diff --git a/apps/dokploy/pages/dashboard/settings/cluster.tsx b/apps/dokploy/pages/dashboard/settings/cluster.tsx index 5551b999..b7c7ed87 100644 --- a/apps/dokploy/pages/dashboard/settings/cluster.tsx +++ b/apps/dokploy/pages/dashboard/settings/cluster.tsx @@ -1,5 +1,4 @@ import { ShowNodes } from "@/components/dashboard/settings/cluster/nodes/show-nodes"; -import { ShowRegistry } from "@/components/dashboard/settings/cluster/registry/show-registry"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { SettingsLayout } from "@/components/layouts/settings-layout"; import { IS_CLOUD, validateRequest } from "@dokploy/server"; diff --git a/apps/dokploy/server/api/root.ts b/apps/dokploy/server/api/root.ts index ad08911d..1b67d350 100644 --- a/apps/dokploy/server/api/root.ts +++ b/apps/dokploy/server/api/root.ts @@ -29,6 +29,7 @@ import { securityRouter } from "./routers/security"; import { serverRouter } from "./routers/server"; import { settingsRouter } from "./routers/settings"; import { sshRouter } from "./routers/ssh-key"; +import { stripeRouter } from "./routers/stripe"; import { userRouter } from "./routers/user"; /** @@ -69,6 +70,7 @@ export const appRouter = createTRPCRouter({ gitlab: gitlabRouter, github: githubRouter, server: serverRouter, + stripe: stripeRouter, }); // export type definition of API diff --git a/apps/dokploy/server/api/routers/stripe.ts b/apps/dokploy/server/api/routers/stripe.ts new file mode 100644 index 00000000..ec3a35df --- /dev/null +++ b/apps/dokploy/server/api/routers/stripe.ts @@ -0,0 +1,22 @@ +import Stripe from "stripe"; +import { adminProcedure, createTRPCRouter } from "../trpc"; + +export const stripeRouter = createTRPCRouter({ + getProducts: adminProcedure.query(async () => { + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", { + apiVersion: "2024-09-30.acacia", + }); + + const products = await stripe.products.list({ + expand: ["data.default_price"], + }); + console.log(products); + return products.data; + }), +}); +// { +// "Parallelism": 1, +// "Delay": 10000000000, +// "FailureAction": "rollback", +// "Order": "start-first" +// } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11189f2f..be31816a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -353,6 +353,9 @@ importers: ssh2: specifier: 1.15.0 version: 1.15.0 + stripe: + specifier: 17.2.0 + version: 17.2.0 superjson: specifier: ^2.2.1 version: 2.2.1 @@ -7641,6 +7644,10 @@ packages: strip-literal@2.1.0: resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==} + stripe@17.2.0: + resolution: {integrity: sha512-KuDplY9WrNKi07+uEFeguis/Mh+HC+hfEMy8P5snhQzCXUv01o+4KcIJ9auFxpv4Odp2R2krs9rZ9PhQl8+Sdw==} + engines: {node: '>=12.*'} + style-mod@4.1.2: resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} @@ -16297,6 +16304,11 @@ snapshots: dependencies: js-tokens: 9.0.0 + stripe@17.2.0: + dependencies: + '@types/node': 20.14.10 + qs: 6.12.3 + style-mod@4.1.2: {} style-to-object@0.4.4: