ai-wpa/app/services/vpn/page.tsx

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>
)
}