Skip to content

Commit e854dc5

Browse files
committed
feat: Enhanced Admin Panel with full User/Appointment CRUD
1 parent f300449 commit e854dc5

File tree

1 file changed

+82
-63
lines changed

1 file changed

+82
-63
lines changed

frontend/views/admin_view.py

Lines changed: 82 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)