From 0cb6ee81392af7a0684fd398f27820126df98d84 Mon Sep 17 00:00:00 2001 From: poyrazavsever Date: Mon, 20 Jul 2026 11:08:43 +0300 Subject: [PATCH] feat(i18n): integrate multilingual support into clients views and forms --- app/(dashboard)/clients/[id]/actions.ts | 11 +- .../clients/[id]/client-detail-client.tsx | 74 +++++---- app/(dashboard)/clients/[id]/page.tsx | 35 ++++- app/(dashboard)/clients/actions.ts | 12 +- app/(dashboard)/clients/clients-client.tsx | 142 ++++++++++-------- app/(dashboard)/clients/page.tsx | 36 ++++- 6 files changed, 206 insertions(+), 104 deletions(-) diff --git a/app/(dashboard)/clients/[id]/actions.ts b/app/(dashboard)/clients/[id]/actions.ts index 5d16f4a..259eaa4 100644 --- a/app/(dashboard)/clients/[id]/actions.ts +++ b/app/(dashboard)/clients/[id]/actions.ts @@ -3,6 +3,7 @@ import { revalidatePath } from "next/cache"; import { cleanText, optionalDate, requiredText } from "@/server/web/form-data"; import { requireFreelancerBackend } from "@/server/web/freelancer"; +import { parseContentTranslationsFromFormData } from "@/server/i18n/content"; const ACTIVITY_TYPES = ["note", "call", "meeting", "email"] as const; @@ -13,12 +14,18 @@ export async function addClientActivity(clientId: string, formData: FormData) { ? rawType as (typeof ACTIVITY_TYPES)[number] : "note"; + const context = service.contentTranslations.getLocalizationContext(actor); + const translations = parseContentTranslationsFromFormData(formData, "client_activity", context); + const defaultTitle = translations?.[context.defaultLocale]?.title ?? ""; + const defaultContent = translations?.[context.defaultLocale]?.content ?? ""; + service.addClientActivity(actor, { clientId, type, - title: requiredText(formData.get("title"), "Aktivite başlığı zorunludur."), - content: cleanText(formData.get("content")), + title: defaultTitle || requiredText(formData.get("title"), "Aktivite başlığı zorunludur."), + content: defaultContent || cleanText(formData.get("content")), activityDate: optionalDate(formData.get("activity_date")) ?? new Date(), + translations, }); revalidatePath(`/clients/${clientId}`); diff --git a/app/(dashboard)/clients/[id]/client-detail-client.tsx b/app/(dashboard)/clients/[id]/client-detail-client.tsx index c99a5a0..899c0b0 100644 --- a/app/(dashboard)/clients/[id]/client-detail-client.tsx +++ b/app/(dashboard)/clients/[id]/client-detail-client.tsx @@ -4,10 +4,11 @@ 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 { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DialogDescription, Tabs, TabsList, TabsTrigger, TabsContent } 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"; +import { useTranslations } from "@/components/i18n/i18n-provider"; export type ClientDetailData = { id: string; @@ -30,6 +31,7 @@ export type ClientActivity = { content: string | null; activity_date: string; created_at: string; + translations?: Record>; }; export function ClientDetailClient({ @@ -44,6 +46,7 @@ export function ClientDetailClient({ const [isAddingActivity, setIsAddingActivity] = useState(false); const [openDialog, setOpenDialog] = useState(false); const [portalLocale, setPortalLocale] = useState(client.portal_locale); + const t = useTranslations(); const getActivityIcon = (type: string) => { switch (type) { @@ -56,10 +59,10 @@ export function ClientDetailClient({ const getActivityBadge = (type: string) => { switch (type) { - case "call": return Arama; - case "meeting": return Toplantı; - case "email": return E-posta; - default: return Not; + case "call": return {t("clients.detail.activityTypes.call")}; + case "meeting": return {t("clients.detail.activityTypes.meeting")}; + case "email": return {t("clients.detail.activityTypes.email")}; + default: return {t("clients.detail.activityTypes.note")}; } }; @@ -142,7 +145,7 @@ export function ClientDetailClient({ @@ -155,11 +158,11 @@ export function ClientDetailClient({
- +
- + @@ -233,7 +236,7 @@ export function ClientDetailClient({
-

İletişim Bilgileri

+

{t("clients.detail.contactInfo")}

{client.email ? (
@@ -264,7 +267,7 @@ export function ClientDetailClient({ -

Genel Notlar

+

{t("clients.form.notes")}

{client.notes ? (

{client.notes}

) : ( @@ -284,24 +287,24 @@ export function ClientDetailClient({
- Yeni Aktivite Ekle + {t("clients.detail.addActivity")}
- +
@@ -310,17 +313,32 @@ export function ClientDetailClient({
- +
-
- -