|
| 1 | +import streamlit as st |
| 2 | +from main import FamilyExpenseTracker |
| 3 | +import matplotlib.pyplot as plt |
| 4 | +from streamlit_option_menu import option_menu |
| 5 | + |
| 6 | +# Streamlit configuration |
| 7 | +st.set_page_config(page_title="Family Expense Tracker", page_icon="💰") |
| 8 | + |
| 9 | +st.title("") # Clear the default title |
| 10 | + |
| 11 | +# Hide Streamlit Style |
| 12 | +hide_st_style = """ |
| 13 | + <style> |
| 14 | + #MainMenu {visibility: hidden;} |
| 15 | + footer {visibility: hidden;} |
| 16 | + header {visibility: hidden;} |
| 17 | + </style> |
| 18 | + """ |
| 19 | +st.markdown(hide_st_style, unsafe_allow_html=True) |
| 20 | + |
| 21 | +# Create a session state object |
| 22 | +session_state = st.session_state |
| 23 | + |
| 24 | +# Check if the 'expense_tracker' object exists in the session state |
| 25 | +if "expense_tracker" not in session_state: |
| 26 | + # If not, create and initialize it |
| 27 | + session_state.expense_tracker = FamilyExpenseTracker() |
| 28 | + |
| 29 | +# Center-align the heading using HTML |
| 30 | +st.markdown( |
| 31 | + '<h1 style="text-align: center;">Family Expense Tracker</h1>', |
| 32 | + unsafe_allow_html=True, |
| 33 | +) |
| 34 | + |
| 35 | +# Navigation Menu |
| 36 | +selected = option_menu( |
| 37 | + menu_title=None, |
| 38 | + options=["Data Entry", "Data Overview", "Data Visualization"], |
| 39 | + icons=[ |
| 40 | + "pencil-fill", |
| 41 | + "clipboard2-data", |
| 42 | + "bar-chart-fill", |
| 43 | + ], # https://icons.getbootstrap.com/ |
| 44 | + orientation="horizontal", |
| 45 | +) |
| 46 | + |
| 47 | +# Access the 'expense_tracker' object from session state |
| 48 | +expense_tracker = session_state.expense_tracker |
| 49 | + |
| 50 | +if selected == "Data Entry": |
| 51 | + st.header("Add Family Member") |
| 52 | + with st.expander("Add Family Member"): |
| 53 | + # Sidebar for adding family members |
| 54 | + member_name = st.text_input("Name").title() |
| 55 | + earning_status = st.checkbox("Earning Status") |
| 56 | + if earning_status: |
| 57 | + earnings = st.number_input("Earnings", value=1, min_value=1) |
| 58 | + else: |
| 59 | + earnings = 0 |
| 60 | + |
| 61 | + if st.button("Add Member"): |
| 62 | + try: |
| 63 | + # Check if family member exists |
| 64 | + member = [ |
| 65 | + member |
| 66 | + for member in expense_tracker.members |
| 67 | + if member.name == member_name |
| 68 | + ] |
| 69 | + # If not exist add family member |
| 70 | + if not member: |
| 71 | + expense_tracker.add_family_member( |
| 72 | + member_name, earning_status, earnings |
| 73 | + ) |
| 74 | + st.success("Member added successfully!") |
| 75 | + # Else, update it |
| 76 | + else: |
| 77 | + expense_tracker.update_family_member( |
| 78 | + member[0], earning_status, earnings |
| 79 | + ) |
| 80 | + st.success("Member updated successfully!") |
| 81 | + except ValueError as e: |
| 82 | + st.error(str(e)) |
| 83 | + |
| 84 | + # Sidebar for adding expenses |
| 85 | + st.header("Add Expenses") |
| 86 | + with st.expander("Add Expenses"): |
| 87 | + expense_category = st.selectbox( |
| 88 | + "Category", |
| 89 | + ( |
| 90 | + "Housing", |
| 91 | + "Food", |
| 92 | + "Transportation", |
| 93 | + "Entertainment", |
| 94 | + "Child-Related", |
| 95 | + "Medical", |
| 96 | + "Investment", |
| 97 | + "Miscellaneous", |
| 98 | + ), |
| 99 | + ) |
| 100 | + expense_description = st.text_input("Description (optional)").title() |
| 101 | + expense_value = st.number_input("Value", min_value=0) |
| 102 | + expense_date = st.date_input("Date", value="today") |
| 103 | + |
| 104 | + if st.button("Add Expense"): |
| 105 | + try: |
| 106 | + # Add the expense |
| 107 | + expense_tracker.merge_similar_category( |
| 108 | + expense_value, expense_category, expense_description, expense_date |
| 109 | + ) |
| 110 | + st.success("Expense added successfully!") |
| 111 | + except ValueError as e: |
| 112 | + st.error(str(e)) |
| 113 | +elif selected == "Data Overview": |
| 114 | + # Display family members |
| 115 | + if not expense_tracker.members: |
| 116 | + st.info( |
| 117 | + "Start by adding family members to track your expenses together! Currently, no members have been added. Get started by clicking the 'Add Member' from the Data Entry Tab" |
| 118 | + ) |
| 119 | + else: |
| 120 | + st.header("Family Members") |
| 121 | + ( |
| 122 | + name_column, |
| 123 | + earning_status_column, |
| 124 | + earnings_column, |
| 125 | + family_delete_column, |
| 126 | + ) = st.columns(4) |
| 127 | + name_column.write("**Name**") |
| 128 | + earning_status_column.write("**Earning status**") |
| 129 | + earnings_column.write("**Earnings**") |
| 130 | + family_delete_column.write("**Action**") |
| 131 | + |
| 132 | + for member in expense_tracker.members: |
| 133 | + name_column.write(member.name) |
| 134 | + earning_status_column.write( |
| 135 | + "Earning" if member.earning_status else "Not Earning" |
| 136 | + ) |
| 137 | + earnings_column.write(member.earnings) |
| 138 | + |
| 139 | + if family_delete_column.button(f"Delete {member.name}"): |
| 140 | + expense_tracker.delete_family_member(member) |
| 141 | + st.rerun() |
| 142 | + |
| 143 | + # Display expenses |
| 144 | + st.header("Expenses") |
| 145 | + if not expense_tracker.expense_list: |
| 146 | + st.info( |
| 147 | + "Currently, no expenses have been added. Get started by clicking the 'Add Expenses' from the Data Entry Tab" |
| 148 | + ) |
| 149 | + else: |
| 150 | + ( |
| 151 | + value_column, |
| 152 | + category_column, |
| 153 | + description_column, |
| 154 | + date_column, |
| 155 | + expense_delete_column, |
| 156 | + ) = st.columns(5) |
| 157 | + value_column.write("**Value**") |
| 158 | + category_column.write("**Category**") |
| 159 | + description_column.write("**Description**") |
| 160 | + date_column.write("**Date**") |
| 161 | + expense_delete_column.write("**Delete**") |
| 162 | + |
| 163 | + for expense in expense_tracker.expense_list: |
| 164 | + value_column.write(expense.value) |
| 165 | + category_column.write(expense.category) |
| 166 | + description_column.write(expense.description) |
| 167 | + date_column.write(expense.date) |
| 168 | + |
| 169 | + if expense_delete_column.button(f"Delete {expense.category}"): |
| 170 | + expense_tracker.delete_expense(expense) |
| 171 | + st.rerun() |
| 172 | + |
| 173 | + total_earnings = expense_tracker.calculate_total_earnings() # Calculate total earnings |
| 174 | + total_expenditure = expense_tracker.calculate_total_expenditure() # Calculate total expenditure |
| 175 | + remaining_balance = total_earnings - total_expenditure # Calculate remaining balance |
| 176 | + col1, col2, col3 = st.columns(3) |
| 177 | + col1.metric("Total Earnings", f"{total_earnings}") # Display total earnings |
| 178 | + col2.metric("Total Expenditure", f"{total_expenditure}") # Display total expenditure |
| 179 | + col3.metric("Remaining Balance", f"{remaining_balance}") # Display remaining balance |
| 180 | + |
| 181 | +elif selected == "Data Visualization": |
| 182 | + # Create a list of expenses and their values |
| 183 | + expense_data = [ |
| 184 | + (expense.category, expense.value) for expense in expense_tracker.expense_list |
| 185 | + ] |
| 186 | + if expense_data: |
| 187 | + # Calculate the percentage of expenses for the pie chart |
| 188 | + expenses = [data[0] for data in expense_data] |
| 189 | + values = [data[1] for data in expense_data] |
| 190 | + total = sum(values) |
| 191 | + percentages = [(value / total) * 100 for value in values] |
| 192 | + |
| 193 | + # Create a smaller pie chart with a transparent background |
| 194 | + fig, ax = plt.subplots(figsize=(3, 3), dpi=300) |
| 195 | + ax.pie( |
| 196 | + percentages, |
| 197 | + labels=expenses, |
| 198 | + autopct="%1.1f%%", |
| 199 | + startangle=140, |
| 200 | + textprops={"fontsize": 6, "color": "white"}, |
| 201 | + ) |
| 202 | + ax.set_title("Expense Distribution", fontsize=12, color="white") |
| 203 | + |
| 204 | + # Set the background color to be transparent |
| 205 | + fig.patch.set_facecolor("none") |
| 206 | + |
| 207 | + # Display the pie chart in Streamlit |
| 208 | + st.pyplot(fig) |
| 209 | + else: |
| 210 | + st.info( |
| 211 | + "Start by adding family members to track your expenses together! Currently, no members have been added. Get started by clicking the 'Add Member' from the Data Entry Tab." |
| 212 | + ) |
0 commit comments