import React, { useState } from 'react';
import {
CheckCircle,
AlertTriangle,
Server,
CreditCard,
Code,
Smartphone,
ArrowRight,
ShieldCheck,
Loader2,
HelpCircle,
UserCheck,
Zap,
Coffee,
Image as ImageIcon,
UploadCloud,
Copy,
Trash2,
FileUp,
Terminal,
Globe,
Printer,
X,
Link as LinkIcon,
ExternalLink,
User,
Mail,
Tag,
Info,
Eye,
Lock,
Menu,
Settings,
UserPlus
} from 'lucide-react';
// --- UI Components ---
const Card = ({ children, className = "" }) => (
{children}
);
const Button = ({ children, onClick, disabled, variant = "primary", className = "", ...props }) => {
const baseStyle = "px-6 py-3 rounded-lg font-bold transition-all duration-200 flex items-center justify-center gap-2 tracking-wide";
const styles = {
primary: "bg-stone-900 hover:bg-stone-800 text-white shadow-md disabled:opacity-50 disabled:cursor-not-allowed border border-stone-900",
secondary: "bg-stone-50 border-2 border-stone-200 text-stone-700 hover:border-stone-400 hover:bg-stone-100",
outline: "bg-transparent border border-stone-300 text-stone-700 hover:bg-stone-50",
danger: "bg-red-50 text-red-800 border border-red-200 hover:bg-red-100",
paypal: "bg-[#FFC439] hover:brightness-95 text-stone-900 shadow-sm disabled:opacity-50 disabled:cursor-not-allowed",
venmo: "bg-[#008CFF] hover:brightness-95 text-white shadow-sm disabled:opacity-50 disabled:cursor-not-allowed",
action: "px-3 py-1.5 text-xs bg-white border border-stone-200 shadow-sm hover:border-amber-500 hover:text-amber-800",
checklist: "px-8 py-4 bg-stone-100 text-stone-900 border-2 border-stone-900 font-serif italic text-lg hover:bg-stone-200 shadow-sm"
};
return (
{children}
);
};
const Input = ({ label, type = "text", value, onChange, placeholder, icon: Icon, required = false, error = "" }) => (
{label} {required && * }
onChange(e.target.value)}
className={`w-full pl-10 pr-4 py-3 border rounded-lg focus:ring-2 focus:ring-amber-600 focus:border-amber-600 transition-all bg-stone-50 focus:bg-white ${error ? 'border-red-500 ring-1 ring-red-200' : 'border-stone-300'}`}
placeholder={placeholder}
/>
{Icon && }
{error &&
{error}
}
);
export default function App() {
const [step, setStep] = useState(0);
const [deployMode, setDeployMode] = useState("concierge");
const [showChecklistModal, setShowChecklistModal] = useState(false);
const [showDelegateGuide, setShowDelegateGuide] = useState(false);
// Payment State
const [price, setPrice] = useState(99);
const [promoCode, setPromoCode] = useState("");
const [promoMessage, setPromoMessage] = useState("");
const [showPromoInput, setShowPromoInput] = useState(false);
const [formData, setFormData] = useState({
domainName: "",
gdEmail: "",
htmlCode: "",
customerName: "",
customerEmail: ""
});
const [uploadedFiles, setUploadedFiles] = useState([]);
const [codeErrors, setCodeErrors] = useState([]);
const [emailError, setEmailError] = useState("");
const [emailWarning, setEmailWarning] = useState("");
const [highlightUpload, setHighlightUpload] = useState(false);
const [deployStatus, setDeployStatus] = useState("idle");
const [paymentProcessing, setPaymentProcessing] = useState(false);
// --- Helpers ---
const handleEmailChange = (val) => {
setFormData({ ...formData, customerEmail: val });
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (val && !emailRegex.test(val)) {
setEmailError("Please enter a valid email address.");
} else {
setEmailError("");
}
if (val && formData.gdEmail && val !== formData.gdEmail) {
setEmailWarning("Note: This is different from your GoDaddy email. That's okay, just checking!");
} else {
setEmailWarning("");
}
};
const applyPromoCode = () => {
const code = promoCode.trim().toUpperCase();
if (code === "UPDATE") {
setPrice(29);
setPromoMessage("Success! Returning customer rate applied.");
} else if (code === "FRIEND") {
setPrice(84);
setPromoMessage("Success! Friend discount applied.");
} else {
setPromoMessage("Invalid code.");
setTimeout(() => setPromoMessage(""), 2000);
}
};
const handleFileUpload = (e) => {
const newFiles = Array.from(e.target.files).map(f => ({
name: f.name,
size: (f.size / 1024).toFixed(0) + 'KB',
type: f.type
}));
setUploadedFiles([...uploadedFiles, ...newFiles]);
setHighlightUpload(false);
};
const removeFile = (fileName) => {
setUploadedFiles(uploadedFiles.filter(f => f.name !== fileName));
};
const copySnippet = (fileName) => {
alert(`Copied to clipboard: `);
};
const handlePreviewCode = () => {
if (!formData.htmlCode) return;
const blob = new Blob([formData.htmlCode], { type: 'text/html' });
const url = URL.createObjectURL(blob);
window.open(url, '_blank');
};
const validateCodeAndAssets = () => {
const errors = [];
const code = formData.htmlCode;
// V23: Empty Code Check
if (!code || code.trim().length < 20) {
errors.push({ type: "empty_code", msg: "Error: Your code looks empty or too short." });
}
const srcMatches = [...code.matchAll(/src=["']([^"']+)["']/g)];
srcMatches.forEach(match => {
const srcValue = match[1];
if (srcValue.startsWith('http') || srcValue.startsWith('//') || srcValue.startsWith('data:')) return;
const fileExists = uploadedFiles.some(f => f.name === srcValue);
if (!fileExists) {
errors.push({ type: "missing_file", file: srcValue, msg: `Missing file: "${srcValue}"` });
}
});
if (code.match(/src=["'](file:|[A-Z]:\\|\/Users\/)/i)) {
errors.push({ type: "local_path", msg: "Detected a local computer link (C:/...). Please replace it." });
}
if (!code.toLowerCase().match(/paypal|venmo|stripe/)) {
errors.push({ type: "business_logic", msg: "Warning: No payment link (PayPal/Venmo) found. Are you sure?" });
}
setCodeErrors(errors);
return errors.length === 0 || errors.every(e => e.type === "business_logic");
};
const handlePayment = (provider) => {
setPaymentProcessing(true);
setTimeout(() => {
setPaymentProcessing(false);
setStep(5);
}, 2000);
};
// --- Delegate Guide Modal ---
const DelegateGuideModal = () => (
How to Grant Access
setShowDelegateGuide(false)} className="text-stone-400 hover:text-white transition-colors" aria-label="Close guide">
Account Settings
Log in to GoDaddy. Click your Name in the top right, then select Account Settings .
Account Settings
Delegate Access & Security
Click Delegate Access . GoDaddy will text a verification code to your phone. Enter it to proceed.
Verify Code
Invite to Access
Click "Invite to Access" on the right. Fill out the form exactly like this:
Name: 1845 Dev Team
Email: deploy@1845.ai
Access Level & Invite
Select "Products & Domains" and click Invite .
Products & Domains
setShowDelegateGuide(false)} className="w-full">I've Done This
);
// --- Checklist Modal Component ---
const ChecklistModal = () => (
HTMLtoWeb Checklist
setShowChecklistModal(false)} className="text-stone-400 hover:text-white transition-colors print:hidden" aria-label="Close checklist">
Have these items ready for your concierge deployment.
{[
{ icon: Globe, title: "1. Domain Name", desc: "Know exactly which URL you are updating." },
{ icon: Server, title: "2. GoDaddy Login", desc: "You will need to log in to grant us access." },
{ icon: UserCheck, title: "3. Delegate Access", desc: "We will ask you to invite 'deploy@1845.ai' in your settings." },
{ icon: Code, title: "4. Your HTML Code", desc: "Your HTML code you created and tested on Gemini or Claude." }
].map((item, i) => (
))}
window.print()} className="flex-1"> Print This
setShowChecklistModal(false)} className="flex-1">Got it
);
// --- Step 0: Preview ---
const StepPreview = () => (
HTMLtoWeb
We Deploy Your AI Code To GoDaddy
Your code is ready. You just need it online.
Secure "Delegate Access" Service. We never ask for your password.
Live within 2-4 hours of request.
{[
{ icon: CreditCard, title: "1. One-Time Fee", desc: "$99 Service Fee. Returning customers get updates for $29." },
{ icon: Code, title: "2. Paste Code", desc: "Your HTML code you created and tested on Gemini or Claude." },
{ icon: Globe, title: "3. We Deploy", desc: "Our team securely uploads your files via Delegate Access." }
].map((item, i) => (
))}
setShowChecklistModal(true)} variant="checklist">
Print Checklist
setStep(1)} className="w-full md:w-auto px-16 py-4 text-lg shadow-xl bg-stone-900 hover:bg-black border-amber-900/50">
Start Launch
I have everything & am ready to launch.
);
// --- Step 1: Checklist ---
const StepChecklist = () => (
Pre-Flight Checklist
Gather these items before we begin.
{[
{ icon: Server, title: "GoDaddy Login", desc: "Username & Password." },
{ icon: UserCheck, title: "Delegate Access", desc: "You'll invite us to access your hosting safely." },
{ icon: CreditCard, title: "Payment Method", desc: "For the $99 setup fee." }
].map((item, i) => (
))}
setStep(0)}>Back
setStep(2)} className="flex-1">I'm Ready
);
// --- Step 2: Config ---
const StepConfig = () => (
Connect Host
Securely grant access to your hosting.
Delegate Access
setShowDelegateGuide(true)}
className="text-xs bg-stone-100 hover:bg-stone-200 text-stone-700 font-bold px-3 py-1.5 rounded-full flex items-center gap-1 transition-colors"
>
Show me how
GoDaddy makes this tricky to find. Click "Show me how" above if you get stuck.
1. Go to Account Settings {'>'} Delegate Access .
2. Invite Name: 1845 Dev Team
3. Invite Email: deploy@1845.ai
4. Access Level: Products & Domains (Required).
Confirm your GoDaddy Email
setFormData({...formData, gdEmail: val})} />
We use this to verify your invitation.
setStep(1)}>Back
setStep(3)} className="flex-1" disabled={!formData.domainName || !formData.gdEmail}>Next: Upload Code
);
// --- Step 3: Editor ---
const StepEditor = () => (
Code & Assets
1. Upload Images. 2. Paste Code.
{uploadedFiles.map((file, idx) => (
{file.name}
copySnippet(file.name)} className="p-1 hover:bg-stone-100 rounded text-stone-500" title="Copy" aria-label="Copy snippet"> removeFile(file.name)} className="p-1 hover:bg-red-50 rounded text-stone-400 hover:text-red-500" aria-label="Remove file">
))}
{codeErrors.length > 0 && (
Action Required ({codeErrors.length})
)}
setStep(2)}>Back
{ if (validateCodeAndAssets()) { setStep(4); } }} className="flex-1" disabled={!formData.htmlCode}>{codeErrors.some(e => e.type !== 'business_logic') ? 'Upload Missing Files' : 'Next: Activate'}
);
// --- Step 4: Payment ---
const StepPayment = () => {
const isFormValid = formData.customerName.trim() !== "" && formData.customerEmail.trim().includes("@") && !emailError;
return (
Activate Deployment
Your code and connection are ready. Complete payment to go live.
${price}.00
{price < 99 && $99.00 }
One-time service fee
100% Money-Back Guarantee
{!showPromoInput ? (
setShowPromoInput(true)} className="text-xs text-amber-400 hover:text-amber-300 underline flex items-center gap-1"> Have a promo code?
) : (
setPromoCode(e.target.value)} />
Apply
)}
{promoMessage &&
{promoMessage}
}
{paymentProcessing ? (
Processing secure payment...
) : (
Pay & Deploy with
handlePayment('paypal')} disabled={!isFormValid} className="w-full justify-center">PayPal
handlePayment('venmo')} disabled={!isFormValid} className="w-full justify-center">venmo
)}
Note: This fee covers one deployment. Returning customers get updates at a reduced rate.
{!isFormValid &&
* Please enter Name & Valid Email to proceed.
}
setStep(3)} disabled={paymentProcessing} className="w-full text-stone-300 border-stone-700 hover:bg-stone-800 hover:text-white">Back to Code
);
};
const StepFinal = () => (
{deployStatus === 'idle' ? (
) : (
<>
Request Received!
We have received your code and payment.
Next Steps:
Please ensure you have sent the Delegate Access invite to deploy@1845.ai .
Our team will accept the invite and upload your files securely.
You will receive an email confirmation when live (usually < 2 hours).
Done
{/* V23: Support Link */}
Contact Support
>
)}
);
return (
{step > 0 && (
{[1, 2, 3, 4, 5].map((num) => (
= num ? "bg-amber-700" : "bg-stone-300"}`} />
))}
)}
{step === 0 && }
{step === 1 && }
{step === 2 && }
{step === 3 && }
{step === 4 && }
{step === 5 && }
{showChecklistModal &&
}
{showDelegateGuide &&
}
Real Sites Launched with HTMLtoWeb
{[1, 2, 3].map((i) => (
Example Site Preview
))}
© 2026 1845.ai. All rights reserved.
Disclaimer: HTMLtoWeb is a deployment automation tool provided by 1845.ai. We are not affiliated with GoDaddy Operating Company, LLC.
Users are responsible for their own hosting accounts, billing, and content. We do not store your credentials.
);
}