Compare commits

..

3 Commits

Author SHA1 Message Date
1c9ed4bd65 fix: remove last classItem.class.academic_year reference in MyClassesPage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 13:50:27 +01:00
de21c56543 fix: navigate scope in CCGraphNavPanel, class.code -> class_code in MyClassesPage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 13:45:12 +01:00
7a1032a3bd fix(classes): flat shape for MyClassesPage, SubjectClass nav -> class detail page
- MyClassesPage: fix all classItem.class?.* references to flat field access (class_code, name, description etc)
- MyClassesPage: fix class detail link /timetable/classes/:id -> /classes/:id (actual route)
- CCGraphNavPanel: SubjectClass click navigates to /classes/:id since no Neo4j SubjectClass nodes exist yet

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 13:30:38 +01:00
2 changed files with 26 additions and 20 deletions

View File

@ -88,25 +88,25 @@ const MyClassesPage: React.FC = () => {
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3"> <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{teachingClasses.map((classItem) => ( {teachingClasses.map((classItem) => (
<Link <Link
key={classItem.class_id} key={classItem.id}
to={`/timetable/classes/${classItem.class_id}`} to={`/classes/${classItem.id}`}
className="block bg-white rounded-lg shadow hover:shadow-md transition-shadow border border-gray-200" className="block bg-white rounded-lg shadow hover:shadow-md transition-shadow border border-gray-200"
> >
<div className="p-5"> <div className="p-5">
<div className="flex items-start justify-between mb-3"> <div className="flex items-start justify-between mb-3">
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<h3 className="text-lg font-semibold text-gray-900 truncate"> <h3 className="text-lg font-semibold text-gray-900 truncate">
{classItem.class?.name} {classItem.name}
</h3> </h3>
{classItem.class?.code && ( {classItem.class_code && (
<p className="text-sm text-gray-500">{classItem.class.code}</p> <p className="text-sm text-gray-500">{classItem.class_code}</p>
)} )}
</div> </div>
<KeyboardArrowRight className="text-gray-400 flex-shrink-0 ml-2" size={20} /> <KeyboardArrowRight className="text-gray-400 flex-shrink-0 ml-2" size={20} />
</div> </div>
<p className="text-gray-600 text-sm mb-4 line-clamp-2"> <p className="text-gray-600 text-sm mb-4 line-clamp-2">
{classItem.class?.description || 'No description'} {classItem.description || 'No description'}
</p> </p>
<div className="flex items-center gap-2 flex-wrap"> <div className="flex items-center gap-2 flex-wrap">
@ -121,12 +121,12 @@ const MyClassesPage: React.FC = () => {
<div className="mt-4 pt-4 border-t border-gray-100 flex items-center gap-4 text-sm text-gray-500"> <div className="mt-4 pt-4 border-t border-gray-100 flex items-center gap-4 text-sm text-gray-500">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<People size={14} /> <People size={14} />
<span>{classItem.class?.enrolled_count || 0} students</span> <span>{(classItem as any).enrolled_count || 0} students</span>
</div> </div>
{classItem.class?.academic_year && ( {classItem.academic_year && (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<School size={14} /> <School size={14} />
<span>{classItem.class.academic_year}</span> <span>{classItem.academic_year}</span>
</div> </div>
)} )}
</div> </div>
@ -151,25 +151,25 @@ const MyClassesPage: React.FC = () => {
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3"> <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{enrolledClasses.map((classItem) => ( {enrolledClasses.map((classItem) => (
<Link <Link
key={classItem.class_id} key={classItem.id}
to={`/timetable/classes/${classItem.class_id}`} to={`/classes/${classItem.id}`}
className="block bg-white rounded-lg shadow hover:shadow-md transition-shadow border border-gray-200" className="block bg-white rounded-lg shadow hover:shadow-md transition-shadow border border-gray-200"
> >
<div className="p-5"> <div className="p-5">
<div className="flex items-start justify-between mb-3"> <div className="flex items-start justify-between mb-3">
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<h3 className="text-lg font-semibold text-gray-900 truncate"> <h3 className="text-lg font-semibold text-gray-900 truncate">
{classItem.class?.name} {classItem.name}
</h3> </h3>
{classItem.class?.code && ( {classItem.class_code && (
<p className="text-sm text-gray-500">{classItem.class.code}</p> <p className="text-sm text-gray-500">{classItem.class_code}</p>
)} )}
</div> </div>
<KeyboardArrowRight className="text-gray-400 flex-shrink-0 ml-2" size={20} /> <KeyboardArrowRight className="text-gray-400 flex-shrink-0 ml-2" size={20} />
</div> </div>
<p className="text-gray-600 text-sm mb-4 line-clamp-2"> <p className="text-gray-600 text-sm mb-4 line-clamp-2">
{classItem.class?.description || 'No description'} {classItem.description || 'No description'}
</p> </p>
<div className="flex items-center gap-2 flex-wrap"> <div className="flex items-center gap-2 flex-wrap">
@ -182,13 +182,13 @@ const MyClassesPage: React.FC = () => {
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<School size={14} /> <School size={14} />
<span> <span>
{classItem.class?.teachers?.[0]?.first_name} {classItem.class?.teachers?.[0]?.last_name} {(classItem as any).primary_teacher_name} {}
</span> </span>
</div> </div>
{classItem.class?.academic_year && ( {classItem.academic_year && (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<School size={14} /> <School size={14} />
<span>{classItem.class.academic_year}</span> <span>{classItem.academic_year}</span>
</div> </div>
)} )}
</div> </div>
@ -208,7 +208,7 @@ const MyClassesPage: React.FC = () => {
You are not enrolled in or teaching any classes yet. You are not enrolled in or teaching any classes yet.
</p> </p>
<Link <Link
to="/timetable/classes" to="/classes"
className="mt-4 inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-blue-700 bg-blue-100 hover:bg-blue-200" className="mt-4 inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-blue-700 bg-blue-100 hover:bg-blue-200"
> >
Browse Available Classes Browse Available Classes

View File

@ -484,6 +484,7 @@ function TreeItem({ node, depth, onSelect, onExpand }: TreeItemProps) {
export function CCGraphNavPanel() { export function CCGraphNavPanel() {
const { accessToken } = useAuth(); const { accessToken } = useAuth();
const navigate = useNavigate();
const { navigateToNeoNode, context } = useNavigationStore(); const { navigateToNeoNode, context } = useNavigationStore();
const [tree, setTree] = useState<TreeNode | null>(null); const [tree, setTree] = useState<TreeNode | null>(null);
const [schoolStatus, setSchoolStatus] = useState<SchoolStatus | null>(null); const [schoolStatus, setSchoolStatus] = useState<SchoolStatus | null>(null);
@ -626,8 +627,13 @@ export function CCGraphNavPanel() {
const handleSelect = useCallback((node: TreeNode) => { const handleSelect = useCallback((node: TreeNode) => {
// Section nodes with artificial IDs (node_type="Section") have no canvas shape util // Section nodes with artificial IDs (node_type="Section") have no canvas shape util
if (node.is_section && node.node_type === "Section") return; if (node.is_section && node.node_type === "Section") return;
// SubjectClass nodes don't yet exist in Neo4j — navigate to class detail page
if (node.node_type === "SubjectClass") {
navigate(`/classes/${node.neo4j_node_id}`);
return;
}
navigateToNeoNode(node); navigateToNeoNode(node);
}, [navigateToNeoNode]); }, [navigateToNeoNode, navigate]);
const refreshAll = useCallback(() => { const refreshAll = useCallback(() => {
setTree(null); setTree(null);