Files
gulermak_metro/lib/dataStore.ts
Şahan Hasret 76c31274d5 Database
2025-11-21 17:46:30 +03:00

800 lines
24 KiB
TypeScript
Raw Permalink 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.
// Veri yönetimi için API tabanlı store
import { newsData, type NewsItem } from '@/data/news';
import { mediaData, type MediaItem } from '@/data/media';
import { documentsData, type Document } from '@/data/documents';
import { metroStations, type MetroStation } from '@/data/metroStations';
export interface SliderItem {
id: number;
title: string;
description: string;
buttonText: string;
buttonLink: string;
active: boolean;
}
export interface LiveStreamConfig {
url: string;
active: boolean;
title?: string;
}
export interface Message {
id: string | number;
name: string;
email: string;
phone: string;
subject: string;
type: 'sikayet' | 'oneri' | 'bilgi';
message: string;
date: string;
read: boolean;
}
export interface FAQ {
id: number;
question: string;
answer: string;
order: number;
}
export interface Camera {
id: number;
name: string;
location: string;
videoUrl: string;
status: 'online' | 'offline';
viewers?: number;
order: number;
}
export interface SiteSettings {
contact: {
phone: string;
email: string;
address: string;
kep: string;
};
social: {
facebook: string;
twitter: string;
instagram: string;
youtube: string;
linkedin?: string;
};
companyInfo: {
name: string;
fullName: string;
foundedYear: string;
};
}
// API helper
const API_BASE = '/api';
const isBrowser = typeof window !== 'undefined';
// Default slider data
export const defaultSliderData: SliderItem[] = [
{
id: 1,
title: 'Ankara Metro Altyapı Projelerinde Öncü Çözümler',
description: 'Ankara Büyükşehir Belediyesi ile birlikte, modern teknoloji ve mühendislik uzmanlığımızla başkentin ulaşım ağını inşa ediyor, geleceğin metro sistemlerini bugünden hayata geçiriyoruz.',
buttonText: 'Detayları Gör',
buttonLink: '#proje-detay',
active: true
},
{
id: 2,
title: 'A2 Metro Hattı İnşaatında Son Aşamaya Gelindi',
description: '15 istasyonlu A2 Metro Hattı projemiz %75 tamamlandı. 2026 yılında hizmete açılacak modern metro hattımız, günlük 300 bin yolcuya hizmet verecek.',
buttonText: 'İlerlemeyi İzle',
buttonLink: '#metro-hatti',
active: true
},
{
id: 3,
title: 'Çevre Dostu Metro Teknolojileri',
description: 'Yenilenebilir enerji kaynakları ve sürdürülebilir inşaat teknikleri ile çevre dostu metro projelerine imza atıyoruz. Karbon emisyonunu %40 azaltan yenilikçi çözümlerimiz.',
buttonText: 'Yeşil Projeler',
buttonLink: '#cevre',
active: true
},
{
id: 4,
title: 'Güvenli İnşaat, Güvenli Gelecek',
description: 'ISO 45001 sertifikalı iş güvenliği sistemlerimiz ile 2000+ çalışanımızın güvenliğini en üst düzeyde tutuyoruz. Sıfır iş kazası hedefiyle çalışıyoruz.',
buttonText: 'Güvenlik Önlemleri',
buttonLink: '#guvenlik',
active: true
}
];
// Default FAQ data
export const defaultFAQData: FAQ[] = [
{
id: 1,
question: 'A2 Metro Hattı projesi ne zaman tamamlanacak?',
answer: 'A2 Metro Hattı projesinin 2026 yılı sonunda tamamlanması planlanmaktadır. Proje, Dikimevi-Natoyolu güzergâhında 6.5 kilometre uzunluğunda ve 5 istasyonlu bir metro hattı inşasını kapsamaktadır.',
order: 1
},
{
id: 2,
question: 'Metro hattı hangi istasyonları kapsayacak?',
answer: 'A2 Metro Hattı aşağıdaki istasyonları içerecektir: Dikimevi İstasyonu, Tuzluçayır İstasyonu, Natoyolu İstasyonu ve diğer ara istasyonlar. Toplam 5 istasyon bulunacaktır.',
order: 2
},
{
id: 3,
question: 'İnşaat çalışmaları sırasında trafik nasıl etkilenecek?',
answer: 'İnşaat çalışmaları sırasında geçici trafik düzenlemeleri uygulanacaktır. Alternatif güzergâhlar belirlenecek ve yönlendirme levhaları yerleştirilecektir. Vatandaşlarımızın anlayışına sığınıyoruz.',
order: 3
},
{
id: 4,
question: 'Proje maliyeti ne kadar?',
answer: 'A2 Metro Hattı projesinin toplam maliyeti yaklaşık 2.5 milyar TL olarak belirlenmiştir. Bu maliyet, tünel kazısı, istasyon inşaatı, ray döşeme ve elektrik-elektronik sistemleri kapsamaktadır.',
order: 4
},
{
id: 5,
question: 'Çevreye etkisi ne olacak?',
answer: 'Proje, çevre dostu teknolojiler kullanılarak gerçekleştirilmektedir. Çevresel Etki Değerlendirme (ÇED) raporu hazırlanmış ve gerekli izinler alınmıştır. İnşaat sırasında toz kontrolü ve gürültü önleme tedbirleri uygulanacaktır.',
order: 5
},
{
id: 6,
question: 'İstasyonlar hangi özelliklere sahip olacak?',
answer: 'İstasyonlar modern mimari tasarımla, enerji verimliliği, erişilebilirlik ve güvenlik ön planda tutularak inşa edilecektir. Güneş enerjisi panelleri, LED aydınlatma ve akıllı havalandırma sistemleri kullanılacaktır.',
order: 6
},
{
id: 7,
question: 'İnşaatta hangi teknolojiler kullanılacak?',
answer: 'Proje kapsamında TBM (Tunnel Boring Machine) tünel açma makinesi kullanılacaktır. Bu teknoloji sayesinde kazı çalışmaları daha hızlı ve güvenli şekilde gerçekleştirilecektir.',
order: 7
},
{
id: 8,
question: 'Proje ilerleme durumu nasıl takip edilebilir?',
answer: 'Bu web sitesi üzerinden canlı yayın, haberler ve medya galerisi bölümlerinden proje ilerleme durumunu takip edebilirsiniz. Ayrıca aylık ilerleme raporları yayınlanmaktadır.',
order: 8
}
];
// Default Camera data
export const defaultCameraData: Camera[] = [
{
id: 1,
name: 'Dikimevi İstasyonu - Ana Giriş',
location: 'Dikimevi',
videoUrl: 'https://www.youtube.com/embed/b9q88QDEcKg?autoplay=1',
status: 'online',
viewers: 1243,
order: 1
},
{
id: 2,
name: 'Tuzluçayır İstasyonu - İnşaat Sahası',
location: 'Tuzluçayır',
videoUrl: 'https://www.youtube.com/embed/b9q88QDEcKg?autoplay=1',
status: 'online',
viewers: 856,
order: 2
},
{
id: 3,
name: 'A2 Metro Hattı - Tünel Kazı Çalışması',
location: 'Mamak',
videoUrl: 'https://www.youtube.com/embed/b9q88QDEcKg?autoplay=1',
status: 'online',
viewers: 2134,
order: 3
},
{
id: 4,
name: 'İstasyon Binası İç Mekan',
location: 'Dikimevi',
videoUrl: 'https://www.youtube.com/embed/b9q88QDEcKg?autoplay=1',
status: 'online',
viewers: 534,
order: 4
}
];
export const dataStore = {
// Slider
getSlider: async (): Promise<SliderItem[]> => {
if (!isBrowser) return defaultSliderData;
try {
const res = await fetch(`${API_BASE}/slider`);
if (!res.ok) throw new Error('Failed to fetch');
const data = await res.json();
return data.length > 0 ? data : defaultSliderData;
} catch (error) {
console.error('Slider fetch error:', error);
return defaultSliderData;
}
},
setSlider: async () => {
// Not used - individual items updated via API
console.warn('setSlider deprecated - use addSlider/updateSlider/deleteSlider');
},
addSlider: async (item: Omit<SliderItem, 'id'>) => {
try {
const res = await fetch(`${API_BASE}/slider`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(item),
});
if (!res.ok) throw new Error('Failed to add');
return await res.json();
} catch (error) {
console.error('Slider add error:', error);
throw error;
}
},
updateSlider: async (id: number, item: Partial<SliderItem>) => {
try {
const res = await fetch(`${API_BASE}/slider`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, ...item }),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('Slider update error:', error);
throw error;
}
},
deleteSlider: async (id: number) => {
try {
const res = await fetch(`${API_BASE}/slider?id=${id}`, {
method: 'DELETE',
credentials: 'include',
});
if (!res.ok) throw new Error('Failed to delete');
return await res.json();
} catch (error) {
console.error('Slider delete error:', error);
throw error;
}
},
// News
getNews: async (): Promise<NewsItem[]> => {
if (!isBrowser) return newsData;
try {
const res = await fetch(`${API_BASE}/news`);
if (!res.ok) throw new Error('Failed to fetch');
const data = await res.json();
return data.length > 0 ? data : newsData;
} catch (error) {
console.error('News fetch error:', error);
return newsData;
}
},
setNews: async () => {
console.warn('setNews deprecated - use addNews/updateNews/deleteNews');
},
addNews: async (newsItem: Omit<NewsItem, 'id'>) => {
try {
const res = await fetch(`${API_BASE}/news`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newsItem),
});
if (!res.ok) throw new Error('Failed to add');
return await res.json();
} catch (error) {
console.error('News add error:', error);
throw error;
}
},
updateNews: async (id: number, newsItem: Partial<NewsItem>) => {
try {
const res = await fetch(`${API_BASE}/news`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, ...newsItem }),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('News update error:', error);
throw error;
}
},
deleteNews: async (id: number) => {
try {
const res = await fetch(`${API_BASE}/news?id=${id}`, {
method: 'DELETE',
credentials: 'include',
});
if (!res.ok) throw new Error('Failed to delete');
return await res.json();
} catch (error) {
console.error('News delete error:', error);
throw error;
}
},
// Media
getMedia: async (): Promise<MediaItem[]> => {
if (!isBrowser) return mediaData;
try {
const res = await fetch(`${API_BASE}/media`);
if (!res.ok) throw new Error('Failed to fetch');
const data = await res.json();
return data.length > 0 ? data : mediaData;
} catch (error) {
console.error('Media fetch error:', error);
return mediaData;
}
},
setMedia: async () => {
console.warn('setMedia deprecated - use addMedia/updateMedia/deleteMedia');
},
addMedia: async (mediaItem: Omit<MediaItem, 'id'>) => {
try {
const res = await fetch(`${API_BASE}/media`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(mediaItem),
});
if (!res.ok) throw new Error('Failed to add');
return await res.json();
} catch (error) {
console.error('Media add error:', error);
throw error;
}
},
updateMedia: async (id: number, mediaItem: Partial<MediaItem>) => {
try {
const res = await fetch(`${API_BASE}/media`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, ...mediaItem }),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('Media update error:', error);
throw error;
}
},
deleteMedia: async (id: number) => {
try {
const res = await fetch(`${API_BASE}/media?id=${id}`, {
method: 'DELETE',
credentials: 'include',
});
if (!res.ok) throw new Error('Failed to delete');
return await res.json();
} catch (error) {
console.error('Media delete error:', error);
throw error;
}
},
// Documents
getDocuments: async (): Promise<Document[]> => {
if (!isBrowser) return documentsData;
try {
const res = await fetch(`${API_BASE}/documents`);
if (!res.ok) throw new Error('Failed to fetch');
const data = await res.json();
return data.length > 0 ? data : documentsData;
} catch (error) {
console.error('Documents fetch error:', error);
return documentsData;
}
},
setDocuments: async () => {
console.warn('setDocuments deprecated - use addDocument/updateDocument/deleteDocument');
},
addDocument: async (document: Omit<Document, 'id'>) => {
try {
const res = await fetch(`${API_BASE}/documents`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(document),
});
if (!res.ok) throw new Error('Failed to add');
return await res.json();
} catch (error) {
console.error('Document add error:', error);
throw error;
}
},
updateDocument: async (id: number, document: Partial<Document>) => {
try {
const res = await fetch(`${API_BASE}/documents`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, ...document }),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('Document update error:', error);
throw error;
}
},
deleteDocument: async (id: number) => {
try {
const res = await fetch(`${API_BASE}/documents?id=${id}`, {
method: 'DELETE',
credentials: 'include',
});
if (!res.ok) {
console.error('Delete document failed - Status:', res.status, res.statusText);
const text = await res.text();
console.error('Response body:', text);
try {
const errorData = JSON.parse(text);
throw new Error(errorData.error || 'Failed to delete');
} catch {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
}
return await res.json();
} catch (error) {
console.error('Document delete error:', error);
throw error;
}
},
// Metro Stations
getMetroStations: async (): Promise<MetroStation[]> => {
if (!isBrowser) return metroStations;
try {
const res = await fetch(`${API_BASE}/stations`);
if (!res.ok) throw new Error('Failed to fetch');
const data = await res.json();
return data.length > 0 ? data : metroStations;
} catch (error) {
console.error('Stations fetch error:', error);
return metroStations;
}
},
setMetroStations: async () => {
console.warn('setMetroStations deprecated - use updateStation');
},
updateStation: async (id: number, station: Partial<MetroStation>) => {
try {
const res = await fetch(`${API_BASE}/stations`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, ...station }),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('Station update error:', error);
throw error;
}
},
// Live Stream
getLiveStream: async (): Promise<LiveStreamConfig> => {
if (!isBrowser) {
return {
url: 'https://www.youtube.com/embed/jfKfPfyJRdk?si=example',
active: true,
title: 'Canlı Yayın'
};
}
try {
const res = await fetch(`${API_BASE}/live-stream`);
if (!res.ok) throw new Error('Failed to fetch');
return await res.json();
} catch (error) {
console.error('Live stream fetch error:', error);
return {
url: 'https://www.youtube.com/embed/jfKfPfyJRdk?si=example',
active: true,
title: 'Canlı Yayın'
};
}
},
setLiveStream: async (config: LiveStreamConfig) => {
try {
const res = await fetch(`${API_BASE}/live-stream`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(config),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('Live stream update error:', error);
throw error;
}
},
// Messages
getMessages: async (): Promise<Message[]> => {
if (!isBrowser) return [];
try {
const res = await fetch(`${API_BASE}/messages`);
if (!res.ok) throw new Error('Failed to fetch');
return await res.json();
} catch (error) {
console.error('Messages fetch error:', error);
return [];
}
},
addMessage: async (message: Omit<Message, 'id' | 'createdAt' | 'updatedAt'>) => {
try {
const res = await fetch(`${API_BASE}/messages`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(message),
});
if (!res.ok) throw new Error('Failed to add');
return await res.json();
} catch (error) {
console.error('Message add error:', error);
throw error;
}
},
markMessageAsRead: async (id: string | number) => {
try {
const res = await fetch(`${API_BASE}/messages`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: typeof id === 'string' ? parseInt(id) : id, read: true }),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('Message update error:', error);
throw error;
}
},
deleteMessage: async (id: string | number) => {
try {
const res = await fetch(`${API_BASE}/messages?id=${id}`, {
method: 'DELETE',
credentials: 'include',
});
if (!res.ok) throw new Error('Failed to delete');
return await res.json();
} catch (error) {
console.error('Message delete error:', error);
throw error;
}
},
// Site Settings
getSiteSettings: async (): Promise<SiteSettings> => {
if (!isBrowser) {
return {
contact: {
phone: '+90 (312) 123 45 67',
email: 'info@a2metro.com.tr',
address: 'Ankara Teknokent, Cyberpark C Blok Kat:3 No:301 Çankaya/ANKARA',
kep: 'a2metro@hs03.kep.tr'
},
social: {
facebook: 'https://facebook.com/a2metro',
twitter: 'https://twitter.com/a2metro',
instagram: 'https://instagram.com/a2metro',
youtube: 'https://youtube.com/@a2metro',
linkedin: 'https://linkedin.com/company/a2metro'
},
companyInfo: {
name: 'A2 Metro',
fullName: 'A2 Metro Yapı ve İnşaat A.Ş.',
foundedYear: '2010'
}
};
}
try {
const res = await fetch(`${API_BASE}/settings`);
if (!res.ok) throw new Error('Failed to fetch');
return await res.json();
} catch (error) {
console.error('Settings fetch error:', error);
return {
contact: {
phone: '+90 (312) 123 45 67',
email: 'info@a2metro.com.tr',
address: 'Ankara Teknokent, Cyberpark C Blok Kat:3 No:301 Çankaya/ANKARA',
kep: 'a2metro@hs03.kep.tr'
},
social: {
facebook: 'https://facebook.com/a2metro',
twitter: 'https://twitter.com/a2metro',
instagram: 'https://instagram.com/a2metro',
youtube: 'https://youtube.com/@a2metro',
linkedin: 'https://linkedin.com/company/a2metro'
},
companyInfo: {
name: 'A2 Metro',
fullName: 'A2 Metro Yapı ve İnşaat A.Ş.',
foundedYear: '2010'
}
};
}
},
updateSiteSettings: async (settings: Partial<SiteSettings>) => {
try {
const current = await dataStore.getSiteSettings();
const updated = {
...current,
...settings,
contact: { ...current.contact, ...(settings.contact || {}) },
social: { ...current.social, ...(settings.social || {}) },
companyInfo: { ...current.companyInfo, ...(settings.companyInfo || {}) }
};
const res = await fetch(`${API_BASE}/settings`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updated),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('Settings update error:', error);
throw error;
}
},
// FAQs
getFAQs: async (): Promise<FAQ[]> => {
if (!isBrowser) return defaultFAQData;
try {
const res = await fetch(`${API_BASE}/faqs`);
if (!res.ok) throw new Error('Failed to fetch');
const data = await res.json();
return data.length > 0 ? data : defaultFAQData;
} catch (error) {
console.error('FAQs fetch error:', error);
return defaultFAQData;
}
},
setFAQs: async () => {
console.warn('setFAQs deprecated - use addFAQ/updateFAQ/deleteFAQ');
},
addFAQ: async (faq: Omit<FAQ, 'id'>) => {
try {
const res = await fetch(`${API_BASE}/faqs`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(faq),
});
if (!res.ok) throw new Error('Failed to add');
return await res.json();
} catch (error) {
console.error('FAQ add error:', error);
throw error;
}
},
updateFAQ: async (id: number, updates: Partial<FAQ>) => {
try {
const res = await fetch(`${API_BASE}/faqs`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, ...updates }),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('FAQ update error:', error);
throw error;
}
},
deleteFAQ: async (id: number) => {
try {
const res = await fetch(`${API_BASE}/faqs?id=${id}`, {
method: 'DELETE',
credentials: 'include',
});
if (!res.ok) throw new Error('Failed to delete');
return await res.json();
} catch (error) {
console.error('FAQ delete error:', error);
throw error;
}
},
// Cameras
getCameras: async (): Promise<Camera[]> => {
if (!isBrowser) return defaultCameraData;
try {
const res = await fetch(`${API_BASE}/cameras`);
if (!res.ok) throw new Error('Failed to fetch');
const data = await res.json();
return data.length > 0 ? data : defaultCameraData;
} catch (error) {
console.error('Cameras fetch error:', error);
return defaultCameraData;
}
},
setCameras: async () => {
console.warn('setCameras deprecated - use addCamera/updateCamera/deleteCamera');
},
addCamera: async (camera: Omit<Camera, 'id' | 'createdAt' | 'updatedAt'>) => {
try {
const res = await fetch(`${API_BASE}/cameras`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(camera),
});
if (!res.ok) throw new Error('Failed to add');
return await res.json();
} catch (error) {
console.error('Camera add error:', error);
throw error;
}
},
updateCamera: async (id: number, updates: Partial<Camera>) => {
try {
const res = await fetch(`${API_BASE}/cameras`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, ...updates }),
});
if (!res.ok) throw new Error('Failed to update');
return await res.json();
} catch (error) {
console.error('Camera update error:', error);
throw error;
}
},
deleteCamera: async (id: number) => {
try {
const res = await fetch(`${API_BASE}/cameras?id=${id}`, {
method: 'DELETE',
credentials: 'include',
});
if (!res.ok) throw new Error('Failed to delete');
return await res.json();
} catch (error) {
console.error('Camera delete error:', error);
throw error;
}
},
// Reset all data (Not applicable for API-based storage)
resetAll: () => {
console.warn('resetAll not applicable for API-based storage');
}
};