gor-deploy/src/components/URLForm.tsx
shreerang ed08ace0a4 Improve checks and warnings while connecting to wallets (#10)
Part of https://www.notion.so/Laconic-Mainnet-Plan-1eca6b22d47280569cd0d1e6d711d949

Co-authored-by: Shreerang Kale <shreerangkale@gmail.com>
Co-authored-by: Nabarun <nabarun@deepstacksoft.com>
Reviewed-on: #10
Co-authored-by: shreerang <shreerang@noreply.git.vdb.to>
Co-committed-by: shreerang <shreerang@noreply.git.vdb.to>
2025-07-30 03:12:14 +00:00

111 lines
3.5 KiB
TypeScript

'use client';
import { useState } from 'react';
interface URLFormProps {
onSubmit: (url: string) => void;
disabled: boolean;
}
export default function URLForm({ onSubmit, disabled }: URLFormProps) {
// Get example URL from environment variables or use a default
const exampleUrl = process.env.NEXT_PUBLIC_EXAMPLE_URL || 'https://example.com';
const [url, setUrl] = useState('');
const [error, setError] = useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// Trim the URL to remove any whitespace
const trimmedUrl = url.trim();
if (!trimmedUrl) {
setError('Please enter a URL');
return;
}
// Validate URL format
try {
const parsedUrl = new URL(trimmedUrl);
// Check for protocol
if (!parsedUrl.protocol.startsWith('http')) {
setError('URL must use HTTP or HTTPS protocol');
return;
}
// Check for hostname
if (!parsedUrl.hostname || parsedUrl.hostname.length < 3) {
setError('URL must contain a valid hostname');
return;
}
// Basic sanity check for common invalid URLs
if (parsedUrl.href === 'http://localhost' || parsedUrl.href === 'https://localhost') {
setError('Please enter a valid public URL, not localhost');
return;
}
// All validations passed
setError('');
onSubmit(trimmedUrl);
} catch (error) {
console.error(error);
setError('Please enter a valid URL (e.g., https://example.com)');
}
};
return (
<form onSubmit={handleSubmit} className="w-full space-y-6">
<div className="flex flex-col">
<label htmlFor="url" className="mb-2 text-sm font-semibold" style={{ color: 'var(--foreground)' }}>
URL to Deploy
</label>
<div className="relative">
<input
id="url"
type="text"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder={exampleUrl}
className="w-full p-3 rounded-md transition-colors"
style={{
background: 'var(--card-bg)',
border: '1px solid var(--input-border)',
color: 'var(--foreground)',
opacity: disabled ? '0.6' : '1'
}}
disabled={disabled}
/>
<div className="absolute right-3 top-1/2 transform -translate-y-1/2 opacity-60">
{url && (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
</svg>
)}
</div>
</div>
{error && (
<p className="mt-2 text-sm font-medium px-3 py-2 rounded-md" style={{ color: 'var(--error)', background: 'var(--error-light)' }}>
{error}
</p>
)}
</div>
<button
type="submit"
disabled={disabled || !url}
className="w-full px-6 py-3 rounded-md transition-colors"
style={{
backgroundColor: (disabled || !url) ? 'var(--muted)' : 'var(--primary)',
color: 'var(--primary-foreground)',
opacity: (disabled || !url) ? '0.7' : '1',
}}
>
Deploy URL
</button>
</form>
);
}