import React, { useState, useMemo, useCallback } from 'react';
import { Search, Users, DollarSign, Calendar, FileText, Bell, Shield, Download, Printer, MessageSquare, Plus, Edit, Eye, ChevronLeft, ChevronRight, X, Check, AlertTriangle, Clock, Upload, Database } from 'lucide-react';
const COMPANY = {
name: 'Athena Intellects Company Limited',
program: 'MI AKidamy 升幼必修班',
address: '荃灣新領域廣場1205室',
logo: '🎒'
};
const COURSES = {
1: 'Trial Class',
2: 'Playgroup',
3: 'Independence Class',
4: 'Kinder',
5: 'ABC Course',
6: 'Special Events',
7: 'Talk/Workshop',
8: 'IGS (Current student discount)',
9: 'Private class 1:1(30mins)',
10: '音樂班',
11: 'Summer course',
12: '中文認字班',
13: '面試班(kg)'
};
const STUDENTS_DATA = [
{ id: 'ST220001', name: '何星樂', status: 'Active', gender: 'Female', dob: '2020-10-25', parent: 'Dorothy/Ho Chung Hang', phone: '96130912', email: 'dorothyip@live.hk', joinDate: '2022-09-14', courseCode: 1, payments: [{ invoice: 'AK220001', amount: 300, date: '2022-09-10', method: 'Bank In', course: 'Trial Class' }] },
{ id: 'ST220034', name: '林葆姸 Lam Po Yin', status: 'Active', gender: 'Female', dob: '2021-07-02', parent: '莉', phone: '91279303', joinDate: '2022-09-24', courseCode: 4, payments: [{ invoice: 'AK240007', amount: 2400, date: '2024-01-31', method: 'Payme', course: 'Kinder' }, { invoice: 'AK240062', amount: 2400, date: '2024-06-30', method: 'Bank In', course: 'Kinder' }, { invoice: 'AK250035', amount: 420, date: '2025-04-15', method: 'Bank In', course: 'Special Events' }] },
{ id: 'ST220145', name: 'Ho Shing Wing 何承穎', status: 'Active', gender: 'Male', dob: '2021-08-28', parent: 'Angie Luk', phone: '9282 3344', joinDate: '2022-12-16', courseCode: 4, payments: [{ invoice: 'AK240035', amount: 3600, date: '2024-04-29', method: 'Bank In', course: 'Kinder' }, { invoice: 'AK240098', amount: 4700, date: '2024-09-15', method: 'Bank In', course: 'Kinder' }, { invoice: 'AK250025', amount: 4800, date: '2025-03-17', method: 'Bank In', course: 'Kinder' }] },
{ id: 'ST220309', name: '董諭橋 Quinton Kiu Tung', status: 'Active', gender: 'Male', dob: '2022-09-28', parent: 'Mrs Tung', phone: '96630062', joinDate: '2023-11-27', courseCode: 4, payments: [{ invoice: 'AK240034', amount: 4700, date: '2024-04-27', method: 'Payme', course: 'Kinder' }] },
{ id: 'ST220319', name: '林僖晴', status: 'Active', gender: 'Female', dob: '2022-09-27', parent: 'Jane Cheung', phone: '69932752', joinDate: '2024-03-01', courseCode: 3, payments: [{ invoice: 'AK240100', amount: 4700, date: '2024-09-29', method: 'Bank In', course: 'Independence Class' }] },
{ id: 'ST220334', name: '馮悦晞 Fung Yuet Hei', status: 'Active', gender: 'Female', dob: '2023-01-19', parent: 'ladyukawaiii', phone: '6227 8392', joinDate: '2024-05-18', courseCode: 2, payments: [{ invoice: 'AK240030', amount: 99, date: '2024-04-20', method: 'Payme', course: 'Trial Class' }, { invoice: 'AK240088', amount: 3600, date: '2024-08-27', method: 'Bank In', course: 'Playgroup' }, { invoice: 'AK250005', amount: 3600, date: '2025-01-24', method: 'Bank In', course: 'Playgroup' }] },
{ id: 'ST220335', name: 'Abby Li', status: 'Active', gender: 'Female', dob: null, parent: 'Ray Li', phone: '6803 0209', joinDate: '2024-05-18', courseCode: 2, payments: [{ invoice: 'AK240031', amount: 99, date: '2024-04-22', method: 'Payme', course: 'Trial Class' }, { invoice: 'AK240052', amount: 2400, date: '2024-05-29', method: 'Bank In', course: 'Playgroup' }, { invoice: 'AK240087', amount: 3600, date: '2024-08-27', method: 'Cash', course: 'Playgroup' }] },
{ id: 'ST220366', name: '何溢 Ho Yat', status: 'Active', gender: null, dob: '2022-11-01', parent: '吳', phone: '9209 4144', joinDate: null, courseCode: 2, payments: [{ invoice: 'AK240080', amount: 99, date: '2024-08-17', method: 'Bank In', course: 'Trial Class' }, { invoice: 'AK240086', amount: 2400, date: '2024-08-27', method: 'Cash', course: 'Playgroup' }, { invoice: 'AK240110', amount: 2400, date: '2024-11-18', method: 'Cash', course: 'Playgroup' }] },
{ id: 'ST220374', name: 'Alfie', status: 'Active', gender: null, dob: null, parent: 'Daddy', phone: '60487740', joinDate: null, courseCode: 2, payments: [{ invoice: 'AK240092', amount: 99, date: '2024-08-31', method: 'Bank In', course: 'Trial Class' }, { invoice: 'AK240096', amount: 3600, date: '2024-09-11', method: 'Bank In', course: 'Playgroup' }, { invoice: 'AK250029', amount: 1596, date: '2025-04-07', method: 'Bank In', course: 'Special Events' }, { invoice: 'AK250030', amount: 2400, date: '2025-04-07', method: 'Bank In', course: 'Kinder' }] },
{ id: 'ST220391', name: '黃天擎 Huang Tin King Quinton', status: 'Active', gender: null, dob: '2024-01-17', parent: 'Kinki Chan', phone: '9307 8436', joinDate: null, courseCode: 2, payments: [{ invoice: 'AK250011', amount: 99, date: '2025-02-17', method: 'Bank In', course: 'Trial Class' }, { invoice: 'AK250014', amount: 2400, date: '2025-02-21', method: 'Bank In', course: 'Playgroup' }] },
{ id: 'ST220400', name: '文祉萱 Man Tse Huen', status: 'Active', gender: null, dob: '2024-01-08', parent: 'Hin Hin', phone: '9887 6639', joinDate: null, courseCode: 2, payments: [{ invoice: 'AK250027', amount: 99, date: '2025-03-31', method: 'Bank In', course: 'Trial Class' }, { invoice: 'AK250028', amount: 3600, date: '2025-04-02', method: 'Bank In', course: 'Playgroup' }] },
{ id: 'ST220401', name: '勞心柔 Christy Lo', status: 'Active', gender: null, dob: '2023-11-16', parent: 'Sara Ho', phone: '9408 6079', joinDate: null, courseCode: 2, payments: [{ invoice: 'AK250031', amount: 99, date: '2025-04-07', method: 'Bank In', course: 'Trial Class' }, { invoice: 'AK250029_e', amount: 1596, date: '2025-04-16', method: 'Bank In', course: 'Special Events (Easter)' }, { invoice: 'AK250071', amount: 3600, date: '2025-08-22', method: 'Bank In', course: 'Playgroup' }] },
{ id: 'ST220417', name: '謝子仟 Jonathan', status: 'Active', gender: 'Male', dob: '2023-09-26', parent: 'KIT', phone: '6439 0803', joinDate: null, courseCode: 2, payments: [{ invoice: 'AK250061', amount: 99, date: '2025-07-10', method: 'Bank In', course: 'Trial Class' }, { invoice: 'AK250065', amount: 2400, date: '2025-07-14', method: 'Bank In', course: 'Playgroup' }] },
{ id: 'ST220422', name: '洪國翊 Hung Kwok Yick Gerard', status: 'Active', gender: 'Male', dob: '2024-07-28', parent: 'irisc0*', phone: '9819 8797', joinDate: null, courseCode: 2, payments: [{ invoice: 'AK250084', amount: 99, date: '2025-10-08', method: 'Cash', course: 'Trial Class' }, { invoice: 'AK250087', amount: 3600, date: '2025-10-10', method: 'Bank In', course: 'Playgroup' }] },
{ id: 'ST220471', name: '曾羽桐 Tsang Yu Tung Aine', status: 'Active', gender: null, dob: '2025-05-03', parent: 'Kerendi Li', phone: '9205 1600', joinDate: null, courseCode: 3, payments: [{ invoice: 'AK260011', amount: 99, date: '2026-01-12', method: 'Bank In', course: 'Trial Class' }, { invoice: 'AK260017', amount: 4800, date: '2026-01-15', method: 'Bank In', course: 'Independence Class' }] },
];
function calcAge(dob) {
if (!dob) return 'N/A';
const b = new Date(dob);
const now = new Date();
const months = (now.getFullYear() - b.getFullYear()) * 12 + (now.getMonth() - b.getMonth());
if (months < 24) return `${months}m`;
const y = Math.floor(months / 12);
const m = months % 12;
return m > 0 ? `${y}y ${m}m` : `${y}y`;
}
function formatDate(d) {
if (!d) return '-';
return new Date(d).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' });
}
function Badge({ children, color = 'blue' }) {
const colors = {
blue: 'bg-blue-100 text-blue-800',
green: 'bg-green-100 text-green-800',
yellow: 'bg-yellow-100 text-yellow-800',
red: 'bg-red-100 text-red-800',
purple: 'bg-purple-100 text-purple-800',
gray: 'bg-gray-100 text-gray-700',
pink: 'bg-pink-100 text-pink-800',
};
return {children} ;
}
function CompanyHeader() {
return (
{COMPANY.logo}
{COMPANY.name}
{COMPANY.program}
{COMPANY.address}
);
}
function StatsCard({ icon: Icon, label, value, sub, color }) {
return (
{value}
{label}
{sub &&
{sub}
}
);
}
function Modal({ open, onClose, title, children }) {
if (!open) return null;
return (
);
}
export default function StudentManagementSystem() {
const [page, setPage] = useState('dashboard');
const [search, setSearch] = useState('');
const [selectedStudent, setSelectedStudent] = useState(null);
const [showInvoice, setShowInvoice] = useState(null);
const [showReminder, setShowReminder] = useState(null);
const [currentUser] = useState('Sharon');
const [listPage, setListPage] = useState(0);
const PER_PAGE = 8;
const filtered = useMemo(() => {
const q = search.toLowerCase();
return STUDENTS_DATA.filter(s => s.name.toLowerCase().includes(q) || s.id.toLowerCase().includes(q) || (s.parent && s.parent.toLowerCase().includes(q)));
}, [search]);
const totalRevenue = useMemo(() => STUDENTS_DATA.reduce((sum, s) => sum + s.payments.reduce((a, p) => a + p.amount, 0), 0), []);
const activeCount = STUDENTS_DATA.filter(s => s.status === 'Active').length;
const paged = filtered.slice(listPage * PER_PAGE, (listPage + 1) * PER_PAGE);
const totalPages = Math.ceil(filtered.length / PER_PAGE);
const viewStudent = useCallback((s) => { setSelectedStudent(s); setPage('profile'); }, []);
const NavBtn = ({ pg, icon: Icon, label }) => (
{ setPage(pg); setSelectedStudent(null); }} className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${page === pg ? 'bg-indigo-600 text-white' : 'text-gray-600 hover:bg-gray-100'}`}>
{label}
);
return (
{COMPANY.logo}
MI AKidamy
Student Management
👤 {currentUser}
{page === 'dashboard' && (
Dashboard
Recent Invoices
{STUDENTS_DATA.slice(0, 5).flatMap(s => s.payments.slice(-1).map(p => ({ ...p, student: s.name, sid: s.id }))).map((p, i) => (
{p.student}
{p.invoice} · {p.course}
${p.amount.toLocaleString()}
{formatDate(p.date)}
))}
Payment Reminders
{[
{ name: '何溢 Ho Yat', id: 'ST220366', due: '2025-04-15', course: 'Playgroup' },
{ name: 'Alfie', id: 'ST220374', due: '2025-04-20', course: 'Kinder' },
{ name: '林僖晴', id: 'ST220319', due: '2025-05-01', course: 'Independence Class' },
].map((r, i) => (
{r.name}
{r.course} · Due {formatDate(r.due)}
setShowReminder(r)} className="text-xs bg-indigo-50 text-indigo-600 px-2 py-1 rounded-lg hover:bg-indigo-100">
Send
))}
Course Enrollment Distribution
{Object.entries(COURSES).map(([code, name]) => {
const count = STUDENTS_DATA.filter(s => s.courseCode === parseInt(code)).length;
return (
);
})}
)}
{page === 'students' && (
Students ({filtered.length})
{ setSearch(e.target.value); setListPage(0); }} placeholder="Search by name, ID or parent..." className="w-full pl-10 pr-4 py-2.5 rounded-xl border border-gray-200 bg-white text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500" />
ID
Name
Age
Course
Parent
Phone
Status
Actions
{paged.map(s => (
viewStudent(s)}>
{s.id}
{s.name}
{calcAge(s.dob)}
{COURSES[s.courseCode] || '-'}
{s.parent || '-'}
{s.phone || '-'}
{s.status}
{ e.stopPropagation(); viewStudent(s); }} className="p-1 rounded hover:bg-gray-100" title="View">
{ e.stopPropagation(); }} className="p-1 rounded hover:bg-gray-100" title="Edit">
{ e.stopPropagation(); setShowReminder({ name: s.name, id: s.id, course: COURSES[s.courseCode] }); }} className="p-1 rounded hover:bg-gray-100" title="Remind">
))}
{totalPages > 1 && (
Page {listPage + 1} of {totalPages}
setListPage(p => Math.max(0, p - 1))} disabled={listPage === 0} className="p-1 rounded hover:bg-gray-100 disabled:opacity-30">
setListPage(p => Math.min(totalPages - 1, p + 1))} disabled={listPage >= totalPages - 1} className="p-1 rounded hover:bg-gray-100 disabled:opacity-30">
)}
)}
{page === 'profile' && selectedStudent && (
setPage('students')} className="flex items-center gap-1 text-sm text-indigo-600 hover:underline">
Back to Students
{selectedStudent.name}
{selectedStudent.id}
Status: {selectedStudent.status}
Gender: {selectedStudent.gender || 'N/A'}
DOB: {selectedStudent.dob ? formatDate(selectedStudent.dob) : 'N/A'}
Age (auto): {calcAge(selectedStudent.dob)}
Joined: {formatDate(selectedStudent.joinDate)}
Contact
Parent: {selectedStudent.parent || 'N/A'}
Phone: {selectedStudent.phone || 'N/A'}
Email: {selectedStudent.email || 'N/A'}
Current Course: {COURSES[selectedStudent.courseCode]}
setShowReminder({ name: selectedStudent.name, id: selectedStudent.id, course: COURSES[selectedStudent.courseCode] })} className="flex items-center gap-1 px-3 py-1.5 bg-green-50 text-green-700 rounded-lg text-xs hover:bg-green-100">
WhatsApp Reminder
Export PDF
Payment History
Total: ${selectedStudent.payments.reduce((a, p) => a + p.amount, 0).toLocaleString()}
Invoice
Course
Amount
Date
Method
Actions
{selectedStudent.payments.map((p, i) => (
{p.invoice}
{p.course}
${p.amount.toLocaleString()}
{formatDate(p.date)}
{p.method}
setShowInvoice({ ...p, student: selectedStudent })} className="text-xs text-indigo-600 hover:underline flex items-center gap-1">
Invoice
))}
)}
{page === 'income' && (
a + s.payments.length, 0)} color="bg-blue-500" />
s.payments.length > 0).length} color="bg-purple-500" />
All Transactions
Invoice
Student
Course
Amount
Date
Method
{STUDENTS_DATA.flatMap(s => s.payments.map(p => ({ ...p, studentName: s.name, sid: s.id }))).sort((a, b) => new Date(b.date) - new Date(a.date)).slice(0, 15).map((p, i) => (
{p.invoice}
{p.studentName}
{p.course}
${p.amount.toLocaleString()}
{formatDate(p.date)}
{p.method}
))}
)}
{page === 'classes' && (
Class Management
{[
{ name: 'Kinder', time: 'Mon 4:00-5:00pm', students: ['Lam Po Yin 林葆姸', 'Ho Shing Wing 何承穎', '董諭橋 Quinton'], topic: 'Letter Recognition - Week 12' },
{ name: 'Playgroup (Tue)', time: 'Tue 3:30-4:30pm', students: ['何溢 Ho Yat', '馮悦晞 Fung Yuet Hei', 'Abby Li', 'Gareth Yu'], topic: 'Sensory Play - Colors' },
{ name: 'Independence Class (Sat)', time: 'Sat 9:00-10:00am', students: ['林僖晴', '陳爾荍 Chan Yi Kiu Alma'], topic: 'Self-care Skills' },
{ name: 'Playgroup (Sat AM)', time: 'Sat 9:00-10:00am', students: ['羅翊僖 Law Yik Hei', '陳迦淳Chan Ka Shun', '張文綽Cheung Man Cheuk'], topic: 'Music & Movement' },
{ name: 'Playgroup (Sat PM)', time: 'Sat 11:30-12:30pm', students: ['Cherise Cheng', 'Alfie', '呂卓熹 Lui Cheuk Hei'], topic: 'Story Time' },
{ name: 'Independence (Sat PM)', time: 'Sat 12:45-1:45pm', students: ['潘泯璇 Poon Man Shuen', '蘇玥澄 So yuet ching'], topic: 'Social Skills' },
].map((c, i) => (
{c.name}
{c.students.length} students
{c.time}
Topic: {c.topic}
{c.students.map((st, j) => (
))}
))}
)}
{page === 'settings' && (
Settings & Permissions
Permission Management
{[
{ user: 'Sharon', role: 'Admin', access: 'Full Access', color: 'purple' },
{ user: 'Winnie', role: 'Staff', access: 'View & Edit (expires 2026-04-30)', color: 'blue' },
{ user: 'Ms Li', role: 'Teacher', access: 'Class View Only', color: 'green' },
].map((u, i) => (
{u.user}
{u.role} · {u.access}
{u.role}
))}
Grant Access
Pricing & Promotions
{[
{ name: 'Facebook $99 Trial', price: '$99', type: 'Trial' },
{ name: 'New Enrollment Discount', price: '$2,400 (10 lessons)', type: 'Discount' },
{ name: 'Re-enrollment Discount', price: '$3,600 (17 lessons)', type: 'Discount' },
{ name: 'Hidden Agenda 🔒', price: 'Sharon Only', type: 'Restricted', locked: true },
].map((p, i) => (
{p.name}{p.locked && }
{p.price}
{p.type}
))}
Backup & Data
Auto Backup: Active
Daily at 2:00 AM · Last: Today
Import Excel Data
Export Full Backup
Recent Changes
{[
{ action: 'Payment recorded for ST220422', by: 'Sharon', time: '2 hours ago' },
{ action: 'New student ST220471 added', by: 'Sharon', time: '5 hours ago' },
{ action: 'Class topic updated: Kinder', by: 'Ms Li', time: '1 day ago' },
{ action: 'Promotion price edited', by: 'Sharon', time: '2 days ago' },
].map((c, i) => (
{c.action}
by {c.by} · {c.time}
))}
)}
setShowInvoice(null)} title="Invoice Preview">
{showInvoice && (
Invoice No:
{showInvoice.invoice}
Date:
{formatDate(showInvoice.date)}
Student:
{showInvoice.student.name}
{showInvoice.student.id}
Payment Method:
{showInvoice.method}
Description
Amount
{showInvoice.course}
${showInvoice.amount.toLocaleString()}
Total
${showInvoice.amount.toLocaleString()}
)}
setShowReminder(null)} title="Payment Reminder">
{showReminder && (
Generate a WhatsApp message for {showReminder.name} :
{`Hi, this is ${COMPANY.name} (${COMPANY.program}).
We'd like to remind you about the upcoming payment for ${showReminder.name}'s ${showReminder.course || 'course'} lessons.
Please feel free to contact us if you have any questions.
📍 ${COMPANY.address}
📞 Contact us via WhatsApp
Thank you! 😊`}
Copy for WhatsApp
Print Version
)}
);
}