diff --git a/README.md b/README.md index 8492eb2..23258af 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,210 @@ -# Contribution Guidelines -We are thrilled to welcome contributors to **Leadlly**! Below are the guidelines to help you contribute efficiently. - -## 📚 Getting Started - -### Prerequisites: - -- **Node.js** (>= 14.x.x) -- **npm** or **yarn** (package manager) - -### Installation: - -1. **Fork the Repository:** - - Click the "Fork" button in the top-right corner of the page to create your own copy of the repository. - -2. **Clone the Forked Repository:** - ```bash - git clone https://github.com/{your-username}/leadlly.admin.web.git - cd leadlly.admin.web - ``` - -3. **Install dependencies**: - ```bash - npm install - ``` - -4. **Run the application**: - ```bash - npm run dev - ``` - -5. **Access the application**: - Open [http://localhost:3000](http://localhost:3000) in your browser. - -## 🎯 How to Contribute - -We welcome contributions! If you'd like to help improve the Leadlly Mentor Platform, follow these steps: - -1. Fork the repository. -2. Create a new branch for your feature or bugfix. -3. Make your changes. -4. Open a pull request and describe your changes. - -## 🐛 Reporting Issues - -If you encounter any issues while using the platform, please feel free to open an issue on the repository. Provide as much detail as possible to help us address the problem quickly. - -## 🛡️ Security - -If you find any security vulnerabilities, please report them privately to [business@leadlly.in](mailto:business@leadlly.in). We take security issues seriously and will address them promptly. - -## 📄 License - -This project is licensed under the MIT License. See the [`LICENSE`](./LICENSE) file for more details. - -## 🎉 Hacktoberfest Participation: - -- Contributions should be meaningful and address an issue or feature request. -- Avoid creating spam or low-quality pull requests, as these will not be accepted. -- Tag your pull requests with "Hacktoberfest" to ensure they count toward Hacktoberfest. - -## 📝 Code Of Conduct: - -- **Be Respectful**: Always be courteous and respectful when interacting with other contributors and maintainers. -- **Collaborate**: Help others by reviewing code, suggesting improvements, or answering questions. -- **Keep Learning**: Open source is a great way to learn and improve your skills, so ask questions and engage with the community. -- **Contribution Process**: - - To indicate you're working on an issue, comment "I am working on this issue." Our team will verify your activity. If there is no response, the issue may be reassigned. - - Please do not claim an issue that is already assigned to someone else. - -## 📞 Contact - -For any further questions or support, reach out to us at: -- **Email**: [support@leadlly.in](mailto:support@leadlly.in) -- **Website**: [Leadlly.in](https://leadlly.in) +# Leadlly Admin Web + +## Overview +Leadlly Admin Web is a comprehensive administration platform for educational institutions. It provides tools for managing students, teachers, batches, and courses with an intuitive interface designed for educational administrators. + +## Features + +### Dashboard +Get a quick overview of your institution's key metrics: +- Total students and teachers +- Active courses and classes +- Performance metrics and attendance rates + +![Dashboard](/Updated%20Images/dashboard.png) + +### Course Management +- Create, edit, and delete courses +- Assign teachers to each course +- View course schedules and attendance + +![Student Batches](/Updated%20Images/batches.png) + +### Student Management +- View and manage all student batches +- Filter students by standard, subject, and teacher +- Track student attendance and performance +- Detailed student profiles + +![Student List](/Updated%20Images/List_students.png) + +### Teacher Management +- Comprehensive teacher profiles +- Track teacher performance and satisfaction rates +- View classes taught by each teacher +- Monitor student attendance in teacher's classes + +![Teacher Profile](/Updated%20Images/teacher_profile.png) + +## Technology Stack +- **Frontend**: Next.js, React, TypeScript, Tailwind CSS +- **State Management**: React Hooks +- **API**: Next.js API Routes +- **Styling**: Tailwind CSS for responsive design + +## API Implementation +The application uses Next.js API Routes to create serverless API endpoints that handle data operations. These API routes are located in the `src/app/api` directory and follow RESTful principles. + +### API Architecture +Leadlly Admin Web implements a modern API architecture using Next.js App Router's route handlers, which provide: +- **Serverless Functions**: Each API endpoint runs as a serverless function +- **TypeScript Integration**: Full type safety for request and response handling +- **Route Parameters**: Dynamic routing with path and query parameter support +- **Error Handling**: Standardized error responses + +### Available API Endpoints + +#### Batches API +- **GET /api/batches** + - Description: Retrieves a list of all batches grouped by standard + - Query Parameters: + - `standard`: Filter batches by standard name (e.g., "11th standard") + - `subject`: Filter batches by subject name (e.g., "Physics") + - `teacher`: Filter batches by teacher name (e.g., "Dr. Sarah Wilson") + - Response: JSON object containing filtered batches grouped by standard + +**Example request:** +``` +GET /api/batches?standard=11th&subject=Physics +``` + +**Example response:** +```json +{ + "standards": [ + { + "name": "11th standard", + "batches": [ + { + "id": "11-omega-1", + "name": "Omega", + "standard": "11th Class", + "subjects": ["Chemistry", "Physics", "Biology"], + "totalStudents": 120, + "maxStudents": 180, + "teacher": "Dr. Sarah Wilson" + } + // More batches... + ] + } + ] +} +``` + +### Implementation Details +The API routes are implemented using Next.js App Router's route handlers. Each API endpoint is defined in a route.ts file within the corresponding directory structure. + +**Request Handling (Example from `src/app/api/batches/route.ts`):** +```typescript +export async function GET(request: NextRequest) { + try { + // Get query parameters for filtering + const searchParams = request.nextUrl.searchParams; + const standard = searchParams.get('standard'); + const subject = searchParams.get('subject'); + const teacher = searchParams.get('teacher'); + + // Process and filter data + // ... + + return NextResponse.json(filteredData, { status: 200 }); + } catch (error) { + console.error('Error fetching batches:', error); + return NextResponse.json( + { error: 'Failed to fetch batches' }, + { status: 500 } + ); + } +} +``` + +### Data Handling +Currently, the application uses mock data for demonstration purposes. In a production environment, these API routes would connect to a database or external API service. + +**Mock data example:** +```typescript +const batchesData = { + standards: [ + { + name: "11th standard", + batches: [ + // Batch data... + ] + } + ] +}; +``` + +### Error Handling +All API routes implement consistent error handling to ensure robust operation: + +```typescript +try { + // API logic +} catch (error) { + console.error('Error:', error); + return NextResponse.json( + { error: 'Error message' }, + { status: 500 } + ); +} +``` + +### Future API Enhancements +Planned API enhancements include: +- Authentication and authorization +- CRUD operations for all resources (students, teachers, courses) +- Pagination for large data sets +- Advanced filtering and search capabilities +- Real-time updates using webhooks or WebSockets + +## Getting Started + +### Prerequisites +- Node.js (v14 or later) +- npm or yarn + +### Installation +Clone the repository: +```bash +git clone https://github.com/your-username/leadlly.admin.web.git +cd leadlly.admin.web +``` + +Install dependencies: +```bash +npm install +``` + +Run the development server: +```bash +npm run dev +``` + +Open `URL_ADDRESS:3000` in your browser + +## Project Structure +``` +leadlly.admin.web/ +├── public/ # Static assets +├── src/ +│ ├── app/ # Next.js App Router +│ │ ├── (root)/ # Main application routes +│ │ │ ├── (dashboard)/ # Dashboard components +│ │ │ ├── batches/ # Batch management +│ │ │ └── teacher/ # Teacher management +│ │ └── api/ # API routes +│ ├── components/ # Shared components +│ └── styles/ # Global styles +├── Updated Images/ # Project screenshots +└── README.md # Project documentation +``` + +This update adds a comprehensive API section to your README.md that explains: +1. The API architecture using Next.js API Routes +2. Available endpoints with examples +3. Implementation details including request handling, data handling, and error handling +4. Future API enhancement plans + +The documentation is based on the existing implementation in your `src/app/api/batches/route.ts` file, which demonstrates how the API routes are structured in your project. diff --git a/Updated Images/List_students.png b/Updated Images/List_students.png new file mode 100644 index 0000000..4724f24 Binary files /dev/null and b/Updated Images/List_students.png differ diff --git a/Updated Images/batches.png b/Updated Images/batches.png new file mode 100644 index 0000000..e410433 Binary files /dev/null and b/Updated Images/batches.png differ diff --git a/Updated Images/dashboard.png b/Updated Images/dashboard.png new file mode 100644 index 0000000..2b6fda6 Binary files /dev/null and b/Updated Images/dashboard.png differ diff --git a/Updated Images/teacher_profile.png b/Updated Images/teacher_profile.png new file mode 100644 index 0000000..8ed8dee Binary files /dev/null and b/Updated Images/teacher_profile.png differ diff --git a/src/app/(root)/(dashboard)/_components/InstituteOverview.tsx b/src/app/(root)/(dashboard)/_components/InstituteOverview.tsx new file mode 100644 index 0000000..1e2023e --- /dev/null +++ b/src/app/(root)/(dashboard)/_components/InstituteOverview.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import Image from 'next/image'; + +interface InstituteOverviewProps { + name: string; + establishedYear: number; + instituteCode: string; + address: string; + contact: string; + email: string; +} + +const InstituteOverview = ({ + name, + establishedYear, + instituteCode, + address, + contact, + email, +}: InstituteOverviewProps) => { + return ( +
+
+
+ {name} +
+ +
+

