IAMTFRMZA commited on
Commit
1c4332a
Β·
verified Β·
1 Parent(s): a40135d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -128
app.py CHANGED
@@ -10,206 +10,200 @@ scope = [
10
  "https://www.googleapis.com/auth/drive"
11
  ]
12
  creds = ServiceAccountCredentials.from_json_keyfile_name(
13
- "deep-mile-461309-t8-0e90103411e0.json",
14
- scope
15
  )
16
  client = gspread.authorize(creds)
17
- sheet_url = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
 
 
18
 
19
  # -------------------- UTILS --------------------
20
- def normalize_columns(df):
21
  df.columns = df.columns.str.strip().str.title()
22
  return df
23
 
24
- def load_sheet(name):
 
25
  try:
26
- ws = client.open_by_url(sheet_url).worksheet(name)
27
- df = pd.DataFrame(ws.get_all_records())
28
- return normalize_columns(df)
 
 
 
 
29
  except Exception as e:
30
  return pd.DataFrame([{"Error": str(e)}])
31
 
 
32
  def get_current_week_range():
33
  today = datetime.now()
34
  start = today - timedelta(days=today.weekday())
35
  end = start + timedelta(days=6)
36
  return start.date(), end.date()
37
 
38
- def filter_week(df, date_col, rep_col=None, rep=None):
39
- df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
40
- s, e = get_current_week_range()
41
- out = df[(df[date_col] >= s) & (df[date_col] <= e)]
42
- if rep:
 
 
43
  out = out[out[rep_col] == rep]
44
  return out
45
 
46
- def filter_date(df, date_col, rep_col, y, m, d, rep):
47
  try:
48
  target = datetime(int(y), int(m), int(d)).date()
49
  except:
50
  return pd.DataFrame([{"Error": "Invalid date input"}])
51
- df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
 
 
52
  out = df[df[date_col] == target]
53
- if rep:
54
  out = out[out[rep_col] == rep]
55
  return out
56
 
57
  # -------------------- REPORT FUNCTIONS --------------------
58
  def get_calls(rep=None):
59
  df = load_sheet("Calls")
60
- if "Call Date" not in df:
61
- return pd.DataFrame([{"Error": "Missing 'Call Date' column"}])
62
  return filter_week(df, "Call Date", "Rep", rep)
63
 
64
- def search_calls_by_date(y, m, d, rep):
 
 
 
 
65
  df = load_sheet("Calls")
66
- if "Call Date" not in df:
67
- return pd.DataFrame([{"Error": "Missing 'Call Date' column"}])
68
- return filter_date(df, "Call Date", "Rep", y, m, d, rep)
69
 
70
- # -------------------- APPOINTMENTS (UPCOMING) --------------------
71
- def upcoming_summary_and_detail(rep=None):
72
- df = load_sheet("Appointments")
73
- if "Appointment Date" not in df:
74
- return pd.DataFrame([{"Error": "Missing 'Appointment Date' column"}]), pd.DataFrame()
75
- df["Appointment Date"] = pd.to_datetime(df["Appointment Date"], errors="coerce").dt.date
76
- today = datetime.now().date()
77
- future = df[df["Appointment Date"] >= today]
78
- if rep:
79
- future = future[future["Rep"] == rep]
80
- summary = future.groupby("Rep").size().reset_index(name="Appointment Count")
81
- return summary, future
82
-
83
- def search_appointments_by_date(y, m, d, rep):
84
  df = load_sheet("Appointments")
85
- if "Appointment Date" not in df:
86
- return pd.DataFrame([{"Error": "Missing 'Appointment Date' column"}]), pd.DataFrame()
87
- try:
88
- target = datetime(int(y), int(m), int(d)).date()
89
- except:
90
- return pd.DataFrame([{"Error": "Invalid date input"}]), pd.DataFrame()
91
- df["Appointment Date"] = pd.to_datetime(df["Appointment Date"], errors="coerce").dt.date
92
- out = df[df["Appointment Date"] == target]
93
- if rep:
94
- out = out[out["Rep"] == rep]
95
- summary = out.groupby("Rep").size().reset_index(name="Appointment Count")
96
- return summary, out
97
-
98
- # -------------------- APPOINTED LEADS --------------------
99
  def get_leads_detail():
