Database
This commit is contained in:
59
lib/auth.ts
Normal file
59
lib/auth.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { jwtVerify, SignJWT } from 'jose';
|
||||
import { cookies } from 'next/headers';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
const secret = new TextEncoder().encode(
|
||||
process.env.JWT_SECRET || 'default-secret-key'
|
||||
);
|
||||
|
||||
export interface SessionPayload {
|
||||
userId: string;
|
||||
username: string;
|
||||
iat?: number;
|
||||
exp?: number;
|
||||
}
|
||||
|
||||
export async function encrypt(payload: SessionPayload) {
|
||||
return await new SignJWT(payload as unknown as Record<string, unknown>)
|
||||
.setProtectedHeader({ alg: 'HS256' })
|
||||
.setIssuedAt()
|
||||
.setExpirationTime('24h')
|
||||
.sign(secret);
|
||||
}
|
||||
|
||||
export async function decrypt(token: string): Promise<SessionPayload | null> {
|
||||
try {
|
||||
const { payload } = await jwtVerify(token, secret, {
|
||||
algorithms: ['HS256'],
|
||||
});
|
||||
return payload as unknown as SessionPayload;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSession() {
|
||||
const cookieStore = await cookies();
|
||||
const token = cookieStore.get('session')?.value;
|
||||
if (!token) return null;
|
||||
return await decrypt(token);
|
||||
}
|
||||
|
||||
export async function withAuth(
|
||||
request: NextRequest,
|
||||
handler: (req: NextRequest, session: SessionPayload) => Promise<NextResponse>
|
||||
) {
|
||||
const token = request.cookies.get('session')?.value;
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
const session = await decrypt(token);
|
||||
|
||||
if (!session) {
|
||||
return NextResponse.json({ error: 'Invalid token' }, { status: 401 });
|
||||
}
|
||||
|
||||
return handler(request, session);
|
||||
}
|
||||
738
lib/dataStore.ts
738
lib/dataStore.ts
@@ -1,4 +1,4 @@
|
||||
// Veri yönetimi için localStorage tabanlı store
|
||||
// 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';
|
||||
@@ -20,7 +20,7 @@ export interface LiveStreamConfig {
|
||||
}
|
||||
|
||||
export interface Message {
|
||||
id: string;
|
||||
id: string | number;
|
||||
name: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
@@ -69,6 +69,10 @@ export interface SiteSettings {
|
||||
};
|
||||
}
|
||||
|
||||
// API helper
|
||||
const API_BASE = '/api';
|
||||
const isBrowser = typeof window !== 'undefined';
|
||||
|
||||
// Default slider data
|
||||
export const defaultSliderData: SliderItem[] = [
|
||||
{
|
||||
@@ -197,147 +201,301 @@ export const defaultCameraData: Camera[] = [
|
||||
}
|
||||
];
|
||||
|
||||
// LocalStorage keys
|
||||
const KEYS = {
|
||||
SLIDER: 'a2metro_slider',
|
||||
NEWS: 'a2metro_news',
|
||||
MEDIA: 'a2metro_media',
|
||||
DOCUMENTS: 'a2metro_documents',
|
||||
METRO_STATIONS: 'a2metro_stations',
|
||||
LIVE_STREAM: 'a2metro_live_stream',
|
||||
SITE_SETTINGS: 'a2metro_site_settings',
|
||||
MESSAGES: 'a2metro_messages',
|
||||
FAQS: 'a2metro_faqs',
|
||||
CAMERAS: 'a2metro_cameras'
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
const isBrowser = typeof window !== 'undefined';
|
||||
|
||||
export const dataStore = {
|
||||
// Slider
|
||||
getSlider: (): SliderItem[] => {
|
||||
getSlider: async (): Promise<SliderItem[]> => {
|
||||
if (!isBrowser) return defaultSliderData;
|
||||
const stored = localStorage.getItem(KEYS.SLIDER);
|
||||
return stored ? JSON.parse(stored) : 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: (data: SliderItem[]) => {
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.SLIDER, JSON.stringify(data));
|
||||
|
||||
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: (): NewsItem[] => {
|
||||
getNews: async (): Promise<NewsItem[]> => {
|
||||
if (!isBrowser) return newsData;
|
||||
const stored = localStorage.getItem(KEYS.NEWS);
|
||||
return stored ? JSON.parse(stored) : newsData;
|
||||
},
|
||||
setNews: (data: NewsItem[]) => {
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.NEWS, JSON.stringify(data));
|
||||
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;
|
||||
}
|
||||
},
|
||||
addNews: (newsItem: Omit<NewsItem, 'id'>) => {
|
||||
const current = dataStore.getNews();
|
||||
const newItem = { ...newsItem, id: Date.now() };
|
||||
dataStore.setNews([newItem, ...current]);
|
||||
return newItem;
|
||||
|
||||
setNews: async () => {
|
||||
console.warn('setNews deprecated - use addNews/updateNews/deleteNews');
|
||||
},
|
||||
updateNews: (id: number, newsItem: Partial<NewsItem>) => {
|
||||
const current = dataStore.getNews();
|
||||
const updated = current.map((item) =>
|
||||
item.id === id ? { ...item, ...newsItem } : item
|
||||
);
|
||||
dataStore.setNews(updated);
|
||||
|
||||
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;
|
||||
}
|
||||
},
|
||||
deleteNews: (id: number) => {
|
||||
const current = dataStore.getNews();
|
||||
const filtered = current.filter((item) => item.id !== id);
|
||||
dataStore.setNews(filtered);
|
||||
|
||||
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: (): MediaItem[] => {
|
||||
getMedia: async (): Promise<MediaItem[]> => {
|
||||
if (!isBrowser) return mediaData;
|
||||
const stored = localStorage.getItem(KEYS.MEDIA);
|
||||
return stored ? JSON.parse(stored) : mediaData;
|
||||
},
|
||||
setMedia: (data: MediaItem[]) => {
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.MEDIA, JSON.stringify(data));
|
||||
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;
|
||||
}
|
||||
},
|
||||
addMedia: (mediaItem: Omit<MediaItem, 'id'>) => {
|
||||
const current = dataStore.getMedia();
|
||||
const newItem = { ...mediaItem, id: Date.now() };
|
||||
dataStore.setMedia([newItem, ...current]);
|
||||
return newItem;
|
||||
|
||||
setMedia: async () => {
|
||||
console.warn('setMedia deprecated - use addMedia/updateMedia/deleteMedia');
|
||||
},
|
||||
updateMedia: (id: number, mediaItem: Partial<MediaItem>) => {
|
||||
const current = dataStore.getMedia();
|
||||
const updated = current.map((item) =>
|
||||
item.id === id ? { ...item, ...mediaItem } : item
|
||||
);
|
||||
dataStore.setMedia(updated);
|
||||
|
||||
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;
|
||||
}
|
||||
},
|
||||
deleteMedia: (id: number) => {
|
||||
const current = dataStore.getMedia();
|
||||
const filtered = current.filter((item) => item.id !== id);
|
||||
dataStore.setMedia(filtered);
|
||||
|
||||
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: (): Document[] => {
|
||||
getDocuments: async (): Promise<Document[]> => {
|
||||
if (!isBrowser) return documentsData;
|
||||
const stored = localStorage.getItem(KEYS.DOCUMENTS);
|
||||
return stored ? JSON.parse(stored) : documentsData;
|
||||
},
|
||||
setDocuments: (data: Document[]) => {
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.DOCUMENTS, JSON.stringify(data));
|
||||
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;
|
||||
}
|
||||
},
|
||||
addDocument: (document: Omit<Document, 'id'>) => {
|
||||
const current = dataStore.getDocuments();
|
||||
const newItem = { ...document, id: Date.now() };
|
||||
dataStore.setDocuments([newItem, ...current]);
|
||||
return newItem;
|
||||
|
||||
setDocuments: async () => {
|
||||
console.warn('setDocuments deprecated - use addDocument/updateDocument/deleteDocument');
|
||||
},
|
||||
updateDocument: (id: number, document: Partial<Document>) => {
|
||||
const current = dataStore.getDocuments();
|
||||
const updated = current.map((item) =>
|
||||
item.id === id ? { ...item, ...document } : item
|
||||
);
|
||||
dataStore.setDocuments(updated);
|
||||
|
||||
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;
|
||||
}
|
||||
},
|
||||
deleteDocument: (id: number) => {
|
||||
const current = dataStore.getDocuments();
|
||||
const filtered = current.filter((item) => item.id !== id);
|
||||
dataStore.setDocuments(filtered);
|
||||
|
||||
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: (): MetroStation[] => {
|
||||
getMetroStations: async (): Promise<MetroStation[]> => {
|
||||
if (!isBrowser) return metroStations;
|
||||
const stored = localStorage.getItem(KEYS.METRO_STATIONS);
|
||||
return stored ? JSON.parse(stored) : metroStations;
|
||||
},
|
||||
setMetroStations: (data: MetroStation[]) => {
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.METRO_STATIONS, JSON.stringify(data));
|
||||
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;
|
||||
}
|
||||
},
|
||||
updateStation: (id: number, station: Partial<MetroStation>) => {
|
||||
const current = dataStore.getMetroStations();
|
||||
const updated = current.map((item) =>
|
||||
item.id === id ? { ...item, ...station } : item
|
||||
);
|
||||
dataStore.setMetroStations(updated);
|
||||
|
||||
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: (): LiveStreamConfig => {
|
||||
getLiveStream: async (): Promise<LiveStreamConfig> => {
|
||||
if (!isBrowser) {
|
||||
return {
|
||||
url: 'https://www.youtube.com/embed/jfKfPfyJRdk?si=example',
|
||||
@@ -345,62 +503,96 @@ export const dataStore = {
|
||||
title: 'Canlı Yayın'
|
||||
};
|
||||
}
|
||||
const stored = localStorage.getItem(KEYS.LIVE_STREAM);
|
||||
return stored ? JSON.parse(stored) : {
|
||||
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: (config: LiveStreamConfig) => {
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.LIVE_STREAM, JSON.stringify(config));
|
||||
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: (): Message[] => {
|
||||
getMessages: async (): Promise<Message[]> => {
|
||||
if (!isBrowser) return [];
|
||||
const stored = localStorage.getItem(KEYS.MESSAGES);
|
||||
return stored ? JSON.parse(stored) : [];
|
||||
},
|
||||
|
||||
addMessage: (message: Omit<Message, 'id' | 'date' | 'read'>) => {
|
||||
const messages = dataStore.getMessages();
|
||||
const newMessage: Message = {
|
||||
...message,
|
||||
id: Date.now().toString(),
|
||||
date: new Date().toISOString(),
|
||||
read: false
|
||||
};
|
||||
messages.unshift(newMessage);
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.MESSAGES, JSON.stringify(messages));
|
||||
}
|
||||
return newMessage;
|
||||
},
|
||||
|
||||
markMessageAsRead: (id: string) => {
|
||||
const messages = dataStore.getMessages();
|
||||
const updated = messages.map(msg =>
|
||||
msg.id === id ? { ...msg, read: true } : msg
|
||||
);
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.MESSAGES, JSON.stringify(updated));
|
||||
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 [];
|
||||
}
|
||||
},
|
||||
|
||||
deleteMessage: (id: string) => {
|
||||
const messages = dataStore.getMessages();
|
||||
const filtered = messages.filter(msg => msg.id !== id);
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.MESSAGES, JSON.stringify(filtered));
|
||||
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: (): SiteSettings => {
|
||||
getSiteSettings: async (): Promise<SiteSettings> => {
|
||||
if (!isBrowser) {
|
||||
return {
|
||||
contact: {
|
||||
@@ -423,133 +615,185 @@ export const dataStore = {
|
||||
}
|
||||
};
|
||||
}
|
||||
const stored = localStorage.getItem(KEYS.SITE_SETTINGS);
|
||||
if (stored) return JSON.parse(stored);
|
||||
|
||||
// Default settings
|
||||
const defaultSettings: SiteSettings = {
|
||||
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'
|
||||
}
|
||||
};
|
||||
localStorage.setItem(KEYS.SITE_SETTINGS, JSON.stringify(defaultSettings));
|
||||
return defaultSettings;
|
||||
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: (settings: Partial<SiteSettings>) => {
|
||||
const current = dataStore.getSiteSettings();
|
||||
const updated = {
|
||||
...current,
|
||||
...settings,
|
||||
contact: { ...current.contact, ...(settings.contact || {}) },
|
||||
social: { ...current.social, ...(settings.social || {}) },
|
||||
companyInfo: { ...current.companyInfo, ...(settings.companyInfo || {}) }
|
||||
};
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.SITE_SETTINGS, JSON.stringify(updated));
|
||||
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: (): FAQ[] => {
|
||||
getFAQs: async (): Promise<FAQ[]> => {
|
||||
if (!isBrowser) return defaultFAQData;
|
||||
const stored = localStorage.getItem(KEYS.FAQS);
|
||||
return stored ? JSON.parse(stored) : defaultFAQData;
|
||||
},
|
||||
|
||||
setFAQs: (faqs: FAQ[]) => {
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.FAQS, JSON.stringify(faqs));
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
addFAQ: (faq: Omit<FAQ, 'id'>) => {
|
||||
const faqs = dataStore.getFAQs();
|
||||
const newFAQ: FAQ = {
|
||||
...faq,
|
||||
id: faqs.length > 0 ? Math.max(...faqs.map(f => f.id)) + 1 : 1
|
||||
};
|
||||
dataStore.setFAQs([...faqs, newFAQ]);
|
||||
return newFAQ;
|
||||
setFAQs: async () => {
|
||||
console.warn('setFAQs deprecated - use addFAQ/updateFAQ/deleteFAQ');
|
||||
},
|
||||
|
||||
updateFAQ: (id: number, updates: Partial<FAQ>) => {
|
||||
const faqs = dataStore.getFAQs();
|
||||
const updated = faqs.map(faq =>
|
||||
faq.id === id ? { ...faq, ...updates } : faq
|
||||
);
|
||||
dataStore.setFAQs(updated);
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
deleteFAQ: (id: number) => {
|
||||
const faqs = dataStore.getFAQs();
|
||||
dataStore.setFAQs(faqs.filter(faq => faq.id !== id));
|
||||
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: (): Camera[] => {
|
||||
getCameras: async (): Promise<Camera[]> => {
|
||||
if (!isBrowser) return defaultCameraData;
|
||||
const stored = localStorage.getItem(KEYS.CAMERAS);
|
||||
return stored ? JSON.parse(stored) : defaultCameraData;
|
||||
},
|
||||
|
||||
setCameras: (cameras: Camera[]) => {
|
||||
if (isBrowser) {
|
||||
localStorage.setItem(KEYS.CAMERAS, JSON.stringify(cameras));
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
addCamera: (camera: Omit<Camera, 'id'>) => {
|
||||
const cameras = dataStore.getCameras();
|
||||
const newCamera: Camera = {
|
||||
...camera,
|
||||
id: cameras.length > 0 ? Math.max(...cameras.map(c => c.id)) + 1 : 1
|
||||
};
|
||||
dataStore.setCameras([...cameras, newCamera]);
|
||||
return newCamera;
|
||||
setCameras: async () => {
|
||||
console.warn('setCameras deprecated - use addCamera/updateCamera/deleteCamera');
|
||||
},
|
||||
|
||||
updateCamera: (id: number, updates: Partial<Camera>) => {
|
||||
const cameras = dataStore.getCameras();
|
||||
const updated = cameras.map(camera =>
|
||||
camera.id === id ? { ...camera, ...updates } : camera
|
||||
);
|
||||
dataStore.setCameras(updated);
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
deleteCamera: (id: number) => {
|
||||
const cameras = dataStore.getCameras();
|
||||
dataStore.setCameras(cameras.filter(camera => camera.id !== id));
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
// Reset all data
|
||||
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: () => {
|
||||
if (isBrowser) {
|
||||
localStorage.removeItem(KEYS.SLIDER);
|
||||
localStorage.removeItem(KEYS.NEWS);
|
||||
localStorage.removeItem(KEYS.MEDIA);
|
||||
localStorage.removeItem(KEYS.DOCUMENTS);
|
||||
localStorage.removeItem(KEYS.METRO_STATIONS);
|
||||
localStorage.removeItem(KEYS.LIVE_STREAM);
|
||||
localStorage.removeItem(KEYS.SITE_SETTINGS);
|
||||
localStorage.removeItem(KEYS.MESSAGES);
|
||||
localStorage.removeItem(KEYS.FAQS);
|
||||
localStorage.removeItem(KEYS.CAMERAS);
|
||||
}
|
||||
console.warn('resetAll not applicable for API-based storage');
|
||||
}
|
||||
};
|
||||
|
||||
9
lib/prisma.ts
Normal file
9
lib/prisma.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const globalForPrisma = globalThis as unknown as {
|
||||
prisma: PrismaClient | undefined;
|
||||
};
|
||||
|
||||
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
|
||||
Reference in New Issue
Block a user