"use client"; import { useState } from "react"; import { format } from "date-fns"; import { getDocumentDateFnsLocale } from "@/lib/i18n/date-fns"; import { Card, CardContent, Badge, Button, Input, Textarea, Label } from "poyraz-ui/atoms"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DialogDescription } from "poyraz-ui/molecules"; import { Phone, Mail, ExternalLink, Calendar, Plus, MessageSquare, UserPlus, Loader2, Copy } from "lucide-react"; import { toast } from "poyraz-ui/molecules"; import { addClientActivity } from "./actions"; export type ClientDetailData = { id: string; name: string; company_name: string | null; email: string | null; phone: string | null; website: string | null; pipeline_stage: string; status: string; notes: string | null; client_auth_id: string | null; portal_locale: string; }; export type ClientActivity = { id: string; type: "note" | "call" | "meeting" | "email"; title: string; content: string | null; activity_date: string; created_at: string; }; export function ClientDetailClient({ client, activities, locales, }: { client: ClientDetailData; activities: ClientActivity[]; locales: Array<{ code: string; nativeName: string; name: string }>; }) { const [isAddingActivity, setIsAddingActivity] = useState(false); const [openDialog, setOpenDialog] = useState(false); const [portalLocale, setPortalLocale] = useState(client.portal_locale); const getActivityIcon = (type: string) => { switch (type) { case "call": return ; case "meeting": return ; case "email": return ; default: return ; } }; const getActivityBadge = (type: string) => { switch (type) { case "call": return Arama; case "meeting": return Toplantı; case "email": return E-posta; default: return Not; } }; async function handleAddActivity(formData: FormData) { setIsAddingActivity(true); try { await addClientActivity(client.id, formData); setOpenDialog(false); } finally { setIsAddingActivity(false); } } const [isCreatingUser, setIsCreatingUser] = useState(false); const [createUserOpen, setCreateUserOpen] = useState(false); const [invitationUrl, setInvitationUrl] = useState(null); async function handleCreateUser(e: React.FormEvent) { e.preventDefault(); const formData = new FormData(e.currentTarget); const email = formData.get("email") as string; const locale = formData.get("locale") as string; setIsCreatingUser(true); try { const res = await fetch("/api/create-client-user", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, client_id: client.id, locale }) }); const data = await res.json(); if (!res.ok || data.error) { throw new Error(data.error || "Kullanıcı oluşturulamadı."); } setInvitationUrl(data.invitation.invitationUrl); setPortalLocale(data.invitation.locale ?? locale); toast.success("Güvenli portal daveti oluşturuldu."); } catch (error: unknown) { toast.error(error instanceof Error ? error.message : "Davet oluşturulamadı."); } finally { setIsCreatingUser(false); } } async function handlePortalLocaleChange(nextLocale: string) { setPortalLocale(nextLocale); try { const response = await fetch(`/api/portal-clients/${client.id}/locale`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ locale: nextLocale }), }); const data = await response.json(); if (!response.ok || data.error) throw new Error(data.error || "Portal dili güncellenemedi."); toast.success("Portal dili güncellendi."); } catch (error) { setPortalLocale(client.portal_locale); toast.error(error instanceof Error ? error.message : "Portal dili güncellenemedi."); } } return ( {/* Header Info */} {client.name.split(" ").slice(0, 2).map(n => n[0]?.toUpperCase()).join("")} {client.name} {client.status} {client.pipeline_stage.replace('_', ' ')} {!client.client_auth_id && ( Portal Hesabı Aç Müşteri Portalına Davet Et Müşterin bağlantıyı açıp kendi şifresini belirler. Davet 72 saat geçerlidir ve yalnızca bir kez kullanılabilir. E-posta Adresi Portal dili {locales.map((locale) => ( {locale.nativeName || locale.name} ))} {invitationUrl ? ( Davet bağlantısı { await navigator.clipboard.writeText(invitationUrl); toast.success("Davet bağlantısı kopyalandı."); }} > Bağlantı yalnızca bu ekranda düz metin olarak gösterilir. ) : null} setCreateUserOpen(false)}>İptal {isCreatingUser && } Davet Oluştur )} {client.client_auth_id && ( <> Portal Aktif {locales.map((locale) => ( {locale.nativeName || locale.name} ))} > )} {/* Left Column: Contact & Details */} İletişim Bilgileri {client.email ? ( {client.email} ) : null} {client.phone ? ( {client.phone} ) : null} {client.website ? ( {client.website.replace(/^https?:\/\//, "")} ) : null} {!client.email && !client.phone && !client.website && ( İletişim bilgisi girilmemiş. )} Genel Notlar {client.notes ? ( {client.notes} ) : ( Müşteriye ait genel not bulunmuyor. )} {/* Right Column: Activities & Timeline */} Aktivite Geçmişi Aktivite Ekle Yeni Aktivite Ekle Tip Not Arama Toplantı E-posta Başlık Tarih İçerik (Opsiyonel) {isAddingActivity ? "Ekleniyor..." : "Ekle"} {activities.length === 0 ? ( Henüz kaydedilmiş bir aktivite yok. ) : ( activities.map((activity) => ( {/* Icon */} {getActivityIcon(activity.type)} {/* Card */} {activity.title} {getActivityBadge(activity.type)} {format(new Date(activity.activity_date), "d MMM yyyy, HH:mm", { locale: getDocumentDateFnsLocale() })} {activity.content && ( {activity.content} )} )) )} ); }
Bağlantı yalnızca bu ekranda düz metin olarak gösterilir.
İletişim bilgisi girilmemiş.
{client.notes}
Müşteriye ait genel not bulunmuyor.
Henüz kaydedilmiş bir aktivite yok.
{activity.content}