import streamlit as st import firebase_admin from firebase_admin import credentials, firestore import pandas as pd # Set Page Configuration (must be the first Streamlit command) st.set_page_config( page_title="ERP Admin Panel", page_icon="🛠️", layout="wide", initial_sidebar_state="expanded" ) # Initialize Firebase try: cred = credentials.Certificate("serviceAccountKey.json") firebase_admin.initialize_app(cred) except ValueError: # If the app is already initialized, skip re-initialization pass db = firestore.client() # Default User Authentication DEFAULT_USERS = { "Admin": {"password": "Admin", "role": "Admin"}, "Manager": {"password": "Manager", "role": "Manager"}, } def normalize_email(email): """Normalize email by converting it to lowercase.""" return email.strip().lower() def initialize_default_users(): """ Initialize default users in Firestore if they don't already exist. """ for email, user_data in DEFAULT_USERS.items(): normalized_email = normalize_email(email) emp_doc = db.collection("Employees").document(normalized_email).get() if not emp_doc.exists: with st.spinner(f"⏳ Initializing default user: {email}"): db.collection("Employees").document(normalized_email).set({ "name": email.capitalize(), # Use email as name for simplicity "email": normalized_email, "phone": "N/A", # Default placeholder "designation": "Default User", "role": user_data["role"], "password": user_data["password"], "force_password_change": False # No need to change default passwords }) st.success(f"✅ Default user '{email}' initialized successfully.") def login_user(email, password): # Normalize email email = normalize_email(email) # Check if the user is a default user (Admin/Manager) if email in DEFAULT_USERS and DEFAULT_USERS[email]["password"] == password: return DEFAULT_USERS[email]["role"] # Check if the user exists in Firestore (employees) emp_doc = db.collection("Employees").document(email).get() if emp_doc.exists: emp_data = emp_doc.to_dict() if "password" in emp_data and emp_data["password"] == password: return emp_data.get("role", "Employee") # Default role is "Employee" # If no match is found, return None st.error("❌ Invalid credentials. Please try again.") return None # Sidebar Navigation with Icons st.sidebar.markdown(""" """, unsafe_allow_html=True) st.sidebar.title("🚀 Admin Panel 🛠️") # Initialize Default Users if "default_users_initialized" not in st.session_state: initialize_default_users() st.session_state.default_users_initialized = True # Login Section if "logged_in" not in st.session_state: st.session_state.logged_in = False st.session_state.user_role = None if not st.session_state.logged_in: st.sidebar.subheader("🔑 Login") email = st.sidebar.text_input("📧 Email", placeholder="Enter your email") password = st.sidebar.text_input("🔒 Password", type="password", placeholder="Enter your password") if st.sidebar.button("🔓 Login"): user_role = login_user(email, password) if user_role: # Check if the user needs to change their password emp_doc = db.collection("Employees").document(normalize_email(email)).get() if emp_doc.exists: emp_data = emp_doc.to_dict() if emp_data.get("force_password_change", False): st.session_state.force_password_change = True st.session_state.temp_email = normalize_email(email) st.experimental_rerun() # Update session state for successful login st.session_state.logged_in = True st.session_state.user_role = user_role st.experimental_rerun() else: if "force_password_change" in st.session_state and st.session_state.force_password_change: st.header("⚠️ Change Password") st.warning("🔒 You must change your password before proceeding.") new_password = st.text_input("🔐 New Password", type="password", placeholder="Enter a new password") confirm_password = st.text_input("🔒 Confirm Password", type="password", placeholder="Confirm your new password") if st.button("✅ Save Password"): if not new_password or not confirm_password: st.error("❌ Please fill in both fields.") elif new_password != confirm_password: st.error("❌ Passwords do not match.") elif len(new_password) < 8 or not any(char.isdigit() for char in new_password) or not any(char.isupper() for char in new_password): st.error("❌ Password must be at least 8 characters long, include a number, and an uppercase letter.") else: # Update password in Firestore db.collection("Employees").document(st.session_state.temp_email).update({ "password": new_password, "force_password_change": False }) st.success("✅ Password changed successfully!") st.session_state.force_password_change = False st.session_state.logged_in = True st.experimental_rerun() else: st.sidebar.subheader(f"👋 Welcome, {st.session_state.user_role}") menu = { "👥 Employee Management": "employee", "🛡️ Role Management": "role", "🔒 Access Control": "access", "📊 Dashboards": "dashboard", "📋 Reporting Templates": "report", "🤖 Chatbot": "chatbot", "🧠 Advanced Analytics": "analytics", } choice = st.sidebar.radio("📚 Menu", list(menu.keys())) # Logout Button if st.sidebar.button("🚪 Logout"): st.session_state.logged_in = False st.session_state.user_role = None st.experimental_rerun() # Theme Selection st.sidebar.subheader("🎨 Appearance") theme = st.sidebar.selectbox("🌙 Choose Theme", ["☀️ Light", "🌙 Dark"]) if theme == "☀️ Light": st.markdown(""" """, unsafe_allow_html=True) elif theme == "🌙 Dark": st.markdown(""" """, unsafe_allow_html=True) # Main Content if "logged_in" in st.session_state and st.session_state.logged_in: # Role-Based Access Control user_role = st.session_state.user_role if user_role not in ["Admin", "Manager", "Engineer", "Accountant"]: st.error("❌ Unauthorized access. Please contact the administrator.") st.stop() if menu[choice] == "employee": if user_role not in ["Admin", "Manager"]: st.error("❌ You do not have permission to access this module.") st.stop() st.header("👥 Employee Management") # Real-Time Updates for Employees def fetch_employees(): employees_ref = db.collection("Employees").stream() return [{"ID": emp.id, "Name": emp.to_dict()["name"], "Email": emp.to_dict()["email"], "Role": emp.to_dict()["role"]} for emp in employees_ref] # Add Employee Form with st.form("add_employee_form"): st.subheader("📝 Add Employee") col1, col2 = st.columns(2) with col1: name = st.text_input("👤 Name", placeholder="Enter full name", help="Full name of the employee") email = st.text_input("📧 Email", placeholder="Enter email address", help="Official email address") with col2: phone = st.text_input("📞 Phone", placeholder="Enter phone number", help="Contact number") designation = st.text_input("💼 Designation", placeholder="Enter job title", help="Job role or position") role = st.selectbox("🛡️ Role", ["Admin", "Manager", "Engineer", "Accountant"], help="Select the employee's role.") temp_password = st.text_input("🔒 Temporary Password", type="password", placeholder="Set a temporary password", help="The employee will be forced to change this on first login.") submitted = st.form_submit_button("✅ Save Employee") if submitted: if not name or not email or not phone or not designation or not temp_password: st.error("❌ Please fill in all fields.") elif len(temp_password) < 8 or not any(char.isdigit() for char in temp_password) or not any(char.isupper() for char in temp_password): st.error("❌ Temporary password must be at least 8 characters long, include a number, and an uppercase letter.") else: # Normalize email before saving normalized_email = normalize_email(email) with st.spinner("⏳ Saving employee details..."): db.collection("Employees").document(normalized_email).set({ # Use normalized email as document ID "name": name, "email": normalized_email, "phone": phone, "designation": designation, "role": role, "password": temp_password, "force_password_change": True # Enforce password change on first login }) st.success("✅ Employee Added Successfully!") # Display Employees st.subheader("📋 All Employees") employees_data = fetch_employees() df = pd.DataFrame(employees_data) st.dataframe(df, use_container_width=True) # Modify or Remove Employee if user_role == "Admin": st.subheader("📝 Modify or Remove Employee") selected_employee = st.selectbox("👥 Select Employee to Modify/Remove", [emp["Email"] for emp in employees_data]) if selected_employee: emp_doc = db.collection("Employees").document(selected_employee).get() if emp_doc.exists: emp_data = emp_doc.to_dict() # Modify Employee Form with st.form("modify_employee_form"): st.subheader("📝 Modify Employee Details") col1, col2 = st.columns(2) with col1: name = st.text_input("👤 Name", value=emp_data.get("name", ""), help="Full name of the employee") email = st.text_input("📧 Email", value=emp_data.get("email", ""), help="Official email address") with col2: phone = st.text_input("📞 Phone", value=emp_data.get("phone", ""), help="Contact number") designation = st.text_input("💼 Designation", value=emp_data.get("designation", ""), help="Job role or position") role = st.selectbox("🛡️ Role", ["Admin", "Manager", "Engineer", "Accountant"], index=["Admin", "Manager", "Engineer", "Accountant"].index(emp_data.get("role", "Employee"))) submitted = st.form_submit_button("✅ Update Employee") if submitted: # Normalize email before saving normalized_email = normalize_email(email) with st.spinner("⏳ Updating employee details..."): db.collection("Employees").document(normalized_email).update({ "name": name, "email": normalized_email, "phone": phone, "designation": designation, "role": role }) st.success("✅ Employee Updated Successfully!") # Remove Employee Button if st.button("🗑️ Remove Employee"): with st.spinner("⏳ Removing employee..."): db.collection("Employees").document(selected_employee).delete() st.success("✅ Employee Removed Successfully!") # Export Data as CSV if not df.empty: csv = df.to_csv(index=False).encode('utf-8') st.download_button( label="📥 Download Employee Data as CSV", data=csv, file_name="employees.csv", mime="text/csv" ) elif menu[choice] == "role": if user_role not in ["Admin"]: st.error("❌ You do not have permission to access this module.") st.stop() st.header("🛡️ Role Management") # Add Role Form with st.form("add_role_form"): st.subheader("📝 Add Role") role_name = st.text_input("📜 Role Name", placeholder="Enter role name", help="Name of the role") col1, col2 = st.columns(2) with col1: project_management = st.checkbox("📊 Project Management Access", help="Grant access to project management tools") finance_access = st.checkbox("💰 Finance Access", help="Grant access to financial tools") with col2: hr_access = st.checkbox("👥 HR Access", help="Grant access to HR tools") submitted = st.form_submit_button("✅ Save Role") if submitted: if not role_name: st.error("❌ Please enter a role name.") else: with st.spinner("⏳ Saving role details..."): db.collection("Roles").add({ "role_name": role_name, "permissions": { "Project Management": project_management, "Finance": finance_access, "HR": hr_access } }) st.success(f"✅ Role '{role_name}' Added Successfully!") # Display Roles st.subheader("📋 All Roles") roles_ref = db.collection("Roles").stream() role_data = [{"ID": role.id, "Role Name": role.to_dict()["role_name"], "Permissions": role.to_dict()["permissions"]} for role in roles_ref] st.table(pd.DataFrame(role_data)) elif menu[choice] == "access": st.header("🔒 Access Control") st.write("Control access to modules based on roles here.") # Example: Simulate role-based access control user_role = st.selectbox("🛡️ Select User Role", ["Admin", "Manager", "Engineer", "Accountant"]) if user_role == "Admin": st.info("✅ Full Access Granted.") elif user_role == "Manager": st.info("✅ Access to Project Management and Dashboards.") else: st.warning("⚠️ Limited Access.") elif menu[choice] == "dashboard": st.header("📊 Admin Dashboards") # Employee Count by Role st.subheader("👥 Employees by Role") roles_count = {} employees_ref = db.collection("Employees").stream() for emp in employees_ref: role = emp.to_dict()["role"] roles_count[role] = roles_count.get(role, 0) + 1 roles = list(roles_count.keys()) counts = list(roles_count.values()) # Bar Chart st.bar_chart(pd.DataFrame({"Role": roles, "Count": counts}).set_index("Role")) # Pie Chart st.subheader("📊 Role Distribution") fig = px.pie(names=roles, values=counts, title="Role Distribution") st.plotly_chart(fig) elif menu[choice] == "report": st.header("📋 Reporting Templates") # Add Template Form with st.form("add_template_form"): st.subheader("📝 Add Report Template") template_name = st.text_input("📄 Template Name", placeholder="Enter template name", help="Name of the report template") fields = st.text_area("📋 Fields (comma-separated)", "Project Name, Start Date, End Date", help="Enter fields separated by commas.") submitted = st.form_submit_button("✅ Save Template") if submitted: if not template_name or not fields: st.error("❌ Please fill in all fields.") else: with st.spinner("⏳ Saving report template..."): db.collection("Reports").add({ "template_name": template_name, "fields": fields.split(",") }) st.success(f"✅ Template '{template_name}' Added Successfully!") # Display Templates st.subheader("📋 All Templates") templates_ref = db.collection("Reports").stream() template_data = [{"ID": temp.id, "Template Name": temp.to_dict()["template_name"], "Fields": temp.to_dict()["fields"]} for temp in templates_ref] st.table(pd.DataFrame(template_data)) elif menu[choice] == "chatbot": st.header("🤖 Chatbot") # Load QA model qa_pipeline = pipeline("question-answering") # Chatbot Interface st.subheader("💬 Ask a Question") question = st.text_input("❓ Your Question") context = "The Admin module allows you to manage employees, roles, and access control. Use the sidebar to navigate." if st.button("🔍 Get Answer"): try: result = qa_pipeline(question=question, context=context) st.write("💡 Answer:", result["answer"]) except Exception as e: st.error(f"❌ An error occurred: {e}") elif menu[choice] == "analytics": st.header("🧠 Advanced Analytics") # Predictive Analytics: Role Recommendations st.subheader("👥 Employee Role Recommendations") employees_ref = db.collection("Employees").stream() employee_data = [{"Name": emp.to_dict()["name"], "Role": emp.to_dict()["role"]} for emp in employees_ref] df = pd.DataFrame(employee_data) if not df.empty: # Encode roles for clustering role_mapping = {role: idx for idx, role in enumerate(df["Role"].unique())} df["Role_Encoded"] = df["Role"].map(role_mapping) # Perform K-Means Clustering kmeans = KMeans(n_clusters=len(role_mapping), random_state=42) df["Cluster"] = kmeans.fit_predict(df[["Role_Encoded"]]) # Display Recommendations st.write("👥 Clustered Employees:") st.dataframe(df) # Predict Role for New Employee st.subheader("🎯 Predict Role for New Employee") new_employee_name = st.text_input("👤 New Employee Name") if st.button("🔮 Predict Role"): if not new_employee_name: st.error("❌ Please enter the employee's name.") else: # Randomly assign a cluster (for demonstration purposes) predicted_cluster = np.random.randint(0, len(role_mapping)) predicted_role = [role for role, idx in role_mapping.items() if idx == predicted_cluster][0] st.success(f"🎯 Recommended Role for {new_employee_name}: {predicted_role}") # Anomaly Detection st.subheader("⚠️ Anomaly Detection in Employee Data") if not df.empty: # Use Isolation Forest for anomaly detection iso_forest = IsolationForest(contamination=0.1, random_state=42) df["Anomaly"] = iso_forest.fit_predict(df[["Role_Encoded"]]) anomalies = df[df["Anomaly"] == -1] st.write("⚠️ Detected Anomalies:") st.dataframe(anomalies) # Notifications Feature st.sidebar.subheader("🔔 Notifications") st.sidebar.info("🎉 New feature: Advanced reporting tools added!") st.sidebar.warning("⏰ Reminder: Save your changes before navigating away.")