432 lines
16 KiB
TypeScript
432 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 { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
|
import { Label } from '@/components/ui/label'
|
|
import { Alert, AlertDescription } from '@/components/ui/alert'
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
|
import { Shield, MapPin, Download, QrCode, AlertCircle, Lock, Globe, Zap, Eye } from 'lucide-react'
|
|
import { useAuth } from '@/contexts/AuthContext'
|
|
import { env } from 'process'
|
|
|
|
interface VPNLocation {
|
|
code: string
|
|
name: string
|
|
flag: string
|
|
popular?: boolean
|
|
endpoint: string
|
|
}
|
|
|
|
export default function VPNPage() {
|
|
const router = useRouter()
|
|
const { user } = useAuth()
|
|
const [loading, setLoading] = useState(false)
|
|
const [error, setError] = useState('')
|
|
const [billingCycle, setBillingCycle] = useState<'monthly' | 'yearly'>('monthly')
|
|
const [selectedLocation, setSelectedLocation] = useState('')
|
|
const [showConfig, setShowConfig] = useState(false)
|
|
const [apiEndpoint, setApiEndpoint] = useState('')
|
|
const [mockConfig, setMockConfig] = useState()
|
|
// VPN pricing
|
|
const pricing = {
|
|
monthly: 300,
|
|
yearly: 4023, // Save 17%
|
|
}
|
|
|
|
// Available VPN locations
|
|
const locations: VPNLocation[] = [
|
|
// { code: 'india', name: 'Mumbai, India', flag: '🇮🇳', popular: true },
|
|
{
|
|
code: 'america',
|
|
name: 'America, USA',
|
|
flag: '🇺🇸',
|
|
popular: true,
|
|
endpoint: 'https://wireguard-vpn.3027622.siliconpin.com/vpn',
|
|
},
|
|
{
|
|
code: 'europe',
|
|
name: 'Europe, UK',
|
|
flag: '🇬🇧',
|
|
popular: true,
|
|
endpoint: 'https://wireguard.vps20.siliconpin.com/vpn',
|
|
},
|
|
// { code: 'singapore', name: 'Singapore', flag: '🇸🇬' },
|
|
// { code: 'japan', name: 'Tokyo, Japan', flag: '🇯🇵' },
|
|
// { code: 'canada', name: 'Toronto, Canada', flag: '🇨🇦' },
|
|
]
|
|
|
|
// Mock user balance
|
|
const userBalance = 8000
|
|
|
|
const handleSetupVPN = async (e: React.FormEvent) => {
|
|
e.preventDefault()
|
|
setError('')
|
|
|
|
if (!user) {
|
|
router.push('/auth?redirect=/services/vpn')
|
|
return
|
|
}
|
|
|
|
if (!selectedLocation) {
|
|
setError('Please select a VPN location')
|
|
return
|
|
}
|
|
|
|
const totalPrice = pricing[billingCycle]
|
|
if (userBalance < totalPrice) {
|
|
setError(`Insufficient balance. You need ₹${totalPrice} but only have ₹${userBalance}`)
|
|
return
|
|
}
|
|
|
|
setLoading(true)
|
|
|
|
try {
|
|
// Generate a unique order ID (you might want to use a proper ID generation)
|
|
const orderId = `vpn-${Date.now()}`
|
|
// const orderId = `vpn-${Date.now()}-${user.id.slice(0, 8)}`
|
|
|
|
// Make API request to our backend
|
|
const response = await fetch('/api/services/deploy-vpn', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
orderId,
|
|
location: selectedLocation,
|
|
plan: billingCycle,
|
|
}),
|
|
})
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json()
|
|
throw new Error(errorData.error || 'Failed to setup VPN service')
|
|
}
|
|
|
|
const { data } = await response.json()
|
|
|
|
// Set the config content and show the config section
|
|
setMockConfig(data.config)
|
|
setShowConfig(true)
|
|
} catch (err) {
|
|
setError(err.message || 'Failed to setup VPN service')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
const downloadConfig = () => {
|
|
const blob = new Blob([mockConfig], { type: 'application/octet-stream' }) // force binary
|
|
const url = URL.createObjectURL(blob)
|
|
|
|
const a = document.createElement('a')
|
|
a.href = url
|
|
// quote filename properly
|
|
a.setAttribute('download', `siliconpin-vpn-${selectedLocation}.conf`)
|
|
a.setAttribute('type', 'application/octet-stream')
|
|
|
|
document.body.appendChild(a)
|
|
a.click()
|
|
document.body.removeChild(a)
|
|
URL.revokeObjectURL(url)
|
|
}
|
|
|
|
console.log('selectedLocation', selectedLocation)
|
|
|
|
return (
|
|
<div className="min-h-screen bg-background">
|
|
<Header />
|
|
|
|
<div className="container mx-auto px-4 pt-24 pb-16">
|
|
<div className="max-w-4xl 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">
|
|
<Shield className="w-8 h-8 text-white" />
|
|
</div>
|
|
<h1 className="text-4xl font-bold mb-4">WireGuard VPN</h1>
|
|
<p className="text-xl text-muted-foreground">
|
|
Secure, fast, and private VPN service with WireGuard protocol
|
|
</p>
|
|
</div>
|
|
|
|
{!user && (
|
|
<Alert className="mb-8">
|
|
<AlertCircle className="h-4 w-4" />
|
|
<AlertDescription>
|
|
You need to be logged in to setup VPN.{' '}
|
|
<a href="/auth?redirect=/services/vpn" className="text-primary underline">
|
|
Click here to login
|
|
</a>
|
|
</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
|
|
{!showConfig ? (
|
|
<form onSubmit={handleSetupVPN}>
|
|
<div className="space-y-8">
|
|
{/* Billing Cycle */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Billing Plan</CardTitle>
|
|
<CardDescription>Choose your preferred billing cycle</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 - ₹{pricing.monthly}</TabsTrigger>
|
|
<TabsTrigger value="yearly">
|
|
Yearly - ₹{pricing.yearly} (Save 17%)
|
|
</TabsTrigger>
|
|
</TabsList>
|
|
</Tabs>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Location Selection */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Select VPN Location</CardTitle>
|
|
<CardDescription>
|
|
Choose the server location for your VPN connection
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<RadioGroup value={selectedLocation} onValueChange={setSelectedLocation}>
|
|
<div className="grid md:grid-cols-2 gap-4">
|
|
{locations.map((location) => (
|
|
<div key={location.code} className="relative">
|
|
<RadioGroupItem
|
|
value={location.code}
|
|
id={location.code}
|
|
className="peer sr-only"
|
|
/>
|
|
<Label
|
|
htmlFor={location.code}
|
|
className={`flex items-center justify-between p-4 border-2 rounded-lg cursor-pointer transition-all hover:border-primary/50 peer-checked:border-primary peer-checked:bg-primary/5 ${
|
|
location.popular ? 'border-primary/30' : 'border-border'
|
|
}`}
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-2xl">{location.flag}</span>
|
|
<div>
|
|
<div className="font-medium">{location.name}</div>
|
|
{location.popular && (
|
|
<div className="text-xs text-primary font-medium">
|
|
Most Popular
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<MapPin className="w-4 h-4 text-muted-foreground" />
|
|
</Label>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</RadioGroup>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Order Summary */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Order Summary</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-2">
|
|
<div className="flex justify-between">
|
|
<span className="text-muted-foreground">WireGuard VPN</span>
|
|
<span>₹{pricing[billingCycle]}</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">₹{pricing[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 >= pricing[billingCycle]
|
|
? '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>
|
|
)}
|
|
|
|
{/* Setup Button */}
|
|
<Button type="submit" className="w-full" size="lg" disabled={loading || !user}>
|
|
{loading ? 'Setting up VPN...' : 'Setup VPN Service'}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
) : (
|
|
/* VPN Configuration */
|
|
<div className="space-y-8">
|
|
<Alert>
|
|
<Shield className="h-4 w-4" />
|
|
<AlertDescription>
|
|
Your VPN service has been activated! Download the configuration file below.
|
|
</AlertDescription>
|
|
</Alert>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>VPN Configuration</CardTitle>
|
|
<CardDescription>
|
|
Use this configuration with any WireGuard client
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
{/* Config File */}
|
|
<div>
|
|
<Label>Configuration File</Label>
|
|
<div className="mt-2 p-4 bg-muted rounded-lg">
|
|
<pre className="text-xs font-mono whitespace-pre-wrap text-muted-foreground">
|
|
{mockConfig}
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Download Buttons */}
|
|
<div className="flex flex-col sm:flex-row gap-4">
|
|
<Button onClick={downloadConfig} className="flex-1">
|
|
<Download className="w-4 h-4 mr-2" />
|
|
Download Config File
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
className="flex-1"
|
|
onClick={() => alert('QR Code functionality would be implemented here')}
|
|
>
|
|
<QrCode className="w-4 h-4 mr-2" />
|
|
Show QR Code
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Reset */}
|
|
<div className="pt-4 border-t">
|
|
<Button
|
|
variant="outline"
|
|
onClick={() => setShowConfig(false)}
|
|
className="w-full"
|
|
>
|
|
Setup New VPN
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Setup Instructions */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Setup Instructions</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="space-y-3">
|
|
<h4 className="font-medium">For Desktop/Laptop:</h4>
|
|
<ol className="text-sm space-y-1 list-decimal list-inside text-muted-foreground">
|
|
<li>Download and install WireGuard client from wireguard.com</li>
|
|
<li>Import the downloaded configuration file</li>
|
|
<li>Click "Activate" to connect to the VPN</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<h4 className="font-medium">For Mobile:</h4>
|
|
<ol className="text-sm space-y-1 list-decimal list-inside text-muted-foreground">
|
|
<li>Install WireGuard app from App Store/Play Store</li>
|
|
<li>Scan the QR code or import the config file</li>
|
|
<li>Toggle the connection on</li>
|
|
</ol>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)}
|
|
|
|
{/* Features */}
|
|
{!showConfig && (
|
|
<div className="mt-16 grid md:grid-cols-4 gap-6">
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<div className="text-center">
|
|
<Zap className="w-8 h-8 text-primary mx-auto mb-3" />
|
|
<h4 className="font-semibold mb-2">Lightning Fast</h4>
|
|
<p className="text-sm text-muted-foreground">
|
|
WireGuard protocol for maximum speed
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<div className="text-center">
|
|
<Eye className="w-8 h-8 text-primary mx-auto mb-3" />
|
|
<h4 className="font-semibold mb-2">No Logs Policy</h4>
|
|
<p className="text-sm text-muted-foreground">
|
|
We don't track or store your activity
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<div className="text-center">
|
|
<Lock className="w-8 h-8 text-primary mx-auto mb-3" />
|
|
<h4 className="font-semibold mb-2">Strong Encryption</h4>
|
|
<p className="text-sm text-muted-foreground">
|
|
ChaCha20 encryption for security
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<div className="text-center">
|
|
<Globe className="w-8 h-8 text-primary mx-auto mb-3" />
|
|
<h4 className="font-semibold mb-2">Multiple Locations</h4>
|
|
<p className="text-sm text-muted-foreground">Servers across the globe</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<Footer />
|
|
</div>
|
|
)
|
|
}
|