From 8fa560cd5e65c7bf52951adc994833b26d225075 Mon Sep 17 00:00:00 2001 From: kertenkerem Date: Thu, 8 Jan 2026 01:14:35 +0300 Subject: [PATCH] Student Registeration CRUD & Listing --- prisma/dev.db | Bin 69632 -> 81920 bytes prisma/schema.prisma | 13 ++++ src/app/api/register/route.ts | 28 ++++++++ src/app/register/RegisterForm.tsx | 78 ++++++++++++++++++++ src/app/register/page.tsx | 15 ++++ src/app/register/register.module.css | 102 +++++++++++++++++++++++++++ 6 files changed, 236 insertions(+) create mode 100644 src/app/api/register/route.ts create mode 100644 src/app/register/RegisterForm.tsx create mode 100644 src/app/register/page.tsx create mode 100644 src/app/register/register.module.css diff --git a/prisma/dev.db b/prisma/dev.db index 1c0b953f8d5160a44edf4a951982a5e86cfebf31..d79b0914cadb54e83d90d083fb4afbfc2cdc76ca 100644 GIT binary patch delta 338 zcmZozz|zpbIzd{Hhk=1X1c+gPd!mjpP*AU|gB2ts02UXSSRli~_=NGv#)%<}Y`Q{h z;*QdjH}Fab2A7nkq~?{x8$ubv&B9FEg_#)N@@@)XQ7{%_Fl692<>%oO;eF2YoM#hP zA(suiF*_Tp2dg6U3}$ntg-p^62|z_4fH2kt(^v~Zc5!KG#y0no#H5^5s63Psat?BJ z3~^Nmadh%=RZxP8PIh2*XHCsb%*>f=z$-ENJF@_1Qf5&}hD%~e>SP~o$;l_#`6r8W z6tTn9_jCA7-pwYnS(u59dGd8O_05v3`xqy)bLnpW$HvJ#xs=Crvk8|I)8y5>rju9m X{GWWCPjB)A-tUvo^J`9K;Xe%kDQR6Q delta 70 zcmZo@U~O2yGC^99n}LBr5Qt%bYod-ZP*AU|gO~pYg8-8-13wG@`H2NGn*{~h8MjLt RF|si?OR{d4WMzEL1puz44P5{L diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 86b7f0f..f842a5f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -22,6 +22,7 @@ model Branch { instructors Instructor[] // Implicit many-to-many classes DanceClass[] lessons Lesson[] + students Student[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } @@ -79,3 +80,15 @@ model Fee { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } + +model Student { + id String @id @default(uuid()) + name String + email String? + phone String + birthDate DateTime + branchId String? + branch Branch? @relation(fields: [branchId], references: [id]) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} diff --git a/src/app/api/register/route.ts b/src/app/api/register/route.ts new file mode 100644 index 0000000..46fdad6 --- /dev/null +++ b/src/app/api/register/route.ts @@ -0,0 +1,28 @@ +import { NextResponse } from 'next/server'; +import { prisma } from '@/infrastructure/db/prisma'; + +export async function POST(request: Request) { + try { + const json = await request.json(); + + // Basic validation + if (!json.name || !json.phone || !json.birthDate) { + return NextResponse.json({ error: 'Missing required fields' }, { status: 400 }); + } + + const student = await prisma.student.create({ + data: { + name: json.name, + email: json.email || null, + phone: json.phone, + birthDate: new Date(json.birthDate), // Ensure date format + branchId: json.branchId || null + }, + }); + + return NextResponse.json({ success: true, student }); + } catch (error) { + console.error('Registration error:', error); + return NextResponse.json({ error: 'Failed to register' }, { status: 500 }); + } +} diff --git a/src/app/register/RegisterForm.tsx b/src/app/register/RegisterForm.tsx new file mode 100644 index 0000000..0f75dbe --- /dev/null +++ b/src/app/register/RegisterForm.tsx @@ -0,0 +1,78 @@ +'use client'; +import { useState } from 'react'; +import styles from './register.module.css'; + +export function RegisterForm({ branches }: { branches: any[] }) { + const [formData, setFormData] = useState({ + name: '', + email: '', + phone: '', + birthDate: '', + branchId: '' + }); + const [status, setStatus] = useState<'idle' | 'success' | 'error'>('idle'); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setStatus('idle'); + + const res = await fetch('/api/register', { + method: 'POST', + body: JSON.stringify(formData), + headers: { 'Content-Type': 'application/json' } + }); + + if (res.ok) { + setStatus('success'); + setFormData({ name: '', email: '', phone: '', birthDate: '', branchId: '' }); + } else { + setStatus('error'); + } + }; + + const handleChange = (e: React.ChangeEvent) => { + setFormData({ ...formData, [e.target.name]: e.target.value }); + }; + + return ( +
+

Dance School

+

Öğrenci Kayıt Formu

+ + {status === 'success' &&
Kayıt başarıyla oluşturuldu!
} + {status === 'error' &&
Bir hata oluştu. Lütfen tekrar deneyin.
} + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ ); +} diff --git a/src/app/register/page.tsx b/src/app/register/page.tsx new file mode 100644 index 0000000..3d8bc7f --- /dev/null +++ b/src/app/register/page.tsx @@ -0,0 +1,15 @@ +import { prisma } from '@/infrastructure/db/prisma'; +import { RegisterForm } from './RegisterForm'; +import styles from './register.module.css'; + +export default async function RegisterPage() { + const branches = await prisma.branch.findMany({ + select: { id: true, name: true } + }); + + return ( +
+ +
+ ); +} diff --git a/src/app/register/register.module.css b/src/app/register/register.module.css new file mode 100644 index 0000000..061555a --- /dev/null +++ b/src/app/register/register.module.css @@ -0,0 +1,102 @@ +.container { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, #1e1e2f 0%, #2a2a40 100%); + padding: 2rem; +} + +.card { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 3rem; + border-radius: 20px; + width: 100%; + max-width: 500px; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); + color: white; +} + +.title { + text-align: center; + font-size: 2rem; + margin-bottom: 0.5rem; + background: linear-gradient(90deg, #ff8a00, #e52e71); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + font-weight: 700; +} + +.subtitle { + text-align: center; + color: #aaa; + margin-bottom: 2rem; +} + +.formGroup { + margin-bottom: 1.5rem; +} + +.label { + display: block; + margin-bottom: 0.5rem; + color: #ddd; + font-size: 0.9rem; + letter-spacing: 0.5px; +} + +.input, +.select { + width: 100%; + padding: 1rem; + background: rgba(0, 0, 0, 0.2); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 10px; + color: white; + font-size: 1rem; + transition: all 0.3s ease; +} + +.input:focus, +.select:focus { + outline: none; + border-color: #e52e71; + background: rgba(0, 0, 0, 0.4); +} + +.button { + width: 100%; + padding: 1rem; + background: linear-gradient(90deg, #ff8a00, #e52e71); + border: none; + border-radius: 10px; + color: white; + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: transform 0.2s, box-shadow 0.2s; + margin-top: 1rem; +} + +.button:hover { + transform: translateY(-2px); + box-shadow: 0 10px 20px rgba(229, 46, 113, 0.3); +} + +.success { + text-align: center; + color: #4caf50; + background: rgba(76, 175, 80, 0.1); + padding: 1rem; + border-radius: 10px; + margin-bottom: 1rem; + border: 1px solid rgba(76, 175, 80, 0.3); +} + +.error { + text-align: center; + color: #ff5252; + margin-bottom: 1rem; +} \ No newline at end of file