"use client" import { useState, useEffect } from "react" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import * as z from "zod" import { Customer } from "@/types/customer" import { sendBulkSms } from "@/lib/sms/actions" import { getTemplates, createTemplate, deleteTemplate, SmsTemplate } from "@/lib/sms/templates" import { Button } from "@/components/ui/button" import { Textarea } from "@/components/ui/textarea" import { Checkbox } from "@/components/ui/checkbox" import { Label } from "@/components/ui/label" import { Input } from "@/components/ui/input" import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/ui/card" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Loader2, Send, Save, Trash2, BookOpen, Smartphone } from "lucide-react" import { toast } from "sonner" import { ScrollArea } from "@/components/ui/scroll-area" const formSchema = z.object({ manualNumbers: z.string().optional(), message: z.string().min(1, "Mesaj içeriği boş olamaz").max(900, "Mesaj çok uzun (max 900 karakter)"), selectedCustomers: z.array(z.string()).optional() }) interface SmsPageProps { customers: Customer[] } export default function SmsPageClient({ customers }: SmsPageProps) { const [loading, setLoading] = useState(false) const [templates, setTemplates] = useState([]) // Template Management States const [isTemplateModalOpen, setIsTemplateModalOpen] = useState(false) const [newTemplateTitle, setNewTemplateTitle] = useState("") const [newTemplateMessage, setNewTemplateMessage] = useState("") const [templateLoading, setTemplateLoading] = useState(false) // Contact Picker States const [isContactModalOpen, setIsContactModalOpen] = useState(false) const [searchTerm, setSearchTerm] = useState("") const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { manualNumbers: "", message: "", selectedCustomers: [] }, }) async function handleNativeContactPicker() { if (!('contacts' in navigator && 'ContactsManager' in window)) { toast.error("Rehber özelliği desteklenmiyor (HTTPS gerekli olabilir).") return } try { const props = ['tel']; const opts = { multiple: true }; // eslint-disable-next-line @typescript-eslint/no-explicit-any const contacts = await (navigator as any).contacts.select(props, opts); if (contacts && contacts.length > 0) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const newNumbers = contacts.map((contact: any) => { const phone = contact.tel?.[0] return phone ? phone.replace(/\s/g, '') : null; }).filter(Boolean).join(", "); if (newNumbers) { const current = form.getValues("manualNumbers"); const updated = current ? `${current}, ${newNumbers}` : newNumbers; form.setValue("manualNumbers", updated); toast.success(`${contacts.length} numara eklendi.`); } } } catch (ex) { console.error(ex); } } // Load templates on mount useEffect(() => { loadTemplates() }, []) async function loadTemplates() { const result = await getTemplates() if (result.success && result.data) { setTemplates(result.data) } } async function handleSaveTemplate() { if (!newTemplateTitle || !newTemplateMessage) { toast.error("Başlık ve mesaj zorunludur") return } setTemplateLoading(true) const result = await createTemplate(newTemplateTitle, newTemplateMessage) setTemplateLoading(false) if (result.success) { toast.success("Şablon kaydedildi") setNewTemplateTitle("") setNewTemplateMessage("") setIsTemplateModalOpen(false) loadTemplates() } else { toast.error(result.error || "Şablon kaydedilemedi") } } async function handleDeleteTemplate(id: string) { if (!confirm("Bu şablonu silmek istediğinize emin misiniz?")) return const result = await deleteTemplate(id) if (result.success) { toast.success("Şablon silindi") loadTemplates() } else { toast.error("Şablon silinemedi") } } const handleSelectTemplate = (id: string) => { const template = templates.find(t => t.id === id) if (template) { form.setValue("message", template.message) } } // Filter customers for contact picker const filteredCustomers = customers.filter(c => c.full_name?.toLowerCase().includes(searchTerm.toLowerCase()) || c.phone?.includes(searchTerm) ) const toggleCustomerSelection = (phone: string) => { const current = form.getValues("selectedCustomers") || [] if (current.includes(phone)) { form.setValue("selectedCustomers", current.filter(p => p !== phone)) } else { form.setValue("selectedCustomers", [...current, phone]) } } const selectAllFiltered = () => { const current = form.getValues("selectedCustomers") || [] const newPhones = filteredCustomers.map(c => c.phone).filter(Boolean) as string[] // Merge unique const merged = Array.from(new Set([...current, ...newPhones])) form.setValue("selectedCustomers", merged) } const deselectAll = () => { form.setValue("selectedCustomers", []) } async function onSubmit(values: z.infer) { const manualPhones = values.manualNumbers ?.split(/[,\n]/) .map(p => p.trim()) .filter(p => p !== "") || [] const customerPhones = values.selectedCustomers || [] const allPhones = [...manualPhones, ...customerPhones] if (allPhones.length === 0) { toast.error("Lütfen en az bir alıcı seçin veya numara girin.") return } setLoading(true) try { const result = await sendBulkSms(allPhones, values.message) if (result.success) { toast.success(result.message) form.reset({ manualNumbers: "", message: "", selectedCustomers: [] }) } else { toast.error(result.error || "SMS gönderilirken hata oluştu") } } catch { toast.error("Bir hata oluştu") } finally { setLoading(false) } } const watchedSelected = form.watch("selectedCustomers") || [] return (

SMS Gönderimi

Mesaj Bilgileri Toplu veya tekil SMS gönderin. (Türkçe karakter desteklenir)
{/* Templates Section */}
Yeni SMS Şablonu Sık kullandığınız mesajları şablon olarak kaydedin.
setNewTemplateTitle(e.target.value)} />