Proje: Okul.com.tr CRM · Hub: Okul.com.tr CRM — Conventions

CRM Form Pattern (React Hook Form + Zod)

Temel Yapı

// 1. Zod schema tanımla
const entitySchema = z.object({
    name: z.string().min(1, { message: "Alan zorunludur." }),
    count: z.coerce.number().min(0),
    flag: z.boolean(),
    optional_id: z.coerce.number().optional().nullable(),
});
 
type EntityFormValues = z.infer<typeof entitySchema>;
 
// 2. useForm
const form = useForm<EntityFormValues>({
    resolver: zodResolver(entitySchema),
    defaultValues: { name: "", count: 0, flag: false, optional_id: null },
});
 
// 3. isDirty tracking
const isDirty = form.formState.isDirty;

Sayısal Alanlar

z.coerce.number() kullanılır — input’tan gelen string’i number’a çevirir. Min/max validation ile birlikte kullanılır.

HTML Entity Decode

API’den gelen HTML entity’li metinler (&amp;, &lt; vb.) form’a yüklenirken decode edilir:

const decodeHtmlEntities = (text: string | null | undefined): string => {
    if (!text) return "";
    const textarea = document.createElement('textarea');
    textarea.innerHTML = text;
    return textarea.value;
};

Dirty Check ile Cancel

const handleCancel = () => {
    if (isDirty) {
        if (window.confirm("Kaydedilmemiş değişiklikler var. Çıkmak istediğinize emin misiniz?")) {
            navigate(`/entity/${id}`);
        }
    } else {
        navigate(`/entity/${id}`);
    }
};

Form Section Card Pattern

Edit sayfaları birden fazla Card ile bölümlere ayrılır, her bölümün bir ikonu ve rengi vardır:

  • Type ikonu (mavi) — temel bilgiler
  • Settings ikonu (mor) — ayarlar
  • BarChart3 ikonu (yeşil) — istatistikler
  • ShieldCheck ikonu (amber) — güvenlik/durum

Sticky Action Bar

Edit sayfalarının altında sticky action bar:

<div className="sticky bottom-0 bg-background border-t p-4 flex justify-end gap-2">
    <Button type="button" variant="outline" onClick={handleCancel}>İptal</Button>
    <Button type="submit" disabled={loading || !isDirty}>
        {loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
        Kaydet
    </Button>
</div>

Combobox Pattern (Arama ile Select)

Popover + Command + CommandInput kombinasyonu — özellikle büyük listeler için (college, school seçimi).