import streamlit as st from supabase import create_client, Client import os from datetime import datetime, date import json def init_supabase(): """Initialize Supabase client""" try: url = st.secrets.get("SUPABASE_URL") key = st.secrets.get("SUPABASE_KEY") except: url = os.getenv("SUPABASE_URL") key = os.getenv("SUPABASE_KEY") if not url or not key: st.error("Supabase credentials not found.") return None return create_client(url, key) def get_all_students(): """Get all students from database""" supabase = init_supabase() if not supabase: return [] try: response = supabase.table('users').select('*').eq('role', 'student').execute() return response.data if response.data else [] except Exception as e: st.error(f"Error fetching students: {str(e)}") return [] def get_instructor_id(username): """Get instructor ID from database by username""" supabase = init_supabase() if not supabase: return None try: response = supabase.rpc('get_user_by_username', {'username_param': username}).execute() if response.data: return response.data[0]['id'] # Fallback: query the table directly response = supabase.table('users').select('id').eq('username', username).execute() if response.data: return response.data[0]['id'] return None except Exception as e: st.error(f"Database error: {str(e)}") return None def save_instructor_notes(instructor_id, class_date, attendance_data, writing_skills_notes, debate_skills_notes, parent_communication_notes, upcoming_events_notes, general_notes): """Save instructor notes to the database""" supabase = init_supabase() if not supabase: return False try: data = { 'instructor_id': instructor_id, 'class_date': class_date, 'attendance_data': attendance_data, 'writing_skills_notes': writing_skills_notes, 'debate_skills_notes': debate_skills_notes, 'parent_communication_notes': parent_communication_notes, 'upcoming_events_notes': upcoming_events_notes, 'general_notes': general_notes } response = supabase.table('instructor_notes').insert(data).execute() return True if response.data else False except Exception as e: st.error(f"Error saving notes: {str(e)}") return False def get_previous_notes(instructor_id, limit=10): """Get previous instructor notes""" supabase = init_supabase() if not supabase: return [] try: response = supabase.table('instructor_notes').select('*').eq('instructor_id', instructor_id).order('class_date', desc=True).limit(limit).execute() return response.data if response.data else [] except Exception as e: st.error(f"Error fetching previous notes: {str(e)}") return [] def show_instructor_notes(): """Show the instructor notes interface""" st.title("📝 Instructor Notes") st.markdown("---") # Check if current user is instructor current_user = st.session_state.get('username') if not current_user: st.error("Please log in to access instructor notes.") return # Get current user's role supabase = init_supabase() if supabase: try: response = supabase.rpc('get_user_by_username', {'username_param': current_user}).execute() if response.data: user_role = response.data[0].get('role', 'student') if user_role != 'instructor': st.error("Access denied. Only instructors can access instructor notes.") return else: st.error("User not found.") return except Exception as e: st.error(f"Error checking user role: {str(e)}") return # Get instructor ID instructor_id = get_instructor_id(current_user) if not instructor_id: st.error("Could not retrieve instructor information.") return # Get all students students = get_all_students() if not students: st.error("No students found in the database.") return # Tabs for different functions tab1, tab2 = st.tabs(["📝 Take Notes", "📊 View Previous Notes"]) with tab1: show_take_notes_form(instructor_id, students) with tab2: show_previous_notes(instructor_id) def show_take_notes_form(instructor_id, students): """Show form to take instructor notes""" st.subheader("📝 Take Class Notes") # Initialize session state for attendance tracking if 'attendance_selections' not in st.session_state: st.session_state.attendance_selections = {} # Class date class_date = st.date_input("Class Date", value=date.today(), key="class_date_input") st.markdown("### 📋 Select Students Present") st.markdown("Check the students who are present today:") # Track which students are present using session state present_students = [] for student in students: # Create a unique key for each student's attendance attendance_key = f"attendance_{student['id']}" # Initialize the attendance state if not exists if attendance_key not in st.session_state.attendance_selections: st.session_state.attendance_selections[attendance_key] = False # Default to absent # Checkbox for attendance is_present = st.checkbox( f"{student['full_name']} is present", value=st.session_state.attendance_selections[attendance_key], key=attendance_key, on_change=lambda s=student, k=attendance_key: st.session_state.attendance_selections.update({k: not st.session_state.attendance_selections.get(k, True)}) ) # Update session state st.session_state.attendance_selections[attendance_key] = is_present if is_present: present_students.append(student) st.markdown(f"**Students Present:** {len(present_students)}") # Create attendance data attendance_data = { "students": [ { "student_id": student['id'], "username": student['username'], "full_name": student['full_name'], "present": student in present_students } for student in students ], "total_present": len(present_students), "total_absent": len(students) - len(present_students) } # Show notes section only for present students if present_students: st.markdown("### 📝 Student Notes") st.markdown("Add notes for each present student:") student_notes = {"students": []} for student in present_students: notes = st.text_area( f"Notes for {student['full_name']}", key=f"notes_{student['id']}", placeholder="Enter notes about writing skills, debate performance, parent communication, etc...", height=100 ) student_notes["students"].append({ "student_id": student['id'], "username": student['username'], "full_name": student['full_name'], "notes": notes }) # Use the same notes for all three categories (simplified) writing_skills_notes = student_notes debate_skills_notes = student_notes parent_communication_notes = student_notes else: # Empty notes if no students present writing_skills_notes = {"students": []} debate_skills_notes = {"students": []} parent_communication_notes = {"students": []} st.markdown("### 📅 Upcoming Events") upcoming_events_notes = {"tournaments": [], "important_dates": []} # Simple event input event_name = st.text_input("Event/Tournament Name (optional)", key="event_name") if event_name: event_date = st.date_input("Event Date", key="event_date") event_notes = st.text_area("Event Notes (optional)", key="event_notes") upcoming_events_notes["important_dates"].append({ "event": event_name, "date": str(event_date), "notes": event_notes }) st.markdown("### 📝 General Notes") general_notes = st.text_area("Any additional notes or observations:", height=100) # Submit button submit_button = st.button("💾 Save Notes") if submit_button: # Convert date to string for JSON serialization class_date_str = class_date.strftime('%Y-%m-%d') if class_date else str(date.today()) if save_instructor_notes(instructor_id, class_date_str, attendance_data, writing_skills_notes, debate_skills_notes, parent_communication_notes, upcoming_events_notes, general_notes): st.success("Notes saved successfully!") # Clear attendance selections after successful save st.session_state.attendance_selections = {} st.rerun() else: st.error("Failed to save notes. Please try again.") def show_previous_notes(instructor_id): """Show previous instructor notes""" st.subheader("📊 Previous Notes") notes = get_previous_notes(instructor_id) if not notes: st.info("No previous notes found.") return # Create a selectbox for choosing which note to view note_options = {f"{note['class_date']} - {len(note['attendance_data']['students'])} students": note for note in notes} selected_note_display = st.selectbox("Choose a class session to view:", list(note_options.keys())) if selected_note_display: selected_note = note_options[selected_note_display] st.markdown(f"**Class Date:** {selected_note['class_date']}") st.markdown(f"**Created:** {selected_note['created_at']}") # Display attendance with st.expander("📋 Attendance", expanded=True): attendance = selected_note['attendance_data'] st.markdown(f"**Summary:** {attendance['total_present']} present, {attendance['total_absent']} absent") for student in attendance['students']: status = "✅ Present" if student['present'] else "❌ Absent" st.write(f"**{student['full_name']}:** {status}") # Display student notes (simplified - all notes are the same) if selected_note['writing_skills_notes'] and selected_note['writing_skills_notes']['students']: with st.expander("📝 Student Notes", expanded=False): for student in selected_note['writing_skills_notes']['students']: st.markdown(f"**{student['full_name']}:**") if student['notes']: st.write(f" {student['notes']}") st.write("---") # Display upcoming events if selected_note['upcoming_events_notes']: with st.expander("📅 Upcoming Events", expanded=False): events = selected_note['upcoming_events_notes'] if events.get('tournaments') and events['tournaments']: st.markdown("**Tournaments:**") for tournament in events['tournaments']: st.write(f" **{tournament['name']}** - {tournament['date']}") if tournament.get('location'): st.write(f" Location: {tournament['location']}") if tournament.get('notes'): st.write(f" Notes: {tournament['notes']}") st.write("---") if events.get('important_dates') and events['important_dates']: st.markdown("**Important Dates:**") for event in events['important_dates']: st.write(f" **{event['event']}** - {event['date']}") if event.get('notes'): st.write(f" Notes: {event['notes']}") st.write("---") # Display general notes if selected_note['general_notes']: with st.expander("📝 General Notes", expanded=False): st.write(selected_note['general_notes'])