426 lines
16 KiB
TypeScript
426 lines
16 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { useRouter } from 'next/navigation'
|
|
import { Header } from '@/components/header'
|
|
import { Footer } from '@/components/footer'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
import { Input } from '@/components/ui/input'
|
|
import { Label } from '@/components/ui/label'
|
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
|
import { Alert, AlertDescription } from '@/components/ui/alert'
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
|
import { Server, Shield, HardDrive, Globe, Mail, AlertCircle, Check, Settings } from 'lucide-react'
|
|
import { useAuth } from '@/contexts/AuthContext'
|
|
|
|
interface HostingPlan {
|
|
id: string
|
|
controlPanel: string
|
|
billingCycle: string[]
|
|
price: {
|
|
monthly: number
|
|
yearly: number
|
|
}
|
|
storage: string
|
|
bandwidth: string
|
|
domainsAllowed: string
|
|
ssl: boolean
|
|
support: string
|
|
popular?: boolean
|
|
}
|
|
|
|
export default function HostingControlPanelPage() {
|
|
const router = useRouter()
|
|
const { user } = useAuth()
|
|
const [loading, setLoading] = useState(false)
|
|
const [error, setError] = useState('')
|
|
const [billingCycle, setBillingCycle] = useState<'monthly' | 'yearly'>('monthly')
|
|
const [selectedPlan, setSelectedPlan] = useState('')
|
|
const [domain, setDomain] = useState('')
|
|
|
|
// Available hosting plans
|
|
const plans: HostingPlan[] = [
|
|
{
|
|
id: 'plan_001',
|
|
controlPanel: 'cPanel',
|
|
billingCycle: ['monthly', 'yearly'],
|
|
price: { monthly: 500, yearly: 5000 },
|
|
storage: '100 GB SSD',
|
|
bandwidth: 'Unlimited',
|
|
domainsAllowed: 'Unlimited',
|
|
ssl: true,
|
|
support: '24/7 Priority Support',
|
|
popular: true,
|
|
},
|
|
{
|
|
id: 'plan_002',
|
|
controlPanel: 'Plesk',
|
|
billingCycle: ['monthly', 'yearly'],
|
|
price: { monthly: 450, yearly: 4500 },
|
|
storage: '80 GB SSD',
|
|
bandwidth: 'Unlimited',
|
|
domainsAllowed: '50',
|
|
ssl: true,
|
|
support: '24/7 Support',
|
|
},
|
|
{
|
|
id: 'plan_003',
|
|
controlPanel: 'DirectAdmin',
|
|
billingCycle: ['monthly', 'yearly'],
|
|
price: { monthly: 350, yearly: 3500 },
|
|
storage: '60 GB SSD',
|
|
bandwidth: '2TB/month',
|
|
domainsAllowed: '25',
|
|
ssl: true,
|
|
support: 'Email & Chat',
|
|
},
|
|
{
|
|
id: 'plan_004',
|
|
controlPanel: 'HestiaCP',
|
|
billingCycle: ['monthly', 'yearly'],
|
|
price: { monthly: 199, yearly: 1999 },
|
|
storage: '50 GB SSD',
|
|
bandwidth: 'Unlimited',
|
|
domainsAllowed: 'Unlimited',
|
|
ssl: true,
|
|
support: 'Email & Chat',
|
|
},
|
|
{
|
|
id: 'plan_005',
|
|
controlPanel: 'Webmin',
|
|
billingCycle: ['monthly', 'yearly'],
|
|
price: { monthly: 149, yearly: 1499 },
|
|
storage: '40 GB SSD',
|
|
bandwidth: 'Unlimited',
|
|
domainsAllowed: '10',
|
|
ssl: true,
|
|
support: 'Email Only',
|
|
},
|
|
{
|
|
id: 'plan_006',
|
|
controlPanel: 'VestaCP',
|
|
billingCycle: ['monthly', 'yearly'],
|
|
price: { monthly: 129, yearly: 1299 },
|
|
storage: '30 GB SSD',
|
|
bandwidth: '500 GB/month',
|
|
domainsAllowed: '5',
|
|
ssl: true,
|
|
support: 'Email Only',
|
|
},
|
|
]
|
|
|
|
// Mock user balance
|
|
const userBalance = 10000
|
|
|
|
const handlePurchase = async (e: React.FormEvent) => {
|
|
e.preventDefault()
|
|
setError('')
|
|
|
|
if (!user) {
|
|
router.push('/auth?redirect=/services/hosting-control-panel')
|
|
return
|
|
}
|
|
|
|
// Validate form
|
|
if (!domain || !selectedPlan) {
|
|
setError('Please fill in all required fields')
|
|
return
|
|
}
|
|
|
|
// Validate domain format
|
|
const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/
|
|
if (!domainRegex.test(domain)) {
|
|
setError('Please enter a valid domain name')
|
|
return
|
|
}
|
|
|
|
// Get selected plan price
|
|
const plan = plans.find(p => p.id === selectedPlan)
|
|
if (!plan) {
|
|
setError('Please select a valid plan')
|
|
return
|
|
}
|
|
|
|
const totalPrice = plan.price[billingCycle]
|
|
|
|
// Check balance
|
|
if (userBalance < totalPrice) {
|
|
setError(`Insufficient balance. You need ₹${totalPrice.toFixed(2)} but only have ₹${userBalance.toFixed(2)}`)
|
|
return
|
|
}
|
|
|
|
setLoading(true)
|
|
|
|
// Simulate API call
|
|
setTimeout(() => {
|
|
setLoading(false)
|
|
alert('Hosting package purchased successfully! (This is a demo - no actual purchase)')
|
|
}, 2000)
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-background">
|
|
<Header />
|
|
|
|
<div className="container mx-auto px-4 pt-24 pb-16">
|
|
<div className="max-w-6xl mx-auto">
|
|
{/* Page Header */}
|
|
<div className="text-center mb-12">
|
|
<div className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-blue-500 to-purple-600 rounded-full mb-4">
|
|
<Settings className="w-8 h-8 text-white" />
|
|
</div>
|
|
<h1 className="text-4xl font-bold mb-4">Hosting Control Panels</h1>
|
|
<p className="text-xl text-muted-foreground">
|
|
Professional web hosting with your preferred control panel
|
|
</p>
|
|
</div>
|
|
|
|
{!user && (
|
|
<Alert className="mb-8">
|
|
<AlertCircle className="h-4 w-4" />
|
|
<AlertDescription>
|
|
You need to be logged in to purchase hosting.{' '}
|
|
<a href="/auth?redirect=/services/hosting-control-panel" className="text-primary underline">
|
|
Click here to login
|
|
</a>
|
|
</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
|
|
<form onSubmit={handlePurchase}>
|
|
<div className="space-y-8">
|
|
{/* Billing Cycle Selection */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Billing Cycle</CardTitle>
|
|
<CardDescription>Choose your preferred billing period</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Tabs value={billingCycle} onValueChange={(v) => setBillingCycle(v as 'monthly' | 'yearly')}>
|
|
<TabsList className="grid w-full grid-cols-2">
|
|
<TabsTrigger value="monthly">Monthly</TabsTrigger>
|
|
<TabsTrigger value="yearly">Yearly (Save 17%)</TabsTrigger>
|
|
</TabsList>
|
|
</Tabs>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Available Plans */}
|
|
<div>
|
|
<h2 className="text-2xl font-semibold mb-6">Choose Your Control Panel</h2>
|
|
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{plans.map((plan) => (
|
|
<Card
|
|
key={plan.id}
|
|
className={`relative cursor-pointer transition-all ${
|
|
selectedPlan === plan.id ? 'ring-2 ring-primary' : ''
|
|
} ${plan.popular ? 'border-primary' : ''}`}
|
|
onClick={() => setSelectedPlan(plan.id)}
|
|
>
|
|
{plan.popular && (
|
|
<div className="absolute -top-3 left-1/2 transform -translate-x-1/2">
|
|
<span className="bg-gradient-to-r from-blue-500 to-purple-600 text-white px-3 py-1 rounded-full text-xs font-semibold">
|
|
Most Popular
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
<CardHeader>
|
|
<CardTitle className="text-xl">{plan.controlPanel}</CardTitle>
|
|
<div className="text-2xl font-bold text-primary">
|
|
₹{plan.price[billingCycle]}
|
|
<span className="text-sm font-normal text-muted-foreground">
|
|
/{billingCycle === 'monthly' ? 'month' : 'year'}
|
|
</span>
|
|
</div>
|
|
</CardHeader>
|
|
|
|
<CardContent className="space-y-3">
|
|
<div className="space-y-2">
|
|
<div className="flex items-center gap-2">
|
|
<HardDrive className="w-4 h-4 text-muted-foreground" />
|
|
<span className="text-sm">{plan.storage}</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<Globe className="w-4 h-4 text-muted-foreground" />
|
|
<span className="text-sm">{plan.bandwidth} Bandwidth</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<Server className="w-4 h-4 text-muted-foreground" />
|
|
<span className="text-sm">{plan.domainsAllowed} Domains</span>
|
|
</div>
|
|
{plan.ssl && (
|
|
<div className="flex items-center gap-2">
|
|
<Shield className="w-4 h-4 text-green-500" />
|
|
<span className="text-sm">Free SSL Certificate</span>
|
|
</div>
|
|
)}
|
|
<div className="flex items-center gap-2">
|
|
<Mail className="w-4 h-4 text-muted-foreground" />
|
|
<span className="text-sm">{plan.support}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<RadioGroup value={selectedPlan}>
|
|
<div className="flex items-center justify-center pt-2">
|
|
<RadioGroupItem value={plan.id} id={plan.id} />
|
|
<Label htmlFor={plan.id} className="ml-2 cursor-pointer">
|
|
Select this plan
|
|
</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Domain Configuration */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Domain Configuration</CardTitle>
|
|
<CardDescription>Enter the primary domain for your hosting account</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div>
|
|
<Label htmlFor="domain">Primary Domain</Label>
|
|
<Input
|
|
id="domain"
|
|
type="text"
|
|
placeholder="example.com"
|
|
value={domain}
|
|
onChange={(e) => setDomain(e.target.value)}
|
|
required
|
|
/>
|
|
<p className="text-xs text-muted-foreground mt-1">
|
|
You can add more domains later from your control panel
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Order Summary */}
|
|
{selectedPlan && (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Order Summary</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-2">
|
|
<div className="flex justify-between">
|
|
<span className="text-muted-foreground">Control Panel</span>
|
|
<span>{plans.find(p => p.id === selectedPlan)?.controlPanel}</span>
|
|
</div>
|
|
<div className="flex justify-between">
|
|
<span className="text-muted-foreground">Billing Cycle</span>
|
|
<span className="capitalize">{billingCycle}</span>
|
|
</div>
|
|
<div className="border-t pt-2">
|
|
<div className="flex justify-between font-semibold">
|
|
<span>Total</span>
|
|
<span className="text-primary">
|
|
₹{plans.find(p => p.id === selectedPlan)?.price[billingCycle]}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div className="pt-2">
|
|
<div className="flex justify-between text-sm">
|
|
<span className="text-muted-foreground">Your Balance</span>
|
|
<span className={userBalance >= (plans.find(p => p.id === selectedPlan)?.price[billingCycle] || 0) ? 'text-green-600' : 'text-red-600'}>
|
|
₹{userBalance.toFixed(2)}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{error && (
|
|
<Alert variant="destructive">
|
|
<AlertCircle className="h-4 w-4" />
|
|
<AlertDescription>{error}</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
|
|
{/* Purchase Button */}
|
|
<Button
|
|
type="submit"
|
|
className="w-full"
|
|
size="lg"
|
|
disabled={loading || !user || !selectedPlan}
|
|
>
|
|
{loading ? 'Processing...' : 'Purchase Hosting Package'}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
|
|
{/* Features Grid */}
|
|
<div className="mt-16">
|
|
<h3 className="text-2xl font-semibold mb-8 text-center">All Plans Include</h3>
|
|
<div className="grid md:grid-cols-4 gap-6">
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<div className="text-center">
|
|
<div className="inline-flex items-center justify-center w-12 h-12 bg-primary/10 rounded-full mb-3">
|
|
<Check className="w-6 h-6 text-primary" />
|
|
</div>
|
|
<h4 className="font-semibold mb-2">One-Click Apps</h4>
|
|
<p className="text-sm text-muted-foreground">
|
|
Install WordPress, Joomla, and more with one click
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<div className="text-center">
|
|
<div className="inline-flex items-center justify-center w-12 h-12 bg-primary/10 rounded-full mb-3">
|
|
<Shield className="w-6 h-6 text-primary" />
|
|
</div>
|
|
<h4 className="font-semibold mb-2">Free SSL</h4>
|
|
<p className="text-sm text-muted-foreground">
|
|
Secure your website with free SSL certificates
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<div className="text-center">
|
|
<div className="inline-flex items-center justify-center w-12 h-12 bg-primary/10 rounded-full mb-3">
|
|
<Server className="w-6 h-6 text-primary" />
|
|
</div>
|
|
<h4 className="font-semibold mb-2">Daily Backups</h4>
|
|
<p className="text-sm text-muted-foreground">
|
|
Automatic daily backups with easy restore
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<div className="text-center">
|
|
<div className="inline-flex items-center justify-center w-12 h-12 bg-primary/10 rounded-full mb-3">
|
|
<Mail className="w-6 h-6 text-primary" />
|
|
</div>
|
|
<h4 className="font-semibold mb-2">Email Accounts</h4>
|
|
<p className="text-sm text-muted-foreground">
|
|
Create professional email addresses
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Footer />
|
|
</div>
|
|
)
|
|
} |