Spaces:
Sleeping
Sleeping
| 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']) |