Files
lab/src/app/(dashboard)/layout.tsx
T
kovakmedya 2c6c074a06 feat: job status/step flow, file upload, finance sync, notifications
Job lifecycle
  - acceptJobAction (lab): pending → in_progress + currentStep=olcu
  - advanceStepAction (lab): step ilerletir, son adım sonrası status=sent
  - markDeliveredAction (clinic): sent → delivered
  - cancelJobAction: pending iş iptali (her iki taraf)
  - job_status_history her step transition'da idempotent kayıt
  - Detay sayfası interactive panel + Aşama Geçmişi kartı

Job files (Appwrite Storage job-files bucket, 30MB/file)
  - uploadJobFilesAction: çoklu dosya, mimeType'tan kind sınıflandırma
    (scan/image/document), her iki team'e read permission, partial-fail
    rollback (storage + row temizliği)
  - deleteJobFileAction: yetkilendirilmiş silme, file + row birlikte
  - JobFilesPanel: client-side select + upload + liste + indir + sil
  - next.config bodySizeLimit 3mb → 100mb (toplu yükleme için)

Finance sync (idempotent)
  - syncFinanceForJob helper: sent/delivered transition'larında klinik
    payable + lab receivable rows (jobId+tenantId+type unique kontrolü,
    her tarafta tek satır garanti)
  - markFinancePaidAction / reopenFinanceAction: manuel ödendi/geri al
  - /finance sayfası: stat kartlar (bekleyen alacak/borç, aylık gelir/gider)
    + hareketler tablosu, role-aware kopyalar
  - Memory rule [[feedback_cross_entity_sync_helpers]]: best-effort, never
    re-throws

Notifications
  - createNotification helper, connection (request/approve) ve job
    (create/accept/sent/delivered) eventlerinde tetikleniyor
  - /notifications sayfası + tek tek / hepsi okundu işaretle
  - Header'a Bell ikonu + okunmamış count badge (layout SSR'de besler)
  - Middleware PROTECTED_PREFIXES'e /notifications ekli
2026-05-21 20:17:33 +03:00

46 lines
1.3 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.
import { redirect } from "next/navigation";
import { getActiveContext } from "@/lib/appwrite/active-context";
import { countUnreadNotifications } from "@/lib/appwrite/notification-helpers";
import { getLogoUrl } from "@/lib/appwrite/storage";
import { getUserPrefs } from "@/lib/appwrite/user-prefs-actions";
import type { UserPrefs as ThemePrefs } from "@/lib/appwrite/user-prefs-actions";
import { DashboardShell } from "./dashboard-shell";
export default async function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
const ctx = await getActiveContext();
if (!ctx) redirect("/onboarding");
const [themePrefs, unreadCount] = (await Promise.all([
getUserPrefs(),
countUnreadNotifications(ctx.tenantId),
])) as [ThemePrefs, number];
const company = {
id: ctx.tenantId,
name: ctx.settings?.companyName ?? "Çalışma alanı",
logoUrl: getLogoUrl(ctx.settings?.logo) ?? null,
kind: (ctx.settings?.kind ?? "lab") as "lab" | "clinic",
};
const user = {
id: ctx.user.id,
name: ctx.user.name || ctx.user.email,
email: ctx.user.email,
};
return (
<DashboardShell
user={user}
company={company}
initialPrefs={themePrefs}
unreadCount={unreadCount}
>
{children}
</DashboardShell>
);
}