Established in {establishedYear}

+

{name}

+

Institute Code: {instituteCode}

+
+ +
+
+ + + + {address} +
+ +
+ + + + {contact} +
+ +
+ + + + + {email} +
+
+
+
+ ); +}; + +export default InstituteOverview; \ No newline at end of file diff --git a/src/app/(root)/(dashboard)/_components/StudentsOverview.tsx b/src/app/(root)/(dashboard)/_components/StudentsOverview.tsx new file mode 100644 index 0000000..6058d85 --- /dev/null +++ b/src/app/(root)/(dashboard)/_components/StudentsOverview.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import Link from 'next/link'; + +interface StudentsOverviewProps { + totalStudents: number; + activeCourses: number; + averageAttendance: number; + performanceIndex: number; +} + +const StudentsOverview = ({ + totalStudents, + activeCourses, + averageAttendance, + performanceIndex, +}: StudentsOverviewProps) => { + return ( +
+

Students Overview

+ +
+
+

Total Students

+
+ + + + {totalStudents} +
+
+ +
+

Active Courses

+
+ + + + {activeCourses} +
+
+ +
+

Average Attendance

+
+ + + + {averageAttendance}% +
+
+ +
+

Performance Index

+
+ + + + {performanceIndex}/10 +
+
+
+ + + + + + + View Students + +
+ ); +}; + +export default StudentsOverview; \ No newline at end of file diff --git a/src/app/(root)/(dashboard)/_components/TeachersOverview.tsx b/src/app/(root)/(dashboard)/_components/TeachersOverview.tsx new file mode 100644 index 0000000..0b510aa --- /dev/null +++ b/src/app/(root)/(dashboard)/_components/TeachersOverview.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import Link from 'next/link'; + +interface TeachersOverviewProps { + totalTeachers: number; + departments: number; + activeClasses: number; + satisfactionRate: number; +} + +const TeachersOverview = ({ + totalTeachers, + departments, + activeClasses, + satisfactionRate, +}: TeachersOverviewProps) => { + return ( +
+

Teachers Overview

+ +
+
+

Total Teachers

+
+ + + + {totalTeachers} +
+
+ +
+

Departments

+
+ + + + {departments} +
+
+ +
+

Active Classes

+
+ + + + {activeClasses} +
+
+ +
+

Satisfaction Rate

+
+ + + + {satisfactionRate}/10 +
+
+
+ + {/* Update the href from "/teacher" to "/teachers" */} + + + + + + View Teachers + +
+ ); +}; + +export default TeachersOverview; \ No newline at end of file diff --git a/src/app/(root)/(dashboard)/_components/index.ts b/src/app/(root)/(dashboard)/_components/index.ts index 28d4d61..63bbbca 100644 --- a/src/app/(root)/(dashboard)/_components/index.ts +++ b/src/app/(root)/(dashboard)/_components/index.ts @@ -1 +1,4 @@ -// here we can add all the components that we want to use in the dashboard (you can rename this file to whatever you want) \ No newline at end of file +// here we can add all the components that we want to use in the dashboard (you can rename this file to whatever you want) +export { default as StudentsOverview } from './StudentsOverview'; +export { default as TeachersOverview } from './TeachersOverview'; +export { default as InstituteOverview } from './InstituteOverview'; \ No newline at end of file diff --git a/src/app/(root)/(dashboard)/page.tsx b/src/app/(root)/(dashboard)/page.tsx index 75a3155..0e2b61b 100644 --- a/src/app/(root)/(dashboard)/page.tsx +++ b/src/app/(root)/(dashboard)/page.tsx @@ -1,7 +1,67 @@ import Image from "next/image"; +import React from "react"; +import { StudentsOverview, TeachersOverview, InstituteOverview } from "./_components"; -export default function Home() { +// Mock data for the dashboard +const dashboardData = { + institute: { + name: "Leadlly Academy", + establishedYear: 2010, + instituteCode: "LA-2010", + address: "123 Education Street, Knowledge City", + contact: "+1 (555) 123-4567", + email: "info@leadlly-academy.com" + }, + students: { + totalStudents: 1250, + activeCourses: 42, + averageAttendance: 92, + performanceIndex: 8.7 + }, + teachers: { + totalTeachers: 68, + departments: 12, + activeClasses: 86, + satisfactionRate: 9.2 + } +}; + +export default function Dashboard() { return ( - <>Home +
+
+

