initial commit
This commit is contained in:
316
app/contact/contact-client.tsx
Normal file
316
app/contact/contact-client.tsx
Normal file
@@ -0,0 +1,316 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { Header } from '@/components/header'
|
||||
import { Footer } from '@/components/footer'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { Mail, Phone, MapPin, Clock, Send, CheckCircle, AlertCircle } from 'lucide-react'
|
||||
|
||||
export function ContactPageClient() {
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
email: '',
|
||||
company: '',
|
||||
service_intrest: '',
|
||||
message: ''
|
||||
})
|
||||
const [errors, setErrors] = useState<Record<string, string>>({})
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [isSuccess, setIsSuccess] = useState(false)
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setIsSubmitting(true)
|
||||
setErrors({})
|
||||
|
||||
// Client-side validation
|
||||
const newErrors: Record<string, string> = {}
|
||||
if (!formData.name.trim()) newErrors.name = 'Name is required'
|
||||
if (!formData.email.trim()) newErrors.email = 'Email is required'
|
||||
if (!formData.service_intrest) newErrors.service_intrest = 'Service interest is required'
|
||||
if (!formData.message.trim()) newErrors.message = 'Message is required'
|
||||
|
||||
if (Object.keys(newErrors).length > 0) {
|
||||
setErrors(newErrors)
|
||||
setIsSubmitting(false)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/contact', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
})
|
||||
|
||||
const result = await response.json()
|
||||
|
||||
if (response.ok && result.success) {
|
||||
setIsSuccess(true)
|
||||
setFormData({
|
||||
name: '',
|
||||
email: '',
|
||||
company: '',
|
||||
service_intrest: '',
|
||||
message: ''
|
||||
})
|
||||
} else {
|
||||
if (result.errors) {
|
||||
setErrors(result.errors)
|
||||
} else {
|
||||
setErrors({ submit: result.message || 'Error submitting form. Please try again.' })
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
setErrors({ submit: 'Network error. Please try again.' })
|
||||
} finally {
|
||||
setIsSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleInputChange = (field: string, value: string) => {
|
||||
setFormData(prev => ({ ...prev, [field]: value }))
|
||||
if (errors[field]) {
|
||||
setErrors(prev => ({ ...prev, [field]: '' }))
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
<main className="container max-w-6xl pt-24 pb-8">
|
||||
{/* Page Header */}
|
||||
<div className="text-center mb-12">
|
||||
<h1 className="text-4xl font-bold tracking-tight mb-4">Contact Us</h1>
|
||||
<p className="text-xl text-muted-foreground max-w-3xl mx-auto">
|
||||
Have questions about our hosting services? Get in touch with our team of experts.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid lg:grid-cols-3 gap-8">
|
||||
{/* Contact Form */}
|
||||
<div className="lg:col-span-2">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl flex items-center">
|
||||
<Send className="w-6 h-6 mr-2 text-blue-600" />
|
||||
Send us a message
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{isSuccess && (
|
||||
<Alert className="mb-6 border-green-200 bg-green-50 dark:bg-green-950/10">
|
||||
<CheckCircle className="h-4 w-4 text-green-600" />
|
||||
<AlertDescription className="text-green-800 dark:text-green-200">
|
||||
Thank you for your message! We'll get back to you soon.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{errors.submit && (
|
||||
<Alert className="mb-6 border-red-200 bg-red-50 dark:bg-red-950/10">
|
||||
<AlertCircle className="h-4 w-4 text-red-600" />
|
||||
<AlertDescription className="text-red-800 dark:text-red-200">
|
||||
{errors.submit}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="name">Name*</Label>
|
||||
<Input
|
||||
id="name"
|
||||
type="text"
|
||||
placeholder="Your name"
|
||||
value={formData.name}
|
||||
onChange={(e) => handleInputChange('name', e.target.value)}
|
||||
className={errors.name ? 'border-red-500' : ''}
|
||||
/>
|
||||
{errors.name && (
|
||||
<p className="text-sm text-red-600">{errors.name}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="email">Email*</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="your.email@example.com"
|
||||
value={formData.email}
|
||||
onChange={(e) => handleInputChange('email', e.target.value)}
|
||||
className={errors.email ? 'border-red-500' : ''}
|
||||
/>
|
||||
{errors.email && (
|
||||
<p className="text-sm text-red-600">{errors.email}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="company">Company</Label>
|
||||
<Input
|
||||
id="company"
|
||||
type="text"
|
||||
placeholder="Your company name"
|
||||
value={formData.company}
|
||||
onChange={(e) => handleInputChange('company', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="service_intrest">Service Interest*</Label>
|
||||
<Select
|
||||
value={formData.service_intrest}
|
||||
onValueChange={(value) => handleInputChange('service_intrest', value)}
|
||||
>
|
||||
<SelectTrigger className={errors.service_intrest ? 'border-red-500' : ''}>
|
||||
<SelectValue placeholder="Select a service" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="Web Hosting">Web Hosting</SelectItem>
|
||||
<SelectItem value="VPS Hosting">VPS Hosting</SelectItem>
|
||||
<SelectItem value="Dedicated Server">Dedicated Server</SelectItem>
|
||||
<SelectItem value="Cloud Instance">Cloud Instance</SelectItem>
|
||||
<SelectItem value="Kubernetes">Kubernetes</SelectItem>
|
||||
<SelectItem value="Control Panel">Control Panel</SelectItem>
|
||||
<SelectItem value="VPN Services">VPN Services</SelectItem>
|
||||
<SelectItem value="Human Developer">Human Developer</SelectItem>
|
||||
<SelectItem value="Others">Others</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{errors.service_intrest && (
|
||||
<p className="text-sm text-red-600">{errors.service_intrest}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="message">Message*</Label>
|
||||
<Textarea
|
||||
id="message"
|
||||
placeholder="Tell us about your project requirements..."
|
||||
rows={5}
|
||||
value={formData.message}
|
||||
onChange={(e) => handleInputChange('message', e.target.value)}
|
||||
className={errors.message ? 'border-red-500' : ''}
|
||||
/>
|
||||
{errors.message && (
|
||||
<p className="text-sm text-red-600">{errors.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full md:w-auto"
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2" />
|
||||
Sending...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Send className="w-4 h-4 mr-2" />
|
||||
Send Message
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Contact Information */}
|
||||
<div className="space-y-6">
|
||||
{/* Our Information */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-xl">Our Information</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-start space-x-3">
|
||||
<Mail className="w-5 h-5 text-blue-600 mt-0.5" />
|
||||
<div>
|
||||
<p className="font-medium">Email</p>
|
||||
<p className="text-sm text-muted-foreground">contact@siliconpin.com</p>
|
||||
<p className="text-sm text-muted-foreground">support@siliconpin.com</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start space-x-3">
|
||||
<Phone className="w-5 h-5 text-green-600 mt-0.5" />
|
||||
<div>
|
||||
<p className="font-medium">Phone</p>
|
||||
<p className="text-sm text-muted-foreground">+91-700-160-1485</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start space-x-3">
|
||||
<MapPin className="w-5 h-5 text-red-600 mt-0.5" />
|
||||
<div>
|
||||
<p className="font-medium">Address</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
121 Lalbari, GourBongo Road<br />
|
||||
Habra, West Bengal 743271<br />
|
||||
India
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Business Hours */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-xl flex items-center">
|
||||
<Clock className="w-5 h-5 mr-2 text-purple-600" />
|
||||
Business Hours
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-sm font-medium">Monday:</span>
|
||||
<span className="text-sm text-muted-foreground">Closed</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-sm font-medium">Tuesday - Friday:</span>
|
||||
<span className="text-sm text-muted-foreground">9:00 AM - 5:00 PM</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-sm font-medium">Saturday:</span>
|
||||
<span className="text-sm text-muted-foreground">10:00 AM - 4:00 PM</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-sm font-medium">Sunday:</span>
|
||||
<span className="text-sm text-muted-foreground">Closed</span>
|
||||
</div>
|
||||
<div className="border-t pt-3 mt-3">
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-sm font-medium text-green-600">Technical Support:</span>
|
||||
<span className="text-sm font-medium text-green-600">24/7</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
12
app/contact/page.tsx
Normal file
12
app/contact/page.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Metadata } from 'next'
|
||||
import { generateMetadata } from '@/lib/seo'
|
||||
import { ContactPageClient } from './contact-client'
|
||||
|
||||
export const metadata: Metadata = generateMetadata({
|
||||
title: 'Contact Us - SiliconPin',
|
||||
description: 'Have questions about our hosting services? Get in touch with our team of experts.',
|
||||
})
|
||||
|
||||
export default function ContactPage() {
|
||||
return <ContactPageClient />
|
||||
}
|
||||
Reference in New Issue
Block a user