feat: Implement student CRUD operations in admin panel with dedicated API routes and updated Prisma schema.
This commit is contained in:
BIN
prisma/dev.db
BIN
prisma/dev.db
Binary file not shown.
@@ -19,12 +19,12 @@ model Branch {
|
|||||||
name String
|
name String
|
||||||
address String?
|
address String?
|
||||||
phone String?
|
phone String?
|
||||||
instructors Instructor[] // Implicit many-to-many
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
classes DanceClass[]
|
classes DanceClass[]
|
||||||
lessons Lesson[]
|
lessons Lesson[]
|
||||||
students Student[]
|
students Student[]
|
||||||
createdAt DateTime @default(now())
|
instructors Instructor[] @relation("BranchToInstructor")
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model Instructor {
|
model Instructor {
|
||||||
@@ -32,11 +32,11 @@ model Instructor {
|
|||||||
name String
|
name String
|
||||||
bio String?
|
bio String?
|
||||||
phone String?
|
phone String?
|
||||||
branches Branch[] // Implicit many-to-many
|
|
||||||
classes DanceClass[]
|
|
||||||
lessons Lesson[]
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
classes DanceClass[]
|
||||||
|
lessons Lesson[]
|
||||||
|
branches Branch[] @relation("BranchToInstructor")
|
||||||
}
|
}
|
||||||
|
|
||||||
model DanceClass {
|
model DanceClass {
|
||||||
@@ -44,29 +44,29 @@ model DanceClass {
|
|||||||
name String
|
name String
|
||||||
description String?
|
description String?
|
||||||
branchId String
|
branchId String
|
||||||
branch Branch @relation(fields: [branchId], references: [id])
|
|
||||||
instructorId String?
|
instructorId String?
|
||||||
instructor Instructor? @relation(fields: [instructorId], references: [id])
|
|
||||||
lessons Lesson[]
|
|
||||||
fees Fee[]
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
instructor Instructor? @relation(fields: [instructorId], references: [id])
|
||||||
|
branch Branch @relation(fields: [branchId], references: [id])
|
||||||
|
fees Fee[]
|
||||||
|
lessons Lesson[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model Lesson {
|
model Lesson {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
name String? // Optional name e.g. "Special Workshop"
|
name String?
|
||||||
startTime DateTime
|
startTime DateTime
|
||||||
endTime DateTime
|
endTime DateTime
|
||||||
type String // GROUP, PRIVATE
|
type String
|
||||||
branchId String
|
branchId String
|
||||||
branch Branch @relation(fields: [branchId], references: [id])
|
|
||||||
instructorId String
|
instructorId String
|
||||||
instructor Instructor @relation(fields: [instructorId], references: [id])
|
|
||||||
classId String?
|
classId String?
|
||||||
class DanceClass? @relation(fields: [classId], references: [id])
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
class DanceClass? @relation(fields: [classId], references: [id])
|
||||||
|
instructor Instructor @relation(fields: [instructorId], references: [id])
|
||||||
|
branch Branch @relation(fields: [branchId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Fee {
|
model Fee {
|
||||||
@@ -74,11 +74,11 @@ model Fee {
|
|||||||
name String
|
name String
|
||||||
amount Float
|
amount Float
|
||||||
currency String @default("TRY")
|
currency String @default("TRY")
|
||||||
type String // MONTHLY, PER_LESSON, PACKAGE
|
type String
|
||||||
classId String?
|
classId String?
|
||||||
class DanceClass? @relation(fields: [classId], references: [id])
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
class DanceClass? @relation(fields: [classId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Student {
|
model Student {
|
||||||
@@ -88,7 +88,7 @@ model Student {
|
|||||||
phone String
|
phone String
|
||||||
birthDate DateTime
|
birthDate DateTime
|
||||||
branchId String?
|
branchId String?
|
||||||
branch Branch? @relation(fields: [branchId], references: [id])
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
branch Branch? @relation(fields: [branchId], references: [id])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import styles from './register.module.css';
|
import { useRouter } from 'next/navigation';
|
||||||
|
import styles from '../branches/branches.module.css';
|
||||||
|
|
||||||
export function RegisterForm({ branches }: { branches: any[] }) {
|
export function RegisterForm({ branches }: { branches: any[] }) {
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
@@ -10,12 +11,10 @@ export function RegisterForm({ branches }: { branches: any[] }) {
|
|||||||
birthDate: '',
|
birthDate: '',
|
||||||
branchId: ''
|
branchId: ''
|
||||||
});
|
});
|
||||||
const [status, setStatus] = useState<'idle' | 'success' | 'error'>('idle');
|
const router = useRouter();
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setStatus('idle');
|
|
||||||
|
|
||||||
const res = await fetch('/api/register', {
|
const res = await fetch('/api/register', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(formData),
|
body: JSON.stringify(formData),
|
||||||
@@ -23,10 +22,8 @@ export function RegisterForm({ branches }: { branches: any[] }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
setStatus('success');
|
|
||||||
setFormData({ name: '', email: '', phone: '', birthDate: '', branchId: '' });
|
setFormData({ name: '', email: '', phone: '', birthDate: '', branchId: '' });
|
||||||
} else {
|
router.refresh();
|
||||||
setStatus('error');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -35,41 +32,38 @@ export function RegisterForm({ branches }: { branches: any[] }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit} className={styles.card}>
|
<form onSubmit={handleSubmit} className={styles.form}>
|
||||||
{status === 'success' && <div className={styles.success}>Kayıt başarıyla oluşturuldu!</div>}
|
<div className={styles.inputGroup}>
|
||||||
{status === 'error' && <div className={styles.error}>Bir hata oluştu. Lütfen tekrar deneyin.</div>}
|
<label>Ad Soyad</label>
|
||||||
|
|
||||||
<div className={styles.formGroup}>
|
|
||||||
<label className={styles.label}>Ad Soyad</label>
|
|
||||||
<input name="name" value={formData.name} onChange={handleChange} className={styles.input} required placeholder="Adınız" />
|
<input name="name" value={formData.name} onChange={handleChange} className={styles.input} required placeholder="Adınız" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.formGroup}>
|
<div className={styles.inputGroup}>
|
||||||
<label className={styles.label}>Email (İsteğe bağlı)</label>
|
<label>Email</label>
|
||||||
<input name="email" type="email" value={formData.email} onChange={handleChange} className={styles.input} placeholder="ornek@email.com" />
|
<input name="email" type="email" value={formData.email} onChange={handleChange} className={styles.input} placeholder="ornek@email.com" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.formGroup}>
|
<div className={styles.inputGroup}>
|
||||||
<label className={styles.label}>Telefon</label>
|
<label>Telefon</label>
|
||||||
<input name="phone" type="tel" value={formData.phone} onChange={handleChange} className={styles.input} required placeholder="5XX XXX XX XX" />
|
<input name="phone" type="tel" value={formData.phone} onChange={handleChange} className={styles.input} required placeholder="5XX XXX XX XX" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.formGroup}>
|
<div className={styles.inputGroup}>
|
||||||
<label className={styles.label}>Doğum Tarihi</label>
|
<label>Doğum Tarihi</label>
|
||||||
<input name="birthDate" type="date" value={formData.birthDate} onChange={handleChange} className={styles.input} required />
|
<input name="birthDate" type="date" value={formData.birthDate} onChange={handleChange} className={styles.input} required />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.formGroup}>
|
<div className={styles.inputGroup}>
|
||||||
<label className={styles.label}>Tercih Edilen Şube</label>
|
<label>Şube</label>
|
||||||
<select name="branchId" value={formData.branchId} onChange={handleChange} className={styles.select}>
|
<select name="branchId" value={formData.branchId} onChange={handleChange} className={styles.input}>
|
||||||
<option value="">Seçiniz (Opsiyonel)</option>
|
<option value="">Seçiniz</option>
|
||||||
{branches.map(b => (
|
{branches.map(b => (
|
||||||
<option key={b.id} value={b.id}>{b.name}</option>
|
<option key={b.id} value={b.id}>{b.name}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" className={styles.button}>Kayıt Ol</button>
|
<button type="submit" className={styles.btn}>Kaydet</button>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
134
src/app/admin/register/StudentList.tsx
Normal file
134
src/app/admin/register/StudentList.tsx
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
'use client';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import styles from '../branches/branches.module.css';
|
||||||
|
|
||||||
|
export function StudentList({ students, branches }: { students: any[], branches: any[] }) {
|
||||||
|
const router = useRouter();
|
||||||
|
const [showSensitive, setShowSensitive] = useState(false);
|
||||||
|
const [editingId, setEditingId] = useState<string | null>(null);
|
||||||
|
const [editForm, setEditForm] = useState<any>(null);
|
||||||
|
|
||||||
|
const handleDelete = async (id: string) => {
|
||||||
|
if (!confirm('Kaydı silmek istediğinize emin misiniz?')) return;
|
||||||
|
const res = await fetch(`/api/students/${id}`, { method: 'DELETE' });
|
||||||
|
if (res.ok) {
|
||||||
|
router.refresh();
|
||||||
|
} else {
|
||||||
|
alert('Silme işlemi başarısız oldu.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const startEdit = (student: any) => {
|
||||||
|
setEditingId(student.id);
|
||||||
|
setEditForm({
|
||||||
|
name: student.name,
|
||||||
|
email: student.email || '',
|
||||||
|
phone: student.phone,
|
||||||
|
branchId: student.branchId || '',
|
||||||
|
birthDate: student.birthDate ? new Date(student.birthDate).toISOString().split('T')[0] : ''
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpdate = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const res = await fetch(`/api/students/${editingId}`, {
|
||||||
|
method: 'PATCH',
|
||||||
|
body: JSON.stringify(editForm),
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
setEditingId(null);
|
||||||
|
router.refresh();
|
||||||
|
} else {
|
||||||
|
alert('Güncelleme başarısız oldu.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const maskInfo = (text: string) => {
|
||||||
|
if (!text) return 'Yok';
|
||||||
|
if (showSensitive) return text;
|
||||||
|
return text.replace(/.(?=.{4})/g, '*');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.list}>
|
||||||
|
<div style={{ marginBottom: '1rem', display: 'flex', justifyContent: 'flex-end' }}>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowSensitive(!showSensitive)}
|
||||||
|
className={styles.btn}
|
||||||
|
style={{ background: showSensitive ? '#666' : '#0056b3' }}
|
||||||
|
>
|
||||||
|
{showSensitive ? 'Bilgileri Gizle' : 'Bilgileri Göster'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{students.map(s => (
|
||||||
|
<div key={s.id} className={styles.card}>
|
||||||
|
{editingId === s.id ? (
|
||||||
|
<form onSubmit={handleUpdate} style={{ width: '100%', display: 'flex', gap: '1rem', flexWrap: 'wrap', alignItems: 'flex-end' }}>
|
||||||
|
<div className={styles.inputGroup}>
|
||||||
|
<label>Ad Soyad</label>
|
||||||
|
<input
|
||||||
|
value={editForm.name}
|
||||||
|
onChange={e => setEditForm({ ...editForm, name: e.target.value })}
|
||||||
|
className={styles.input}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.inputGroup}>
|
||||||
|
<label>Telefon</label>
|
||||||
|
<input
|
||||||
|
value={editForm.phone}
|
||||||
|
onChange={e => setEditForm({ ...editForm, phone: e.target.value })}
|
||||||
|
className={styles.input}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.inputGroup}>
|
||||||
|
<label>Email</label>
|
||||||
|
<input
|
||||||
|
value={editForm.email}
|
||||||
|
onChange={e => setEditForm({ ...editForm, email: e.target.value })}
|
||||||
|
className={styles.input}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.inputGroup}>
|
||||||
|
<label>Şube</label>
|
||||||
|
<select
|
||||||
|
value={editForm.branchId}
|
||||||
|
onChange={e => setEditForm({ ...editForm, branchId: e.target.value })}
|
||||||
|
className={styles.input}
|
||||||
|
>
|
||||||
|
<option value="">Seçiniz</option>
|
||||||
|
{branches.map(b => (
|
||||||
|
<option key={b.id} value={b.id}>{b.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', gap: '0.5rem' }}>
|
||||||
|
<button type="submit" className={styles.btn} style={{ background: '#2e7d32' }}>Kaydet</button>
|
||||||
|
<button type="button" onClick={() => setEditingId(null)} className={styles.btn}>İptal</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<h3>{s.name}</h3>
|
||||||
|
<p>
|
||||||
|
<strong>Tel:</strong> {maskInfo(s.phone)} |
|
||||||
|
<strong> Email:</strong> {maskInfo(s.email)}
|
||||||
|
</p>
|
||||||
|
<small>{s.branch?.name || 'Şube seçilmemiş'}</small>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', gap: '0.5rem' }}>
|
||||||
|
<button onClick={() => startEdit(s)} className={styles.btn} style={{ background: '#ffa000' }}>Düzenle</button>
|
||||||
|
<button onClick={() => handleDelete(s.id)} className={`${styles.btn} ${styles.btnDelete}`}>Sil</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,18 +1,27 @@
|
|||||||
import { prisma } from '@/infrastructure/db/prisma';
|
import { prisma } from '@/infrastructure/db/prisma';
|
||||||
import { RegisterForm } from './RegisterForm';
|
import { RegisterForm } from './RegisterForm';
|
||||||
import styles from './register.module.css';
|
import { StudentList } from './StudentList';
|
||||||
|
import styles from '../branches/branches.module.css';
|
||||||
|
|
||||||
export default async function RegisterPage() {
|
export default async function Page() {
|
||||||
const branches = await prisma.branch.findMany({
|
const [branches, students] = await Promise.all([
|
||||||
select: { id: true, name: true }
|
prisma.branch.findMany({ select: { id: true, name: true } }),
|
||||||
});
|
prisma.student.findMany({
|
||||||
|
include: { branch: true },
|
||||||
|
orderBy: { createdAt: 'desc' }
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<h1 className={styles.title}>Yeni Öğrenci Kaydı</h1>
|
<h1>Öğrenci Kayıt İşlemleri</h1>
|
||||||
</div>
|
</div>
|
||||||
<RegisterForm branches={branches} />
|
<RegisterForm branches={branches} />
|
||||||
|
<div className={styles.header} style={{ marginTop: '2rem' }}>
|
||||||
|
<h2>Kayıtlı Öğrenciler</h2>
|
||||||
|
</div>
|
||||||
|
<StudentList students={students} branches={branches} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
.container {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 2rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
background: white;
|
|
||||||
padding: 2rem;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
||||||
max-width: 800px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formGroup {
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #555;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input,
|
|
||||||
.select {
|
|
||||||
padding: 0.75rem;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 6px;
|
|
||||||
font-size: 1rem;
|
|
||||||
color: #333;
|
|
||||||
background-color: #fff;
|
|
||||||
transition: border-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input:focus,
|
|
||||||
.select:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
padding: 0.75rem 2rem;
|
|
||||||
background: #333;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 6px;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
margin-top: 1rem;
|
|
||||||
align-self: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:hover {
|
|
||||||
background: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.success {
|
|
||||||
background-color: #e8f5e9;
|
|
||||||
color: #2e7d32;
|
|
||||||
padding: 1rem;
|
|
||||||
border-radius: 6px;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
border: 1px solid #c8e6c9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
background-color: #ffebee;
|
|
||||||
color: #c62828;
|
|
||||||
padding: 1rem;
|
|
||||||
border-radius: 6px;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
border: 1px solid #ffcdd2;
|
|
||||||
}
|
|
||||||
@@ -3,11 +3,12 @@ import { prisma } from '@/infrastructure/db/prisma';
|
|||||||
|
|
||||||
export async function DELETE(
|
export async function DELETE(
|
||||||
request: Request,
|
request: Request,
|
||||||
{ params }: { params: { id: string } }
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
const { id } = await params;
|
||||||
await prisma.branch.delete({
|
await prisma.branch.delete({
|
||||||
where: { id: params.id },
|
where: { id },
|
||||||
});
|
});
|
||||||
return NextResponse.json({ success: true });
|
return NextResponse.json({ success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -17,12 +18,13 @@ export async function DELETE(
|
|||||||
|
|
||||||
export async function PUT(
|
export async function PUT(
|
||||||
request: Request,
|
request: Request,
|
||||||
{ params }: { params: { id: string } }
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
const { id } = await params;
|
||||||
const json = await request.json();
|
const json = await request.json();
|
||||||
const branch = await prisma.branch.update({
|
const branch = await prisma.branch.update({
|
||||||
where: { id: params.id },
|
where: { id },
|
||||||
data: json,
|
data: json,
|
||||||
});
|
});
|
||||||
return NextResponse.json(branch);
|
return NextResponse.json(branch);
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import { prisma } from '@/infrastructure/db/prisma';
|
|||||||
|
|
||||||
export async function DELETE(
|
export async function DELETE(
|
||||||
request: Request,
|
request: Request,
|
||||||
{ params }: { params: { id: string } }
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
const { id } = await params;
|
||||||
await prisma.danceClass.delete({
|
await prisma.danceClass.delete({
|
||||||
where: { id: params.id },
|
where: { id },
|
||||||
});
|
});
|
||||||
return NextResponse.json({ success: true });
|
return NextResponse.json({ success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import { prisma } from '@/infrastructure/db/prisma';
|
|||||||
|
|
||||||
export async function DELETE(
|
export async function DELETE(
|
||||||
request: Request,
|
request: Request,
|
||||||
{ params }: { params: { id: string } }
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
const { id } = await params;
|
||||||
await prisma.instructor.delete({
|
await prisma.instructor.delete({
|
||||||
where: { id: params.id },
|
where: { id },
|
||||||
});
|
});
|
||||||
return NextResponse.json({ success: true });
|
return NextResponse.json({ success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
42
src/app/api/students/[id]/route.ts
Normal file
42
src/app/api/students/[id]/route.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { prisma } from '@/infrastructure/db/prisma';
|
||||||
|
|
||||||
|
export async function PATCH(
|
||||||
|
request: Request,
|
||||||
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { id } = await params;
|
||||||
|
const json = await request.json();
|
||||||
|
const student = await prisma.student.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
name: json.name,
|
||||||
|
email: json.email || null,
|
||||||
|
phone: json.phone,
|
||||||
|
birthDate: json.birthDate ? new Date(json.birthDate) : undefined,
|
||||||
|
branchId: json.branchId || null
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return NextResponse.json({ success: true, student });
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Update error:', error);
|
||||||
|
return NextResponse.json({ error: 'Failed to update student', details: error.message }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function DELETE(
|
||||||
|
request: Request,
|
||||||
|
{ params }: { params: Promise<{ id: string }> }
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const { id } = await params;
|
||||||
|
await prisma.student.delete({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
return NextResponse.json({ success: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Delete error:', error);
|
||||||
|
return NextResponse.json({ error: 'Failed to delete student' }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,13 @@ import { PrismaClient } from '@prisma/client';
|
|||||||
|
|
||||||
const globalForPrisma = global as unknown as { prisma: PrismaClient };
|
const globalForPrisma = global as unknown as { prisma: PrismaClient };
|
||||||
|
|
||||||
export const prisma =
|
const prismaInstance = globalForPrisma.prisma || new PrismaClient();
|
||||||
globalForPrisma.prisma ||
|
|
||||||
new PrismaClient();
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
globalForPrisma.prisma = prismaInstance;
|
||||||
|
// Log models to verify generation
|
||||||
|
const models = Object.keys(prismaInstance).filter(k => !k.startsWith('_') && !k.startsWith('$'));
|
||||||
|
console.log('Prisma models available:', models);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const prisma = prismaInstance;
|
||||||
|
|||||||
Reference in New Issue
Block a user