100
  df = load_sheet("AllocatedLeads")
101
- if "Assigned Rep" not in df or "Company Name" not in df:
102
- return pd.DataFrame([{"Error": "Missing 'Assigned Rep' or 'Company Name' column"}])
103
  return df
104
 
105
  def get_leads_summary():
106
  df = get_leads_detail()
107
- if "Error" in df.columns:
108
- return df
109
  return df.groupby("Assigned Rep").size().reset_index(name="Leads Count")
110
 
111
  # -------------------- INSIGHTS --------------------
112
  def compute_insights():
113
  calls = get_calls()
114
- appt_summary, _ = upcoming_summary_and_detail()
115
  leads = get_leads_detail()
116
  def top(df, col):
117
- return df[col].value_counts().idxmax() if not df.empty else "N/A"
118
- return pd.DataFrame([
 
 
 
 
 
119
  {"Metric": "Most Calls This Week", "Rep": top(calls, "Rep")},
120
- {"Metric": "Most Upcoming Appointments", "Rep": top(appt_summary, "Rep")},
121
  {"Metric": "Most Leads Allocated", "Rep": top(leads, "Assigned Rep")},
122
  ])
 
123
 
124
- # -------------------- USER MANAGEMENT --------------------
125
- def load_users():
126
- df = load_sheet("User")
127
- for col in ["Name", "Email", "Company", "Target Figures"]:
128
- if col not in df.columns:
129
- df[col] = ""
130
- return df[["Name", "Email", "Company", "Target Figures"]]
131
 
 
132
  def save_users(df):
133
  ws = client.open_by_url(sheet_url).worksheet("User")
 
 
134
  ws.clear()
135
- rows = [df.columns.tolist()] + df.fillna("").values.tolist()
136
- ws.update(rows)
137
- return df
138
 
139
- # -------------------- DROPDOWN OPTIONS --------------------
140
- def rep_options(sheet, col):
141
- df = load_sheet(sheet)
142
- return sorted(df[col].dropna().unique().tolist()) if col in df else []
143
-
144
- # -------------------- UI LAYOUT --------------------
145
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
146
  gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
147
 
148
- # Calls Report Tab
149
  with gr.Tab("Calls Report"):
150
- rc = gr.Dropdown(label="Optional Rep Filter", choices=rep_options("Calls", "Rep"))
151
- btn_calls = gr.Button("Load Current Week Calls")
152
- tbl_calls = gr.Dataframe()
153
- btn_calls.click(fn=get_calls, inputs=rc, outputs=tbl_calls)
 
 
154
 
155
  gr.Markdown("### πŸ” Search Calls by Specific Date")
156
- y1, m1, d1 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
157
- rc2 = gr.Dropdown(label="Optional Rep Filter", choices=rep_options("Calls", "Rep"))
158
- btn_cd = gr.Button("Search Calls by Date")
159
- tbl_cd = gr.Dataframe()
160
- btn_cd.click(fn=search_calls_by_date, inputs=[y1, m1, d1, rc2], outputs=tbl_cd)
 
 
 
 
161
 
162
- # Appointments Report Tab
163
  with gr.Tab("Appointments Report"):
164
- ra = gr.Dropdown(label="Optional Rep Filter", choices=rep_options("Appointments", "Rep"))
165
- btn_appt = gr.Button("Load Upcoming Appointments")
166
- sum_appt = gr.Dataframe(label="πŸ“Š Upcoming Appointments Summary by Rep")
167
- det_appt = gr.Dataframe(label="πŸ”Ž Detailed Upcoming Appointments")
168
- btn_appt.click(fn=upcoming_summary_and_detail, inputs=ra, outputs=[sum_appt, det_appt])
 
 
 
 
 
 
 
 
 
