diff --git a/apps/dokploy/components/dashboard/settings/billing/show-billing-invoices.tsx b/apps/dokploy/components/dashboard/settings/billing/show-billing-invoices.tsx
new file mode 100644
index 000000000..67c15ee63
--- /dev/null
+++ b/apps/dokploy/components/dashboard/settings/billing/show-billing-invoices.tsx
@@ -0,0 +1,74 @@
+import { CreditCard, FileText } from "lucide-react";
+import Link from "next/link";
+import { useRouter } from "next/router";
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card";
+import { cn } from "@/lib/utils";
+import { ShowInvoices } from "./show-invoices";
+
+const navigationItems = [
+ {
+ name: "Subscription",
+ href: "/dashboard/settings/billing",
+ icon: CreditCard,
+ },
+ {
+ name: "Invoices",
+ href: "/dashboard/settings/invoices",
+ icon: FileText,
+ },
+];
+
+export const ShowBillingInvoices = () => {
+ const router = useRouter();
+
+ return (
+
+
+
+
+
+
+ Billing
+
+
+ Manage your subscription and invoices
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx b/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx
index faa5bcdcc..1d79903cf 100644
--- a/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx
+++ b/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx
@@ -4,11 +4,13 @@ import {
AlertTriangle,
CheckIcon,
CreditCard,
+ FileText,
Loader2,
MinusIcon,
PlusIcon,
} from "lucide-react";
import Link from "next/link";
+import { useRouter } from "next/router";
import { useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@@ -24,7 +26,6 @@ import { Progress } from "@/components/ui/progress";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";
import { api } from "@/utils/api";
-import { ShowInvoices } from "./show-invoices";
const stripePromise = loadStripe(
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!,
@@ -38,7 +39,22 @@ export const calculatePrice = (count: number, isAnnual = false) => {
if (count <= 1) return 4.5;
return count * 3.5;
};
+
+const navigationItems = [
+ {
+ name: "Subscription",
+ href: "/dashboard/settings/billing",
+ icon: CreditCard,
+ },
+ {
+ name: "Invoices",
+ href: "/dashboard/settings/invoices",
+ icon: FileText,
+ },
+];
+
export const ShowBilling = () => {
+ const router = useRouter();
const { data: servers } = api.server.count.useQuery();
const { data: admin } = api.user.get.useQuery();
const { data, isLoading } = api.stripe.getProducts.useQuery();
@@ -76,252 +92,274 @@ export const ShowBilling = () => {
const safePercentage = Math.min(percentage, 100);
return (
-
-
-
-
+
+
+
+
Billing
- Manage your subscription
+
+ Manage your subscription and invoices
+
-
-
-
setIsAnnual(e === "annual")}
- >
-
- Monthly
- Annual
-
-
- {admin?.user.stripeSubscriptionId && (
-
-
Servers Plan
-
- You have {servers} server on your plan of{" "}
- {admin?.user.serversQuantity} servers
-
-
- {admin && admin.user.serversQuantity! <= (servers ?? 0) && (
-
-
-
- You have reached the maximum number of servers you can
- create, please upgrade your plan to add more servers.
-
+
+
+
+
+
setIsAnnual(e === "annual")}
+ >
+
+ Monthly
+ Annual
+
+
+ {admin?.user.stripeSubscriptionId && (
+
+
Servers Plan
+
+ You have {servers} server on your plan of{" "}
+ {admin?.user.serversQuantity} servers
+
+
+ {admin && admin.user.serversQuantity! <= (servers ?? 0) && (
+
+
+
+ You have reached the maximum number of servers you can
+ create, please upgrade your plan to add more servers.
+
+
+ )}
)}
-
- )}
-
-
- Need Help? We are here to help you.
-
-
- Join to our Discord server and we will help you.
-
-
-
- {isLoading ? (
-
- Loading...
-
-
- ) : (
- <>
- {products?.map((product) => {
- const featured = true;
- return (
-
-
+
+ Need Help? We are here to help you.
+
+
+ Join to our Discord server and we will help you.
+
+
+ );
+ })}
+ >
+ )}
+
-
- {admin?.user.stripeCustomerId &&
}
);
};
diff --git a/apps/dokploy/components/dashboard/settings/billing/show-invoices.tsx b/apps/dokploy/components/dashboard/settings/billing/show-invoices.tsx
index 513bb3dc8..73cc82efc 100644
--- a/apps/dokploy/components/dashboard/settings/billing/show-invoices.tsx
+++ b/apps/dokploy/components/dashboard/settings/billing/show-invoices.tsx
@@ -2,13 +2,6 @@ import { Download, ExternalLink, FileText, Loader2 } from "lucide-react";
import type Stripe from "stripe";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
-import {
- Card,
- CardContent,
- CardDescription,
- CardHeader,
- CardTitle,
-} from "@/components/ui/card";
import {
Table,
TableBody,
@@ -63,97 +56,82 @@ export const ShowInvoices = () => {
const { data: invoices, isLoading } = api.stripe.getInvoices.useQuery();
return (
-
-
-
-
-
- Invoices
-
-
- View and download your billing invoices
-
-
-
- {isLoading ? (
-
-
- Loading invoices...
-
-
-
- ) : invoices && invoices.length > 0 ? (
-
-
-
-
- Invoice
- Date
- Due Date
- Amount
- Status
- Actions
-
-
-
- {invoices.map((invoice) => (
-
-
- {invoice.number || invoice.id.slice(0, 12)}
-
- {formatDate(invoice.created)}
- {formatDate(invoice.dueDate)}
-
- {formatAmount(invoice.amountDue, invoice.currency)}
-
- {getStatusBadge(invoice.status)}
-
-
- {invoice.hostedInvoiceUrl && (
-
- )}
- {invoice.invoicePdf && (
-
- )}
-
-
-
- ))}
-
-
-
- ) : (
-
-
-
- No invoices found
-
-
- Your invoices will appear here once you have a subscription
-
-
- )}
-
-
-
+
+ {isLoading ? (
+
+
+ Loading invoices...
+
+
+
+ ) : invoices && invoices.length > 0 ? (
+
+
+
+
+ Invoice
+ Date
+ Due Date
+ Amount
+ Status
+ Actions
+
+
+
+ {invoices.map((invoice) => (
+
+
+ {invoice.number || invoice.id.slice(0, 12)}
+
+ {formatDate(invoice.created)}
+ {formatDate(invoice.dueDate)}
+
+ {formatAmount(invoice.amountDue, invoice.currency)}
+
+ {getStatusBadge(invoice.status)}
+
+
+ {invoice.hostedInvoiceUrl && (
+
+ )}
+ {invoice.invoicePdf && (
+
+ )}
+
+
+
+ ))}
+
+
+
+ ) : (
+
+
+
No invoices found
+
+ Your invoices will appear here once you have a subscription
+
+
+ )}
+
);
};
diff --git a/apps/dokploy/pages/dashboard/settings/invoices.tsx b/apps/dokploy/pages/dashboard/settings/invoices.tsx
new file mode 100644
index 000000000..a37c3607c
--- /dev/null
+++ b/apps/dokploy/pages/dashboard/settings/invoices.tsx
@@ -0,0 +1,63 @@
+import { IS_CLOUD } from "@dokploy/server/constants";
+import { validateRequest } from "@dokploy/server/lib/auth";
+import { createServerSideHelpers } from "@trpc/react-query/server";
+import type { GetServerSidePropsContext } from "next";
+import type { ReactElement } from "react";
+import superjson from "superjson";
+import { ShowBillingInvoices } from "@/components/dashboard/settings/billing/show-billing-invoices";
+import { DashboardLayout } from "@/components/layouts/dashboard-layout";
+import { appRouter } from "@/server/api/root";
+
+const Page = () => {
+ return ;
+};
+
+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 { req, res } = ctx;
+ const { user, session } = await validateRequest(req);
+ if (!user || user.role !== "owner") {
+ return {
+ redirect: {
+ permanent: true,
+ destination: "/",
+ },
+ };
+ }
+
+ const helpers = createServerSideHelpers({
+ router: appRouter,
+ ctx: {
+ req: req as any,
+ res: res as any,
+ db: null as any,
+ session: session as any,
+ user: user as any,
+ },
+ transformer: superjson,
+ });
+
+ await helpers.user.get.prefetch();
+
+ await helpers.settings.isCloud.prefetch();
+
+ return {
+ props: {
+ trpcState: helpers.dehydrate(),
+ },
+ };
+}