11 KiB
Frontend (Next.js) — Site Ayarları Entegrasyonu
Genel Bakış
Backend'den tüm site ayarları tek bir API çağrısı ile alınır. Ayarlar gruplara ayrılmış nested JSON formatında gelir. Bu veri layout, header, footer, SEO meta tag'leri, analytics scriptleri ve tüm sabit içerikleri besler.
Sensitive key'ler (API key, secret, password) public endpoint'ten filtrelenmiştir — güvenle kullanabilirsin.
API Endpoints (Public — Auth Yok)
| Method | Endpoint | Açıklama |
|---|---|---|
GET |
/api/v1/settings |
Tüm public ayarlar (grouped nested JSON) |
GET |
/api/v1/settings/{group} |
Tek grup ayarları (flat key-value) |
GET /api/v1/settings — Response Formatı
{
"general": {
"site_name": "Boğaziçi Denizcilik Eğitim Kurumu",
"site_tagline": "Türkiye'nin Köklü Denizcilik Okulu",
"site_description": "Türkiye'nin köklü denizcilik eğitim kurumu",
"logo_light": "/storage/uploads/logo-white.png",
"logo_dark": "/storage/uploads/logo-dark.png",
"favicon": "/storage/uploads/favicon.png",
"apple_touch_icon": null,
"announcement_bar_active": "true",
"announcement_bar_text": "2026 Kayıtları Devam Ediyor",
"announcement_bar_url": "/kayit",
"announcement_bar_bg_color": "#1a3e74",
"maintenance_mode": "false",
"maintenance_message": "Sitemiz bakımdadır, kısa süre içinde geri döneceğiz."
},
"contact": {
"phone_primary": "+90 532 724 15 32",
"phone_secondary": null,
"email_info": "bilgi@bogazicidenizcilik.com",
"address_full": "Osmanağa Mah. Çuhadarağa Sk. No:21 Kadıköy/İstanbul",
"address_short": "Kadıköy, İstanbul",
"working_hours_weekday": "Hafta İçi 09:00 – 17:00",
"whatsapp_number": null,
"whatsapp_message": "Merhaba, bilgi almak istiyorum."
},
"maps": {
"google_maps_embed_url": null,
"google_maps_place_url": null,
"latitude": "40.9876",
"longitude": "29.0234",
"map_zoom_level": "15"
},
"social": {
"instagram_url": null,
"instagram_handle": null,
"facebook_url": null,
"youtube_url": null,
"linkedin_url": null,
"tiktok_url": null,
"twitter_url": null
},
"seo": {
"meta_title_suffix": "| Boğaziçi Denizcilik",
"meta_title_separator": "|",
"default_meta_description": "IMO ve STCW standartlarında denizcilik eğitimi.",
"default_meta_keywords": "denizcilik kursu, STCW eğitimi, kaptan kursu",
"robots": "index, follow",
"canonical_domain": "https://bogazicidenizcilik.com",
"og_image": null,
"og_type": "website",
"og_locale": "tr_TR",
"og_site_name": "Boğaziçi Denizcilik",
"twitter_card_type": "summary_large_image",
"google_site_verification": null
},
"analytics": {
"google_analytics_id": null,
"google_tag_manager_id": null,
"facebook_pixel_id": null,
"hotjar_id": null,
"clarity_id": null,
"crisp_website_id": null,
"custom_head_scripts": null,
"custom_body_scripts": null
},
"header": {
"navbar_style_default": "transparent",
"cta_button_text": "Başvuru Yap",
"cta_button_url": "/kayit",
"cta_button_color": "#396cab",
"show_phone_topbar": "true",
"show_email_topbar": "true",
"show_address_topbar": "true",
"show_hours_topbar": "true",
"show_social_navbar": "true"
},
"footer": {
"footer_description": "Türkiye'nin köklü denizcilik eğitim kurumlarından biri olarak...",
"footer_logo": null,
"copyright_text": "© 2026 Boğaziçi Denizcilik Eğitim Kurumu. Tüm hakları saklıdır.",
"footer_address": "Osmanağa Bahariye Cad. No:31 Kadıköy/İstanbul",
"footer_phone": "+90 532 724 15 32",
"footer_email": "bilgi@bogazicidenizcilik.com",
"footer_bg_color": "#0f2447",
"show_social_footer": "true"
}
}
Not:
integrationsgrubu public API'den dönmez (tamamıis_public: false).maps.google_maps_api_keyde filtrelenmiştir.
GET /api/v1/settings/{group} — Tek Grup
GET /api/v1/settings/contact
{
"phone_primary": "+90 532 724 15 32",
"email_info": "bilgi@bogazicidenizcilik.com",
"address_full": "Osmanağa Mah. Çuhadarağa Sk. No:21 Kadıköy/İstanbul",
...
}
Geçerli group değerleri: general, contact, maps, social, seo, analytics, header, footer
Önerilen Veri Akışı (Next.js)
1. Layout-Level Fetch (Server Component)
Ayarlar tüm sayfalarda gerekli (header, footer, SEO). Layout'ta bir kez fetch edip context/provider ile dağıt:
// app/layout.tsx
async function getSettings() {
const res = await fetch(`${process.env.API_URL}/api/v1/settings`, {
next: { revalidate: 300 } // 5 dk cache
});
return res.json();
}
export default async function RootLayout({ children }) {
const settings = await getSettings();
return (
<html>
<head>
{/* Analytics Scripts */}
{settings.analytics?.google_tag_manager_id && (
<script>...</script>
)}
{settings.analytics?.custom_head_scripts && (
<div dangerouslySetInnerHTML={{ __html: settings.analytics.custom_head_scripts }} />
)}
</head>
<body>
<SettingsProvider value={settings}>
<Header settings={settings} />
{children}
<Footer settings={settings} />
</SettingsProvider>
{settings.analytics?.custom_body_scripts && (
<div dangerouslySetInnerHTML={{ __html: settings.analytics.custom_body_scripts }} />
)}
</body>
</html>
);
}
2. Boolean Değerler
Backend tüm değerleri string olarak döner. Boolean kontrol:
// Helper fonksiyon
const isEnabled = (value: string | null) => value === "true";
// Kullanım
{isEnabled(settings.general.announcement_bar_active) && (
<AnnouncementBar
text={settings.general.announcement_bar_text}
url={settings.general.announcement_bar_url}
bgColor={settings.general.announcement_bar_bg_color}
/>
)}
{isEnabled(settings.header.show_phone_topbar) && (
<span>{settings.contact.phone_primary}</span>
)}
3. Image Alanları
Image değerleri relative path olarak gelir. API base URL ile birleştir:
const getImageUrl = (path: string | null) => {
if (!path) return null;
if (path.startsWith('http')) return path;
return `${process.env.NEXT_PUBLIC_API_URL}${path}`;
};
// Kullanım
<Image src={getImageUrl(settings.general.logo_light)} alt={settings.general.site_name} />
Bileşen Bazlı Kullanım Haritası
Header / Navbar
| Ayar | Kullanım |
|---|---|
general.logo_light |
Navbar logo (transparent bg) |
general.logo_dark |
Navbar logo (scrolled/white bg) |
general.announcement_bar_* |
Üst duyuru barı |
header.navbar_style_default |
Navbar başlangıç stili |
header.cta_button_text/url/color |
Sağ üst CTA butonu |
header.show_*_topbar |
Topbar'da göster/gizle kontrolleri |
header.show_social_navbar |
Sosyal medya ikonları |
contact.phone_primary |
Topbar telefon |
contact.email_info |
Topbar e-posta |
contact.address_short |
Topbar adres |
contact.working_hours_weekday |
Topbar çalışma saatleri |
social.*_url |
Sosyal medya ikon linkleri |
Footer
| Ayar | Kullanım |
|---|---|
footer.footer_logo |
Footer logo |
footer.footer_description |
Footer açıklama metni |
footer.footer_address |
Adres |
footer.footer_phone |
Telefon |
footer.footer_email |
E-posta |
footer.copyright_text |
Copyright satırı |
footer.footer_bg_color |
Background rengi |
footer.show_social_footer |
Sosyal medya göster/gizle |
social.*_url |
Sosyal medya ikon linkleri |
SEO / Head Meta Tags
// Her sayfa için generateMetadata
export async function generateMetadata(): Promise<Metadata> {
const settings = await getSettings();
const seo = settings.seo;
return {
title: {
template: `%s ${seo.meta_title_separator} ${seo.og_site_name}`,
default: settings.general.site_name,
},
description: seo.default_meta_description,
keywords: seo.default_meta_keywords,
robots: seo.robots,
openGraph: {
type: seo.og_type,
locale: seo.og_locale,
siteName: seo.og_site_name,
images: seo.og_image ? [getImageUrl(seo.og_image)] : [],
},
twitter: {
card: seo.twitter_card_type,
site: seo.twitter_site,
creator: seo.twitter_creator,
},
verification: {
google: seo.google_site_verification,
other: {
'yandex-verification': seo.yandex_verification,
'msvalidate.01': seo.bing_site_verification,
},
},
};
}
İletişim Sayfası
| Ayar | Kullanım |
|---|---|
contact.phone_primary/secondary |
Telefon numaraları |
contact.email_* |
E-posta adresleri |
contact.address_full |
Tam adres |
contact.working_hours_* |
Çalışma saatleri |
contact.whatsapp_number/message |
WhatsApp butonu |
maps.google_maps_embed_url |
Harita iframe |
maps.google_maps_place_url |
"Google Maps'te Aç" linki |
maps.latitude/longitude |
Marker konumu |
WhatsApp Floating Button
const whatsappUrl = settings.contact.whatsapp_number
? `https://wa.me/${settings.contact.whatsapp_number.replace(/\s/g, '')}?text=${encodeURIComponent(settings.contact.whatsapp_message || '')}`
: null;
{whatsappUrl && <a href={whatsappUrl} target="_blank">WhatsApp</a>}
Bakım Modu
// middleware.ts veya layout.tsx
if (isEnabled(settings.general.maintenance_mode)) {
return <MaintenancePage message={settings.general.maintenance_message} />;
}
Cache Stratejisi
| Strateji | Açıklama |
|---|---|
| Backend | 1 saat cache (Cache::remember, 3600s) |
| Frontend (ISR) | next: { revalidate: 300 } — 5 dakika |
| Admin güncelleme sonrası | Backend cache otomatik temizlenir, frontend 5 dk içinde güncellenir |
| Acil güncelleme | Admin panelden "Cache Temizle" → frontend revalidate |
Null Değer Kontrolü
Birçok ayar başlangıçta null olabilir. Her kullanımda null check yap:
// Kötü
<a href={settings.social.instagram_url}>Instagram</a>
// İyi
{settings.social?.instagram_url && (
<a href={settings.social.instagram_url}>Instagram</a>
)}
Sosyal medya ikonlarını dinamik render et — sadece URL'si dolu olanları göster:
const socialLinks = [
{ key: 'instagram_url', icon: Instagram, label: 'Instagram' },
{ key: 'facebook_url', icon: Facebook, label: 'Facebook' },
{ key: 'twitter_url', icon: Twitter, label: 'X' },
{ key: 'youtube_url', icon: Youtube, label: 'YouTube' },
{ key: 'linkedin_url', icon: Linkedin, label: 'LinkedIn' },
{ key: 'tiktok_url', icon: TikTok, label: 'TikTok' },
];
{socialLinks
.filter(s => settings.social?.[s.key])
.map(s => (
<a key={s.key} href={settings.social[s.key]} target="_blank" aria-label={s.label}>
<s.icon />
</a>
))
}
TypeScript Tipi (Önerilen)
interface SiteSettings {
general: Record<string, string | null>;
contact: Record<string, string | null>;
maps: Record<string, string | null>;
social: Record<string, string | null>;
seo: Record<string, string | null>;
analytics: Record<string, string | null>;
header: Record<string, string | null>;
footer: Record<string, string | null>;
}