169
 
170
  gr.Markdown("### πŸ” Search Appointments by Specific Date")
171
- y2, m2, d2 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
172
- ra2 = gr.Dropdown(label="Optional Rep Filter", choices=rep_options("Appointments", "Rep"))
173
- btn_ad = gr.Button("Search Appointments by Date")
174
- sum_ad = gr.Dataframe(label="πŸ“Š Appointments Summary for Date by Rep")
175
- det_ad = gr.Dataframe(label="πŸ”Ž Detailed Appointments for Date")
176
- btn_ad.click(fn=search_appointments_by_date,
177
- inputs=[y2, m2, d2, ra2],
178
- outputs=[sum_ad, det_ad])
179
-
180
- # Appointed Leads Tab
 
 
 
 
 
 
 
181
  with gr.Tab("Appointed Leads"):
182
- btn_leads = gr.Button("View Appointed Leads")
183
- sum_leads = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
184
- det_leads = gr.Dataframe(label="πŸ”Ž Detailed Leads")
185
- btn_leads.click(fn=lambda: (get_leads_summary(), get_leads_detail()),
186
- outputs=[sum_leads, det_leads])
187
 
188
- # Insights Tab
189
  with gr.Tab("Insights"):
190
- btn_ins = gr.Button("Generate Insights")
191
- tbl_ins = gr.Dataframe()
192
- btn_ins.click(fn=compute_insights, outputs=tbl_ins)
193
 
194
- # User Management Tab
195
  with gr.Tab("User Management"):
196
- gr.Markdown("### πŸ§‘β€πŸ’Ό Manage Users\nEdit, add, or remove rows, then click **Save Users**.")
197
- users_df = gr.Dataframe(
198
- value=load_users(),
199
- label="Users",
200
- interactive=True
201
- )
202
  save_btn = gr.Button("Save Users")
203
- save_status = gr.Markdown()
204
-
205
- def on_save(df):
206
- saved = save_users(pd.DataFrame(df))
207
- return "βœ… Users saved!", saved
208
-
209
- save_btn.click(
210
- fn=on_save,
211
- inputs=users_df,
212
- outputs=[save_status, users_df]
213
- )
214
 
215
- app.launch()
 
10
  "https://www.googleapis.com/auth/drive"
11
  ]
12
  creds = ServiceAccountCredentials.from_json_keyfile_name(
13
+ "deep-mile-461309-t8-0e90103411e0.json", scope
 
14
  )
15
  client = gspread.authorize(creds)
16
+ sheet_url = (
17
+ "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
18
+ )
19
 
20
  # -------------------- UTILS --------------------
21
+ def normalize_columns(df: pd.DataFrame) -> pd.DataFrame:
22
  df.columns = df.columns.str.strip().str.title()
23
  return df
24
 
25
+ # Replace get_all_records() to avoid duplicate-header errors
26
+ def load_sheet(sheet_name: str) -> pd.DataFrame:
27
  try:
28
+ ws = client.open_by_url(sheet_url).worksheet(sheet_name)
29
+ all_values = ws.get_all_values()
30
+ if not all_values:
31
+ return pd.DataFrame()
32
+ headers = [h.strip().title() for h in all_values[0]]
33
+ data = all_values[1:]
34
+ return pd.DataFrame(data, columns=headers)
35
  except Exception as e:
36
  return pd.DataFrame([{"Error": str(e)}])
37
 
38
+ # date utilities
39
  def get_current_week_range():
40
  today = datetime.now()
41
  start = today - timedelta(days=today.weekday())
42
  end = start + timedelta(days=6)
43
  return start.date(), end.date()
44
 
45
+ def filter_week(df: pd.DataFrame, date_col: str, rep_col: str = None, rep=None):
46
+ if date_col not in df.columns:
47
+ return df
48
+ df[date_col] = pd.to_datetime(df[date_col], errors='coerce').dt.date
49
+ start, end = get_current_week_range()
50
+ out = df[(df[date_col] >= start) & (df[date_col] <= end)]
51
+ if rep and rep_col in df.columns:
52
  out = out[out[rep_col] == rep]
