arif670 commited on
Commit
4cb18f4
Β·
verified Β·
1 Parent(s): f671a9f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +247 -124
app.py CHANGED
@@ -5,17 +5,70 @@ import pandas as pd
5
  import plotly.express as px
6
  from datetime import datetime, timedelta
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  # Initialize Firebase
9
  if not firebase_admin._apps:
10
  cred = credentials.Certificate("firebase_credentials.json")
11
  firebase_admin.initialize_app(cred)
12
  db = firestore.client()
13
 
14
- # Hash Password
15
  def hash_password(password):
16
  return hashlib.sha256(password.encode()).hexdigest()
17
 
18
- # Register User
19
  def register_user(email, password):
20
  try:
21
  user = auth.create_user(email=email, password=password)
@@ -24,7 +77,6 @@ def register_user(email, password):
24
  except Exception as e:
25
  st.error(f"Error: {e}")
26
 
27
- # Authenticate User
28
  def authenticate_user(email, password):
29
  try:
30
  user = auth.get_user_by_email(email)
@@ -38,36 +90,35 @@ st.set_page_config(page_title="Construction To-Do List", layout="wide")
38
  if "authenticated" not in st.session_state:
39
  st.session_state["authenticated"] = False
40
  st.session_state["email"] = ""
 
41
 
42
  if not st.session_state["authenticated"]:
43
  st.title("πŸ” User Authentication")
44
- choice = st.radio("Select Option", ["Sign In", "Sign Up"])
45
 
46
  if choice == "Sign Up":
47
- new_email = st.text_input("Enter your email")
48
- new_password = st.text_input("Enter a password", type="password")
49
- if st.button("Register") and new_email and new_password:
50
- register_user(new_email, new_password)
 
51
 
52
  elif choice == "Sign In":
53
- email = st.text_input("Enter your email")
54
- password = st.text_input("Enter your password", type="password")
55
- if st.button("Login"):
56
- if authenticate_user(email, password):
57
- st.session_state["authenticated"] = True
58
- st.session_state["email"] = email
59
- st.rerun()
60
- else:
61
- st.error("Invalid email or password")
 
62
  st.stop()
63
 
64
- # Main Dashboard After Login
65
- st.sidebar.title(f"Welcome, {st.session_state['email']}")
66
- menu = st.sidebar.radio("Go to", ["Dashboard View", "Task Entry", "View Tasks", "Add New Project", "Edit Task"])
67
- email = st.session_state['email']
68
-
69
  def get_tasks():
70
- tasks_ref = db.collection("tasks").where("user", "==", email)
71
  return [{"id": task.id, **task.to_dict()} for task in tasks_ref.stream()]
72
 
73
  def calculate_deadline_status(task_date):
@@ -84,143 +135,215 @@ def calculate_deadline_status(task_date):
84
  else:
85
  return "On Track", delta
86
 
87
- if menu == "Dashboard View":
88
- st.title("πŸ“Š Dashboard Overview")
89
  tasks = get_tasks()
 
 
90
 
91
- if not tasks:
92
- st.info("No tasks found.")
93
- else:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  df = pd.DataFrame(tasks)
95
- total_tasks = len(df)
96
- completed_tasks = len(df[df['status'] == "Completed"])
97
 
98
- # Add deadline calculations
99
- df['deadline_status'] = df['date'].apply(lambda x: calculate_deadline_status(x)[0])
100
- overdue_tasks = df[(df['status'].isin(["Pending", "In Progress"])) &
101
- (df['deadline_status'].isin(["Overdue", "Due Today", "Due in 1-3 days"]))]
 
 
102
 
103
- col1, col2, col3 = st.columns(3)
104
- col1.metric("Total Tasks", total_tasks)
105
- col2.metric("Completed Tasks", completed_tasks)
106
- col3.metric("Urgent Tasks", len(overdue_tasks))
107
-
108
- st.subheader("Tasks by Status")
109
- status_counts = df['status'].value_counts().reset_index()
110
- fig = px.pie(status_counts, values='count', names='status', hole=0.3)
111
- st.plotly_chart(fig)
112
 
113
- # Deadline Alerts
114
- st.subheader("⚠️ Upcoming Deadlines")
115
- if not overdue_tasks.empty:
116
- for _, task in overdue_tasks.iterrows():
117
- status, days = calculate_deadline_status(task['date'])
118
- emoji = "❗" if "Overdue" in status else "⏳"
119
- st.write(f"{emoji} {task['task']} ({task['project']}) - {status}")
120
- else:
121
- st.info("No upcoming deadlines!")
 
 
 
 
 
