"use server"; import { ID, Permission, Query, Role } from "node-appwrite"; import { revalidatePath } from "next/cache"; import { customerSearchSchema } from "@/lib/validation/customer-searches"; import { DATABASE_ID, TABLES, type Property } from "./schema"; import { createAdminClient } from "./server"; import { requireTenant } from "@/lib/appwrite/tenant-guard"; import { matchPropertyToSearches } from "./matching"; type ActionState = { ok: boolean; error?: string; fieldErrors?: Record }; function toJsonList(csv?: string | null): string | undefined { if (!csv || !csv.trim()) return undefined; const items = csv .split(",") .map((s) => s.trim()) .filter(Boolean); return items.length ? JSON.stringify(items) : undefined; } async function syncMatchesForSearch(tenantId: string, userId: string): Promise { const { tablesDB } = createAdminClient(); const result = await tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.properties, queries: [ Query.equal("tenantId", tenantId), Query.equal("status", "aktif"), Query.limit(200), ], }); const properties = result.rows as unknown as Property[]; for (const property of properties) { await matchPropertyToSearches(property, tenantId, userId).catch(() => {}); } } export async function createCustomerSearchAction( _prev: ActionState, formData: FormData, ): Promise { const ctx = await requireTenant(); const raw = Object.fromEntries(formData.entries()); const parsed = customerSearchSchema.safeParse(raw); if (!parsed.success) { return { ok: false, fieldErrors: parsed.error.flatten().fieldErrors }; } const { tablesDB } = createAdminClient(); const data = parsed.data; try { await tablesDB.createRow( DATABASE_ID, TABLES.customerSearches, ID.unique(), { tenantId: ctx.tenantId, customerId: data.customerId, listingType: data.listingType || undefined, propertyTypes: toJsonList(data.propertyTypes), roomCounts: toJsonList(data.roomCounts), minPrice: data.minPrice, maxPrice: data.maxPrice, minM2: data.minM2, maxM2: data.maxM2, cities: toJsonList(data.cities), districts: toJsonList(data.districts), isActive: true, notes: data.notes, priceWeight: data.priceWeight, m2Weight: data.m2Weight, locationWeight: data.locationWeight, roomCountWeight: data.roomCountWeight, propertyTypeWeight: data.propertyTypeWeight, createdBy: ctx.user.id, }, [ Permission.read(Role.team(ctx.tenantId)), Permission.update(Role.team(ctx.tenantId)), Permission.delete(Role.team(ctx.tenantId, "owner")), Permission.delete(Role.team(ctx.tenantId, "admin")), ], ); await syncMatchesForSearch(ctx.tenantId, ctx.user.id); } catch { return { ok: false, error: "Arama kriteri oluşturulamadı." }; } revalidatePath("/customers/searches"); return { ok: true }; } export async function updateCustomerSearchAction( id: string, _prev: ActionState, formData: FormData, ): Promise { const ctx = await requireTenant(); const raw = Object.fromEntries(formData.entries()); const parsed = customerSearchSchema.safeParse(raw); if (!parsed.success) { return { ok: false, fieldErrors: parsed.error.flatten().fieldErrors }; } const { tablesDB } = createAdminClient(); const data = parsed.data; try { await tablesDB.updateRow(DATABASE_ID, TABLES.customerSearches, id, { customerId: data.customerId, listingType: data.listingType || undefined, propertyTypes: toJsonList(data.propertyTypes), roomCounts: toJsonList(data.roomCounts), minPrice: data.minPrice, maxPrice: data.maxPrice, minM2: data.minM2, maxM2: data.maxM2, cities: toJsonList(data.cities), districts: toJsonList(data.districts), notes: data.notes, priceWeight: data.priceWeight, m2Weight: data.m2Weight, locationWeight: data.locationWeight, roomCountWeight: data.roomCountWeight, propertyTypeWeight: data.propertyTypeWeight, }); await syncMatchesForSearch(ctx.tenantId, ctx.user.id); } catch { return { ok: false, error: "Arama kriteri güncellenemedi." }; } revalidatePath("/customers/searches"); return { ok: true }; } export async function toggleCustomerSearchActiveAction( id: string, isActive: boolean, ): Promise { await requireTenant(); const { tablesDB } = createAdminClient(); try { await tablesDB.updateRow(DATABASE_ID, TABLES.customerSearches, id, { isActive }); } catch { return { ok: false, error: "Durum güncellenemedi." }; } revalidatePath("/customers/searches"); return { ok: true }; } export async function deleteCustomerSearchAction(id: string): Promise { await requireTenant(); const { tablesDB } = createAdminClient(); try { await tablesDB.deleteRow(DATABASE_ID, TABLES.customerSearches, id); } catch { return { ok: false, error: "Arama kriteri silinemedi." }; } revalidatePath("/customers/searches"); return { ok: true }; }