53
  return out
54
 
55
+ def filter_date(df: pd.DataFrame, date_col: str, rep_col: str, y, m, d, rep):
56
  try:
57
  target = datetime(int(y), int(m), int(d)).date()
58
  except:
59
  return pd.DataFrame([{"Error": "Invalid date input"}])
60
+ if date_col not in df.columns:
61
+ return pd.DataFrame([{"Error": f"Missing '{date_col}' column"}])
62
+ df[date_col] = pd.to_datetime(df[date_col], errors='coerce').dt.date
63
  out = df[df[date_col] == target]
64
+ if rep and rep_col in df.columns:
65
  out = out[out[rep_col] == rep]
66
  return out
67
 
68
  # -------------------- REPORT FUNCTIONS --------------------
69
  def get_calls(rep=None):
70
  df = load_sheet("Calls")
 
 
71
  return filter_week(df, "Call Date", "Rep", rep)
72
 
73
+ def get_appointments(rep=None):
74
+ df = load_sheet("Appointments")
75
+ return filter_week(df, "Appointment Date", "Rep", rep)
76
+
77
+ def search_calls_by_date(y,m,d,rep):
78
  df = load_sheet("Calls")
79
+ return filter_date(df, "Call Date", "Rep", y,m,d,rep)
 
 
80
 
81
+ def search_appointments_by_date(y,m,d,rep):
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  df = load_sheet("Appointments")
83
+ return filter_date(df, "Appointment Date", "Rep", y,m,d,rep)
84
+
85
+ # Leads
86
+
 
 
 
 
 
 
 
 
 
 
87
  def get_leads_detail():
88
  df = load_sheet("AllocatedLeads")
 
 
89
  return df
90
 
91
  def get_leads_summary():
92
  df = get_leads_detail()
93
+ if "Assigned Rep" not in df.columns:
94
+ return pd.DataFrame([{"Error": "Missing 'Assigned Rep'"}])
95
  return df.groupby("Assigned Rep").size().reset_index(name="Leads Count")
96
 
97
  # -------------------- INSIGHTS --------------------
98
  def compute_insights():
99
  calls = get_calls()
100
+ appts = get_appointments()
101
  leads = get_leads_detail()
102
  def top(df, col):
103
+ if col in df.columns and not df.empty:
104
+ try:
105
+ return df[col].mode()[0]
106
+ except:
107
+ return "N/A"
108
+ return "N/A"
109
+ insights = pd.DataFrame([
110
  {"Metric": "Most Calls This Week", "Rep": top(calls, "Rep")},
111
+ {"Metric": "Most Appointments This Week", "Rep": top(appts, "Rep")},
112
  {"Metric": "Most Leads Allocated", "Rep": top(leads, "Assigned Rep")},
113
  ])
114
+ return insights
115
 
116
+ # -------------------- DROPDOWN OPTIONS --------------------
117
+ def rep_options(sheet_name, rep_col):
118
+ df = load_sheet(sheet_name)
119
+ if rep_col in df.columns:
120
+ return sorted(df[rep_col].dropna().unique().tolist())
121
+ return []
 
122
 
123
+ # -------------------- USER MANAGEMENT --------------------
124
  def save_users(df):
125
  ws = client.open_by_url(sheet_url).worksheet("User")
126
+ headers = df.columns.tolist()
127
+ rows = df.fillna("").values.tolist()
128
  ws.clear()
129
+ ws.update([headers] + rows)
130
+ return pd.DataFrame([{"Status": "Users saved."}])
 
131
 
132
+ # -------------------- UI --------------------
 
 
 
 
 
133
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
134
  gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
135
 
 
136
  with gr.Tab("Calls Report"):