Dashboard

+
+ +
+
+ + + +
+ + + +
+
); } diff --git a/src/app/(root)/batches/[batchId]/students/page.tsx b/src/app/(root)/batches/[batchId]/students/page.tsx new file mode 100644 index 0000000..9f763dc --- /dev/null +++ b/src/app/(root)/batches/[batchId]/students/page.tsx @@ -0,0 +1,227 @@ +import React from 'react'; +import Link from 'next/link'; + +// Mock data for students in a batch +const getStudentsData = (batchId: string) => { + // This would typically come from an API or database + return { + batchInfo: { + id: batchId, + name: batchId.includes('omega') ? 'Omega' : 'Sigma', + standard: batchId.startsWith('11') ? '11th Class' : '12th Class', + subjects: batchId.includes('omega') ? ['Physics', 'Chemistry'] : ['Mathematics'], + teacher: "Dr. Sarah Wilson" + }, + students: [ + { + id: "s1", + name: "Alex Johnson", + rollNumber: "R2023001", + attendance: 92, + performance: 8.7, + email: "alex.j@student.edu", + contact: "+1234567890" + }, + { + id: "s2", + name: "Emma Williams", + rollNumber: "R2023002", + attendance: 98, + performance: 9.5, + email: "emma.w@student.edu", + contact: "+1234567891" + }, + { + id: "s3", + name: "Michael Brown", + rollNumber: "R2023003", + attendance: 85, + performance: 7.8, + email: "michael.b@student.edu", + contact: "+1234567892" + }, + { + id: "s4", + name: "Sophia Davis", + rollNumber: "R2023004", + attendance: 94, + performance: 8.9, + email: "sophia.d@student.edu", + contact: "+1234567893" + }, + { + id: "s5", + name: "James Miller", + rollNumber: "R2023005", + attendance: 90, + performance: 8.2, + email: "james.m@student.edu", + contact: "+1234567894" + }, + { + id: "s6", + name: "Olivia Wilson", + rollNumber: "R2023006", + attendance: 96, + performance: 9.1, + email: "olivia.w@student.edu", + contact: "+1234567895" + }, + { + id: "s7", + name: "William Taylor", + rollNumber: "R2023007", + attendance: 88, + performance: 7.9, + email: "william.t@student.edu", + contact: "+1234567896" + }, + { + id: "s8", + name: "Ava Anderson", + rollNumber: "R2023008", + attendance: 93, + performance: 8.6, + email: "ava.a@student.edu", + contact: "+1234567897" + } + ] + }; +}; + +export default function BatchStudentsPage({ params }: { params: { batchId: string } }) { + const { batchInfo, students } = getStudentsData(params.batchId); + + return ( +
+
+
+ + + + + Back to Batches + +

