diff --git a/app.py b/app.py index bb5b8ed..76531e4 100644 --- a/app.py +++ b/app.py @@ -6,7 +6,7 @@ ############################################################################# import streamlit as st -from modules import display_my_custom_component, display_post, display_genai_advice, display_activity_summary, display_recent_workouts +from modules import display_my_custom_component, study_group_card, navigation_bar, display_explore_page, display_genai_advice, display_activity_summary, display_recent_workouts from data_fetcher import get_user_posts, get_genai_advice, get_user_profile, get_user_sensor_data, get_user_workouts userId = 'user1' @@ -14,11 +14,24 @@ def display_app_page(): """Displays the home page of the app.""" - st.title('Welcome to SDS!') + # st.title('Welcome to SDS!') + + # # An example of displaying a custom component called "my_custom_component" + # value = st.text_input('Enter your name') + # display_my_custom_component(value) + + mock_data = [ + {"group_title": "Calc II Cram Session", "subject": "Math", "description": "Preparing for midterm", "date": "Oct 12", "time": "4PM", "location": "Library Room 3", "members": "4/6"}, + {"group_title": "Bio 101 Lab Prep", "subject": "Science", "description": "Reviewing cell structures", "date": "Oct 13", "time": "2PM", "location": "Science Hall", "members": "2/4"}, + {"group_title": "Art History Chat", "subject": "Arts", "description": "Renaissance era discussion", "date": "Oct 15", "time": "11AM", "location": "Cafe Blue", "members": "8/10"}, + {"group_title": "Python Basics", "subject": "CS", "description": "Looping and logic", "date": "Oct 16", "time": "6PM", "location": "Zoom", "members": "12/20"}, +] + + # Run the page + filtered_list = navigation_bar(mock_data) + display_explore_page(filtered_list) + - # An example of displaying a custom component called "my_custom_component" - value = st.text_input('Enter your name') - display_my_custom_component(value) # This is the starting point for your app. You do not need to change these lines diff --git a/modules.py b/modules.py index 93795df..dcf7fb1 100644 --- a/modules.py +++ b/modules.py @@ -8,6 +8,33 @@ ############################################################################# from internals import create_component +import streamlit as st + +# CSS style for modules +st.markdown(""" + +""", unsafe_allow_html=True) # Written by Chat GPT # This one has been written for you as an example. You may change it as wanted. @@ -28,10 +55,112 @@ def display_my_custom_component(value): html_file_name = "my_custom_component" create_component(data, html_file_name) +def navigation_bar(full_group_list): + """ + Renders a simple search bar and returns a filtered list of groups. + """ + # Simple search input + search_query = st.text_input( + "Search", + placeholder="Search by title or description...", + label_visibility="collapsed" + ) -def display_post(username, user_image, timestamp, content, post_image): - """Write a good docstring here.""" - pass + # Filtering Logic + if not search_query: + return full_group_list + + filtered_list = [ + group for group in full_group_list + if search_query.lower() in group['group_title'].lower() or + search_query.lower() in group['description'].lower() + ] + + return filtered_list + +def study_group_card(group_title, subject, description, date, time, location, members): + """ + Render a styled study group preview card. + + Args + + group_title : str + The name of the study group. + subject : str + Academic subject or category label displayed at the top. + description : str + Short summary describing the study group. + date : str + Meeting date (formatted string). + time : str + Meeting time (formatted string). + location : str + Physical or virtual meeting location. + members : str + Current and maximum number of members (e.g., "6/12"). + """ + + with st.container(border=True): + + # Title + st.subheader(group_title) + + # Description + st.write(description) + + # Date & Time + st.write(f"**Date:** {date}") + st.write(f"**Time:** {time}") + + # Location + st.markdown( + f'
📍 {location}
', + unsafe_allow_html=True + ) + + # Members + st.write(f"👥 {members} members") + + # View Details Button + if st.button("View Details", key=f"btn_{group_title}"): + st.session_state.selected_group = group_title + # st.switch_page("pages/group_page.py") + + st.markdown('', unsafe_allow_html=True) + +def display_explore_page(group_list): + """ + Render the explore page with study group cards arranged in rows. + + Args + group_list : list of dict + Each dictionary should have keys: + 'group_title', 'subject', 'description', 'date', 'time', 'location', 'members' + """ + if not group_list: + st.info("No groups found") + return + + + num_columns = 3 # Number of cards per row + for i in range(0, len(group_list), num_columns): + row_groups = group_list[i:i + num_columns] + cols = st.columns(len(row_groups)) # Column for each card in this row + for col, group in zip(cols, row_groups): + with col: + study_group_card( + group_title=group['group_title'], + subject=group['subject'], + description=group['description'], + date=group['date'], + time=group['time'], + location=group['location'], + members=group['members'] + ) + + + + def display_activity_summary(workouts_list): diff --git a/modules_test.py b/modules_test.py index 03c03ae..497f300 100644 --- a/modules_test.py +++ b/modules_test.py @@ -7,18 +7,57 @@ ############################################################################# import unittest +from unittest.mock import MagicMock, patch +import streamlit as st from streamlit.testing.v1 import AppTest -from modules import display_post, display_activity_summary, display_genai_advice, display_recent_workouts +from modules import display_explore_page, navigation_bar, study_group_card # display_activity_summary, display_genai_advice, display_recent_workouts # Write your tests below +APP_FILE = "app.py" -class TestDisplayPost(unittest.TestCase): - """Tests the display_post function.""" +class TestDisplayExplorePage(unittest.TestCase): + """Tests the study group app using Streamlit AppTest.""" - def test_foo(self): - """Tests foo.""" - pass + def test_app_initial_load(self): + """Test that the app loads and displays the initial grid of cards.""" + at = AppTest.from_file(APP_FILE).run() + + assert not at.exception + + assert len(at.text_input) == 1 + assert at.text_input[0].placeholder == "Search by title or description..." + + def test_search_filtering_logic(self): + """Test that typing 'Python' in the search bar filters the results.""" + at = AppTest.from_file(APP_FILE).run() + + at.text_input[0].set_value("Python").run() + + assert not at.exception + + assert len(at.subheader) == 1 + assert at.subheader[0].value == "Python Basics" + + def test_search_no_results(self): + """Test the state when a search matches nothing.""" + at = AppTest.from_file(APP_FILE).run() + + at.text_input[0].set_value("NonExistentSubject123").run() + + assert len(at.info) == 1 + assert "No groups found" in at.info[0].value + + assert len(at.subheader) == 0 + + def test_view_details_button(self): + """Test that clicking 'View Details' works (triggers no errors).""" + at = AppTest.from_file(APP_FILE).run() + + at.button[0].click().run() + + assert not at.exception + assert at.session_state.selected_group == "Calc II Cram Session" class TestDisplayActivitySummary(unittest.TestCase): """Tests the display_activity_summary function."""