137
+ rep_calls = gr.Dropdown(label="Optional Rep Filter",
138
+ choices=rep_options("Calls","Rep"),
139
+ allow_custom_value=True)
140
+ calls_btn = gr.Button("Load Current Week Calls")
141
+ calls_tbl = gr.Dataframe()
142
+ calls_btn.click(fn=get_calls, inputs=rep_calls, outputs=calls_tbl)
143
 
144
  gr.Markdown("### πŸ” Search Calls by Specific Date")
145
+ y1,m1,d1 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
146
+ rep1 = gr.Dropdown(label="Optional Rep Filter",
147
+ choices=rep_options("Calls","Rep"),
148
+ allow_custom_value=True)
149
+ calls_date_btn = gr.Button("Search Calls by Date")
150
+ calls_date_tbl = gr.Dataframe()
151
+ calls_date_btn.click(fn=search_calls_by_date,
152
+ inputs=[y1,m1,d1,rep1],
153
+ outputs=calls_date_tbl)
154
 
 
155
  with gr.Tab("Appointments Report"):
156
+ rep_appt = gr.Dropdown(label="Optional Rep Filter",
157
+ choices=rep_options("Appointments","Rep"),
158
+ allow_custom_value=True)
159
+ appt_btn = gr.Button("Load Current Week Appointments")
160
+ appt_summary = gr.Dataframe(label="πŸ“Š Weekly Appointments Summary by Rep")
161
+ appt_tbl = gr.Dataframe()
162
+ appt_btn.click(
163
+ fn=lambda rep: (
164
+ get_appointments(rep).groupby("Rep").size().reset_index(name="Count"),
165
+ get_appointments(rep)
166
+ ),
167
+ inputs=rep_appt,
168
+ outputs=[appt_summary, appt_tbl]
169
+ )
170
 
171
  gr.Markdown("### πŸ” Search Appointments by Specific Date")
172
+ y2,m2,d2 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
173
+ rep2 = gr.Dropdown(label="Optional Rep Filter",
174
+ choices=rep_options("Appointments","Rep"),
175
+ allow_custom_value=True)
176
+ appt_date_btn = gr.Button("Search Appointments by Date")
177
+ appt_date_sum = gr.Dataframe(label="πŸ“Š Appointments Summary for Date by Rep")
178
+ appt_date_tbl = gr.Dataframe()
179
+ appt_date_btn.click(
180
+ fn=lambda y,m,d,rep: (
181
+ search_appointments_by_date(y,m,d,rep)
182
+ .groupby("Rep").size().reset_index(name="Count"),
183
+ search_appointments_by_date(y,m,d,rep)
184
+ ),
185
+ inputs=[y2,m2,d2,rep2],
186
+ outputs=[appt_date_sum, appt_date_tbl]
187
+ )
188
+
189
  with gr.Tab("Appointed Leads"):
190
+ leads_btn = gr.Button("View Appointed Leads")
191
+ leads_sum = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
192
+ leads_det = gr.Dataframe(label="πŸ”Ž Detailed Leads")
193
+ leads_btn.click(fn=lambda: (get_leads_summary(), get_leads_detail()),
194
+ outputs=[leads_sum, leads_det])
195
 
 
196
  with gr.Tab("Insights"):
197
+ insights_btn = gr.Button("Generate Insights")
198
+ insights_tbl = gr.Dataframe()
199
+ insights_btn.click(fn=compute_insights, outputs=insights_tbl)
200
 
 
201
  with gr.Tab("User Management"):
202
+ gr.Markdown("## πŸ‘€ Manage Users\nEdit the grid and click **Save Users** to push changes.")
203
+ users_df = load_sheet("User")
204
+ users_grid = gr.Dataframe(value=users_df, interactive=True)
 
 
 
205
  save_btn = gr.Button("Save Users")
206
+ status = gr.Dataframe()
207
+ save_btn.click(fn=save_users, inputs=users_grid, outputs=status)
 
 
 
 
 
 
 
 
 
208
 
209
+ app.launch()