init
This commit is contained in:
713
src/components/DomainSetupForm.jsx
Normal file
713
src/components/DomainSetupForm.jsx
Normal file
@@ -0,0 +1,713 @@
|
||||
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
|
||||
});
|
||||
|
||||
// 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, 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
|
||||
});
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
type="button"
|
||||
onClick={validateDomain}
|
||||
className="px-4 py-2 bg-neutral-600 text-white font-medium rounded-md hover:bg-neutral-500 transition-colors focus:outline-none focus:ring-2 focus:ring-neutral-500"
|
||||
>
|
||||
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">
|
||||
<div className="flex items-start">
|
||||
<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>
|
||||
</div>
|
||||
</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">
|
||||
<div className="flex items-start">
|
||||
<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>
|
||||
</div>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user