This commit is contained in:
gpt-engineer-app[bot]
2025-12-19 16:37:01 +00:00
parent 461a14dfdc
commit cc7c330e83
13 changed files with 756 additions and 14 deletions

View File

@@ -0,0 +1,112 @@
import { useState } from 'react';
import { supabase } from '@/integrations/supabase/client';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { toast } from '@/hooks/use-toast';
import { Star } from 'lucide-react';
interface ReviewFormProps {
userId: string;
productId?: string;
type: 'consulting' | 'bootcamp' | 'webinar' | 'general';
onSuccess?: () => void;
}
export function ReviewForm({ userId, productId, type, onSuccess }: ReviewFormProps) {
const [rating, setRating] = useState(0);
const [hoverRating, setHoverRating] = useState(0);
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const [submitting, setSubmitting] = useState(false);
const handleSubmit = async () => {
if (rating === 0) {
toast({ title: 'Error', description: 'Pilih rating terlebih dahulu', variant: 'destructive' });
return;
}
if (!title.trim()) {
toast({ title: 'Error', description: 'Judul tidak boleh kosong', variant: 'destructive' });
return;
}
setSubmitting(true);
const { error } = await supabase.from('reviews').insert({
user_id: userId,
product_id: productId || null,
type,
rating,
title: title.trim(),
body: body.trim(),
is_approved: false,
});
if (error) {
toast({ title: 'Error', description: 'Gagal mengirim ulasan', variant: 'destructive' });
} else {
toast({ title: 'Berhasil', description: 'Ulasan Anda akan ditinjau oleh admin' });
setRating(0);
setTitle('');
setBody('');
onSuccess?.();
}
setSubmitting(false);
};
return (
<Card className="border-2 border-border">
<CardHeader>
<CardTitle className="text-lg">Beri Ulasan</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<label className="text-sm font-medium">Rating</label>
<div className="flex gap-1">
{[1, 2, 3, 4, 5].map((i) => (
<button
key={i}
type="button"
onClick={() => setRating(i)}
onMouseEnter={() => setHoverRating(i)}
onMouseLeave={() => setHoverRating(0)}
className="p-1 transition-transform hover:scale-110"
>
<Star
className={`w-6 h-6 ${
i <= (hoverRating || rating)
? 'fill-primary text-primary'
: 'text-muted-foreground'
}`}
/>
</button>
))}
</div>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Judul</label>
<Input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Ringkasan pengalaman Anda"
className="border-2"
maxLength={100}
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Ulasan (Opsional)</label>
<Textarea
value={body}
onChange={(e) => setBody(e.target.value)}
placeholder="Ceritakan pengalaman Anda..."
className="border-2 min-h-[80px]"
maxLength={500}
/>
</div>
<Button onClick={handleSubmit} disabled={submitting} className="w-full">
{submitting ? 'Mengirim...' : 'Kirim Ulasan'}
</Button>
</CardContent>
</Card>
);
}