- getActiveContext now verifies team still exists (teams.get) before
trusting the cookie/prefs tenantId, preventing stale E Ofis cookie
from causing an onboarding redirect loop
- Resolved tenantId from getUserTeams() is now persisted to cookie so
subsequent requests skip the resolution path
- Added catch+log on presentations data fetch to surface the actual
error in server logs
- ensureSettings() creates a minimal settings row if one is missing for
a team the user is already a member of, instead of returning null and
letting the onboarding redirect fire
- resolveFirstValidTenantId() falls back to any membership when no team
has settings yet, so new registrations without a completed onboarding
still land on the correct tenant
- teams.get() is now fetched alongside listMemberships in a single
Promise.all so the team name is available for the fallback row
- Yükseklik: calc(100dvh - var(--header-height) - 8rem)
- Sağ panel ve sol panel h-full aldı
- PropertiesMapView sarmalayıcısına h-full w-full eklendi
- Sol kart listesi w-72'ye daraltıldı
- Liste / Harita toggle butonu header'da
- Harita modunda sol panel: kart listesi (fotoğraf, fiyat, oda/m²)
+ sağ panel: MapLibre harita tüm koordinatlı ilanlar
- İlan renkleri duruma göre: aktif=mavi, pasif=gri, satıldı=turuncu, kiralandı=mor
- Pini tıkla → kart listesinde o ilanın kartına scroll
- Kartı tıkla → haritada o ilanın pinine flyTo + popup açılır
- Popup içinde başlık, fiyat, özellikler, 'Detay →' linki
- Koordinatsız ilanlar listede görünür ama haritada pin yok (📍 Konum yok)
- PropertiesMapView: dynamic next/dynamic wrapper (ssr: false)
- 3 karakter sonrası 400ms debounce ile Nominatim'den öneri çeker
- Yükleniyor spinner input sağında
- Dropdown: MapPin + tam adres, onMouseDown ile blur çakışması önlendi
- Seçim sonrası kısa isim input'a yazılır, harita flyTo ile konuma gider
- Dışarı tıklanınca dropdown kapanır
Önceki hata: ThemeTab her iki setter'ı da çağırıyordu (setSelectedTheme +
setSelectedTweakcnTheme). Bunlar wrapper'a bağlıydı, her wrapper kendi
saveThemePrefsAction'ını çağırıyordu. İkinci çağrı colorTheme:'' yazarak
birincinin kaydını siliyordu.
Düzeltme:
- ThemeTab'a RAW React state setter'ları iletildi (wrapper değil)
- ThemeTab'ın cross-clear mantığı olduğu gibi kaldı
- Appwrite kaydı useEffect'e taşındı: React 18 olay yöneticisindeki
tüm state güncellemelerini batch'ledikten SONRA tek seferde tetiklenir
→ selectedTheme ve selectedTweakcnTheme doğru nihai değerleriyle kaydedilir
- saveThemePrefsAction: account.updatePrefs ile mevcut prefs'i merge eder
- Dashboard layout'ta account.getPrefs ile prefs server-side yüklenir
- PrefsInitializer: mount'ta dark/light, renk teması, radius, sidebar
config'ini Appwrite'dan gelen initialPrefs ile uygular
- ThemeCustomizer: renk teması / tweakcn / radius / sidebar değişikliği
anında Appwrite'a kaydedilir; dark/light toggle useEffect ile izlenir
- Sayfa yenileme ve farklı cihazda giriş sonrasında ayarlar korunur
Header'da ilan sayısının yanına creator adı + şirket adı eklendi.
Footer'da 'Kovak Emlak CRM' yerine dinamik ad/şirket yazıyor.
users.get(createdBy) + teams.get(tenantId) ile çekilir;
her ikisi de allSettled ile hata toleranslı.
- Koyu gradyan hero header (slate-900), Building2 ikon, ilan sayısı pill
- Kartlar: h-52 fotoğraf, hover scale efekti, gölge animasyonu
- Status + listing type badge overlay fotoğraf üstünde (backdrop-blur)
- Fotoğraf sayısı pill (sağ alt köşe)
- Spec pill'leri: emlak tipi, oda, m²
- Fiyat büyük ve dominant (2xl), mt-auto ile alta sabitlenmiş
- MapPin ikonu konum satırında ve harita linkinde
- Footer: Kovak Emlak CRM branding
- Süresi dolmuş sunum için iyileştirilmiş boş state
- Install maplibre-gl; use OpenFreeMap tiles (no API key)
- PropertyMapPickerInner: address search via Nominatim, draggable
marker, click-to-place, geolocation, clear button
- PropertyMapPicker/View: dynamic next/dynamic wrappers (ssr: false)
- PropertyMapViewInner: read-only marker view with navigation control
- PropertyFormSheet: hidden mapLat/mapLng inputs, picker renders only
when sheet is open, resets on property change
- Property detail page: Konum section with PropertyMapView + Google Maps link
- Sunum page: Google Maps deep link on PropertyCard when coordinates exist
Empty string sent to Appwrite datetime column was being interpreted as creation
timestamp, making every no-expiry sunum immediately expired. Fix:
- Only include expiresAt in payload when user actually set a date
- Convert date-only string (YYYY-MM-DD) to YYYY-MM-DDT23:59:59.000Z so the
sunum stays valid for the entire chosen day across all time zones
- Strip empty customerId/notes to avoid empty-string writes
- Sol: koyu panel — logo, özellikler listesi (portföy/eşleşme/sunum/müşteri), alt imza
- Sağ: temiz form — email + şifre, mobil responsive
- İşletmem referansları kaldırıldı, Emlak CRM olarak güncellendi
matchPropertyToSearches now:
- scores every search (listing type mismatch = 0 score)
- score >= 20: create or update match
- score < 20 AND existing match: delete stale record
Prevents outdated match records after criteria/weight updates.
- Server actions: property/customer/search/presentation/activity/investor CRUD
- Matching engine: matchPropertyToSearches + syncMatchesForSearch on search save
- UI: form sheets + table clients for all modules
- Public /sunum/[token] page (no auth) with property card grid + expiry check
- All pages force-dynamic for auth guard compatibility