@@ -50,74 +50,93 @@ def render_admin_page():
5050 with col2 :
5151 st .success (f"Database: { stats .get ('database_status' , 'Unknown' )} " )
5252
53- # 4. Recent Users & Management
54- st .subheader ( "👥 User Management" )
53+ # TABS for Management
54+ tab1 , tab2 = st .tabs ([ "👥 User Management" , "📅 Global Appointments" ] )
5555
56- users_resp = requests .get (f"{ backend_url } /admin/users" , headers = headers , timeout = 5 )
57- if users_resp .status_code == 200 :
58- users = users_resp .json ()
59- if users :
60- # Convert to DataFrame for better display
61- import pandas as pd
62- df = pd .DataFrame (users )
63- if 'role' not in df .columns :
64- df ['role' ] = 'patient' # Fallback
65-
66- # Reorder columns
67- cols = ['id' , 'username' , 'role' , 'full_name' , 'email' , 'joined' ]
68- st .dataframe (df [cols ], use_container_width = True , hide_index = True )
69-
70- st .markdown ("### ✏️ Update Role" )
71- c1 , c2 , c3 = st .columns ([2 , 1 , 1 ])
72- with c1 :
73- user_names = {u ['username' ]: u ['id' ] for u in users }
74- selected_username = st .selectbox ("Select User" , list (user_names .keys ()))
75-
76- with c2 :
77- new_role = st .selectbox ("New Role" , ["patient" , "doctor" , "admin" ])
56+ # --- TAB 1: USERS ---
57+ with tab1 :
58+ st .subheader ("User Database" )
59+ users_resp = requests .get (f"{ backend_url } /admin/users" , headers = headers , timeout = 5 )
60+ if users_resp .status_code == 200 :
61+ users = users_resp .json ()
62+ if users :
63+ # Convert to DataFrame
64+ import pandas as pd
65+ df = pd .DataFrame (users )
66+ if 'role' not in df .columns : df ['role' ] = 'patient'
67+
68+ # Display Table
69+ st .dataframe (
70+ df [['id' , 'username' , 'role' , 'full_name' , 'email' , 'joined' ]],
71+ use_container_width = True ,
72+ hide_index = True
73+ )
7874
79- with c3 :
80- st .write ("" ) # Spacer
81- st .write ("" )
82- if st .button ("Update Role" , type = "primary" ):
83- uid = user_names [selected_username ]
84- if api .update_user_role (uid , new_role ):
85- st .rerun ()
75+ st .divider ()
76+
77+ # Actions Section
78+ c1 , c2 = st .columns (2 )
79+
80+ # Edit Role
81+ with c1 :
82+ with st .expander ("✏️ Edit User Role" ):
83+ user_names = {f"{ u ['username' ]} (ID: { u ['id' ]} )" : u for u in users }
84+ sel_u = st .selectbox ("Select User" , list (user_names .keys ()), key = "role_sel" )
85+ target_user = user_names [sel_u ]
86+ new_r = st .selectbox ("New Role" , ["patient" , "doctor" , "admin" ], key = "role_val" , index = ["patient" , "doctor" , "admin" ].index (target_user .get ('role' ,'patient' )))
87+
88+ if st .button ("Update Role" , type = "primary" ):
89+ if api .update_user_role (target_user ['id' ], new_r ):
90+ st .success (f"Updated { target_user ['username' ]} to { new_r } !" )
91+ st .rerun ()
92+
93+ # Delete User
94+ with c2 :
95+ with st .expander ("🗑️ Delete User" ):
96+ st .warning ("⚠️ This action is permanent!" )
97+ del_u = st .selectbox ("Select User to Delete" , list (user_names .keys ()), key = "del_sel" )
98+ target_del = user_names [del_u ]
99+
100+ if st .button (f"DELETE { target_del ['username' ]} " , type = "secondary" ):
101+ if api .delete_user (target_del ['id' ]):
102+ st .success (f"Deleted { target_del ['username' ]} " )
103+ st .rerun ()
104+ else :
105+ st .info ("No users found." )
86106 else :
87- st .caption ("No users found." )
88-
89- # 5. Appointment Management
90- st .markdown ("---" )
91- st .subheader ("📅 Global Appointments" )
92-
93- appointments = api .fetch_appointments ()
94- if appointments :
95- import pandas as pd
96- df_appt = pd .DataFrame (appointments )
97-
98- # Enrich with logic if needed, but raw display is fine for MVP
99- # Columns: id, specialist, date_time, reason, status
107+ st .error ("Failed to fetch users." )
108+
109+ # --- TAB 2: APPOINTMENTS ---
110+ with tab2 :
111+ st .subheader ("Appointment Operations" )
100112
101- # Simple status filter
102- status_filter = st .selectbox ("Filter Status" , ["All" , "Scheduled" , "Completed" , "Cancelled" ])
103- if status_filter != "All" :
104- df_appt = df_appt [df_appt ['status' ] == status_filter ]
113+ appointments = api .fetch_appointments ()
114+ if appointments :
115+ # Filter
116+ status_filter = st .selectbox ("Filter by Status" , ["All" , "Scheduled" , "Completed" , "Cancelled" , "Rescheduled" ])
117+ filtered_appts = [a for a in appointments if status_filter == "All" or a ['status' ] == status_filter ]
105118
106- st .dataframe (
107- df_appt ,
108- column_config = {
109- "date_time" : st .column_config .DatetimeColumn ("Date & Time" , format = "D MMM YYYY, h:mm a" ),
110- "specialist" : "Doctor" ,
111- "reason" : "Patient Note" ,
112- "status" : "Status"
113- },
114- use_container_width = True ,
115- hide_index = True
116- )
117- else :
118- st .info ("No appointments found in the system." )
119-
120- st .markdown ("---" )
119+ if filtered_appts :
120+ for appt in filtered_appts :
121+ date_str = appt ['date_time' ].replace ("T" , " " )[:16 ]
122+ color = "#34D399" if appt ['status' ] in ['Scheduled' , 'Rescheduled' ] else "#94A3B8"
123+
124+ with st .expander (f"{ date_str } | { appt ['specialist' ]} (ID: { appt ['id' ]} )" ):
125+ c_a , c_b = st .columns ([3 , 1 ])
126+ with c_a :
127+ st .markdown (f"**Patient ID:** `{ appt ['user_id' ]} `" )
128+ st .markdown (f"**Status:** <span style='color:{ color } '>{ appt ['status' ]} </span>" , unsafe_allow_html = True )
129+ st .markdown (f"**Reason:** { appt ['reason' ]} " )
130+
131+ with c_b :
132+ if st .button ("🗑️ Delete" , key = f"del_apt_{ appt ['id' ]} " ):
133+ if api .delete_appointment (appt ['id' ]):
134+ st .success ("Deleted!" )
135+ st .rerun ()
136+ else :
137+ st .info (f"No { status_filter } appointments found." )
138+ else :
139+ st .info ("No appointments in system." )
121140
122141 except Exception as e :
123142 st .error (f"Connection Error: { e } " )
0 commit comments