diff --git a/prisma/dev.db b/prisma/dev.db index eeb0ec3..5b73134 100644 Binary files a/prisma/dev.db and b/prisma/dev.db differ diff --git a/prisma/schema.prisma b/prisma/schema.prisma index f983f60..423aca8 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -19,6 +19,7 @@ model Branch { name String address String? phone String? + hallCount Int? @default(1) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt classes DanceClass[] diff --git a/src/app/admin/branches/AddBranchForm.tsx b/src/app/admin/branches/AddBranchForm.tsx index c3f66bb..b09d862 100644 --- a/src/app/admin/branches/AddBranchForm.tsx +++ b/src/app/admin/branches/AddBranchForm.tsx @@ -6,16 +6,20 @@ import styles from './branches.module.css'; export function AddBranchForm() { const [name, setName] = useState(''); const [address, setAddress] = useState(''); + const [phone, setPhone] = useState(''); + const [hallCount, setHallCount] = useState('1'); const router = useRouter(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); await fetch('/api/branches', { method: 'POST', - body: JSON.stringify({ name, address }), + body: JSON.stringify({ name, address, phone, hallCount: parseInt(hallCount) }), }); setName(''); setAddress(''); + setPhone(''); + setHallCount('1'); router.refresh(); }; @@ -25,10 +29,18 @@ export function AddBranchForm() { setName(e.target.value)} className={styles.input} required /> +
+ + setPhone(e.target.value)} className={styles.input} /> +
setAddress(e.target.value)} className={styles.input} />
+
+ + setHallCount(e.target.value)} className={styles.input} /> +
); diff --git a/src/app/admin/branches/BranchList.tsx b/src/app/admin/branches/BranchList.tsx index dc83b0a..8295334 100644 --- a/src/app/admin/branches/BranchList.tsx +++ b/src/app/admin/branches/BranchList.tsx @@ -17,7 +17,8 @@ export function BranchList({ branches }: { branches: any[] }) {

{b.name}

-

{b.address}

+

{b.phone ? `Tel: ${b.phone}` : 'Telefon yok'} | {b.address || 'Adres yok'}

+ Salon Sayısı: {b.hallCount || 1}
diff --git a/src/app/api/branches/[id]/route.ts b/src/app/api/branches/[id]/route.ts index 5a68415..5682546 100644 --- a/src/app/api/branches/[id]/route.ts +++ b/src/app/api/branches/[id]/route.ts @@ -25,7 +25,10 @@ export async function PUT( const json = await request.json(); const branch = await prisma.branch.update({ where: { id }, - data: json, + data: { + ...json, + hallCount: json.hallCount ? parseInt(json.hallCount) : undefined + }, }); return NextResponse.json(branch); } catch (error) { diff --git a/src/app/api/branches/route.ts b/src/app/api/branches/route.ts index 6055b85..6de689d 100644 --- a/src/app/api/branches/route.ts +++ b/src/app/api/branches/route.ts @@ -16,7 +16,8 @@ export async function POST(request: Request) { data: { name: json.name, address: json.address, - phone: json.phone + phone: json.phone, + hallCount: json.hallCount ? parseInt(json.hallCount) : undefined } }); return NextResponse.json(branch); diff --git a/src/app/page.module.css b/src/app/page.module.css index 59dea42..e370f6d 100644 --- a/src/app/page.module.css +++ b/src/app/page.module.css @@ -1,141 +1,101 @@ .page { - --background: #fafafa; - --foreground: #fff; + --primary: #b21f1f; + --secondary: #1a2a6c; + --accent: #fdbb2d; + --bg-gradient: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); + --white: #ffffff; + --text: #333333; + --text-muted: #666666; - --text-primary: #000; - --text-secondary: #666; - - --button-primary-hover: #383838; - --button-secondary-hover: #f2f2f2; - --button-secondary-border: #ebebeb; - - display: flex; min-height: 100vh; + display: flex; + flex-direction: column; + background: var(--bg-gradient); + font-family: var(--font-outfit, 'Outfit', sans-serif); + color: var(--text); +} + +.nav { + padding: 1.5rem 4rem; + display: flex; + justify-content: space-between; align-items: center; - justify-content: center; - font-family: var(--font-geist-sans); - background-color: var(--background); + background: rgba(255, 255, 255, 0.9); + backdrop-filter: blur(10px); + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); + position: sticky; + top: 0; + z-index: 1000; +} + +.logo { + font-size: 1.5rem; + font-weight: 800; + background: linear-gradient(to right, var(--secondary), var(--primary)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + letter-spacing: -1px; +} + +.adminLink { + padding: 0.6rem 1.2rem; + background: var(--secondary); + color: white; + border-radius: 8px; + text-decoration: none; + font-weight: 600; + transition: all 0.3s; +} + +.adminLink:hover { + background: var(--primary); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } .main { + flex: 1; + padding: 4rem 2rem; display: flex; - min-height: 100vh; - width: 100%; + flex-direction: column; + gap: 3rem; +} + +.hero { + text-align: center; max-width: 800px; - flex-direction: column; - align-items: flex-start; - justify-content: space-between; - background-color: var(--foreground); - padding: 120px 60px; + margin: 0 auto; } -.intro { - display: flex; - flex-direction: column; - align-items: flex-start; - text-align: left; - gap: 24px; +.hero h1 { + font-size: 3.5rem; + font-weight: 900; + margin-bottom: 1rem; + color: #111; + letter-spacing: -2px; } -.intro h1 { - max-width: 320px; - font-size: 40px; - font-weight: 600; - line-height: 48px; - letter-spacing: -2.4px; - text-wrap: balance; - color: var(--text-primary); +.hero p { + font-size: 1.25rem; + color: var(--text-muted); } -.intro p { - max-width: 440px; - font-size: 18px; - line-height: 32px; - text-wrap: balance; - color: var(--text-secondary); +.footer { + padding: 2rem; + text-align: center; + background: rgba(255, 255, 255, 0.5); + border-top: 1px solid rgba(0, 0, 0, 0.05); + color: var(--text-muted); + font-size: 0.9rem; } -.intro a { - font-weight: 500; - color: var(--text-primary); -} - -.ctas { - display: flex; - flex-direction: row; - width: 100%; - max-width: 440px; - gap: 16px; - font-size: 14px; -} - -.ctas a { - display: flex; - justify-content: center; - align-items: center; - height: 40px; - padding: 0 16px; - border-radius: 128px; - border: 1px solid transparent; - transition: 0.2s; - cursor: pointer; - width: fit-content; - font-weight: 500; -} - -a.primary { - background: var(--text-primary); - color: var(--background); - gap: 8px; -} - -a.secondary { - border-color: var(--button-secondary-border); -} - -/* Enable hover only on non-touch devices */ -@media (hover: hover) and (pointer: fine) { - a.primary:hover { - background: var(--button-primary-hover); - border-color: transparent; +@media (max-width: 768px) { + .nav { + padding: 1rem 2rem; } - a.secondary:hover { - background: var(--button-secondary-hover); - border-color: transparent; + .hero h1 { + font-size: 2.5rem; } -} - -@media (max-width: 600px) { - .main { - padding: 48px 24px; - } - - .intro { - gap: 16px; - } - - .intro h1 { - font-size: 32px; - line-height: 40px; - letter-spacing: -1.92px; - } -} - -@media (prefers-color-scheme: dark) { - .logo { - filter: invert(); - } - - .page { - --background: #000; - --foreground: #000; - - --text-primary: #ededed; - --text-secondary: #999; - - --button-primary-hover: #ccc; - --button-secondary-hover: #1a1a1a; - --button-secondary-border: #1a1a1a; - } -} +} \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index 7b947a2..cac642d 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,66 +1,57 @@ -import Image from "next/image"; +import { prisma } from "@/infrastructure/db/prisma"; +import { ScheduleCalendar } from "@/components/ScheduleCalendar"; +import Link from "next/link"; import styles from "./page.module.css"; -export default function Home() { +export default async function Home() { + // Calculate start and end of current week + const now = new Date(); + const dayOfWeek = now.getDay(); // 0 is Sunday + const diff = now.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1); // Adjust to Monday + const startOfWeek = new Date(now.setDate(diff)); + startOfWeek.setHours(0, 0, 0, 0); + + const endOfWeek = new Date(startOfWeek); + endOfWeek.setDate(endOfWeek.getDate() + 7); + + const lessons = await prisma.lesson.findMany({ + where: { + startTime: { + gte: startOfWeek, + lt: endOfWeek, + }, + }, + include: { + instructor: true, + branch: true, + class: true, + }, + orderBy: { + startTime: 'asc', + }, + }); + return (
+ +
- Next.js logo -
-

To get started, edit the page.tsx file.

-

- Looking for a starting point or more instructions? Head over to{" "} - - Templates - {" "} - or the{" "} - - Learning - {" "} - center. -

-
-
- - Vercel logomark - Deploy Now - - - Documentation - -
+
+

Dansın Ritmini Keşfedin

+

Haftalık kurs programımızı aşağıdan takip edebilirsiniz.

+
+ +
+ +
); } diff --git a/src/components/ScheduleCalendar.module.css b/src/components/ScheduleCalendar.module.css new file mode 100644 index 0000000..9011ebe --- /dev/null +++ b/src/components/ScheduleCalendar.module.css @@ -0,0 +1,93 @@ +.container { + padding: 2rem; + max-width: 1200px; + margin: 0 auto; + font-family: var(--font-outfit, 'Outfit', sans-serif); +} + +.title { + text-align: center; + margin-bottom: 2rem; + font-size: 2.5rem; + background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + font-weight: 800; +} + +.calendar { + display: grid; + grid-template-columns: repeat(7, 1fr); + gap: 1rem; + background: rgba(255, 255, 255, 0.8); + backdrop-filter: blur(10px); + border-radius: 16px; + padding: 1.5rem; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); + border: 1px solid rgba(255, 255, 255, 0.2); +} + +.dayColumn { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.dayHeader { + text-align: center; + padding: 1rem; + background: #333; + color: white; + border-radius: 8px; + font-weight: 600; +} + +.lessonCard { + background: white; + padding: 1rem; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); + border-left: 4px solid #b21f1f; + transition: transform 0.2s, box-shadow 0.2s; + cursor: default; +} + +.lessonCard:hover { + transform: translateY(-4px); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1); +} + +.lessonTime { + font-size: 0.85rem; + color: #666; + font-weight: 500; + display: block; + margin-bottom: 0.5rem; +} + +.lessonName { + font-size: 1.1rem; + font-weight: 700; + color: #333; + margin-bottom: 0.5rem; +} + +.lessonDetails { + font-size: 0.8rem; + color: #888; +} + +.empty { + text-align: center; + padding: 2rem; + color: #aaa; + font-style: italic; + grid-column: span 7; +} + +@media (max-width: 1024px) { + .calendar { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/src/components/ScheduleCalendar.tsx b/src/components/ScheduleCalendar.tsx new file mode 100644 index 0000000..3567df1 --- /dev/null +++ b/src/components/ScheduleCalendar.tsx @@ -0,0 +1,80 @@ +'use client'; +import { useMemo } from 'react'; +import styles from './ScheduleCalendar.module.css'; + +interface Lesson { + id: string; + name?: string | null; + startTime: Date | string; + endTime: Date | string; + type: string; + class?: { name: string } | null; + instructor: { name: string }; + branch: { name: string }; +} + +export function ScheduleCalendar({ lessons }: { lessons: Lesson[] }) { + const days = ['Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi', 'Pazar']; + + // Group lessons by day + const groupedLessons = useMemo(() => { + const groups: Record = {}; + lessons.forEach(lesson => { + const date = new Date(lesson.startTime); + // JS getDay() returns 0 for Sunday, 1 for Monday etc. + // We want 0 for Monday, 6 for Sunday + let dayIndex = date.getDay() - 1; + if (dayIndex === -1) dayIndex = 6; + + if (!groups[dayIndex]) groups[dayIndex] = []; + groups[dayIndex].push(lesson); + }); + + // Sort lessons by time in each day + Object.keys(groups).forEach(day => { + groups[parseInt(day)].sort((a, b) => + new Date(a.startTime).getTime() - new Date(b.startTime).getTime() + ); + }); + + return groups; + }, [lessons]); + + const formatTime = (dateStr: string | Date) => { + const date = new Date(dateStr); + return date.toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit', hour12: false }); + }; + + return ( +
+

Haftalık Ders Programı

+
+ {days.map((day, index) => ( +
+
{day}
+ {groupedLessons[index]?.map(lesson => ( +
+ + {formatTime(lesson.startTime)} - {formatTime(lesson.endTime)} + +
+ {lesson.class?.name || lesson.name || 'İsimsiz Ders'} +
+
+
Eğitmen: {lesson.instructor.name}
+
Şube: {lesson.branch.name}
+
Tür: {lesson.type}
+
+
+ ))} + {(!groupedLessons[index] || groupedLessons[index].length === 0) && ( +
+ Ders yok +
+ )} +
+ ))} +
+
+ ); +}