122
 
123
- elif menu == "Task Entry":
 
124
  st.title("πŸ“ Add New Task")
125
  projects_ref = db.collection("projects")
126
  projects = [proj.id for proj in projects_ref.stream()]
127
  projects.append("Add New Project")
128
 
129
- with st.form("task_form"):
130
- task = st.text_input("Task Description:")
131
- task_type = st.selectbox("Task Type:", ["Design", "Procurement", "Construction", "Testing", "Other"])
132
- selected_project = st.selectbox("Project Name:", projects)
 
133
  if selected_project == "Add New Project":
134
- new_project = st.text_input("Enter New Project Name:")
135
  if new_project:
136
- db.collection("projects").document(new_project).set({"created_by": email})
137
  selected_project = new_project
138
- status = st.selectbox("Status:", ["Pending", "In Progress", "Completed"])
139
- date = st.date_input("Target Date:")
 
 
 
 
 
140
  if st.form_submit_button("Add Task"):
141
  db.collection("tasks").add({
142
- "user": email,
143
  "task": task,
144
  "type": task_type,
145
  "project": selected_project,
146
  "status": status,
147
  "date": str(date)
148
  })
149
- st.success("Task Added Successfully!")
150
- st.rerun()
151
-
152
- elif menu == "Add New Project":
153
- st.title("πŸ—οΈ Add New Project")
154
- with st.form("project_form"):
155
- new_project_name = st.text_input("Enter New Project Name:")
156
- if st.form_submit_button("Add Project"):
157
- db.collection("projects").document(new_project_name).set({"created_by": email})
158
- st.success("Project Added Successfully!")
159
  st.rerun()
160
 
161
- elif menu == "View Tasks":
162
- st.subheader("πŸ“‹ All Tasks")
 
163
  tasks = get_tasks()
164
 
165
  if tasks:
166
  df = pd.DataFrame(tasks)
167
 
168
- # Add filtering options
169
- col1, col2 = st.columns(2)
170
  with col1:
171
- selected_status = st.selectbox("Filter by Status:", ["All"] + ["Pending", "In Progress", "Completed"])
 
 
172
  with col2:
173
- projects = ["All"] + list(df['project'].unique())
174
- selected_project = st.selectbox("Filter by Project:", projects)
 
 
175
 
176
  # Apply filters
177
- if selected_status != "All":
178
- df = df[df['status'] == selected_status]
179
- if selected_project != "All":
180
- df = df[df['project'] == selected_project]
 
 
 
181
 
182
- # Add deadline status column
183
- df['deadline_status'] = df['date'].apply(lambda x: calculate_deadline_status(x)[0])
184
-
185
- # Display table with styling
186
- st.dataframe(
187
- df[['task', 'type', 'project', 'status', 'date', 'deadline_status']]
188
- .style.apply(lambda x: ['background: #ffcccc' if v == "Overdue" else
189
- 'background: #fff3cd' if "Due" in v else ''
190
- for v in x], subset=['deadline_status']),
191
- height=400
192
- )
 
 
 
193
  else:
194
- st.info("No tasks found.")
195
 
196
- elif menu == "Edit Task":
197
- st.title("✏️ Edit Task")
198
- tasks = get_tasks()
199
 
