init: lab project bootstrapped from isletmem-kovakcrm
- CRM domain modules removed (customers, services, software, calendar, tasks, invoices, leads, finance, etc.)
- DLS branding: package name=lab, logo wordmark, sidebar nav, header CTA
- Tenant layer extended with kind dimension (lab|clinic) + requireTenantKind helper
- Schema rewritten for DLS domain: jobs, job_files, job_status_history, prosthetics, connections, finance_entries, notifications
- Onboarding form: clinic/lab account-type selection + auto-generated memberNumber
- Placeholder routes for jobs/{inbound,outbound,new}, products, finance, connections
- PDF spec + spec.md under belgeler/
- db: lab database + 13 collections + indexes + storage bucket (job-files) provisioned via Appwrite MCP
Ref: belgeler/dls-ui-tasarim.pdf
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
"use server";
|
||||
|
||||
import { ID, Permission, Query, Role } from "node-appwrite";
|
||||
|
||||
import { createAdminClient, createSessionClient } from "./server";
|
||||
import { DATABASE_ID, TABLES } from "./schema";
|
||||
|
||||
export interface UserPrefs {
|
||||
theme?: "dark" | "light" | "system";
|
||||
colorTheme?: string;
|
||||
tweakcnTheme?: string;
|
||||
radius?: string;
|
||||
sidebarVariant?: "sidebar" | "floating" | "inset";
|
||||
sidebarCollapsible?: "offcanvas" | "icon" | "none";
|
||||
sidebarSide?: "left" | "right";
|
||||
}
|
||||
|
||||
export async function getUserPrefs(): Promise<UserPrefs> {
|
||||
try {
|
||||
const { account } = await createSessionClient();
|
||||
const user = await account.get();
|
||||
const { tablesDB } = createAdminClient();
|
||||
|
||||
const result = await tablesDB.listRows({
|
||||
databaseId: DATABASE_ID,
|
||||
tableId: TABLES.userPreferences,
|
||||
queries: [Query.equal("userId", user.$id), Query.limit(1)],
|
||||
});
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
// Pre-create an empty row so saveUserPrefsAction always calls updateRow
|
||||
// (createRow inside a Server Action causes router cache invalidation → remount loop)
|
||||
try {
|
||||
await tablesDB.createRow(
|
||||
DATABASE_ID,
|
||||
TABLES.userPreferences,
|
||||
ID.unique(),
|
||||
{ userId: user.$id },
|
||||
[
|
||||
Permission.read(Role.user(user.$id)),
|
||||
Permission.update(Role.user(user.$id)),
|
||||
Permission.delete(Role.user(user.$id)),
|
||||
],
|
||||
);
|
||||
} catch {
|
||||
// race condition or already exists — fine
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
const row = result.rows[0] as Record<string, unknown>;
|
||||
const str = (v: unknown) => (v && typeof v === "string" ? v : undefined);
|
||||
return {
|
||||
theme: (row.theme as UserPrefs["theme"]) ?? undefined,
|
||||
colorTheme: str(row.colorTheme),
|
||||
tweakcnTheme: str(row.tweakcnTheme),
|
||||
radius: str(row.radius),
|
||||
sidebarVariant: (row.sidebarVariant as UserPrefs["sidebarVariant"]) ?? undefined,
|
||||
sidebarCollapsible: (row.sidebarCollapsible as UserPrefs["sidebarCollapsible"]) ?? undefined,
|
||||
sidebarSide: (row.sidebarSide as UserPrefs["sidebarSide"]) ?? undefined,
|
||||
};
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveUserPrefsAction(
|
||||
update: Partial<UserPrefs>,
|
||||
): Promise<{ ok: boolean; error?: string }> {
|
||||
try {
|
||||
const { account } = await createSessionClient();
|
||||
const user = await account.get();
|
||||
const { tablesDB } = createAdminClient();
|
||||
|
||||
// undefined → skip, "" → null (Appwrite rejects empty strings on nullable attrs)
|
||||
const clean: Record<string, unknown> = {};
|
||||
for (const [k, v] of Object.entries(update)) {
|
||||
if (v === undefined) continue;
|
||||
clean[k] = v === "" ? null : v;
|
||||
}
|
||||
if (Object.keys(clean).length === 0) return { ok: true };
|
||||
|
||||
const existing = await tablesDB.listRows({
|
||||
databaseId: DATABASE_ID,
|
||||
tableId: TABLES.userPreferences,
|
||||
queries: [Query.equal("userId", user.$id), Query.limit(1)],
|
||||
});
|
||||
|
||||
const perms = [
|
||||
Permission.read(Role.user(user.$id)),
|
||||
Permission.update(Role.user(user.$id)),
|
||||
Permission.delete(Role.user(user.$id)),
|
||||
];
|
||||
|
||||
if (existing.rows.length === 0) {
|
||||
await tablesDB.createRow(
|
||||
DATABASE_ID,
|
||||
TABLES.userPreferences,
|
||||
ID.unique(),
|
||||
{ userId: user.$id, ...clean },
|
||||
perms,
|
||||
);
|
||||
} else {
|
||||
await tablesDB.updateRow(
|
||||
DATABASE_ID,
|
||||
TABLES.userPreferences,
|
||||
existing.rows[0].$id,
|
||||
clean,
|
||||
);
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
console.error("[saveUserPrefsAction]", msg);
|
||||
return { ok: false, error: msg };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user