{batchInfo.name} - {batchInfo.standard}

+

Subjects: {batchInfo.subjects.join(", ")} | Teacher: {batchInfo.teacher}

+
+ +
+ +
+
+

Students List

+
+
+ + + + +
+ +
+
+ +
+ + + + + + + + + + + + + {students.map((student) => ( + + + + + + + + + ))} + +
+ Student + + Roll Number + + Attendance + + Performance + + Contact + + Actions +
+
+
+ {student.name.charAt(0)} +
+
+
{student.name}
+
{student.email}
+
+
+
+ {student.rollNumber} + +
+
{student.attendance}%
+
+
= 90 ? 'bg-green-500' : student.attendance >= 75 ? 'bg-yellow-500' : 'bg-red-500'}`} + style={{ width: `${student.attendance}%` }} + >
+
+
+
+
+
{student.performance}/10
+
+
= 8.5 ? 'bg-green-500' : student.performance >= 7 ? 'bg-yellow-500' : 'bg-red-500'}`} + style={{ width: `${student.performance * 10}%` }} + >
+
+
+
+ {student.contact} + +
+ + +
+
+
+ +
+
+ Showing 1 to {students.length} of {students.length} students +
+
+ + + +
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/app/(root)/batches/page.tsx b/src/app/(root)/batches/page.tsx new file mode 100644 index 0000000..d7af38a --- /dev/null +++ b/src/app/(root)/batches/page.tsx @@ -0,0 +1,217 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; +import Link from 'next/link'; + +interface Batch { + id: string; + name: string; + standard: string; + subjects: string[]; + totalStudents: number; + maxStudents: number; + teacher: string; +} + +interface Standard { + name: string; + batches: Batch[]; +} + +interface BatchesData { + standards: Standard[]; +} + +export default function BatchesPage() { + const [batchesData, setBatchesData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [filters, setFilters] = useState({ + standard: '', + subject: '', + teacher: '' + }); + + useEffect(() => { + const fetchBatches = async () => { + try { + setLoading(true); + + // Build query string from filters + const queryParams = new URLSearchParams(); + if (filters.standard) queryParams.append('standard', filters.standard); + if (filters.subject) queryParams.append('subject', filters.subject); + if (filters.teacher) queryParams.append('teacher', filters.teacher); + + const response = await fetch(`/api/batches?${queryParams.toString()}`); + + if (!response.ok) { + throw new Error('Failed to fetch batches'); + } + + const data = await response.json(); + setBatchesData(data); + } catch (err) { + setError('Error loading batches. Please try again later.'); + console.error('Error fetching batches:', err); + } finally { + setLoading(false); + } + }; + + fetchBatches(); + }, [filters]); + + const handleFilterChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setFilters(prev => ({ + ...prev, + [name]: value + })); + }; + + if (loading) { + return ( +
+

Student Batches of Institute

+
+
+
+
+ ); + } + + if (error) { + return ( +
+

Student Batches of Institute

+
+ Error: + {error} +
+
+ ); + } + + return ( +
+

Student Batches of Institute

+ +
+
+ Filter by : +
+ + + +
+
+
+ + {batchesData && batchesData.standards.length > 0 ? ( + batchesData.standards.map((standard, index) => ( +
+
+

{standard.name}

+ +
+ +
+ {standard.batches.map((batch) => ( +
+
+
+ {batch.name === "Omega" ? ( + + + + ) : ( + + + + )} +
+
+

{batch.name}

+

{batch.standard}

+
+ Active +
+ +
+

+ Subject: + {batch.subjects.join(", ")} +

+

+ Total Students: + {batch.totalStudents} +

+
+ +
+
+
+
+

{batch.totalStudents}/{batch.maxStudents}

+
+ +
+

-By {batch.teacher}

+
+ + + View More + +
+ ))} +
+
+ )) + ) : ( +
+

No batches found. Try adjusting your filters.

+
+ )} +
+ ); +} \ No newline at end of file diff --git a/src/app/(root)/teacher/[teacherId]/_components/TeacherClasses.tsx b/src/app/(root)/teacher/[teacherId]/_components/TeacherClasses.tsx new file mode 100644 index 0000000..2b40ce0 --- /dev/null +++ b/src/app/(root)/teacher/[teacherId]/_components/TeacherClasses.tsx @@ -0,0 +1,58 @@ +import React from 'react'; + +interface Class { + id: string; + name: string; + subject: string; + students: number; + schedule: string; +} + +interface TeacherClassesProps { + classes: Class[]; +} + +const TeacherClasses = ({ classes }: TeacherClassesProps) => { + return ( +
+
+

Active Classes

+ +
+ +
+ + + + + + + + + + + + {classes.map((cls) => ( + + + + + + + + ))} + +
Class NameSubjectStudentsScheduleAction
{cls.name}{cls.subject}{cls.students}{cls.schedule} + +
+
+
+ ); +}; + +export default TeacherClasses; \ No newline at end of file diff --git a/src/app/(root)/teacher/[teacherId]/_components/TeacherHeader.tsx b/src/app/(root)/teacher/[teacherId]/_components/TeacherHeader.tsx new file mode 100644 index 0000000..015f306 --- /dev/null +++ b/src/app/(root)/teacher/[teacherId]/_components/TeacherHeader.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import Image from 'next/image'; + +interface TeacherHeaderProps { + teacherId: string; + name: string; + joinedYear: number; + teacherCode: string; + email: string; + address: string; + contact: string; +} + +const TeacherHeader = ({ + teacherId, + name, + joinedYear, + teacherCode, + email, + address, + contact, +}: TeacherHeaderProps) => { + return ( +
+
+
+ {name} +
+ +
+

Joined in {joinedYear}

+

{name}

+

Teacher Code: {teacherCode}

+
+ +
+
+ + + + {address} +
+ +
+ + + + {contact} +
+ +
+ + + + + {email} +
+
+
+
+ ); +}; + +export default TeacherHeader; \ No newline at end of file diff --git a/src/app/(root)/teacher/[teacherId]/_components/TeacherPerformance.tsx b/src/app/(root)/teacher/[teacherId]/_components/TeacherPerformance.tsx new file mode 100644 index 0000000..2c879d9 --- /dev/null +++ b/src/app/(root)/teacher/[teacherId]/_components/TeacherPerformance.tsx @@ -0,0 +1,36 @@ +import React from 'react'; + +interface TeacherPerformanceProps { + performanceData: { + category: string; + score: number; + maxScore: number; + }[]; +} + +const TeacherPerformance = ({ performanceData }: TeacherPerformanceProps) => { + return ( +
+

Performance Metrics

+ +
+ {performanceData.map((item, index) => ( +
+
+ {item.category} + {item.score}/{item.maxScore} +
+
+
+
+
+ ))} +
+
+ ); +}; + +export default TeacherPerformance; \ No newline at end of file diff --git a/src/app/(root)/teacher/[teacherId]/_components/TeacherStats.tsx b/src/app/(root)/teacher/[teacherId]/_components/TeacherStats.tsx new file mode 100644 index 0000000..e906778 --- /dev/null +++ b/src/app/(root)/teacher/[teacherId]/_components/TeacherStats.tsx @@ -0,0 +1,79 @@ +import React from 'react'; + +interface TeacherStatsProps { + activeClasses: number; + totalStudents: number; + averageAttendance: number; + satisfactionRate: number; +} + +const TeacherStats = ({ + activeClasses, + totalStudents, + averageAttendance, + satisfactionRate, +}: TeacherStatsProps) => { + return ( +
+ + + + } + /> + + + + + } + /> + + + + + } + /> + + + + + } + /> +
+ ); +}; + +interface StatCardProps { + title: string; + value: string | number; + icon: React.ReactNode; +} + +const StatCard = ({ title, value, icon }: StatCardProps) => { + return ( +
+
+

{title}

+ {icon} +
+

{value}

+
+ ); +}; + +export default TeacherStats; \ No newline at end of file diff --git a/src/app/(root)/teacher/[teacherId]/_components/index.ts b/src/app/(root)/teacher/[teacherId]/_components/index.ts index 28d4d61..1e500b2 100644 --- a/src/app/(root)/teacher/[teacherId]/_components/index.ts +++ b/src/app/(root)/teacher/[teacherId]/_components/index.ts @@ -1 +1,6 @@ -// here we can add all the components that we want to use in the dashboard (you can rename this file to whatever you want) \ No newline at end of file +// here we can add all the components that we want to use in the dashboard (you can rename this file to whatever you want) +// Export all components for the teacher dashboard +export { default as TeacherHeader } from './TeacherHeader'; +export { default as TeacherStats } from './TeacherStats'; +export { default as TeacherClasses } from './TeacherClasses'; +export { default as TeacherPerformance } from './TeacherPerformance'; \ No newline at end of file diff --git a/src/app/(root)/teacher/[teacherId]/page.tsx b/src/app/(root)/teacher/[teacherId]/page.tsx index 3017769..62400c2 100644 --- a/src/app/(root)/teacher/[teacherId]/page.tsx +++ b/src/app/(root)/teacher/[teacherId]/page.tsx @@ -1,9 +1,80 @@ -import React from 'react' +import React from 'react'; +import { + TeacherHeader, + TeacherStats, + TeacherClasses, + TeacherPerformance +} from './_components'; -const TeacherPage = () => { - return ( -
TeacherPage
- ) -} +// This would typically come from an API or database +const getTeacherData = (teacherId: string) => { + // Mock data for demonstration + return { + id: teacherId, + name: "Dr. Sarah Johnson", + joinedYear: 2018, + teacherCode: "TCH" + teacherId, + email: "sarah.johnson@institute.com", + address: "456 Education Ave, City, Country", + contact: "+1234567890", + stats: { + activeClasses: 8, + totalStudents: 245, + averageAttendance: 98, + satisfactionRate: 9.0 + }, + classes: [ + { id: "c1", name: "Advanced Mathematics", subject: "Mathematics", students: 32, schedule: "Mon, Wed 10:00 AM" }, + { id: "c2", name: "Physics 101", subject: "Physics", students: 28, schedule: "Tue, Thu 1:00 PM" }, + { id: "c3", name: "Chemistry Lab", subject: "Chemistry", students: 24, schedule: "Fri 9:00 AM" }, + { id: "c4", name: "Computer Science", subject: "CS", students: 30, schedule: "Mon, Wed 2:00 PM" }, + ], + performanceData: [ + { category: "Student Feedback", score: 9.2, maxScore: 10 }, + { category: "Attendance Rate", score: 98, maxScore: 100 }, + { category: "Course Completion", score: 95, maxScore: 100 }, + { category: "Academic Results", score: 8.7, maxScore: 10 }, + ] + }; +}; -export default TeacherPage \ No newline at end of file +export default function TeacherPage({ params }: { params: { teacherId: string } }) { + const teacherData = getTeacherData(params.teacherId); + + return ( +
+
+

