Files
isletmem-kovakcrm/src/lib/validation/workspace.ts
T
kovakmedya fc091b9e0d feat(settings): /settings/workspace — edit company info + invoice defaults
Owner/admin edit, member read-only.

Schema/validation:
- lib/validation/workspace.ts (workspaceSettingsSchema)
- lib/appwrite/workspace-actions.ts:
  * updateWorkspaceSettingsAction — requireRole owner|admin, upserts the
    tenant_settings row (creates one with team-scoped perms if absent,
    e.g. for tenants created before tenant_settings was a table; just
    defense). Audit-logged.
  * Forces invoicePrefix to uppercase. defaultVatRate clamped to [0, 100].
  * revalidatePath('/', 'layout') so the new company name updates in
    sidebar header and dashboard greeting on next render.

UI:
- /settings/workspace page (server) — pulls active tenant settings
  via requireTenant, shows form pre-filled.
- WorkspaceSettingsForm: 2 cards
  * Şirket — name (required), tax id, phone, email, address
  * Faturalama — invoicePrefix, defaultVatRate, read-only invoiceCounter
- All inputs disabled if user is a member (canEdit=false). Submit button
  hidden in that case. Description on the page changes accordingly.
- Toast feedback for success/error.

Skipped: logo upload (storage bucket pending). Will revisit.
2026-04-30 06:44:11 +03:00

45 lines
1.2 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 { z } from "zod";
export const workspaceSettingsSchema = z.object({
companyName: z.string().trim().min(1, "Şirket adı zorunlu.").max(255),
companyTaxId: z
.string()
.trim()
.max(50)
.optional()
.transform((v) => (v ? v : undefined)),
companyAddress: z
.string()
.trim()
.max(500)
.optional()
.transform((v) => (v ? v : undefined)),
companyEmail: z
.union([z.string().email("Geçerli bir email girin."), z.literal("")])
.optional()
.transform((v) => (v ? v : undefined)),
companyPhone: z
.string()
.trim()
.max(30)
.optional()
.transform((v) => (v ? v : undefined)),
defaultVatRate: z
.union([z.number(), z.string()])
.optional()
.transform((v) => {
if (v === undefined || v === "") return 20;
const n = typeof v === "string" ? Number(v.replace(",", ".")) : v;
return Number.isFinite(n) ? n : 20;
})
.pipe(z.number().min(0, "Negatif olamaz.").max(100, "100'den büyük olamaz.")),
invoicePrefix: z
.string()
.trim()
.max(10)
.optional()
.transform((v) => (v ? v.toUpperCase() : "INV")),
});
export type WorkspaceSettingsInput = z.infer<typeof workspaceSettingsSchema>;