feat: leads module — kanban board, aktiviteler, takvim entegrasyonu, müşteriye dönüştür

This commit is contained in:
kovakmedya
2026-05-01 03:26:31 +03:00
parent 9e1355a137
commit ea3d6f6045
13 changed files with 1590 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
import type { Metadata } from "next";
import { redirect } from "next/navigation";
import { listLeads } from "@/lib/appwrite/lead-queries";
import { createAdminClient } from "@/lib/appwrite/server";
import { requireTenant } from "@/lib/appwrite/tenant-guard";
import { LeadsBoard } from "./components/leads-board";
import type { LeadRow } from "./components/types";
export const metadata: Metadata = {
title: "İşletmem — Müşteri Adayları",
};
export default async function LeadsPage() {
let ctx;
try {
ctx = await requireTenant();
} catch {
redirect("/onboarding");
}
const { teams } = createAdminClient();
const [leads, membershipsResult] = await Promise.all([
listLeads(ctx.tenantId),
teams.listMemberships(ctx.tenantId).catch(() => ({ memberships: [] })),
]);
const memberMap = new Map(
membershipsResult.memberships
.filter((m) => m.confirm)
.map((m) => [m.userId, m.userName || m.userEmail]),
);
const members = membershipsResult.memberships
.filter((m) => m.confirm)
.map((m) => ({ id: m.userId, name: m.userName || m.userEmail, email: m.userEmail }));
const leadRows: LeadRow[] = leads.map((l) => ({
id: l.$id,
name: l.name,
contactName: l.contactName ?? "",
email: l.email ?? "",
phone: l.phone ?? "",
source: l.source ?? "other",
status: l.status ?? "cold",
estimatedValue: l.estimatedValue ?? null,
currency: l.currency ?? "TRY",
notes: l.notes ?? "",
assigneeId: l.assigneeId ?? "",
assigneeName: l.assigneeId ? (memberMap.get(l.assigneeId) ?? "") : "",
lastContactAt: l.lastContactAt ?? null,
nextFollowUpAt: l.nextFollowUpAt ?? null,
calendarEventId: l.calendarEventId ?? null,
customerId: l.customerId ?? null,
createdAt: l.$createdAt,
}));
return (
<div className="flex-1 space-y-4 px-6 pt-0">
<div className="flex flex-col gap-1">
<p className="text-muted-foreground text-sm">{ctx.settings?.companyName ?? "Çalışma alanı"}</p>
<h1 className="text-2xl font-bold tracking-tight">Müşteri Adayları</h1>
<p className="text-muted-foreground text-sm">
Müşteri adaylarını takip edin, ısıtın ve müşteriye dönüştürün.
</p>
</div>
<LeadsBoard
leads={leadRows}
members={members}
currentUserId={ctx.user.id}
/>
</div>
);
}