Skip to content

Commit b835391

Browse files
authored
improvement: Show custom domain TXT record (#879)
* console logs * handle txt * Update VerifyStep.tsx * Update CustomDomain.tsx * Update VerifyStep.tsx * Update VerifyStep.tsx * cleanup * Update VerifyStep.tsx
1 parent c8b4bf6 commit b835391

File tree

2 files changed

+90
-8
lines changed

2 files changed

+90
-8
lines changed

apps/web/app/(org)/dashboard/settings/organization/components/CustomDomain.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export function CustomDomain() {
9595
className="text-red-200 size-3"
9696
icon={faExclamationCircle}
9797
/>
98-
<p className="text-white text-xs">
98+
<p className="text-xs text-white">
9999
Custom domains are not available in development mode
100100
</p>
101101
</div>
@@ -145,8 +145,8 @@ export function CustomDomain() {
145145
type="submit"
146146
size="sm"
147147
className="min-w-fit"
148-
spinner={removeDomainMutation.isPending}
149-
disabled={removeDomainMutation.isPending}
148+
spinner={isVerified ? removeDomainMutation.isPending : undefined}
149+
disabled={isVerified ? removeDomainMutation.isPending : undefined}
150150
variant="dark"
151151
onClick={async (e) => {
152152
e.preventDefault();

apps/web/app/(org)/dashboard/settings/organization/components/CustomDomainDialog/VerifyStep.tsx

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Check, Copy } from "lucide-react";
44
import { useEffect, useState } from "react";
55
import { toast } from "sonner";
66
import { useDashboardContext } from "@/app/(org)/dashboard/Contexts";
7-
import type { DomainConfig } from "./types";
7+
import type { DomainConfig, DomainVerification } from "./types";
88

99
interface VerifyStepProps {
1010
domain: string;
@@ -31,8 +31,10 @@ const VerifyStep = ({
3131
const recommendedARecord = domainConfig?.requiredAValue;
3232
const currentCnames = domainConfig?.cnames || [];
3333
const currentAValues = domainConfig?.currentAValues || [];
34+
const verificationRecords = domainConfig?.verification || [];
3435

3536
const hasRecommendedCNAME = recommendedCnames.length > 0;
37+
const hasTXTVerification = verificationRecords.length > 0;
3638

3739
const getRecommendedAValues = () => {
3840
if (recommendedARecord) return [recommendedARecord];
@@ -64,14 +66,15 @@ const VerifyStep = ({
6466

6567
const showARecord = recommendedARecord && !aRecordConfigured;
6668
const showCNAMERecord = hasRecommendedCNAME && !cnameConfigured;
69+
const showTXTRecord = hasTXTVerification && !isVerified;
6770

6871
const handleCopy = async (text: string, fieldId: string) => {
6972
try {
7073
await navigator.clipboard.writeText(text);
7174
setCopiedField(fieldId);
7275
setTimeout(() => setCopiedField(null), 2000);
7376
toast.success("Copied to clipboard");
74-
} catch (err) {
77+
} catch {
7578
toast.error("Failed to copy to clipboard");
7679
}
7780
};
@@ -91,6 +94,16 @@ const VerifyStep = ({
9194
};
9295
}, [activeOrganization?.organization.customDomain, isVerified]);
9396

97+
const TXTDomainValueHandler = (record: DomainVerification) => {
98+
if (!record.domain) return "@";
99+
if (record.domain === domain) return "@";
100+
const suffix = `.${domain}`;
101+
if (record.domain.endsWith(suffix)) {
102+
return record.domain.replace(suffix, "") || "@";
103+
}
104+
return record.domain;
105+
};
106+
94107
return (
95108
<div className="space-y-6">
96109
<div className="text-center">
@@ -112,6 +125,75 @@ const VerifyStep = ({
112125
!isVerified &&
113126
domainConfig && (
114127
<div className="space-y-4">
128+
{/* TXT Record Configuration for Verification */}
129+
{showTXTRecord && (
130+
<div className="overflow-hidden rounded-lg border border-gray-4">
131+
<div className="px-4 py-3 border-b bg-gray-2 border-gray-4">
132+
<p className="font-medium text-md text-gray-12">
133+
TXT Record Configuration
134+
</p>
135+
<p className="mt-1 text-sm text-gray-10">
136+
Add this TXT record to verify domain ownership:
137+
</p>
138+
</div>
139+
<div className="px-4 py-3">
140+
<dl className="grid gap-4">
141+
{verificationRecords.map((record, index) => (
142+
<div key={index.toString()} className="space-y-4">
143+
<div className="grid grid-cols-[100px,1fr] items-center">
144+
<dt className="text-sm font-medium text-gray-12">
145+
Type
146+
</dt>
147+
<dd className="text-sm text-gray-10">
148+
{record.type || "TXT"}
149+
</dd>
150+
</div>
151+
<div className="grid grid-cols-[100px,1fr] items-center">
152+
<dt className="text-sm font-medium text-gray-12">
153+
Name
154+
</dt>
155+
<dd className="text-sm text-gray-10">
156+
<code className="px-2 py-1 text-xs rounded bg-gray-4">
157+
{TXTDomainValueHandler(record)}
158+
</code>
159+
</dd>
160+
</div>
161+
<div className="grid grid-cols-[100px,1fr] items-center">
162+
<dt className="text-sm font-medium text-gray-12">
163+
Value
164+
</dt>
165+
<dd className="text-sm text-gray-10">
166+
<div className="flex items-center justify-between gap-1.5 bg-gray-3 px-2 py-1 rounded-lg flex-1 min-w-0 border border-gray-4">
167+
<code className="text-xs break-all text-gray-10">
168+
{record.value}
169+
</code>
170+
<button
171+
type="button"
172+
onClick={() =>
173+
handleCopy(
174+
record.value,
175+
`txt-record-${index}`,
176+
)
177+
}
178+
className="p-1 rounded-md transition-colors hover:bg-gray-1 shrink-0"
179+
title="Copy to clipboard"
180+
>
181+
{copiedField === `txt-record-${index}` ? (
182+
<Check className="size-3.5 text-green-500" />
183+
) : (
184+
<Copy className="size-3.5 text-gray-10" />
185+
)}
186+
</button>
187+
</div>
188+
</dd>
189+
</div>
190+
</div>
191+
))}
192+
</dl>
193+
</div>
194+
</div>
195+
)}
196+
115197
{/* A Record Configuration */}
116198
{showARecord && (
117199
<div className="overflow-hidden rounded-lg border border-gray-4">
@@ -134,7 +216,7 @@ const VerifyStep = ({
134216
<dd className="space-y-1.5 text-sm text-gray-10">
135217
{currentAValues.map((value, index) => (
136218
<div
137-
key={`a-${index}`}
219+
key={`a-${index.toString()}`}
138220
className={clsx(
139221
recommendedAValues.includes(value)
140222
? "flex items-center gap-2 text-green-300"
@@ -178,7 +260,7 @@ const VerifyStep = ({
178260
<dd className="space-y-2 text-sm text-gray-10">
179261
{recommendedAValues.map((ipAddress, index) => (
180262
<div
181-
key={`ip-${index}`}
263+
key={`ip-${index.toString()}`}
182264
className="flex gap-2 items-center"
183265
>
184266
<div className="flex items-center justify-between gap-1.5 bg-gray-3 px-2 py-1 rounded-lg flex-1 min-w-0 border border-gray-4">
@@ -236,7 +318,7 @@ const VerifyStep = ({
236318
<dd className="space-y-1.5 text-sm text-gray-10">
237319
{currentCnames.map((value, index) => (
238320
<div
239-
key={`cname-${index}`}
321+
key={`cname-${index.toString()}`}
240322
className={clsx(
241323
recommendedCnames.some(
242324
(rec) => rec.value === value,

0 commit comments

Comments
 (0)