import { Button, Notice, Spinner, TextControl } from '@wordpress/components'; import { useEffect, useState } from '@wordpress/element'; import { api } from '../api'; import type { DomainVerificationData, DomainVerificationStatus } from '../types'; interface DomainVerificationCardProps { connected: boolean; } function formatExpiresAt(value: string | null): string | null { if (!value) return null; const date = new Date(value); if (Number.isNaN(date.getTime())) return null; return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric', }); } function statusLabel(status: DomainVerificationStatus | null): { text: string; color: string } { switch (status) { case 'verified': return { text: 'Verified', color: '#00a32a' }; case 'failed': return { text: 'Failed', color: '#d63638' }; case 'expired': return { text: 'Expired', color: '#dba617' }; case 'pending': return { text: 'Pending', color: '#2271b1' }; default: return { text: 'Not set up', color: '#757575' }; } } export default function DomainVerificationCard({ connected }: DomainVerificationCardProps): JSX.Element | null { const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [data, setData] = useState(null); const [error, setError] = useState(null); const [copied, setCopied] = useState(false); useEffect(() => { if (!connected) { setLoading(false); return; } (async () => { try { const response = await api.get('/domain-verification'); setData(response); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to load domain verification.'; setError(message); } finally { setLoading(false); } })(); }, [connected]); if (!connected) { return null; } if (loading) { return (

Domain verification

); } const status = data?.status ?? null; const domain = data?.domain ?? null; // The backend's record_name ("mintall-verification") is not a DNS hostname - // it's the prefix baked into record_value's content. The actual TXT record // has to live on the verified domain itself (lookup(domain) in // domain_verification.py queries the bare domain, never a // "mintall-verification." subdomain), so this is never shown as a // host/name to create - doing that is exactly the bug that sent a real // merchant's DNS record to the wrong place. const recordValue = data?.record_value ?? null; const domainLabels = domain ? domain.split('.') : []; const subdomainHint = domainLabels.length > 2 ? domainLabels[0] : null; const expiresLabel = formatExpiresAt(data?.expires_at ?? null); const verifiedLabel = formatExpiresAt(data?.verified_at ?? null); const badge = statusLabel(status); const handleStart = async (): Promise => { setSubmitting(true); setError(null); try { const response = await api.post('/domain-verification/start'); setData(response); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to start domain verification.'; setError(message); } finally { setSubmitting(false); } }; const handleCheck = async (): Promise => { setSubmitting(true); setError(null); try { const response = await api.post('/domain-verification/check'); setData((prev) => ({ ...response, record_value: prev?.record_value ?? response.record_value, })); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to verify domain.'; setError(message); } finally { setSubmitting(false); } }; const handleCopy = async (): Promise => { if (!recordValue) return; try { await navigator.clipboard.writeText(recordValue); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch { // Ignore — clipboard may be unavailable. } }; const notStarted = status === null; const verified = status === 'verified'; const inProgress = !verified && !notStarted; const currentHost = data?.current_site_host ?? null; const hostIsVerifiable = data?.host_is_verifiable ?? true; const registeredDomain = domain ? domain.toLowerCase() : null; const hostMismatch = !!(currentHost && registeredDomain && currentHost !== registeredDomain); const disableActions = submitting || !hostIsVerifiable; return (

Domain verification{' '} ({badge.text})

Prove you own {domain ?? currentHost ?? 'your storefront domain'} by adding a DNS TXT record. Verified domains earn a trust boost on every product certificate.

Verification uses the customer-facing URL set in{' '} WordPress Admin → Settings → General → Site Address (URL). Set this to your custom domain before verifying — verifying a default/dev host has no effect on product trust.

{verified && verifiedLabel && (

Verified on {verifiedLabel}.

)}
{notStarted && ( )} {verified && ( )}
{!hostIsVerifiable && (
Your Site Address isn't a public domain. The current value ( {currentHost ?? 'unset'}) can't be verified via DNS. Update{' '} Settings → General → Site Address (URL) to your custom domain (for example, https://shop.example.com), then disconnect and reconnect Mintall.
)} {hostMismatch && hostIsVerifiable && (
Domain mismatch. Your WordPress Site Address is {currentHost} but Mintall is verifying {registeredDomain}. To verify the current domain, disconnect and reconnect Mintall so the new address is registered.
)} {error && (
{error}
)} {status === 'failed' && (
Token mismatch. We found a Mintall verification TXT record on{' '} {domain ?? 'your domain'}, but its value doesn't match. Confirm the TXT value matches the one shown below exactly, then try again.
)} {status === 'expired' && (
Verification token expired. Tokens are valid for a limited window. Reissue a new token and update your DNS TXT record.
)} {inProgress && (
{recordValue ? ( <>

Add a TXT record directly on {domain ?? 'your domain'} itself (not a new subdomain) with this value:

undefined} __nextHasNoMarginBottom />

In your DNS provider's Host/Name field for this record, use @ if{' '} {domain} is the domain you manage there {subdomainHint && ( <> , or just {subdomainHint} if {domain} is a subdomain of a larger zone you manage there )} . Leave the record type as TXT.

) : (

Verification is in progress for {domain ?? 'your domain'}. If you no longer have the TXT record value, reissue a new token to see it again.

)} {expiresLabel && (

Token expires {expiresLabel}. DNS changes can take up to 48 hours to propagate.

)}
)}
); }