ai-wpa/app/feedback/feedback-client.tsx

322 lines
12 KiB
TypeScript

'use client'
import { useState } from 'react'
import { Header } from '@/components/header'
import { Footer } from '@/components/footer'
import { useAuth } from '@/contexts/AuthContext'
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 { Switch } from '@/components/ui/switch'
import { MessageSquare, AlertTriangle, Send, CheckCircle, AlertCircle } from 'lucide-react'
export function FeedbackPageClient() {
const { user } = useAuth()
const [formType, setFormType] = useState<'suggestion' | 'report'>('suggestion')
const [formData, setFormData] = useState({
name: user?.name || '',
email: user?.email || '',
title: '',
details: '',
category: 'general',
urgency: 'low'
})
const [errors, setErrors] = useState<Record<string, string>>({})
const [isSubmitting, setIsSubmitting] = useState(false)
const [isSuccess, setIsSuccess] = useState(false)
const categoryOptions = [
{ value: 'general', label: 'General' },
{ value: 'ui', label: 'User Interface' },
{ value: 'performance', label: 'Performance' },
{ value: 'feature', label: 'Feature Request' },
{ value: 'technical', label: 'Technical Issue' },
{ value: 'billing', label: 'Billing/Payment' },
{ value: 'security', label: 'Security' },
{ value: 'other', label: 'Other' }
]
const urgencyOptions = [
{ value: 'low', label: 'Low - Not urgent' },
{ value: 'medium', label: 'Medium - Needs attention' },
{ value: 'high', label: 'High - Impacts usage' },
{ value: 'critical', label: 'Critical - Service unavailable' }
]
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 = 'Please enter your name.'
if (!formData.email.trim() || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.email = 'Please enter a valid email address.'
}
if (!formData.title.trim()) newErrors.title = `Please enter a title for your ${formType}.`
if (!formData.details.trim()) newErrors.details = `Please provide details for your ${formType}.`
if (Object.keys(newErrors).length > 0) {
setErrors(newErrors)
setIsSubmitting(false)
return
}
try {
const response = await fetch('/api/feedback', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...formData,
type: formType,
siliconId: user?.id || null
}),
})
const result = await response.json()
if (response.ok && result.success) {
setIsSuccess(true)
setFormData({
name: user?.name || '',
email: user?.email || '',
title: '',
details: '',
category: 'general',
urgency: 'low'
})
setFormType('suggestion')
} 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]: '' }))
}
}
const handleTypeToggle = (checked: boolean) => {
setFormType(checked ? 'report' : 'suggestion')
setIsSuccess(false)
}
return (
<div className="min-h-screen bg-background">
<Header />
<main className="container max-w-4xl pt-24 pb-8">
{/* Page Header */}
<div className="text-center mb-12">
<h1 className="text-4xl font-bold tracking-tight mb-4">Suggestion or Report</h1>
<p className="text-xl text-muted-foreground max-w-3xl mx-auto">
We value your feedback! Use this form to submit suggestions or report any issues you've encountered.
</p>
</div>
<Card>
<CardContent className="pt-6">
{/* Success Message */}
{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">
{formType === 'suggestion'
? 'Thank you for your suggestion! We appreciate your feedback.'
: 'Your report has been submitted. We will look into it as soon as possible.'
}
</AlertDescription>
</Alert>
)}
{/* Error Message */}
{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">
{/* Form Type Toggle */}
<div className="flex items-center justify-center space-x-4 p-4 bg-muted rounded-lg">
<div className={`flex items-center space-x-2 ${formType === 'suggestion' ? 'text-primary font-medium' : 'text-muted-foreground'}`}>
<MessageSquare className="w-4 h-4" />
<span>Suggestion</span>
</div>
<Switch
checked={formType === 'report'}
onCheckedChange={handleTypeToggle}
className="data-[state=checked]:bg-orange-600"
/>
<div className={`flex items-center space-x-2 ${formType === 'report' ? 'text-orange-600 font-medium' : 'text-muted-foreground'}`}>
<AlertTriangle className="w-4 h-4" />
<span>Report</span>
</div>
</div>
{/* Name and Email */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="name">Name <span className="text-red-600">*</span></Label>
<Input
id="name"
type="text"
placeholder="Your full 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 <span className="text-red-600">*</span></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>
{/* Title */}
<div className="space-y-2">
<Label htmlFor="title">
{formType === 'suggestion' ? 'Suggestion Title' : 'Report Title'} <span className="text-red-600">*</span>
</Label>
<Input
id="title"
type="text"
placeholder={formType === 'suggestion'
? 'Brief title for your suggestion'
: 'Brief title for your report'
}
value={formData.title}
onChange={(e) => handleInputChange('title', e.target.value)}
className={errors.title ? 'border-red-500' : ''}
/>
{errors.title && (
<p className="text-sm text-red-600">{errors.title}</p>
)}
</div>
{/* Category and Urgency */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="category">Category</Label>
<Select
value={formData.category}
onValueChange={(value) => handleInputChange('category', value)}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{categoryOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* Urgency (only for reports) */}
{formType === 'report' && (
<div className="space-y-2">
<Label htmlFor="urgency">Urgency Level</Label>
<Select
value={formData.urgency}
onValueChange={(value) => handleInputChange('urgency', value)}
>
<SelectTrigger className="border-orange-200 focus:border-orange-400">
<SelectValue />
</SelectTrigger>
<SelectContent>
{urgencyOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
)}
</div>
{/* Details */}
<div className="space-y-2">
<Label htmlFor="details">Details <span className="text-red-600">*</span></Label>
<Textarea
id="details"
placeholder={formType === 'suggestion'
? 'Please describe your suggestion in detail. What would you like to see improved or added?'
: 'Please describe the issue in detail. What happened, and what were you trying to do?'
}
rows={6}
value={formData.details}
onChange={(e) => handleInputChange('details', e.target.value)}
className={errors.details ? 'border-red-500' : ''}
/>
{errors.details && (
<p className="text-sm text-red-600">{errors.details}</p>
)}
</div>
{/* Submit Button */}
<Button
type="submit"
className={`w-full md:w-auto ${formType === 'report' ? 'bg-orange-600 hover:bg-orange-700' : ''}`}
disabled={isSubmitting}
>
{isSubmitting ? (
<>
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2" />
Submitting...
</>
) : (
<>
<Send className="w-4 h-4 mr-2" />
Submit {formType === 'suggestion' ? 'Suggestion' : 'Report'}
</>
)}
</Button>
</form>
</CardContent>
</Card>
</main>
<Footer />
</div>
)
}