@@ -4,7 +4,7 @@ import { Check, Copy } from "lucide-react";
44import { useEffect , useState } from "react" ;
55import { toast } from "sonner" ;
66import { useDashboardContext } from "@/app/(org)/dashboard/Contexts" ;
7- import type { DomainConfig } from "./types" ;
7+ import type { DomainConfig , DomainVerification } from "./types" ;
88
99interface 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