Teacher Profile

+ +
+ + + + + +
+
+ +
+
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/src/app/(root)/teachers/page.tsx b/src/app/(root)/teachers/page.tsx new file mode 100644 index 0000000..129f605 --- /dev/null +++ b/src/app/(root)/teachers/page.tsx @@ -0,0 +1,206 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; +import Link from 'next/link'; + +interface Teacher { + id: string; + name: string; + subject: string; + joinedYear: number; + email: string; + contact: string; + activeClasses: number; + totalStudents: number; +} + +export default function TeachersPage() { + const [teachers, setTeachers] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [searchTerm, setSearchTerm] = useState(''); + + useEffect(() => { + // In a real app, this would be an API call + // For now, we'll use mock data + const fetchTeachers = async () => { + try { + setLoading(true); + + // Mock data - in a real app, this would come from an API + const mockTeachers = [ + { + id: "t1", + name: "Dr. Sarah Johnson", + subject: "Mathematics", + joinedYear: 2018, + email: "sarah.johnson@institute.com", + contact: "+1234567890", + activeClasses: 8, + totalStudents: 245 + }, + { + id: "t2", + name: "Prof. Michael Brown", + subject: "Physics", + joinedYear: 2015, + email: "michael.brown@institute.com", + contact: "+1234567891", + activeClasses: 6, + totalStudents: 180 + }, + { + id: "t3", + name: "Dr. Emily Davis", + subject: "Chemistry", + joinedYear: 2019, + email: "emily.davis@institute.com", + contact: "+1234567892", + activeClasses: 5, + totalStudents: 150 + }, + { + id: "t4", + name: "Prof. James Wilson", + subject: "Biology", + joinedYear: 2017, + email: "james.wilson@institute.com", + contact: "+1234567893", + activeClasses: 7, + totalStudents: 210 + } + ]; + + // Simulate API delay + setTimeout(() => { + setTeachers(mockTeachers); + setLoading(false); + }, 500); + + } catch (err) { + setError('Error loading teachers. Please try again later.'); + console.error('Error fetching teachers:', err); + setLoading(false); + } + }; + + fetchTeachers(); + }, []); + + // Filter teachers based on search term + const filteredTeachers = teachers.filter(teacher => + teacher.name.toLowerCase().includes(searchTerm.toLowerCase()) || + teacher.subject.toLowerCase().includes(searchTerm.toLowerCase()) || + teacher.email.toLowerCase().includes(searchTerm.toLowerCase()) + ); + + if (loading) { + return ( +
+

Teachers

+
+
+
+
+ ); + } + + if (error) { + return ( +
+

Teachers

+
+ Error: + {error} +
+
+ ); + } + + return ( +
+
+

Teachers

+ +
+ +
+
+
+ setSearchTerm(e.target.value)} + /> + + + +
+ +
+
+ +
+ {filteredTeachers.length > 0 ? ( + filteredTeachers.map((teacher) => ( + +
+
+ {teacher.name.charAt(0)} +
+
+

{teacher.name}

+

{teacher.subject}

+
+
+ +
+

+ Email: + {teacher.email} +

+

+ Contact: + {teacher.contact} +

+

+ Joined: + {teacher.joinedYear} +

+
+ +
+
+

Active Classes

+

{teacher.activeClasses}

+
+
+

Students

+

{teacher.totalStudents}

+
+
+ + )) + ) : ( +
+

No teachers found. Try adjusting your search.

+
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/src/app/api/batches/[batchId]/students/route.ts b/src/app/api/batches/[batchId]/students/route.ts new file mode 100644 index 0000000..0a99a61 --- /dev/null +++ b/src/app/api/batches/[batchId]/students/route.ts @@ -0,0 +1,181 @@ +import { NextRequest, NextResponse } from 'next/server'; + +// Mock data for students in batches - in a real app, this would come from a database +const getStudentsData = (batchId: string) => { + // Validate batchId format + if (!batchId.match(/^\d{2}-(omega|sigma)-\d+$/i)) { + throw new Error('Invalid batch ID format'); + } + + return { + batchInfo: { + id: batchId, + name: batchId.includes('omega') ? 'Omega' : 'Sigma', + standard: batchId.startsWith('11') ? '11th Class' : '12th Class', + subjects: batchId.includes('omega') ? ['Physics', 'Chemistry'] : ['Mathematics'], + teacher: "Dr. Sarah Wilson" + }, + students: [ + { + id: "s1", + name: "Alex Johnson", + rollNumber: "R2023001", + attendance: 92, + performance: 8.7, + email: "alex.j@student.edu", + contact: "+1234567890" + }, + { + id: "s2", + name: "Emma Williams", + rollNumber: "R2023002", + attendance: 98, + performance: 9.5, + email: "emma.w@student.edu", + contact: "+1234567891" + }, + { + id: "s3", + name: "Michael Brown", + rollNumber: "R2023003", + attendance: 85, + performance: 7.8, + email: "michael.b@student.edu", + contact: "+1234567892" + }, + { + id: "s4", + name: "Sophia Davis", + rollNumber: "R2023004", + attendance: 94, + performance: 8.9, + email: "sophia.d@student.edu", + contact: "+1234567893" + }, + { + id: "s5", + name: "James Miller", + rollNumber: "R2023005", + attendance: 90, + performance: 8.2, + email: "james.m@student.edu", + contact: "+1234567894" + }, + { + id: "s6", + name: "Olivia Wilson", + rollNumber: "R2023006", + attendance: 96, + performance: 9.1, + email: "olivia.w@student.edu", + contact: "+1234567895" + }, + { + id: "s7", + name: "William Taylor", + rollNumber: "R2023007", + attendance: 88, + performance: 7.9, + email: "william.t@student.edu", + contact: "+1234567896" + }, + { + id: "s8", + name: "Ava Anderson", + rollNumber: "R2023008", + attendance: 93, + performance: 8.6, + email: "ava.a@student.edu", + contact: "+1234567897" + } + ] + }; +}; + +export async function GET( + request: NextRequest, + { params }: { params: { batchId: string } } +) { + try { + const batchId = params.batchId; + + // Validate batchId + if (!batchId) { + return NextResponse.json( + { error: 'Batch ID is required' }, + { status: 400 } + ); + } + + // Get query parameters for filtering and pagination + const searchParams = request.nextUrl.searchParams; + const search = searchParams.get('search'); + const sortBy = searchParams.get('sortBy') || 'name'; + const page = parseInt(searchParams.get('page') || '1'); + const limit = parseInt(searchParams.get('limit') || '10'); + + try { + // Get students data + const { batchInfo, students } = getStudentsData(batchId); + + // Filter students based on search term + let filteredStudents = [...students]; + if (search) { + const searchLower = search.toLowerCase(); + filteredStudents = filteredStudents.filter(student => + student.name.toLowerCase().includes(searchLower) || + student.rollNumber.toLowerCase().includes(searchLower) || + student.email.toLowerCase().includes(searchLower) + ); + } + + // Sort students + filteredStudents.sort((a, b) => { + switch (sortBy) { + case 'rollNumber': + return a.rollNumber.localeCompare(b.rollNumber); + case 'attendance': + return b.attendance - a.attendance; + case 'performance': + return b.performance - a.performance; + case 'name': + default: + return a.name.localeCompare(b.name); + } + }); + + // Paginate results + const startIndex = (page - 1) * limit; + const endIndex = page * limit; + const paginatedStudents = filteredStudents.slice(startIndex, endIndex); + + // Prepare response with pagination metadata + const response = { + batchInfo, + students: paginatedStudents, + pagination: { + total: filteredStudents.length, + page, + limit, + totalPages: Math.ceil(filteredStudents.length / limit) + } + }; + + return NextResponse.json(response, { status: 200 }); + } catch (error: any) { + if (error.message === 'Invalid batch ID format') { + return NextResponse.json( + { error: 'Invalid batch ID format' }, + { status: 400 } + ); + } + throw error; + } + } catch (error) { + console.error('Error fetching students:', error); + return NextResponse.json( + { error: 'Failed to fetch students' }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/src/app/api/batches/route.ts b/src/app/api/batches/route.ts new file mode 100644 index 0000000..f2d1e89 --- /dev/null +++ b/src/app/api/batches/route.ts @@ -0,0 +1,123 @@ +import { NextRequest, NextResponse } from 'next/server'; + +// Mock data for batches - in a real app, this would come from a database +const batchesData = { + standards: [ + { + name: "11th standard", + batches: [ + { + id: "11-omega-1", + name: "Omega", + standard: "11th Class", + subjects: ["Chemistry", "Physics", "Biology"], + totalStudents: 120, + maxStudents: 180, + teacher: "Dr. Sarah Wilson" + }, + { + id: "11-sigma-1", + name: "Sigma", + standard: "11th Class", + subjects: ["Mathematics", "Chemistry", "Physics"], + totalStudents: 120, + maxStudents: 180, + teacher: "Dr. Sarah Wilson" + }, + { + id: "11-omega-2", + name: "Omega", + standard: "11th Class", + subjects: ["Physics"], + totalStudents: 120, + maxStudents: 180, + teacher: "Dr. Sarah Wilson" + } + ] + }, + { + name: "12th standard", + batches: [ + { + id: "12-omega-1", + name: "Omega", + standard: "11th Class", + subjects: ["Chemistry"], + totalStudents: 120, + maxStudents: 180, + teacher: "Dr. Sarah Wilson" + }, + { + id: "12-sigma-1", + name: "Sigma", + standard: "11th Class", + subjects: ["Mathematics"], + totalStudents: 120, + maxStudents: 180, + teacher: "Dr. Sarah Wilson" + }, + { + id: "12-omega-2", + name: "Omega", + standard: "11th Class", + subjects: ["Physics"], + totalStudents: 120, + maxStudents: 180, + teacher: "Dr. Sarah Wilson" + } + ] + } + ] +}; + +export async function GET(request: NextRequest) { + try { + // Get query parameters for filtering + const searchParams = request.nextUrl.searchParams; + const standard = searchParams.get('standard'); + const subject = searchParams.get('subject'); + const teacher = searchParams.get('teacher'); + + // Filter the data based on query parameters + let filteredData = { ...batchesData }; + + if (standard) { + filteredData.standards = filteredData.standards.filter( + std => std.name.toLowerCase().includes(standard.toLowerCase()) + ); + } + + // Filter batches within each standard + filteredData.standards = filteredData.standards.map(std => { + let filteredBatches = [...std.batches]; + + if (subject) { + filteredBatches = filteredBatches.filter(batch => + batch.subjects.some(s => s.toLowerCase().includes(subject.toLowerCase())) + ); + } + + if (teacher) { + filteredBatches = filteredBatches.filter(batch => + batch.teacher.toLowerCase().includes(teacher.toLowerCase()) + ); + } + + return { + ...std, + batches: filteredBatches + }; + }); + + // Remove standards with no batches after filtering + filteredData.standards = filteredData.standards.filter(std => std.batches.length > 0); + + return NextResponse.json(filteredData, { status: 200 }); + } catch (error) { + console.error('Error fetching batches:', error); + return NextResponse.json( + { error: 'Failed to fetch batches' }, + { status: 500 } + ); + } +} \ No newline at end of file