From 85d0255f6ff042aa10c0cc4d5a42d776f75f45fb Mon Sep 17 00:00:00 2001
From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>
Date: Thu, 20 Mar 2025 00:30:20 -0600
Subject: [PATCH] feat: implement Reset License page and update navigation
---
.../app/[locale]/reset-license/page.tsx | 77 +++++++++
apps/website/components/Header.tsx | 1 +
apps/website/components/pricing.tsx | 161 +++++++++++++++++-
apps/website/locales/en.json | 54 ++++++
4 files changed, 291 insertions(+), 2 deletions(-)
create mode 100644 apps/website/app/[locale]/reset-license/page.tsx
diff --git a/apps/website/app/[locale]/reset-license/page.tsx b/apps/website/app/[locale]/reset-license/page.tsx
new file mode 100644
index 0000000..f898edb
--- /dev/null
+++ b/apps/website/app/[locale]/reset-license/page.tsx
@@ -0,0 +1,77 @@
+"use client";
+
+import { Container } from "@/components/Container";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { useState } from "react";
+
+export default function ResetLicensePage() {
+ const [email, setEmail] = useState("");
+ const [isLoading, setIsLoading] = useState(false);
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsLoading(true);
+
+ try {
+ // Here you would add the API call to reset the license
+ // For now, we'll just simulate a success response
+ await new Promise((resolve) => setTimeout(resolve, 1500));
+
+ // toast({
+ // title: "Success!",
+ // description:
+ // "If an account exists with this email, you will receive instructions to reset your license.",
+ // variant: "default",
+ // });
+
+ setEmail("");
+ } catch (error) {
+ // toast({
+ // title: "Error",
+ // description: "Something went wrong. Please try again later.",
+ // variant: "destructive",
+ // });
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+
+
+
+ Reset Your License
+
+
+ Enter your email address and we'll send you instructions to reset your
+ license.
+
+
+
+
+
+ );
+}
diff --git a/apps/website/components/Header.tsx b/apps/website/components/Header.tsx
index b4d9e04..f105ca1 100644
--- a/apps/website/components/Header.tsx
+++ b/apps/website/components/Header.tsx
@@ -168,6 +168,7 @@ export function Header() {
{t("navigation.docs")}
{t("navigation.blog")}
+ Reset License
diff --git a/apps/website/components/pricing.tsx b/apps/website/components/pricing.tsx
index 1664d25..bb7ab57 100644
--- a/apps/website/components/pricing.tsx
+++ b/apps/website/components/pricing.tsx
@@ -87,6 +87,7 @@ export function Pricing() {
const router = useRouter();
const t = useTranslations("Pricing");
const [isAnnual, setIsAnnual] = useState(false);
+ const [isSelfHostedAnnual, setIsSelfHostedAnnual] = useState(false);
const [serverQuantity, setServerQuantity] = useState(1);
const featured = true;
@@ -176,7 +177,6 @@ export function Pricing() {
+
+ {/* Divider */}
+
+
+ {/* Self-hosted License Section */}
+
+
+
+ {t("plan.selfHosted.title")}
+
+
+ {t("plan.selfHosted.description")}
+
+
+ setIsSelfHostedAnnual(e === "annual")}
+ >
+
+
+ {t("plan.selfHosted.billingCycle.monthly")}
+
+
+ {t("plan.selfHosted.billingCycle.annual")}
+
+
+
+
+
+
+ {/* Basic License */}
+
+
+
+ {isSelfHostedAnnual
+ ? t("plan.selfHosted.basic.priceAnnual")
+ : t("plan.selfHosted.basic.priceMonthly")}{" "}
+ USD
+
+
+ / {isSelfHostedAnnual ? "year" : "month"}
+
+
+
+ {t("plan.selfHosted.basic.title")}
+
+
+ {t("plan.selfHosted.basic.description")}
+
+
+ {Object.keys(t.raw("plan.selfHosted.basic.features")).map(
+ (key) => (
+ -
+
+
+ {t(`plan.selfHosted.basic.features.${key}`)}
+
+
+ ),
+ )}
+
+
+
+
+
+
+
+ {/* Professional License */}
+
+
+
+ {isSelfHostedAnnual
+ ? t("plan.selfHosted.professional.priceAnnual")
+ : t("plan.selfHosted.professional.priceMonthly")}{" "}
+ USD
+
+
+ / {isSelfHostedAnnual ? "year" : "month"}
+
+
+
+ {t("plan.selfHosted.professional.title")}
+
+
+ {t("plan.selfHosted.professional.description")}
+
+
+ {Object.keys(
+ t.raw("plan.selfHosted.professional.features"),
+ ).map((key) => (
+ -
+
+
+ {t(`plan.selfHosted.professional.features.${key}`)}
+
+
+ ))}
+
+
+
+
+
+
+ {/* Enterprise License */}
+
+
+
+ {isSelfHostedAnnual
+ ? t("plan.selfHosted.enterprise.priceAnnual")
+ : t("plan.selfHosted.enterprise.priceMonthly")}{" "}
+ USD
+
+
+ / {isSelfHostedAnnual ? "year" : "month"}
+
+
+
+ {t("plan.selfHosted.enterprise.title")}
+
+
+ {t("plan.selfHosted.enterprise.description")}
+
+
+ {Object.keys(
+ t.raw("plan.selfHosted.enterprise.features"),
+ ).map((key) => (
+ -
+
+
+ {t(`plan.selfHosted.enterprise.features.${key}`)}
+
+
+ ))}
+
+
+
+
+
+
+
+
diff --git a/apps/website/locales/en.json b/apps/website/locales/en.json
index d4885dc..2bb6284 100644
--- a/apps/website/locales/en.json
+++ b/apps/website/locales/en.json
@@ -177,6 +177,51 @@
"f8": "New Updates"
},
"go": "Subscribe"
+ },
+ "selfHosted": {
+ "title": "Self-Hosted License",
+ "description": "Deploy and manage Dokploy on your own infrastructure with enterprise-grade features and support",
+ "basic": {
+ "title": "Basic License",
+ "description": "Perfect for small teams and startups",
+ "priceAnnual": "$89.99",
+ "priceMonthly": "$9.99",
+ "features": {
+ "f1": "Remote Servers Monitoring",
+ "f2": "Priority Support",
+ "f3": "New Updates"
+ }
+ },
+ "professional": {
+ "title": "Premium License",
+ "description": "For growing businesses",
+ "priceAnnual": "$199.99",
+ "priceMonthly": "$19.99",
+ "features": {
+ "f1": "Remote Servers Monitoring",
+ "f2": "Priority Support",
+ "f3": "New Updates",
+ "f4": "Custom branding"
+ }
+ },
+ "enterprise": {
+ "title": "Business License",
+ "description": "For large organizations",
+ "priceAnnual": "$299.99",
+ "priceMonthly": "$29.99",
+ "features": {
+ "f1": "Remote Servers Monitoring",
+ "f2": "24/7 Premium support",
+ "f3": "Security updates",
+ "f4": "Custom branding",
+ "f5": "Custom features"
+ }
+ },
+ "buyNow": "Buy Now",
+ "billingCycle": {
+ "monthly": "Monthly",
+ "annual": "Annual"
+ }
}
},
"faq": {
@@ -214,5 +259,14 @@
"backToBlog": "Back to Blog",
"tags": "Tags",
"postsTaggedWith": "Posts tagged with"
+ },
+ "Header": {
+ "signIn": "Sign in",
+ "signInCloud": "Sign in to Dokploy Cloud",
+ "pricing": "Pricing",
+ "faqs": "FAQs",
+ "docs": "Documentation",
+ "blog": "Blog",
+ "resetLicense": "Reset License"
}
}