Files
kovakemlak-crm/src/lib/appwrite/workspace-actions.ts
T

106 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use server";
import { revalidatePath } from "next/cache";
import { AppwriteException, ID, Permission, Query, Role } from "node-appwrite";
import { z } from "zod";
import { logAudit } from "./audit";
import { DATABASE_ID, TABLES, type TenantSettings } from "./schema";
import { createAdminClient } from "./server";
import { requireRole, requireTenant } from "./tenant-guard";
import type { WorkspaceSettingsState } from "./workspace-types";
import { workspaceSettingsSchema } from "@/lib/validation/workspace";
function appwriteError(e: unknown): string {
if (e instanceof AppwriteException) return e.message || "Beklenmeyen hata.";
return "Bağlantı hatası. Tekrar deneyin.";
}
function flattenErrors(err: z.ZodError): Record<string, string> {
const out: Record<string, string> = {};
for (const issue of err.issues) {
const key = issue.path.join(".");
if (key && !out[key]) out[key] = issue.message;
}
return out;
}
function pickFormFields(formData: FormData) {
return {
officeName: String(formData.get("officeName") ?? "").trim(),
phone: String(formData.get("phone") ?? "").trim() || undefined,
email: String(formData.get("email") ?? "").trim() || undefined,
address: String(formData.get("address") ?? "").trim() || undefined,
defaultCurrency: String(formData.get("defaultCurrency") ?? "TRY").trim(),
};
}
export async function updateWorkspaceSettingsAction(
_prev: WorkspaceSettingsState,
formData: FormData,
): Promise<WorkspaceSettingsState> {
let ctx;
try {
ctx = await requireTenant();
requireRole(ctx, ["owner", "admin"]);
} catch {
return { ok: false, error: "Düzenleme yetkiniz yok." };
}
const fields = pickFormFields(formData);
if (!fields.officeName) {
return { ok: false, error: "Ofis adı zorunlu.", fieldErrors: { officeName: "Ofis adı zorunlu." } };
}
const parsed = { data: fields, success: true };
try {
const { tablesDB } = createAdminClient();
const existing = await tablesDB.listRows({
databaseId: DATABASE_ID,
tableId: TABLES.tenantSettings,
queries: [Query.equal("tenantId", ctx.tenantId), Query.limit(1)],
});
const row = existing.rows[0] as unknown as TenantSettings | undefined;
if (row) {
await tablesDB.updateRow(DATABASE_ID, TABLES.tenantSettings, row.$id, parsed.data);
await logAudit({
tenantId: ctx.tenantId,
userId: ctx.user.id,
action: "update",
entityType: "tenant_settings",
entityId: row.$id,
changes: parsed.data,
});
} else {
const created = await tablesDB.createRow(
DATABASE_ID,
TABLES.tenantSettings,
ID.unique(),
{ tenantId: ctx.tenantId, ...parsed.data, createdBy: ctx.user.id },
[
Permission.read(Role.team(ctx.tenantId)),
Permission.update(Role.team(ctx.tenantId, "owner")),
Permission.update(Role.team(ctx.tenantId, "admin")),
Permission.delete(Role.team(ctx.tenantId, "owner")),
],
);
await logAudit({
tenantId: ctx.tenantId,
userId: ctx.user.id,
action: "create",
entityType: "tenant_settings",
entityId: created.$id,
changes: parsed.data,
});
}
} catch (e) {
return { ok: false, error: appwriteError(e) };
}
// Tenant name shows up everywhere — revalidate broadly
revalidatePath("/", "layout");
return { ok: true };
}