Database
This commit is contained in:
73
app/api/auth/login/route.ts
Normal file
73
app/api/auth/login/route.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { compare } from 'bcryptjs';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { encrypt } from '@/lib/auth';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { username, password } = await request.json();
|
||||
|
||||
if (!username || !password) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Kullanıcı adı ve şifre gerekli' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Kullanıcıyı bul
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { username },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Kullanıcı adı veya şifre hatalı' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
// Şifreyi kontrol et
|
||||
const isPasswordValid = await compare(password, user.password);
|
||||
|
||||
if (!isPasswordValid) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Kullanıcı adı veya şifre hatalı' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
// JWT token oluştur
|
||||
const token = await encrypt({
|
||||
userId: user.id.toString(),
|
||||
username: user.username,
|
||||
});
|
||||
|
||||
// Response oluştur
|
||||
const response = NextResponse.json(
|
||||
{
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
},
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
|
||||
// Cookie'ye token ekle
|
||||
response.cookies.set('session', token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax',
|
||||
maxAge: 60 * 60 * 24, // 24 saat
|
||||
path: '/',
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Giriş yapılırken bir hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
13
app/api/auth/logout/route.ts
Normal file
13
app/api/auth/logout/route.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export async function POST() {
|
||||
const response = NextResponse.json(
|
||||
{ message: 'Çıkış başarılı' },
|
||||
{ status: 200 }
|
||||
);
|
||||
|
||||
// Cookie'yi sil
|
||||
response.cookies.delete('session');
|
||||
|
||||
return response;
|
||||
}
|
||||
18
app/api/auth/session/route.ts
Normal file
18
app/api/auth/session/route.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getSession } from '@/lib/auth';
|
||||
|
||||
export async function GET() {
|
||||
const session = await getSession();
|
||||
|
||||
if (!session) {
|
||||
return NextResponse.json({ authenticated: false }, { status: 401 });
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
authenticated: true,
|
||||
user: {
|
||||
id: session.userId,
|
||||
username: session.username,
|
||||
},
|
||||
});
|
||||
}
|
||||
103
app/api/cameras/route.ts
Normal file
103
app/api/cameras/route.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Tüm kameraları getir
|
||||
export async function GET() {
|
||||
try {
|
||||
const cameras = await prisma.camera.findMany({
|
||||
orderBy: { order: 'asc' },
|
||||
});
|
||||
|
||||
return NextResponse.json(cameras);
|
||||
} catch (error) {
|
||||
console.error('Cameras fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Kameralar alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Yeni kamera ekle (Auth gerekli)
|
||||
export async function POST(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const camera = await prisma.camera.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
location: data.location,
|
||||
videoUrl: data.videoUrl,
|
||||
status: data.status,
|
||||
viewers: data.viewers || 0,
|
||||
order: data.order,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(camera, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('Camera create error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Kamera oluşturulurken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PUT - Kamera güncelle (Auth gerekli)
|
||||
export async function PUT(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const camera = await prisma.camera.update({
|
||||
where: { id: data.id },
|
||||
data: {
|
||||
name: data.name,
|
||||
location: data.location,
|
||||
videoUrl: data.videoUrl,
|
||||
status: data.status,
|
||||
viewers: data.viewers,
|
||||
order: data.order,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(camera);
|
||||
} catch (error) {
|
||||
console.error('Camera update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Kamera güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE - Kamera sil (Auth gerekli)
|
||||
export async function DELETE(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get('id');
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
|
||||
}
|
||||
|
||||
await prisma.camera.delete({
|
||||
where: { id: parseInt(id) },
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: 'Kamera silindi' });
|
||||
} catch (error) {
|
||||
console.error('Camera delete error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Kamera silinirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
116
app/api/documents/route.ts
Normal file
116
app/api/documents/route.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Tüm dokümanları getir
|
||||
export async function GET() {
|
||||
try {
|
||||
const documents = await prisma.document.findMany({
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
return NextResponse.json(documents);
|
||||
} catch (error) {
|
||||
console.error('Documents fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Dökümanlar alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Yeni döküman ekle (Auth gerekli)
|
||||
export async function POST(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const document = await prisma.document.create({
|
||||
data: {
|
||||
title: data.title,
|
||||
type: data.type,
|
||||
category: data.category,
|
||||
downloadUrl: data.fileUrl || data.downloadUrl,
|
||||
size: data.fileSize || data.size || '0 MB',
|
||||
description: data.description,
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(document, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('Document create error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Döküman oluşturulurken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PUT - Döküman güncelle (Auth gerekli)
|
||||
export async function PUT(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const document = await prisma.document.update({
|
||||
where: { id: data.id },
|
||||
data: {
|
||||
title: data.title,
|
||||
type: data.type,
|
||||
category: data.category,
|
||||
downloadUrl: data.fileUrl || data.downloadUrl,
|
||||
size: data.fileSize || data.size,
|
||||
description: data.description,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(document);
|
||||
} catch (error) {
|
||||
console.error('Document update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Döküman güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE - Döküman sil (Auth gerekli)
|
||||
export async function DELETE(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get('id');
|
||||
|
||||
console.log('DELETE document - ID:', id);
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
|
||||
}
|
||||
|
||||
await prisma.document.delete({
|
||||
where: { id: parseInt(id) },
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: 'Döküman silindi' });
|
||||
} catch (error: unknown) {
|
||||
console.error('Document delete error:', error);
|
||||
|
||||
// Prisma P2025: Record not found
|
||||
if (error && typeof error === 'object' && 'code' in error && error.code === 'P2025') {
|
||||
return NextResponse.json(
|
||||
{ error: 'Döküman bulunamadı (zaten silinmiş olabilir)' },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: 'Döküman silinirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
97
app/api/faqs/route.ts
Normal file
97
app/api/faqs/route.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Tüm SSS'leri getir
|
||||
export async function GET() {
|
||||
try {
|
||||
const faqs = await prisma.fAQ.findMany({
|
||||
orderBy: { order: 'asc' },
|
||||
});
|
||||
|
||||
return NextResponse.json(faqs);
|
||||
} catch (error) {
|
||||
console.error('FAQs fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'SSS alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Yeni SSS ekle (Auth gerekli)
|
||||
export async function POST(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const faq = await prisma.fAQ.create({
|
||||
data: {
|
||||
question: data.question,
|
||||
answer: data.answer,
|
||||
order: data.order,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(faq, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('FAQ create error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'SSS oluşturulurken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PUT - SSS güncelle (Auth gerekli)
|
||||
export async function PUT(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const faq = await prisma.fAQ.update({
|
||||
where: { id: data.id },
|
||||
data: {
|
||||
question: data.question,
|
||||
answer: data.answer,
|
||||
order: data.order,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(faq);
|
||||
} catch (error) {
|
||||
console.error('FAQ update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'SSS güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE - SSS sil (Auth gerekli)
|
||||
export async function DELETE(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get('id');
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
|
||||
}
|
||||
|
||||
await prisma.fAQ.delete({
|
||||
where: { id: parseInt(id) },
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: 'SSS silindi' });
|
||||
} catch (error) {
|
||||
console.error('FAQ delete error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'SSS silinirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
57
app/api/live-stream/route.ts
Normal file
57
app/api/live-stream/route.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Aktif canlı yayın bilgisini getir
|
||||
export async function GET() {
|
||||
try {
|
||||
const liveStream = await prisma.liveStream.findFirst({
|
||||
where: { active: true },
|
||||
});
|
||||
|
||||
return NextResponse.json(liveStream || { active: false, url: '', title: '' });
|
||||
} catch (error) {
|
||||
console.error('Live stream fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Canlı yayın bilgisi alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Canlı yayın ayarlarını güncelle (Auth gerekli)
|
||||
export async function POST(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
// Önce tüm canlı yayınları pasif yap
|
||||
await prisma.liveStream.updateMany({
|
||||
data: { active: false },
|
||||
});
|
||||
|
||||
// Yeni ayarları oluştur veya güncelle
|
||||
const liveStream = await prisma.liveStream.upsert({
|
||||
where: { id: data.id || 0 },
|
||||
update: {
|
||||
url: data.url,
|
||||
active: data.active,
|
||||
title: data.title,
|
||||
},
|
||||
create: {
|
||||
url: data.url,
|
||||
active: data.active,
|
||||
title: data.title,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(liveStream);
|
||||
} catch (error) {
|
||||
console.error('Live stream update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Canlı yayın güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
102
app/api/media/route.ts
Normal file
102
app/api/media/route.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Tüm medya öğelerini getir
|
||||
export async function GET() {
|
||||
try {
|
||||
const media = await prisma.media.findMany({
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
return NextResponse.json(media);
|
||||
} catch (error) {
|
||||
console.error('Media fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Medya öğeleri alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Yeni medya öğesi ekle (Auth gerekli)
|
||||
export async function POST(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const media = await prisma.media.create({
|
||||
data: {
|
||||
title: data.title,
|
||||
type: data.type,
|
||||
thumbnail: data.thumbnail,
|
||||
videoUrl: data.videoUrl,
|
||||
description: data.description,
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(media, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('Media create error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Medya öğesi oluşturulurken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PUT - Medya öğesi güncelle (Auth gerekli)
|
||||
export async function PUT(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const media = await prisma.media.update({
|
||||
where: { id: data.id },
|
||||
data: {
|
||||
title: data.title,
|
||||
type: data.type,
|
||||
thumbnail: data.thumbnail,
|
||||
videoUrl: data.videoUrl,
|
||||
description: data.description,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(media);
|
||||
} catch (error) {
|
||||
console.error('Media update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Medya öğesi güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE - Medya öğesi sil (Auth gerekli)
|
||||
export async function DELETE(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get('id');
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
|
||||
}
|
||||
|
||||
await prisma.media.delete({
|
||||
where: { id: parseInt(id) },
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: 'Medya öğesi silindi' });
|
||||
} catch (error) {
|
||||
console.error('Media delete error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Medya öğesi silinirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
98
app/api/messages/route.ts
Normal file
98
app/api/messages/route.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Tüm mesajları getir (Auth gerekli)
|
||||
export async function GET(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const messages = await prisma.message.findMany({
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
return NextResponse.json(messages);
|
||||
} catch (error) {
|
||||
console.error('Messages fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Mesajlar alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// POST - Yeni mesaj gönder (Public - iletişim formu)
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const message = await prisma.message.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
phone: data.phone || '',
|
||||
subject: data.subject,
|
||||
type: data.type || 'contact',
|
||||
message: data.message,
|
||||
read: false,
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(message, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('Message create error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Mesaj gönderilirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// PUT - Mesajı okundu olarak işaretle (Auth gerekli)
|
||||
export async function PUT(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const message = await prisma.message.update({
|
||||
where: { id: data.id },
|
||||
data: { read: data.read },
|
||||
});
|
||||
|
||||
return NextResponse.json(message);
|
||||
} catch (error) {
|
||||
console.error('Message update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Mesaj güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE - Mesaj sil (Auth gerekli)
|
||||
export async function DELETE(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get('id');
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
|
||||
}
|
||||
|
||||
await prisma.message.delete({
|
||||
where: { id: parseInt(id) },
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: 'Mesaj silindi' });
|
||||
} catch (error) {
|
||||
console.error('Message delete error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Mesaj silinirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
107
app/api/news/route.ts
Normal file
107
app/api/news/route.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Tüm haberleri getir
|
||||
export async function GET() {
|
||||
try {
|
||||
const news = await prisma.news.findMany({
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
return NextResponse.json(news);
|
||||
} catch (error) {
|
||||
console.error('News fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Haberler alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Yeni haber ekle (Auth gerekli)
|
||||
export async function POST(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const news = await prisma.news.create({
|
||||
data: {
|
||||
title: data.title,
|
||||
summary: data.summary || data.content.substring(0, 150) + '...',
|
||||
content: data.content,
|
||||
category: data.category,
|
||||
image: data.image,
|
||||
author: data.author,
|
||||
tags: data.tags || '',
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
featured: data.featured || false,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(news, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('News create error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Haber oluşturulurken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PUT - Haber güncelle (Auth gerekli)
|
||||
export async function PUT(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const news = await prisma.news.update({
|
||||
where: { id: data.id },
|
||||
data: {
|
||||
title: data.title,
|
||||
summary: data.summary,
|
||||
content: data.content,
|
||||
category: data.category,
|
||||
image: data.image,
|
||||
author: data.author,
|
||||
tags: data.tags,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(news);
|
||||
} catch (error) {
|
||||
console.error('News update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Haber güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE - Haber sil (Auth gerekli)
|
||||
export async function DELETE(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get('id');
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
|
||||
}
|
||||
|
||||
await prisma.news.delete({
|
||||
where: { id: parseInt(id) },
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: 'Haber silindi' });
|
||||
} catch (error) {
|
||||
console.error('News delete error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Haber silinirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
52
app/api/settings/route.ts
Normal file
52
app/api/settings/route.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Site ayarlarını getir
|
||||
export async function GET() {
|
||||
try {
|
||||
const settings = await prisma.siteSettings.findFirst({
|
||||
where: { key: 'main' },
|
||||
});
|
||||
|
||||
if (!settings) {
|
||||
return NextResponse.json({ error: 'Ayarlar bulunamadı' }, { status: 404 });
|
||||
}
|
||||
|
||||
return NextResponse.json(JSON.parse(settings.value));
|
||||
} catch (error) {
|
||||
console.error('Settings fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Ayarlar alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Site ayarlarını güncelle (Auth gerekli)
|
||||
export async function POST(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const settings = await prisma.siteSettings.upsert({
|
||||
where: { key: 'main' },
|
||||
update: {
|
||||
value: JSON.stringify(data),
|
||||
},
|
||||
create: {
|
||||
key: 'main',
|
||||
value: JSON.stringify(data),
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(JSON.parse(settings.value));
|
||||
} catch (error) {
|
||||
console.error('Settings update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Ayarlar güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
101
app/api/slider/route.ts
Normal file
101
app/api/slider/route.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Tüm slider item'ları getir
|
||||
export async function GET() {
|
||||
try {
|
||||
const items = await prisma.sliderItem.findMany({
|
||||
orderBy: { id: 'asc' },
|
||||
});
|
||||
|
||||
return NextResponse.json(items);
|
||||
} catch (error) {
|
||||
console.error('Slider items fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Slider items alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Yeni slider item ekle (Auth gerekli)
|
||||
export async function POST(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const item = await prisma.sliderItem.create({
|
||||
data: {
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
buttonText: data.buttonText,
|
||||
buttonLink: data.buttonLink,
|
||||
active: data.active ?? true,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(item, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('Slider item create error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Slider item oluşturulurken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PUT - Slider item güncelle (Auth gerekli)
|
||||
export async function PUT(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const item = await prisma.sliderItem.update({
|
||||
where: { id: data.id },
|
||||
data: {
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
buttonText: data.buttonText,
|
||||
buttonLink: data.buttonLink,
|
||||
active: data.active,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(item);
|
||||
} catch (error) {
|
||||
console.error('Slider item update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Slider item güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE - Slider item sil (Auth gerekli)
|
||||
export async function DELETE(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get('id');
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
|
||||
}
|
||||
|
||||
await prisma.sliderItem.delete({
|
||||
where: { id: parseInt(id) },
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: 'Slider item silindi' });
|
||||
} catch (error) {
|
||||
console.error('Slider item delete error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Slider item silinirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
101
app/api/stations/route.ts
Normal file
101
app/api/stations/route.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { withAuth } from '@/lib/auth';
|
||||
|
||||
// GET - Tüm metro istasyonlarını getir
|
||||
export async function GET() {
|
||||
try {
|
||||
const stations = await prisma.metroStation.findMany({
|
||||
orderBy: { order: 'asc' },
|
||||
});
|
||||
|
||||
return NextResponse.json(stations);
|
||||
} catch (error) {
|
||||
console.error('Stations fetch error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'İstasyonlar alınırken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST - Yeni istasyon ekle (Auth gerekli)
|
||||
export async function POST(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const station = await prisma.metroStation.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
status: data.status,
|
||||
progress: data.progress,
|
||||
order: data.order,
|
||||
description: data.description || data.estimatedCompletion,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(station, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('Station create error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'İstasyon oluşturulurken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PUT - İstasyon güncelle (Auth gerekli)
|
||||
export async function PUT(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
const station = await prisma.metroStation.update({
|
||||
where: { id: data.id },
|
||||
data: {
|
||||
name: data.name,
|
||||
status: data.status,
|
||||
progress: data.progress,
|
||||
order: data.order,
|
||||
description: data.description || data.estimatedCompletion,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(station);
|
||||
} catch (error) {
|
||||
console.error('Station update error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'İstasyon güncellenirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE - İstasyon sil (Auth gerekli)
|
||||
export async function DELETE(request: NextRequest) {
|
||||
return withAuth(request, async () => {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get('id');
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: 'ID gerekli' }, { status: 400 });
|
||||
}
|
||||
|
||||
await prisma.metroStation.delete({
|
||||
where: { id: parseInt(id) },
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: 'İstasyon silindi' });
|
||||
} catch (error) {
|
||||
console.error('Station delete error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'İstasyon silinirken hata oluştu' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -11,7 +11,7 @@ export default function Documents() {
|
||||
const [selectedCategory, setSelectedCategory] = useState('all');
|
||||
|
||||
useEffect(() => {
|
||||
setDocuments(dataStore.getDocuments());
|
||||
dataStore.getDocuments().then(setDocuments);
|
||||
}, []);
|
||||
|
||||
const categories = [
|
||||
|
||||
@@ -11,13 +11,15 @@ export default function LiveStream() {
|
||||
const [cameras, setCameras] = useState<Camera[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadedCameras = dataStore.getCameras()
|
||||
.filter(cam => cam.status === 'online')
|
||||
.sort((a, b) => a.order - b.order);
|
||||
setCameras(loadedCameras);
|
||||
if (loadedCameras.length > 0) {
|
||||
setSelectedCamera(loadedCameras[0].id);
|
||||
}
|
||||
dataStore.getCameras().then(loadedCameras => {
|
||||
const onlineCameras = loadedCameras
|
||||
.filter(cam => cam.status === 'online')
|
||||
.sort((a, b) => a.order - b.order);
|
||||
setCameras(onlineCameras);
|
||||
if (onlineCameras.length > 0) {
|
||||
setSelectedCamera(onlineCameras[0].id);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
const selectedCam = cameras.find(cam => cam.id === selectedCamera) || cameras[0];
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function News() {
|
||||
const [selectedNews, setSelectedNews] = useState<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setNewsData(dataStore.getNews());
|
||||
dataStore.getNews().then(setNewsData);
|
||||
}, []);
|
||||
|
||||
const filteredNews = selectedCategory === 'all'
|
||||
|
||||
@@ -7,11 +7,51 @@ import { dataStore, type SiteSettings } from '@/lib/dataStore';
|
||||
|
||||
export default function Contact() {
|
||||
const [settings, setSettings] = useState<SiteSettings | null>(null);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
email: '',
|
||||
phone: '',
|
||||
subject: '',
|
||||
message: ''
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setSettings(dataStore.getSiteSettings());
|
||||
dataStore.getSiteSettings().then(setSettings);
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
await dataStore.addMessage({
|
||||
name: formData.name,
|
||||
email: formData.email,
|
||||
phone: formData.phone,
|
||||
subject: formData.subject,
|
||||
message: formData.message,
|
||||
type: 'contact'
|
||||
});
|
||||
|
||||
alert('Mesajınız başarıyla gönderildi! En kısa sürede size dönüş yapacağız.');
|
||||
|
||||
// Formu temizle
|
||||
setFormData({
|
||||
name: '',
|
||||
email: '',
|
||||
phone: '',
|
||||
subject: '',
|
||||
message: ''
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Mesaj gönderilirken hata:', error);
|
||||
alert('Mesaj gönderilirken bir hata oluştu. Lütfen tekrar deneyin.');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (!settings) return null;
|
||||
|
||||
return (
|
||||
@@ -152,10 +192,7 @@ export default function Contact() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form className="max-w-2xl mx-auto space-y-6" onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
alert('Mesajınız gönderildi! (Demo)');
|
||||
}}>
|
||||
<form className="max-w-2xl mx-auto space-y-6" onSubmit={handleSubmit}>
|
||||
{/* İki Sütunlu Alan */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Ad Soyad */}
|
||||
@@ -167,6 +204,8 @@ export default function Contact() {
|
||||
type="text"
|
||||
id="contact-name"
|
||||
required
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#00B4D8] focus:border-transparent outline-none transition-all text-gray-900 placeholder:text-gray-500"
|
||||
placeholder="Adınız ve Soyadınız"
|
||||
/>
|
||||
@@ -181,6 +220,8 @@ export default function Contact() {
|
||||
type="email"
|
||||
id="contact-email"
|
||||
required
|
||||
value={formData.email}
|
||||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#00B4D8] focus:border-transparent outline-none transition-all text-gray-900 placeholder:text-gray-500"
|
||||
placeholder="ornek@email.com"
|
||||
/>
|
||||
@@ -194,6 +235,8 @@ export default function Contact() {
|
||||
<input
|
||||
type="tel"
|
||||
id="contact-phone"
|
||||
value={formData.phone}
|
||||
onChange={(e) => setFormData({ ...formData, phone: e.target.value })}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#00B4D8] focus:border-transparent outline-none transition-all text-gray-900 placeholder:text-gray-500"
|
||||
placeholder="0(5__) ___ __ __"
|
||||
/>
|
||||
@@ -208,6 +251,8 @@ export default function Contact() {
|
||||
type="text"
|
||||
id="contact-subject"
|
||||
required
|
||||
value={formData.subject}
|
||||
onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#00B4D8] focus:border-transparent outline-none transition-all text-gray-900 placeholder:text-gray-500"
|
||||
placeholder="Mesaj konusu"
|
||||
/>
|
||||
@@ -223,6 +268,8 @@ export default function Contact() {
|
||||
id="contact-message"
|
||||
required
|
||||
rows={6}
|
||||
value={formData.message}
|
||||
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#00B4D8] focus:border-transparent outline-none transition-all resize-none text-gray-900 placeholder:text-gray-500"
|
||||
placeholder="Lütfen mesajınızı yazınız..."
|
||||
></textarea>
|
||||
@@ -246,12 +293,25 @@ export default function Contact() {
|
||||
<div className="text-center pt-4">
|
||||
<button
|
||||
type="submit"
|
||||
className="px-8 py-3 bg-[#00B4D8] text-white rounded-lg hover:bg-[#004B87] transition-colors font-semibold shadow-lg hover:shadow-xl flex items-center justify-center space-x-2 mx-auto"
|
||||
disabled={isSubmitting}
|
||||
className="px-8 py-3 bg-[#00B4D8] text-white rounded-lg hover:bg-[#004B87] transition-colors font-semibold shadow-lg hover:shadow-xl flex items-center justify-center space-x-2 mx-auto disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
|
||||
</svg>
|
||||
<span>Gönder</span>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<svg className="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
<span>Gönderiliyor...</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
|
||||
</svg>
|
||||
<span>Gönder</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function MediaGallery() {
|
||||
const [selectedMedia, setSelectedMedia] = useState<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setMediaItems(dataStore.getMedia());
|
||||
dataStore.getMedia().then(setMediaItems);
|
||||
}, []);
|
||||
|
||||
const filteredMedia = selectedTab === 'all'
|
||||
|
||||
15
app/page.tsx
15
app/page.tsx
@@ -10,7 +10,8 @@ import DocumentsSection from "@/components/DocumentsSection";
|
||||
import MediaGallery from "@/components/MediaGallery";
|
||||
import ComplaintForm from "@/components/ComplaintForm";
|
||||
import ContactSection from "@/components/ContactSection";
|
||||
import { dataStore } from '@/lib/dataStore';
|
||||
import { dataStore, type SliderItem, type LiveStreamConfig } from '@/lib/dataStore';
|
||||
import type { NewsItem } from '@/data/news';
|
||||
|
||||
export default function Home() {
|
||||
const [showLiveStream, setShowLiveStream] = useState(false);
|
||||
@@ -23,15 +24,15 @@ export default function Home() {
|
||||
const [currentSlide, setCurrentSlide] = useState(0);
|
||||
|
||||
// Gerçek veriler için state
|
||||
const [heroSlides, setHeroSlides] = useState(dataStore.getSlider());
|
||||
const [newsData, setNewsData] = useState(dataStore.getNews());
|
||||
const [liveStreamConfig, setLiveStreamConfig] = useState(dataStore.getLiveStream());
|
||||
const [heroSlides, setHeroSlides] = useState<SliderItem[]>([]);
|
||||
const [newsData, setNewsData] = useState<NewsItem[]>([]);
|
||||
const [liveStreamConfig, setLiveStreamConfig] = useState<LiveStreamConfig>({ url: '', active: false });
|
||||
|
||||
// Verileri yükle
|
||||
useEffect(() => {
|
||||
setHeroSlides(dataStore.getSlider());
|
||||
setNewsData(dataStore.getNews());
|
||||
setLiveStreamConfig(dataStore.getLiveStream());
|
||||
dataStore.getSlider().then(setHeroSlides);
|
||||
dataStore.getNews().then(setNewsData);
|
||||
dataStore.getLiveStream().then(setLiveStreamConfig);
|
||||
}, []);
|
||||
|
||||
// Modal açıldığında yukarı kaydır - KALDIRILDI (kullanıcı deneyimi için)
|
||||
|
||||
@@ -11,7 +11,9 @@ export default function FAQPage() {
|
||||
const [faqs, setFaqs] = useState<FAQ[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
setFaqs(dataStore.getFAQs().sort((a, b) => a.order - b.order));
|
||||
dataStore.getFAQs().then(faqs => {
|
||||
setFaqs(faqs.sort((a, b) => a.order - b.order));
|
||||
});
|
||||
}, []);
|
||||
|
||||
const toggleFAQ = (id: number) => {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,12 +14,28 @@ export default function AdminLogin() {
|
||||
setLoading(true);
|
||||
setError('');
|
||||
|
||||
// Basit auth - production'da backend ile yapılmalı
|
||||
if (credentials.username === 'admin' && credentials.password === 'A2Metro2025!') {
|
||||
localStorage.setItem('admin_token', 'authenticated');
|
||||
try {
|
||||
const response = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(credentials),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
setError(data.error || 'Giriş başarısız');
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Başarılı giriş
|
||||
router.push('/yonetim-paneli-a2m-secure/dashboard');
|
||||
} else {
|
||||
setError('Kullanıcı adı veya şifre hatalı');
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
setError('Bir hata oluştu. Lütfen tekrar deneyin.');
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user