Refactor License Key Settings UI: Simplify conditional rendering for license key management, update contact link to the official site, and enhance user feedback with improved loading states for activation and validation processes.

This commit is contained in:
Mauricio Siu
2026-01-29 08:14:35 -06:00
parent 2b52332e43
commit 2e7f4dc1a2
@@ -1,4 +1,4 @@
import { Key, Loader2 } from "lucide-react"; import { Key, Loader2, ShieldCheck } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
@@ -50,34 +50,36 @@ export function LicenseKeySettings() {
<CardTitle className="text-xl">License Key</CardTitle> <CardTitle className="text-xl">License Key</CardTitle>
</div> </div>
<div className="flex items-center gap-2"> {enabled && (
<span className="text-xs text-muted-foreground"> <div className="flex items-center gap-2">
{enabled ? "Enabled" : "Disabled"} <span className="text-xs text-muted-foreground">
</span> {enabled ? "Enabled" : "Disabled"}
<Switch </span>
checked={enabled} <Switch
disabled={isLoading || isSaving || isDeactivating} checked={enabled}
onCheckedChange={async (next) => { disabled={isLoading || isSaving || isDeactivating}
try { onCheckedChange={async (next) => {
await updateEnterpriseSettings({ try {
enableEnterpriseFeatures: next, await updateEnterpriseSettings({
}); enableEnterpriseFeatures: next,
await utils.licenseKey.getEnterpriseSettings.invalidate(); });
toast.success("Enterprise features updated"); await utils.licenseKey.getEnterpriseSettings.invalidate();
} catch (error) { toast.success("Enterprise features updated");
console.error(error); } catch (error) {
toast.error("Failed to update enterprise features"); console.error(error);
} toast.error("Failed to update enterprise features");
}} }
/> }}
</div> />
</div>
)}
</div> </div>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
To unlock extra features you need an enterprise license key. To unlock extra features you need an enterprise license key.
Contact us{" "} Contact us{" "}
<Link <Link
href="http://localhost:3001/contact" href="https://dokploy.com/contact"
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
className="underline underline-offset-4" className="underline underline-offset-4"
@@ -87,104 +89,142 @@ export function LicenseKeySettings() {
. .
</p> </p>
</div> </div>
{enabled && ( {enabled ? (
<div className="grid gap-3 md:grid-cols-[1fr_auto] md:items-end"> <>
<div className="space-y-2"> <div className="grid gap-3 md:grid-cols-[1fr_auto] md:items-end">
<label className="text-sm font-medium" htmlFor="licenseKey"> <div className="space-y-2">
License Key <label className="text-sm font-medium" htmlFor="licenseKey">
</label> License Key
<Input </label>
id="licenseKey" <Input
placeholder="Enter your enterprise license key" id="licenseKey"
value={licenseKey} placeholder="Enter your enterprise license key"
onChange={(e) => setLicenseKey(e.target.value)} value={licenseKey}
/> onChange={(e) => setLicenseKey(e.target.value)}
</div> />
<div className="md:justify-self-end flex gap-2"> </div>
{haveValidLicenseKey && ( <div className="md:justify-self-end flex gap-2">
<DialogAction {haveValidLicenseKey && (
title="Deactivate License Key" <DialogAction
description="Are you sure you want to deactivate this license key? This will disable enterprise features." title="Deactivate License Key"
onClick={async () => { description="Are you sure you want to deactivate this license key? This will disable enterprise features."
try { onClick={async () => {
await deactivateLicenseKey(); try {
await utils.licenseKey.getEnterpriseSettings.invalidate(); await deactivateLicenseKey();
await utils.licenseKey.haveValidLicenseKey.invalidate(); await utils.licenseKey.getEnterpriseSettings.invalidate();
toast.success("License key deactivated"); await utils.licenseKey.haveValidLicenseKey.invalidate();
} catch (error) { toast.success("License key deactivated");
console.error(error); } catch (error) {
toast.error( console.error(error);
error instanceof Error toast.error(
? error.message error instanceof Error
: "Failed to deactivate license key", ? error.message
); : "Failed to deactivate license key",
} );
}}
disabled={isDeactivating || !haveValidLicenseKey}
>
<Button
variant="destructive"
disabled={isDeactivating || !haveValidLicenseKey}
isLoading={isDeactivating}
>
Deactivate
</Button>
</DialogAction>
)}
{haveValidLicenseKey && (
<Button
variant="outline"
disabled={
isSaving || isCheckingLicenseKey || isDeactivating
}
isLoading={isValidating}
onClick={async () => {
try {
const valid = await validateLicenseKey({ licenseKey });
console.log("valid", valid);
if (valid) {
toast.success("License key is valid");
} else {
toast.error("License key is invalid");
} }
} catch (error) { }}
console.error(error); disabled={isDeactivating || !haveValidLicenseKey}
toast.error( >
error instanceof Error <Button
? error.message variant="destructive"
: "Failed to validate license key", disabled={isDeactivating || !haveValidLicenseKey}
); isLoading={isDeactivating}
>
Deactivate
</Button>
</DialogAction>
)}
{haveValidLicenseKey && (
<Button
variant="outline"
disabled={
isSaving || isCheckingLicenseKey || isDeactivating
} }
}} isLoading={isValidating}
> onClick={async () => {
Validate try {
</Button> const valid = await validateLicenseKey({
)} licenseKey,
{!haveValidLicenseKey && ( });
<Button console.log("valid", valid);
variant="secondary" if (valid) {
disabled={isSaving || isValidating || isDeactivating} toast.success("License key is valid");
isLoading={isActivating} } else {
onClick={async () => { toast.error("License key is invalid");
try { }
await activateLicenseKey({ licenseKey }); } catch (error) {
await utils.licenseKey.getEnterpriseSettings.invalidate(); console.error(error);
await utils.licenseKey.haveValidLicenseKey.invalidate(); toast.error(
toast.success("License key activated"); error instanceof Error
} catch (error) { ? error.message
console.error(error); : "Failed to validate license key",
toast.error( );
error instanceof Error }
? error.message }}
: "Failed to activate license key", >
); Validate
} </Button>
}} )}
> {!haveValidLicenseKey && (
Activate <Button
</Button> variant="secondary"
)} disabled={isSaving || isValidating || isDeactivating}
isLoading={isActivating}
onClick={async () => {
try {
await activateLicenseKey({ licenseKey });
await utils.licenseKey.getEnterpriseSettings.invalidate();
await utils.licenseKey.haveValidLicenseKey.invalidate();
toast.success("License key activated");
} catch (error) {
console.error(error);
toast.error(
error instanceof Error
? error.message
: "Failed to activate license key",
);
}
}}
>
Activate
</Button>
)}
</div>
</div> </div>
</>
) : (
<div className="flex flex-col items-center gap-4 justify-center min-h-[30vh] text-center">
<div className="flex flex-col items-center gap-2 max-w-[400px]">
<div className="rounded-full bg-muted p-4">
<ShieldCheck className="size-8 text-muted-foreground" />
</div>
<div className="space-y-1">
<h3 className="text-lg font-semibold">Enterprise Features</h3>
<p className="text-sm text-muted-foreground">
Unlock advanced capabilities like SSO, Audit logs,
whitelabeling and more.
</p>
</div>
</div>
<Button
onClick={async () => {
try {
await updateEnterpriseSettings({
enableEnterpriseFeatures: true,
});
await utils.licenseKey.getEnterpriseSettings.invalidate();
toast.success("Enterprise features enabled");
} catch (error) {
console.error(error);
toast.error("Failed to enable enterprise features");
}
}}
isLoading={isSaving}
disabled={isLoading || isDeactivating}
>
Enable Enterprise Features
</Button>
</div> </div>
)} )}
</> </>