753 lines
32 KiB
JavaScript
753 lines
32 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
||
import { Toast } from './Toast';
|
||
import { TemplatePreview } from './TemplatePreview';
|
||
|
||
export const DomainSetupForm = ({ defaultSubdomain }) => {
|
||
// Deployment type and app selections
|
||
const [deploymentType, setDeploymentType] = useState('app');
|
||
const [appType, setAppType] = useState('wordpress');
|
||
const [sampleWebAppType, setSampleWebAppType] = useState('developer'); // New state for sample web app type
|
||
const [sourceType, setSourceType] = useState('public');
|
||
const [repoUrl, setRepoUrl] = useState('');
|
||
const [deploymentKey, setDeploymentKey] = useState('');
|
||
const [fileName, setFileName] = useState('');
|
||
|
||
// Domain configuration
|
||
const [useSubdomain, setUseSubdomain] = useState(true);
|
||
const [useCustomDomain, setUseCustomDomain] = useState(false);
|
||
const [customDomain, setCustomDomain] = useState('');
|
||
const [customSubdomain, setCustomSubdomain] = useState('');
|
||
const [domainType, setDomainType] = useState('domain'); // 'domain' or 'subdomain'
|
||
|
||
// Domain validation states
|
||
const [isValidating, setIsValidating] = useState(false);
|
||
const [isValidDomain, setIsValidDomain] = useState(false);
|
||
const [validationMessage, setValidationMessage] = useState('');
|
||
|
||
// DNS configuration
|
||
const [dnsMethod, setDnsMethod] = useState('cname');
|
||
const [showDnsConfig, setShowDnsConfig] = useState(false);
|
||
const [dnsVerified, setDnsVerified] = useState({
|
||
cname: false,
|
||
ns: false,
|
||
a: false,
|
||
ip: false
|
||
});
|
||
|
||
// Form validation
|
||
const [formValid, setFormValid] = useState(true);
|
||
|
||
// Toast notification
|
||
const [toast, setToast] = useState({ visible: false, message: '' });
|
||
|
||
// File upload reference
|
||
const fileInputRef = React.useRef(null);
|
||
|
||
// Function to clean domain input
|
||
const cleanDomainInput = (input) => {
|
||
// Remove http://, https://, www., and trailing slashes
|
||
return input
|
||
.replace(/^(https?:\/\/)?(www\.)?/i, '')
|
||
.replace(/\/+$/, '')
|
||
.trim();
|
||
};
|
||
|
||
// Effect for handling domain type changes
|
||
useEffect(() => {
|
||
if (!useCustomDomain) {
|
||
setShowDnsConfig(false);
|
||
setIsValidDomain(false);
|
||
setValidationMessage('');
|
||
setIsValidating(false);
|
||
}
|
||
|
||
validateForm();
|
||
}, [useCustomDomain, dnsVerified.cname, dnsVerified.ns, dnsVerified.ns, domainType, dnsMethod]);
|
||
|
||
// Show toast notification
|
||
const showToast = (message) => {
|
||
setToast({ visible: true, message });
|
||
setTimeout(() => setToast({ visible: false, message: '' }), 3000);
|
||
};
|
||
|
||
// Handle deployment type change
|
||
const handleDeploymentTypeChange = (e) => {
|
||
setDeploymentType(e.target.value);
|
||
};
|
||
|
||
// Handle source type change
|
||
const handleSourceTypeChange = (e) => {
|
||
setSourceType(e.target.value);
|
||
};
|
||
|
||
// Handle file upload
|
||
const handleFileChange = (e) => {
|
||
if (e.target.files.length > 0) {
|
||
setFileName(e.target.files[0].name);
|
||
} else {
|
||
setFileName('');
|
||
}
|
||
};
|
||
|
||
// Handle domain checkbox changes
|
||
const handleUseSubdomainChange = (e) => {
|
||
setUseSubdomain(e.target.checked);
|
||
|
||
// If CNAME record is selected, SiliconPin subdomain must be enabled
|
||
if (useCustomDomain && dnsMethod === 'cname' && !e.target.checked) {
|
||
setUseCustomDomain(false);
|
||
}
|
||
|
||
validateForm();
|
||
};
|
||
|
||
const handleUseCustomDomainChange = (e) => {
|
||
setUseCustomDomain(e.target.checked);
|
||
if (!e.target.checked) {
|
||
setShowDnsConfig(false);
|
||
setIsValidDomain(false);
|
||
setValidationMessage('');
|
||
setIsValidating(false);
|
||
setDnsVerified({
|
||
cname: false,
|
||
ns: false,
|
||
a: false,
|
||
ip: false
|
||
});
|
||
} else {
|
||
// Force SiliconPin subdomain to be checked if custom domain is checked
|
||
setUseSubdomain(true);
|
||
}
|
||
|
||
validateForm();
|
||
};
|
||
|
||
// Handle domain type change
|
||
const handleDomainTypeChange = (e) => {
|
||
setDomainType(e.target.value);
|
||
|
||
// Reset validation when changing domain type
|
||
setIsValidDomain(false);
|
||
setValidationMessage('');
|
||
setDnsVerified({
|
||
cname: false,
|
||
ns: false,
|
||
a: false
|
||
});
|
||
|
||
validateForm();
|
||
};
|
||
|
||
// Handle domain and subdomain input changes
|
||
const handleDomainChange = (e) => {
|
||
const cleanedValue = cleanDomainInput(e.target.value);
|
||
setCustomDomain(cleanedValue);
|
||
};
|
||
|
||
const handleSubdomainChange = (e) => {
|
||
const cleanedValue = cleanDomainInput(e.target.value);
|
||
setCustomSubdomain(cleanedValue);
|
||
};
|
||
|
||
// Handle DNS method change
|
||
const handleDnsMethodChange = (e) => {
|
||
setDnsMethod(e.target.value);
|
||
|
||
// If changing to CNAME, ensure SiliconPin subdomain is enabled
|
||
if (e.target.value === 'cname') {
|
||
setUseSubdomain(true);
|
||
}
|
||
|
||
// Reset DNS verification
|
||
setDnsVerified(prev => ({
|
||
...prev,
|
||
[e.target.value]: false
|
||
}));
|
||
|
||
validateForm();
|
||
};
|
||
|
||
// Validate domain
|
||
const validateDomain = () => {
|
||
const domain = domainType === 'domain' ? customDomain : customSubdomain;
|
||
|
||
if (!domain) {
|
||
setValidationMessage('Please enter a domain name.');
|
||
setIsValidDomain(false);
|
||
return;
|
||
}
|
||
|
||
// Initial validation: check format with regex
|
||
const validFormat = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/.test(domain);
|
||
if (!validFormat) {
|
||
setValidationMessage('Domain format is invalid. Please check your entry.');
|
||
setIsValidDomain(false);
|
||
return;
|
||
}
|
||
|
||
setIsValidating(true);
|
||
setValidationMessage('');
|
||
setShowDnsConfig(false);
|
||
|
||
// Simulate an API call to validate the domain
|
||
setTimeout(() => {
|
||
// Simulate a real domain check - in a real app this would be an API call
|
||
const checkResult = true; // Assume domain is valid for demo
|
||
|
||
setIsValidating(false);
|
||
setIsValidDomain(checkResult);
|
||
|
||
if (checkResult) {
|
||
setValidationMessage('Domain is valid and registered.');
|
||
setShowDnsConfig(true);
|
||
} else {
|
||
setValidationMessage('Domain appears to be unregistered or unavailable.');
|
||
}
|
||
|
||
validateForm();
|
||
}, 1500);
|
||
};
|
||
|
||
// Check DNS configuration
|
||
const checkDnsConfig = (type) => {
|
||
showToast(`Checking ${type}... (This would verify DNS in a real app)`);
|
||
|
||
// Simulate DNS check
|
||
setTimeout(() => {
|
||
setDnsVerified(prev => ({
|
||
...prev,
|
||
[type]: true
|
||
}));
|
||
|
||
showToast(`${type} verified successfully!`);
|
||
validateForm();
|
||
}, 1500);
|
||
};
|
||
|
||
// Copy to clipboard
|
||
const copyToClipboard = (text) => {
|
||
navigator.clipboard.writeText(text)
|
||
.then(() => {
|
||
showToast('Copied to clipboard!');
|
||
})
|
||
.catch(err => {
|
||
showToast('Failed to copy: ' + err);
|
||
});
|
||
};
|
||
|
||
// Validate form
|
||
const validateForm = () => {
|
||
// For custom domain, require DNS verification
|
||
if (useCustomDomain) {
|
||
if (dnsMethod === 'cname' && !dnsVerified.cname) {
|
||
setFormValid(false);
|
||
return;
|
||
}
|
||
|
||
if (dnsMethod === 'ns' && !dnsVerified.ns) {
|
||
setFormValid(false);
|
||
return;
|
||
}
|
||
if (dnsMethod === 'ip' && !dnsVerified.ip) {
|
||
setFormValid(false);
|
||
return;
|
||
}
|
||
}
|
||
|
||
setFormValid(true);
|
||
};
|
||
|
||
// Handle form submission
|
||
const handleSubmit = (e) => {
|
||
e.preventDefault();
|
||
|
||
if (!formValid) {
|
||
showToast('Please complete DNS verification before deploying.');
|
||
return;
|
||
}
|
||
|
||
// In a real app, this would submit the form data to the server
|
||
console.log([{ deploymentType, appType, sampleWebAppType, sourceType, repoUrl, deploymentKey, useSubdomain, useCustomDomain, customDomain, customSubdomain, domainType, dnsMethod}]);
|
||
|
||
showToast('Form submitted successfully!');
|
||
};
|
||
|
||
return (
|
||
<div className="bg-neutral-800 rounded-lg p-6 sm:p-8 border border-neutral-700">
|
||
<form onSubmit={handleSubmit} className="space-y-6">
|
||
{/* Deployment Type Selection */}
|
||
<div className="space-y-2">
|
||
<label htmlFor="deployment-type" className="block text-white font-medium">Deployment Type</label>
|
||
<select
|
||
id="deployment-type"
|
||
value={deploymentType}
|
||
onChange={handleDeploymentTypeChange}
|
||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||
>
|
||
<option value="app">💻 Deploy an App</option>
|
||
<option value="source">⚙️ From Source</option>
|
||
<option value="static">📄 Static Site Upload</option>
|
||
<option value="sample-web-app">🌐 Sample Web App</option>
|
||
</select>
|
||
</div>
|
||
|
||
{/* App Options */}
|
||
{deploymentType === 'app' && (
|
||
<div className="space-y-2">
|
||
<label htmlFor="app-type" className="block text-white font-medium">Select Application</label>
|
||
<select
|
||
id="app-type"
|
||
value={appType}
|
||
onChange={(e) => setAppType(e.target.value)}
|
||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||
>
|
||
<option value="wordpress">🔌 WordPress</option>
|
||
<option value="prestashop">🛒 PrestaShop</option>
|
||
<option value="laravel">🚀 Laravel</option>
|
||
<option value="cakephp">🍰 CakePHP</option>
|
||
<option value="symfony">🎯 Symfony</option>
|
||
</select>
|
||
</div>
|
||
)}
|
||
|
||
{/* Sample Web App Options */}
|
||
{deploymentType === 'sample-web-app' && (
|
||
<div className="space-y-2">
|
||
<label htmlFor="sample-web-app-type" className="block text-white font-medium">Select Template Type</label>
|
||
<select
|
||
id="sample-web-app-type"
|
||
value={sampleWebAppType}
|
||
onChange={(e) => setSampleWebAppType(e.target.value)}
|
||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||
>
|
||
<option value="developer">👨💻 Developer Portfolio</option>
|
||
<option value="designer">🎨 Designer Portfolio</option>
|
||
<option value="photographer">📸 Photographer Portfolio</option>
|
||
<option value="documentation">📚 Documentation Site</option>
|
||
<option value="business">🏢 Single Page Business Site</option>
|
||
</select>
|
||
|
||
<div className="mt-4 p-4 bg-neutral-700/30 rounded-md border border-neutral-600">
|
||
<div className="flex items-start">
|
||
<div className="mr-3 text-2xl">ℹ️</div>
|
||
<div className="flex-1">
|
||
<p className="text-sm text-neutral-300">
|
||
Deploy a ready-to-use template that you can customize. We'll set up the basic structure and you can modify it to fit your needs.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Template Preview */}
|
||
<TemplatePreview templateType={sampleWebAppType} />
|
||
</div>
|
||
)}
|
||
|
||
{/* Source Options */}
|
||
{deploymentType === 'source' && (
|
||
<div className="space-y-4">
|
||
<div className="space-y-2">
|
||
<label htmlFor="source-type" className="block text-white font-medium">Source Type</label>
|
||
<select
|
||
id="source-type"
|
||
value={sourceType}
|
||
onChange={handleSourceTypeChange}
|
||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||
>
|
||
<option value="public">🌐 Public Repository</option>
|
||
<option value="private">🔒 Private Repository</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div className="pt-2">
|
||
<label htmlFor="repo-url" className="block text-white font-medium mb-2">Repository URL</label>
|
||
<input
|
||
type="text"
|
||
id="repo-url"
|
||
value={repoUrl}
|
||
onChange={(e) => setRepoUrl(e.target.value)}
|
||
placeholder="https://github.com/username/repository"
|
||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||
/>
|
||
</div>
|
||
|
||
{sourceType === 'private' && (
|
||
<div className="pt-2">
|
||
<div className="flex items-center gap-2 mb-2">
|
||
<label htmlFor="deployment-key" className="block text-white font-medium">Deployment Key</label>
|
||
<button
|
||
type="button"
|
||
onClick={() => showToast('Deployment keys are used for secure access to private repositories')}
|
||
className="text-neutral-400 hover:text-white focus:outline-none"
|
||
aria-label="Deployment Key Information"
|
||
>
|
||
<span className="text-lg">❓</span>
|
||
</button>
|
||
</div>
|
||
<textarea
|
||
id="deployment-key"
|
||
value={deploymentKey}
|
||
onChange={(e) => setDeploymentKey(e.target.value)}
|
||
placeholder="Paste your SSH private key here"
|
||
rows="6"
|
||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37] font-mono text-sm"
|
||
/>
|
||
<p className="mt-1 text-sm text-neutral-400">Your private key is used only for deploying and is never stored on our servers.</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* Static Site Options */}
|
||
{deploymentType === 'static' && (
|
||
<div className="space-y-4">
|
||
<div className="p-4 bg-neutral-700/50 rounded-md text-neutral-300 text-center">
|
||
Upload the zip file containing your static website
|
||
</div>
|
||
|
||
<div className="pt-2">
|
||
<label htmlFor="file-upload" className="block text-white font-medium mb-2">Upload File (ZIP/TAR)</label>
|
||
<div className="flex items-center justify-center w-full">
|
||
<label
|
||
htmlFor="file-upload"
|
||
className="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed rounded-lg cursor-pointer border-neutral-600 hover:border-[#6d9e37]"
|
||
>
|
||
<div className="flex flex-col items-center justify-center pt-5 pb-6">
|
||
<span className="text-3xl mb-3 text-neutral-400">📁</span>
|
||
<p className="mb-2 text-sm text-neutral-400">
|
||
<span className="font-semibold">Click to upload</span> or drag and drop
|
||
</p>
|
||
<p className="text-xs text-neutral-500">ZIP or TAR files only (max. 100MB)</p>
|
||
</div>
|
||
<input
|
||
id="file-upload"
|
||
ref={fileInputRef}
|
||
type="file"
|
||
onChange={handleFileChange}
|
||
className="hidden"
|
||
accept=".zip,.tar"
|
||
/>
|
||
</label>
|
||
</div>
|
||
{fileName && (
|
||
<div className="mt-2 text-sm text-neutral-400">
|
||
Selected file: {fileName}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Domain Configuration */}
|
||
<div className="pt-4 border-t border-neutral-700">
|
||
<h3 className="text-lg font-medium text-white mb-4">Destination</h3>
|
||
|
||
<div className="space-y-4">
|
||
{/* SiliconPin Subdomain */}
|
||
<div className="flex items-start gap-2">
|
||
<input
|
||
type="checkbox"
|
||
id="use-subdomain"
|
||
checked={useSubdomain}
|
||
onChange={handleUseSubdomainChange}
|
||
className="mt-1"
|
||
/>
|
||
<div className="flex-1">
|
||
<label htmlFor="use-subdomain" className="block text-white font-medium">Use SiliconPin Subdomain</label>
|
||
<div className="mt-2 flex">
|
||
<input
|
||
type="text"
|
||
id="subdomain"
|
||
value={defaultSubdomain}
|
||
className="rounded-l-md py-2 px-3 bg-neutral-600 border-y border-l border-neutral-600 text-neutral-300 focus:outline-none w-1/3 font-mono"
|
||
readOnly
|
||
/>
|
||
<span className="rounded-r-md py-2 px-3 bg-neutral-800 border border-neutral-700 text-neutral-400 w-2/3">.subdomain.siliconpin.com</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Custom Domain */}
|
||
<div className="flex items-start gap-2">
|
||
<input
|
||
type="checkbox"
|
||
id="use-custom-domain"
|
||
checked={useCustomDomain}
|
||
onChange={handleUseCustomDomainChange}
|
||
className="mt-1"
|
||
/>
|
||
<div className="flex-1">
|
||
<label htmlFor="use-custom-domain" className="block text-white font-medium">Use Custom Domain</label>
|
||
|
||
{useCustomDomain && (
|
||
<div className="mt-3 space-y-4">
|
||
{/* Domain Type Selection */}
|
||
<div className="flex flex-col space-y-3 sm:flex-row sm:space-y-0 sm:space-x-4">
|
||
<div className="flex items-center">
|
||
<input
|
||
type="radio"
|
||
id="domain-type-domain"
|
||
name="domain-type"
|
||
value="domain"
|
||
checked={domainType === 'domain'}
|
||
onChange={handleDomainTypeChange}
|
||
className="mr-2"
|
||
/>
|
||
<label htmlFor="domain-type-domain" className="text-white">Root Domain</label>
|
||
</div>
|
||
|
||
<div className="flex items-center">
|
||
<input
|
||
type="radio"
|
||
id="domain-type-subdomain"
|
||
name="domain-type"
|
||
value="subdomain"
|
||
checked={domainType === 'subdomain'}
|
||
onChange={handleDomainTypeChange}
|
||
className="mr-2"
|
||
/>
|
||
<label htmlFor="domain-type-subdomain" className="text-white">Subdomain</label>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Domain Input */}
|
||
{domainType === 'domain' ? (
|
||
<div>
|
||
<input
|
||
type="text"
|
||
id="custom-domain"
|
||
value={customDomain}
|
||
onChange={handleDomainChange}
|
||
placeholder="yourdomain.com"
|
||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||
/>
|
||
<p className="mt-1 text-xs text-neutral-400">
|
||
Enter domain without http://, www, or trailing slashes (example.com). You can configure www or other subdomains later.
|
||
</p>
|
||
</div>
|
||
) : (
|
||
<div>
|
||
<input
|
||
type="text"
|
||
id="custom-subdomain"
|
||
value={customSubdomain}
|
||
onChange={handleSubdomainChange}
|
||
placeholder="blog.yourdomain.com"
|
||
className="w-full rounded-md py-2 px-3 bg-neutral-700 border border-neutral-600 text-white focus:outline-none focus:ring-2 focus:ring-[#6d9e37]"
|
||
/>
|
||
<p className="mt-1 text-xs text-neutral-400">
|
||
Enter the full subdomain without http:// or trailing slashes. www and protocol prefixes will be automatically removed.
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{/* Domain Validation */}
|
||
<button
|
||
disabled={!customDomain}
|
||
type="button"
|
||
onClick={validateDomain}
|
||
className={`px-4 py-2 ${!customDomain ? 'bg-neutral-600 cursor-not-allowed' : 'bg-[#6d9e37] focus:ring-[#6d9e37] transition-colors'} text-white font-medium rounded-md transition-colors focus:outline-none`}
|
||
>
|
||
Validate Domain
|
||
</button>
|
||
|
||
{/* Validation Status */}
|
||
{useCustomDomain && isValidating && (
|
||
<div className="p-3 bg-neutral-700/50 rounded-md">
|
||
<div className="flex items-center justify-center space-x-2">
|
||
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
|
||
<p className="text-white">Verifying domain registration and availability...</p>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{useCustomDomain && !isValidating && validationMessage && (
|
||
<div className={`p-3 rounded-md ${isValidDomain ? 'bg-green-900/20 border border-green-700/50' : 'bg-red-900/20 border border-red-700/50'}`}>
|
||
<p className={isValidDomain ? 'text-green-400' : 'text-red-400'}>
|
||
{validationMessage}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{/* DNS Configuration Options */}
|
||
{showDnsConfig && (
|
||
<div className="mt-4 space-y-4 p-4 rounded-md bg-neutral-800/50 border border-neutral-700">
|
||
<h4 className="text-white font-medium">Connect Your Domain</h4>
|
||
|
||
{/* CNAME Record Option */}
|
||
<div className="p-4 bg-neutral-700/30 rounded-md border border-neutral-600 space-y-3">
|
||
<label for="dns-cname" className="flex items-start cursor-pointer">
|
||
<input
|
||
type="radio"
|
||
id="dns-cname"
|
||
name="dns-method"
|
||
value="cname"
|
||
checked={dnsMethod === 'cname'}
|
||
onChange={handleDnsMethodChange}
|
||
className="mt-1 mr-2"
|
||
/>
|
||
<div className="flex-1">
|
||
<label htmlFor="dns-cname" className="block text-white font-medium">Use CNAME Record</label>
|
||
<p className="text-sm text-neutral-300">Point your domain to our SiliconPin subdomain</p>
|
||
|
||
<div className="mt-3 flex items-center">
|
||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">
|
||
{defaultSubdomain}.subdomain.siliconpin.com
|
||
</div>
|
||
<button
|
||
type="button"
|
||
onClick={() => copyToClipboard(`${defaultSubdomain}.subdomain.siliconpin.com`)}
|
||
className="ml-2 text-[#6d9e37] hover:text-white"
|
||
aria-label="Copy CNAME value"
|
||
>
|
||
<span className="text-lg">📋</span>
|
||
</button>
|
||
</div>
|
||
<div className="mt-2 text-right">
|
||
<button
|
||
type="button"
|
||
onClick={() => checkDnsConfig('cname')}
|
||
className={`px-3 py-1 text-white text-sm rounded
|
||
${dnsVerified.cname
|
||
? 'bg-green-700 hover:bg-green-600'
|
||
: 'bg-neutral-600 hover:bg-neutral-500'}`}
|
||
>
|
||
{dnsVerified.cname ? '✓ CNAME Verified' : 'Check CNAME'}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</label>
|
||
</div>
|
||
|
||
{/* Nameserver Option (only for full domains, not subdomains) */}
|
||
{domainType === 'domain' && (
|
||
<>
|
||
<div className="p-4 bg-neutral-700/30 rounded-md border border-neutral-600 space-y-3">
|
||
<label for="dns-ns" className="flex items-start cursor-pointer">
|
||
<input
|
||
type="radio"
|
||
id="dns-ns"
|
||
name="dns-method"
|
||
value="ns"
|
||
checked={dnsMethod === 'ns'}
|
||
onChange={handleDnsMethodChange}
|
||
className="mt-1 mr-2"
|
||
/>
|
||
<div className="flex-1">
|
||
<label htmlFor="dns-ns" className="block text-white font-medium">Use Our Nameservers</label>
|
||
<p className="text-sm text-neutral-300">Update your domain's nameservers to use ours</p>
|
||
|
||
<div className="mt-3 space-y-2">
|
||
<div className="flex items-center">
|
||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">ns1.siliconpin.com</div>
|
||
<button
|
||
type="button"
|
||
onClick={() => copyToClipboard('ns1.siliconpin.com')}
|
||
className="ml-2 text-[#6d9e37] hover:text-white"
|
||
aria-label="Copy nameserver value"
|
||
>
|
||
<span className="text-lg">📋</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div className="flex items-center">
|
||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">ns2.siliconpin.com</div>
|
||
<button
|
||
type="button"
|
||
onClick={() => copyToClipboard('ns2.siliconpin.com')}
|
||
className="ml-2 text-[#6d9e37] hover:text-white"
|
||
aria-label="Copy nameserver value"
|
||
>
|
||
<span className="text-lg">📋</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="mt-2 text-right">
|
||
<button
|
||
type="button"
|
||
onClick={() => checkDnsConfig('ns')}
|
||
className={`px-3 py-1 text-white text-sm rounded
|
||
${dnsVerified.ns
|
||
? 'bg-green-700 hover:bg-green-600'
|
||
: 'bg-neutral-600 hover:bg-neutral-500'}`}
|
||
>
|
||
{dnsVerified.ns ? '✓ Nameservers Verified' : 'Check Nameservers'}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</label>
|
||
</div>
|
||
|
||
<div className="p-4 bg-neutral-700/30 rounded-md border border-neutral-600 space-y-3">
|
||
<label for="dns-ip" className="flex items-start cursor-pointer">
|
||
<input
|
||
type="radio"
|
||
id="dns-ip"
|
||
name="dns-method"
|
||
value="ip"
|
||
checked={dnsMethod === 'ip'}
|
||
onChange={handleDnsMethodChange}
|
||
className="mt-1 mr-2"
|
||
/>
|
||
<div className="flex-1">
|
||
<label htmlFor="dns-ip" className="block text-white font-medium">Use Our IP Address</label>
|
||
<p className="text-sm text-neutral-300">Update your domain's nameservers to use ours</p>
|
||
|
||
<div className="mt-3 space-y-2">
|
||
<div className="flex items-center">
|
||
<div className="bg-neutral-800 p-2 rounded font-mono text-sm text-neutral-300">xxx.xxx.x.xx</div>
|
||
<button
|
||
type="button"
|
||
onClick={() => copyToClipboard('xxx.xxx.x.xx')}
|
||
className="ml-2 text-[#6d9e37] hover:text-white"
|
||
aria-label="Copy nameserver value"
|
||
>
|
||
<span className="text-lg">📋</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div className="mt-2 text-right">
|
||
<button
|
||
type="button"
|
||
onClick={() => checkDnsConfig('ip')}
|
||
className={`px-3 py-1 text-white text-sm rounded
|
||
${dnsMethod === 'ip'
|
||
? 'bg-green-700 hover:bg-green-600'
|
||
: 'bg-neutral-600 hover:bg-neutral-500'}`}
|
||
>
|
||
{/* {dnsVerified.ip ? '✓ IP Address Verified' : 'Check IP Address'} */}
|
||
Proceed to Pay
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</label>
|
||
</div>
|
||
</>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{/* Form Submit Button */}
|
||
<button
|
||
type="submit"
|
||
disabled={useCustomDomain && !formValid}
|
||
className={`w-full mt-6 px-6 py-3 text-white font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-neutral-800
|
||
${useCustomDomain && !formValid
|
||
? 'bg-neutral-600 cursor-not-allowed'
|
||
: 'bg-[#6d9e37] hover:bg-[#598035] focus:ring-[#6d9e37] transition-colors'
|
||
}`}
|
||
>
|
||
Start the Deployment
|
||
</button>
|
||
</form>
|
||
<Toast visible={toast.visible} message={toast.message} />
|
||
</div>
|
||
);
|
||
};
|