Spaces:
Sleeping
Sleeping
| 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(""" | |
| <style> | |
| .sidebar .sidebar-content { | |
| background-color: #e6f7ff; /* Light Blue Background */ | |
| border-radius: 15px; | |
| box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.2); | |
| } | |
| .sidebar .stButton button { | |
| background-color: #007bff; | |
| color: white; | |
| border-radius: 10px; | |
| padding: 10px; | |
| font-size: 16px; | |
| box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3); | |
| } | |
| .sidebar .stButton button:hover { | |
| background-color: #0056b3; | |
| transform: scale(1.05); | |
| transition: all 0.3s ease; | |
| } | |
| </style> | |
| """, 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(""" | |
| <style> | |
| .stApp {background-color: #e6f7ff; color: black;} /* Light Blue Background */ | |
| </style> | |
| """, unsafe_allow_html=True) | |
| elif theme == "๐ Dark": | |
| st.markdown(""" | |
| <style> | |
| .stApp {background-color: #1E1E1E; color: white;} | |
| </style> | |
| """, 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.") |