200
- if not tasks:
201
- st.info("No tasks to edit")
202
- else:
203
- task_options = [f"{task['task']} ({task['id']})" for task in tasks]
204
- selected_task = st.selectbox("Select Task to Edit", task_options)
205
- task_id = selected_task.split("(")[-1].strip(")")
206
-
207
- task_to_edit = next((t for t in tasks if t['id'] == task_id), None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
 
209
- if task_to_edit:
210
- with st.form("edit_form"):
211
- new_task = st.text_input("Task Description", value=task_to_edit['task'])
212
- new_type = st.selectbox("Task Type", ["Design", "Procurement", "Construction", "Testing", "Other"],
213
- index=["Design", "Procurement", "Construction", "Testing", "Other"].index(task_to_edit['type']))
214
- new_status = st.selectbox("Status", ["Pending", "In Progress", "Completed"],
215
- index=["Pending", "In Progress", "Completed"].index(task_to_edit['status']))
216
- new_date = st.date_input("Target Date", value=datetime.strptime(task_to_edit['date'], "%Y-%m-%d"))
217
-
218
- if st.form_submit_button("Update Task"):
219
- db.collection("tasks").document(task_id).update({
220
- "task": new_task,
221
- "type": new_type,
222
- "status": new_status,
223
- "date": str(new_date)
224
- })
225
- st.success("Task updated successfully!")
226
- st.rerun()
 
5
  import plotly.express as px
6
  from datetime import datetime, timedelta
7
 
8
+ # Custom CSS for enhanced UI
9
+ st.markdown("""
10
+ <style>
11
+ /* Main container styling */
12
+ .main .block-container {
13
+ padding-top: 2rem;
14
+ max-width: 1200px;
15
+ }
16
+
17
+ /* Sidebar animations and styling */
18
+ [data-testid="stSidebar"] {
19
+ background: linear-gradient(145deg, #2c3e50, #3498db) !important;
20
+ box-shadow: 5px 0 15px rgba(0,0,0,0.2);
21
+ }
22
+
23
+ .st-emotion-cache-1dj0hjr {
24
+ transition: all 0.3s ease;
25
+ border-radius: 8px;
26
+ padding: 10px 15px;
27
+ margin: 5px 0;
28
+ }
29
+
30
+ .st-emotion-cache-1dj0hjr:hover {
31
+ transform: translateX(10px);
32
+ background: rgba(255,255,255,0.1);
33
+ }
34
+
35
+ /* Professional table styling */
36
+ .dataframe {
37
+ border-radius: 10px;
38
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
39
+ overflow: hidden;
40
+ }
41
+
42
+ .dataframe thead th {
43
+ background: #2c3e50 !important;
44
+ color: white !important;
45
+ font-weight: 600;
46
+ }
47
+
48
+ /* Status badges */
49
+ .status-badge {
50
+ padding: 4px 12px;
51
+ border-radius: 20px;
52
+ font-weight: 500;
53
+ display: inline-block;
54
+ }
55
+
56
+ .pending { background: #fff3cd; color: #856404; }
57
+ .in-progress { background: #cce5ff; color: #004085; }
58
+ .completed { background: #d4edda; color: #155724; }
59
+ </style>
60
+ """, unsafe_allow_html=True)
61
+
62
  # Initialize Firebase
63
  if not firebase_admin._apps:
64
  cred = credentials.Certificate("firebase_credentials.json")
65
  firebase_admin.initialize_app(cred)
66
  db = firestore.client()
67
 
68
+ # Authentication Functions
69
  def hash_password(password):
70
  return hashlib.sha256(password.encode()).hexdigest()
71
 
 
72
  def register_user(email, password):
73
  try:
74
  user = auth.create_user(email=email, password=password)
 
77
  except Exception as e:
78
  st.error(f"Error: {e}")
79
 
 
80
  def authenticate_user(email, password):
81
  try:
82
  user = auth.get_user_by_email(email)
 
90
  if "authenticated" not in st.session_state:
91
  st.session_state["authenticated"] = False
92
  st.session_state["email"] = ""
93
+ st.session_state["first_login"] = True
94
 
95
  if not st.session_state["authenticated"]:
96
  st.title("πŸ” User Authentication")
97
+ choice = st.radio("Select Option", ["Sign In", "Sign Up"], horizontal=True)
98
 
99
  if choice == "Sign Up":
100
+ with st.form("signup_form"):
101
+ new_email = st.text_input("Enter your email")
102
+ new_password = st.text_input("Enter a password", type="password")
103
+ if st.form_submit_button("Register") and new_email and new_password:
104
+ register_user(new_email, new_password)
105
 
106
  elif choice == "Sign In":
107
+ with st.form("signin_form"):
108
+ email = st.text_input("Enter your email")
109
+ password = st.text_input("Enter your password", type="password")
110
+ if st.form_submit_button("Login"):
111
+ if authenticate_user(email, password):
112
+ st.session_state["authenticated"] = True
113
+ st.session_state["email"] = email
114
+ st.rerun()
115
+ else:
116
+ st.error("Invalid email or password")
117
  st.stop()
118
 
119
+ # Main Application
 
 
 
 
120
  def get_tasks():
121
+ tasks_ref = db.collection("tasks").where("user", "==", st.session_state["email"])
122
  return [{"id": task.id, **task.to_dict()} for task in tasks_ref.stream()]
123
 
124
  def calculate_deadline_status(task_date):
 
135
  else:
136
  return "On Track", delta
137
 
138
+ # Show reminders after login
139
+ if st.session_state.get("first_login"):
140
  tasks = get_tasks()
141
+ overdue = []
142
+ due_soon = []
143
 
144
+ for task in tasks:
145
+ if task['status'] in ["Pending", "In Progress"]:
146
+ status, _ = calculate_deadline_status(task['date'])
147
+ if "Overdue" in status or "Due" in status:
148
+ overdue.append(task) if "Overdue" in status else due_soon.append(task)
149
+
150
+ if overdue or due_soon:
151
+ with st.container():
152
+ st.markdown("---")
153
+ cols = st.columns([1, 4, 1])
154
+ with cols[1]:
155
+ st.subheader("πŸ”” Task Reminders")
156
+ if overdue:
157
+ st.error("##### Overdue Tasks")
158
+ for task in overdue:
159
+ st.markdown(f"⚠️ **{task['task']}** ({task['project']}) - Due {task['date']}")
160
+ if due_soon:
161
+ st.warning("##### Upcoming Deadlines")
162
+ for task in due_soon:
163
+ st.markdown(f"⏳ **{task['task']}** ({task['project']}) - Due {task['date']}")
164
+ st.markdown("---")
165
+ st.session_state.first_login = False
166
+
167
+ # Sidebar Navigation
168
+ st.sidebar.title(f"Welcome, {st.session_state['email']}")
169
+ menu = st.sidebar.radio("Navigation", [
170
+ "🏠 Dashboard",
171
+ "πŸ“ Task Entry",
172
+ "πŸ‘€ View Tasks",
173
+ "πŸ—οΈ Projects",
174
+ "βš™οΈ Settings"
175
+ ], label_visibility="collapsed")
176
+
177
+ # Dashboard View
178
+ if menu == "🏠 Dashboard":
179
+ st.title("πŸ“Š Project Dashboard")
180
+ tasks = get_tasks()
181
+
182
+ if tasks:
183
  df = pd.DataFrame(tasks)
 
 
184
 
185
+ # Metrics Row
186
+ col1, col2, col3, col4 = st.columns(4)
187
+ col1.metric("Total Tasks", len(df))
188
+ col2.metric("Completed", len(df[df['status'] == "Completed"]), "tasks")
189
+ col3.metric("In Progress", len(df[df['status'] == "In Progress"]), "tasks")
190
+ col4.metric("Pending", len(df[df['status'] == "Pending"]), "tasks")
191
 
192
+ # Visualizations
193
+ col1, col2 = st.columns(2)
194
+ with col1:
195
+ st.subheader("Status Distribution")
196
+ fig = px.pie(df, names='status', hole=0.3,
197
+ color_discrete_sequence=px.colors.qualitative.Pastel)
198
+ st.plotly_chart(fig, use_container_width=True)
 
 
199
 
200
+ with col2:
201
+ st.subheader("Project Timeline")
202
+ timeline_df = df.copy()
203
+ timeline_df['date'] = pd.to_datetime(timeline_df['date'])
204
+ fig = px.timeline(timeline_df, x_start="date", x_end="date", y="project",
205
+ color="status", title="Project Timeline",
206
+ color_discrete_map={
207
+ "Pending": "#FFD700",
208
+ "In Progress": "#87CEEB",
209
+ "Completed": "#90EE90"
210
+ })
211
+ st.plotly_chart(fig, use_container_width=True)
212
+ else:
213
+ st.info("No tasks found. Start by adding new tasks!")
214
 
215
+ # Task Entry
216
+ elif menu == "πŸ“ Task Entry":
217
  st.title("πŸ“ Add New Task")
218
  projects_ref = db.collection("projects")
219
  projects = [proj.id for proj in projects_ref.stream()]
220
  projects.append("Add New Project")
221
 
222
+ with st.form("task_form", clear_on_submit=True):
223
+ task = st.text_input("Task Description", placeholder="Enter task details...")
224
+ task_type = st.selectbox("Task Type", ["Design", "Procurement", "Construction", "Testing", "Other"])
225
+ selected_project = st.selectbox("Project", projects)
226
+
227
  if selected_project == "Add New Project":
228
+ new_project = st.text_input("New Project Name")
229
  if new_project:
230
+ db.collection("projects").document(new_project).set({"created_by": st.session_state["email"]})
231
  selected_project = new_project
232
+
233
+ col1, col2 = st.columns(2)
234
+ with col1:
235
+ status = st.selectbox("Status", ["Pending", "In Progress", "Completed"])
236
+ with col2:
237
+ date = st.date_input("Target Date", min_value=datetime.today())
238
+
239
  if st.form_submit_button("Add Task"):
240
  db.collection("tasks").add({
241
+ "user": st.session_state["email"],
242
  "task": task,
243
  "type": task_type,
244
  "project": selected_project,
245
  "status": status,
246
  "date": str(date)
247
  })
248
+ st.success("Task added successfully!")
 
 
 
 
 
 
 
 
 
249
  st.rerun()
250
 
251
+ # View Tasks
252
+ elif menu == "πŸ‘€ View Tasks":
253
+ st.title("πŸ” Task Explorer")
254
  tasks = get_tasks()
255
 
256
  if tasks:
257
  df = pd.DataFrame(tasks)
258
 
259
+ # Filters
260
+ col1, col2, col3 = st.columns(3)
261
  with col1:
262
+ status_filter = st.multiselect("Filter by Status",
263
+ options=df['status'].unique(),
264
+ default=df['status'].unique())
265
  with col2:
266
+ project_filter = st.multiselect("Filter by Project",
267
+ options=df['project'].unique())
268
+ with col3:
269
+ date_filter = st.date_input("Filter by Date")
270
 
271
  # Apply filters
272
+ filtered_df = df.copy()
273
+ if status_filter:
274
+ filtered_df = filtered_df[filtered_df['status'].isin(status_filter)]
275
+ if project_filter:
276
+ filtered_df = filtered_df[filtered_df['project'].isin(project_filter)]
277
+ if date_filter:
278
+ filtered_df = filtered_df[filtered_df['date'] == str(date_filter)]
279
 
280
+ # Enhanced Table Display
281
+ if not filtered_df.empty:
282
+ styled_df = filtered_df[['task', 'project', 'status', 'date']].copy()
283
+ styled_df['status'] = styled_df['status'].apply(
284
+ lambda x: f'<span class="status-badge {x.lower().replace(" ", "-")}">{x}</span>'
285
+ )
286
+
287
+ st.markdown(styled_df.style.hide(axis="index")
288
+ .set_table_styles([
289
+ {'selector': 'th', 'props': 'background-color: #2c3e50; color: white;'},
290
+ {'selector': 'td', 'props': 'padding: 12px; border-bottom: 1px solid #ddd;'}
291
+ ]).to_html(), unsafe_allow_html=True)
292
+ else:
293
+ st.info("No tasks match the selected filters")
294
  else:
295
+ st.info("No tasks found. Start by adding new tasks!")
296
 
297
+ # Project Management
298
+ elif menu == "πŸ—οΈ Projects":
299
+ st.title("πŸ—οΈ Project Management")
300
 
301
+ # Existing Projects
302
+ projects_ref = db.collection("projects")
303
+ projects = [proj.id for proj in projects_ref.stream()]
304
+
305
+ if projects:
306
+ st.subheader("Existing Projects")
307
+ for project in projects:
308
+ col1, col2 = st.columns([3, 1])
309
+ with col1:
310
+ st.markdown(f"**{project}**")
311
+ with col2:
312
+ if st.button(f"Delete {project}", key=f"del_{project}"):
313
+ db.collection("projects").document(project).delete()
314
+ st.rerun()
315
+
316
+ # Add New Project
317
+ st.subheader("Add New Project")
318
+ with st.form("project_form"):
319
+ new_project = st.text_input("Project Name")
320
+ if st.form_submit_button("Create Project"):
321
+ if new_project:
322
+ db.collection("projects").document(new_project).set({
323
+ "created_by": st.session_state["email"],
324
+ "created_at": datetime.now().strftime("%Y-%m-%d")
325
+ })
326
+ st.success("Project created successfully!")
327
+ st.rerun()
328
+
329
+ # Settings
330
+ elif menu == "βš™οΈ Settings":
331
+ st.title("βš™οΈ Account Settings")
332
+
333
+ with st.form("password_change"):
334
+ st.subheader("Change Password")
335
+ old_password = st.text_input("Current Password", type="password")
336
+ new_password = st.text_input("New Password", type="password")
337
+ confirm_password = st.text_input("Confirm New Password", type="password")
338
 
339
+ if st.form_submit_button("Update Password"):
340
+ if new_password == confirm_password:
341
+ # Implement password change logic
342
+ st.success("Password updated successfully!")
343
+ else:
344
+ st.error("New passwords do not match")
345
+
346
+ st.markdown("---")
347
+ if st.button("Logout", type="primary"):
348
+ st.session_state.authenticated = False
349
+ st.rerun()