IAMTFRMZA commited on
Commit
2e0be03
Β·
verified Β·
1 Parent(s): c8f0059

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -149
app.py CHANGED
@@ -10,107 +10,95 @@ SHEET_URL = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPf
10
  CREDS_JSON = "deep-mile-461309-t8-0e90103411e0.json"
11
 
12
  # -------------------- AUTH --------------------
13
- scope = [
14
- "https://spreadsheets.google.com/feeds",
15
- "https://www.googleapis.com/auth/drive"
16
- ]
17
  creds = ServiceAccountCredentials.from_json_keyfile_name(CREDS_JSON, scope)
18
  client = gspread.authorize(creds)
19
 
20
- # -------------------- SHEET LOAD/UTILS --------------------
21
  def normalize_columns(df):
22
  df.columns = df.columns.str.strip().str.title()
23
  return df
24
 
25
  def load_sheet_df(sheet_name):
26
  try:
27
- ws = client.open_by_url(SHEET_URL).worksheet(sheet_name)
28
- records= ws.get_all_records()
29
- df = pd.DataFrame(records)
30
  return normalize_columns(df)
31
  except Exception as e:
32
- # return a one-row DF with an Error column
33
  return pd.DataFrame([{"Error": str(e)}])
34
 
 
 
 
 
 
 
35
  # -------------------- DATE FILTERS --------------------
36
  def get_current_week_range():
37
  today = datetime.now()
38
  start = today - timedelta(days=today.weekday())
39
- end = start + timedelta(days=6)
40
- return start.date(), end.date()
41
-
42
- def filter_week(df, date_column, rep_column=None, rep=None):
43
- df[date_column] = pd.to_datetime(df[date_column], errors="coerce").dt.date
44
- start,end = get_current_week_range()
45
- out = df[(df[date_column] >= start) & (df[date_column] <= end)]
46
- if rep and rep in out.columns:
47
- out = out[out[rep_column] == rep]
48
  return out
49
 
50
- def filter_date(df, date_column, rep_column, y,m,d, rep):
51
  try:
52
  target = datetime(int(y), int(m), int(d)).date()
53
  except:
54
  return pd.DataFrame([{"Error":"Invalid date"}])
55
- df[date_column] = pd.to_datetime(df[date_column], errors="coerce").dt.date
56
- out = df[df[date_column] == target]
57
- if rep and rep in out.columns:
58
- out = out[out[rep_column] == rep]
59
  return out
60
 
61
- # -------------------- REPORT DATA --------------------
62
  def get_calls(rep=None):
63
  df = load_sheet_df("Calls")
64
  if "Call Date" not in df.columns:
65
- return pd.DataFrame([{"Error":"Missing 'Call Date' column"}])
66
  return filter_week(df, "Call Date", "Rep", rep)
67
 
68
  def get_calls_summary(rep=None):
69
  df = get_calls(rep)
70
  if "Error" in df.columns or df.empty:
71
  return df
72
- return (
73
- df.groupby("Rep")
74
- .size()
75
- .reset_index(name="Count")
76
- .sort_values("Count", ascending=False)
77
- )
78
 
79
- def search_calls_by_date(y,m,d, rep):
80
  df = load_sheet_df("Calls")
81
  if "Call Date" not in df.columns:
82
- return pd.DataFrame([{"Error":"Missing 'Call Date' column"}])
83
  return filter_date(df, "Call Date", "Rep", y,m,d, rep)
84
 
85
  def get_appointments(rep=None):
86
  df = load_sheet_df("Appointments")
87
  if "Appointment Date" not in df.columns:
88
- return pd.DataFrame([{"Error":"Missing 'Appointment Date' column"}])
89
  return filter_week(df, "Appointment Date", "Rep", rep)
90
 
91
  def get_appointments_summary(rep=None):
92
  df = get_appointments(rep)
93
  if "Error" in df.columns or df.empty:
94
  return df
95
- return (
96
- df.groupby("Rep")
97
- .size()
98
- .reset_index(name="Count")
99
- .sort_values("Count", ascending=False)
100
- )
101
 
102
- def search_appointments_by_date(y,m,d, rep):
103
  df = load_sheet_df("Appointments")
104
  if "Appointment Date" not in df.columns:
105
- return pd.DataFrame([{"Error":"Missing 'Appointment Date' column"}])
106
  return filter_date(df, "Appointment Date", "Rep", y,m,d, rep)
107
 
108
  def get_leads_detail():
109
  df = load_sheet_df("AllocatedLeads")
110
- # rename if needed
111
- df = df.rename(columns={"Assigned Rep":"Assigned Rep"})
112
  if "Assigned Rep" not in df.columns:
113
- return pd.DataFrame([{"Error":"Missing 'Assigned Rep' col"}])
114
  return df
115
 
116
  def get_leads_summary():
@@ -121,34 +109,25 @@ def get_leads_summary():
121
 
122
  # -------------------- INSIGHTS --------------------
123
  def compute_insights():
124
- calls = get_calls()
125
- appts = get_appointments()
126
- leads = get_leads_detail()
127
-
128
  def top_rep(df, col):
129
  if "Error" in df.columns or df.empty:
130
  return "N/A"
131
  counts = df.groupby(col).size()
132
- if counts.empty:
133
- return "N/A"
134
- return counts.idxmax()
135
 
136
- top_calls = top_rep(calls, "Rep")
137
- top_appts = top_rep(appts, "Rep")
138
- # unify column name for leads
139
- leads = leads.rename(columns={"Assigned Rep":"Rep"})
140
- top_leads = top_rep(leads, "Rep")
141
 
142
  return pd.DataFrame([
143
- {"Metric":"Most Calls This Week", "Rep":top_calls},
144
- {"Metric":"Most Appointments This Week", "Rep":top_appts},
145
- {"Metric":"Most Leads Allocated", "Rep":top_leads},
146
  ])
147
 
148
  # -------------------- USER MANAGEMENT --------------------
149
  def load_users():
150
- df = load_sheet_df("userAccess") # your actual tab name
151
- # pick & title-case only the cols you want
152
  wanted = [
153
  "Id","Email","Name","Business","Role",
154
  "Daily Phone Call Target","Daily Phone Appointment Target",
@@ -159,115 +138,81 @@ def load_users():
159
  "Monthly Quote Number Target","Monthly Quote Revenue Target",
160
  "Monthly Sales Revenue Target"
161
  ]
162
- exist = [c for c in wanted if c in df.columns]
163
- return df[exist]
164
 
165
  def save_users(df):
166
- ws = client.open_by_url(SHEET_URL).worksheet("userAccess")
167
  ws.clear()
168
  set_with_dataframe(ws, df)
169
  return "βœ… Users saved!"
170
 
171
  # -------------------- GRADIO UI --------------------
172
- with gr.Blocks(title="πŸ“† Graffiti Field App Admin Dashboard") as app:
173
- gr.Markdown("# πŸ“† Graffiti Field App Admin Dashboard")
174
 
175
- # ─── Calls Report ─────────────────────────────
176
  with gr.Tab("Calls Report"):
177
- rep_calls = gr.Dropdown(
178
- label="Optional Rep Filter",
179
- choices=load_sheet_df("Calls")["Rep"].dropna().unique().tolist(),
180
- allow_custom_value=True
181
- )
182
- calls_btn = gr.Button("Load Current Week Calls")
183
- calls_summary = gr.Dataframe(label="πŸ“Š Calls by Rep")
184
- calls_table = gr.Dataframe(label="πŸ”Ž Detailed Calls")
185
-
186
- calls_btn.click(
187
- fn=lambda r: (get_calls_summary(r), get_calls(r)),
188
- inputs=rep_calls,
189
- outputs=[calls_summary, calls_table]
190
- )
191
-
192
- gr.Markdown("### πŸ” Search Calls by Specific Date")
193
- y1,m1,d1 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
194
- rep1 = gr.Dropdown(
195
- label="Optional Rep Filter",
196
- choices=load_sheet_df("Calls")["Rep"].dropna().unique().tolist(),
197
- allow_custom_value=True
198
- )
199
- calls_date_btn = gr.Button("Search Calls by Date")
200
- calls_date_table = gr.Dataframe()
201
-
202
- calls_date_btn.click(
203
- fn=search_calls_by_date,
204
- inputs=[y1,m1,d1,rep1],
205
- outputs=calls_date_table
206
- )
207
-
208
- # ─── Appointments Report ─────────────────────
209
  with gr.Tab("Appointments Report"):
210
- rep_appt = gr.Dropdown(
211
- label="Optional Rep Filter",
212
- choices=load_sheet_df("Appointments")["Rep"].dropna().unique().tolist(),
213
- allow_custom_value=True
214
- )
215
- appt_btn = gr.Button("Load Current Week Appointments")
216
- appt_summary = gr.Dataframe(label="πŸ“Š Appts by Rep")
217
- appt_table = gr.Dataframe(label="πŸ”Ž Detailed Appointments")
218
-
219
- appt_btn.click(
220
- fn=lambda r: (get_appointments_summary(r), get_appointments(r)),
221
- inputs=rep_appt,
222
- outputs=[appt_summary, appt_table]
223
- )
224
-
225
- gr.Markdown("### πŸ” Search Appointments by Specific Date")
226
- y2,m2,d2 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
227
- rep2 = gr.Dropdown(
228
- label="Optional Rep Filter",
229
- choices=load_sheet_df("Appointments")["Rep"].dropna().unique().tolist(),
230
- allow_custom_value=True
231
- )
232
- appt_date_btn = gr.Button("Search Appts by Date")
233
- appt_date_summary = gr.Dataframe(label="πŸ“Š Appts Summary by Rep")
234
- appt_date_table = gr.Dataframe()
235
-
236
- appt_date_btn.click(
237
  fn=lambda y,m,d,r: (
238
  (lambda df: df.groupby("Rep").size().reset_index(name="Count"))(search_appointments_by_date(y,m,d,r)),
239
  search_appointments_by_date(y,m,d,r)
240
  ),
241
  inputs=[y2,m2,d2,rep2],
242
- outputs=[appt_date_summary, appt_date_table]
243
  )
244
 
245
- # ─── Appointed Leads ──────────────────────────
246
  with gr.Tab("Appointed Leads"):
247
- leads_btn = gr.Button("View Appointed Leads")
248
- leads_summary = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
249
- leads_detail = gr.Dataframe(label="πŸ”Ž Detailed Leads")
250
-
251
- leads_btn.click(
252
- fn=lambda: (get_leads_summary(), get_leads_detail()),
253
- outputs=[leads_summary, leads_detail]
254
- )
255
 
256
- # ─── Insights ─────────────────────────────────
257
  with gr.Tab("Insights"):
258
- insights_btn = gr.Button("Generate Insights")
259
- insights_tbl = gr.Dataframe()
260
-
261
- insights_btn.click(fn=compute_insights, outputs=insights_tbl)
262
 
263
- # ─── User Management ──────────────────────────
264
  with gr.Tab("User Management"):
265
- gr.Markdown("## πŸ‘€ Manage Users\nEdit/add/remove rows below, then click **Save Users**.")
266
- users_tbl = gr.Dataframe(value=load_users(), interactive=True)
267
  save_btn = gr.Button("Save Users")
268
- status = gr.Textbox()
269
-
270
- save_btn.click(fn=save_users, inputs=users_tbl, outputs=status)
271
 
272
- # end Blocks
273
  app.launch()
 
10
  CREDS_JSON = "deep-mile-461309-t8-0e90103411e0.json"
11
 
12
  # -------------------- AUTH --------------------
13
+ scope = ["https://spreadsheets.google.com/feeds","https://www.googleapis.com/auth/drive"]
 
 
 
14
  creds = ServiceAccountCredentials.from_json_keyfile_name(CREDS_JSON, scope)
15
  client = gspread.authorize(creds)
16
 
17
+ # -------------------- SHEET LOAD / UTILS --------------------
18
  def normalize_columns(df):
19
  df.columns = df.columns.str.strip().str.title()
20
  return df
21
 
22
  def load_sheet_df(sheet_name):
23
  try:
24
+ ws = client.open_by_url(SHEET_URL).worksheet(sheet_name)
25
+ df = pd.DataFrame(ws.get_all_records())
 
26
  return normalize_columns(df)
27
  except Exception as e:
 
28
  return pd.DataFrame([{"Error": str(e)}])
29
 
30
+ def rep_options(sheet_name, rep_col="Rep"):
31
+ df = load_sheet_df(sheet_name)
32
+ if rep_col in df.columns:
33
+ return sorted(df[rep_col].dropna().unique().tolist())
34
+ return []
35
+
36
  # -------------------- DATE FILTERS --------------------
37
  def get_current_week_range():
38
  today = datetime.now()
39
  start = today - timedelta(days=today.weekday())
40
+ return start.date(), (start + timedelta(days=6)).date()
41
+
42
+ def filter_week(df, date_col, rep_col=None, rep=None):
43
+ df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
44
+ start,end = get_current_week_range()
45
+ out = df[(df[date_col] >= start) & (df[date_col] <= end)]
46
+ if rep and rep_col in out.columns:
47
+ out = out[out[rep_col] == rep]
 
48
  return out
49
 
50
+ def filter_date(df, date_col, rep_col, y,m,d, rep):
51
  try:
52
  target = datetime(int(y), int(m), int(d)).date()
53
  except:
54
  return pd.DataFrame([{"Error":"Invalid date"}])
55
+ df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
56
+ out = df[df[date_col] == target]
57
+ if rep and rep_col in out.columns:
58
+ out = out[out[rep_col] == rep]
59
  return out
60
 
61
+ # -------------------- REPORT FUNCTIONS --------------------
62
  def get_calls(rep=None):
63
  df = load_sheet_df("Calls")
64
  if "Call Date" not in df.columns:
65
+ return pd.DataFrame([{"Error":"Missing 'Call Date'"}])
66
  return filter_week(df, "Call Date", "Rep", rep)
67
 
68
  def get_calls_summary(rep=None):
69
  df = get_calls(rep)
70
  if "Error" in df.columns or df.empty:
71
  return df
72
+ return df.groupby("Rep").size().reset_index(name="Count")
 
 
 
 
 
73
 
74
+ def search_calls_by_date(y,m,d,rep):
75
  df = load_sheet_df("Calls")
76
  if "Call Date" not in df.columns:
77
+ return pd.DataFrame([{"Error":"Missing 'Call Date'"}])
78
  return filter_date(df, "Call Date", "Rep", y,m,d, rep)
79
 
80
  def get_appointments(rep=None):
81
  df = load_sheet_df("Appointments")
82
  if "Appointment Date" not in df.columns:
83
+ return pd.DataFrame([{"Error":"Missing 'Appointment Date'"}])
84
  return filter_week(df, "Appointment Date", "Rep", rep)
85
 
86
  def get_appointments_summary(rep=None):
87
  df = get_appointments(rep)
88
  if "Error" in df.columns or df.empty:
89
  return df
90
+ return df.groupby("Rep").size().reset_index(name="Count")
 
 
 
 
 
91
 
92
+ def search_appointments_by_date(y,m,d,rep):
93
  df = load_sheet_df("Appointments")
94
  if "Appointment Date" not in df.columns:
95
+ return pd.DataFrame([{"Error":"Missing 'Appointment Date'"}])
96
  return filter_date(df, "Appointment Date", "Rep", y,m,d, rep)
97
 
98
  def get_leads_detail():
99
  df = load_sheet_df("AllocatedLeads")
 
 
100
  if "Assigned Rep" not in df.columns:
101
+ return pd.DataFrame([{"Error":"Missing 'Assigned Rep'"}])
102
  return df
103
 
104
  def get_leads_summary():
 
109
 
110
  # -------------------- INSIGHTS --------------------
111
  def compute_insights():
 
 
 
 
112
  def top_rep(df, col):
113
  if "Error" in df.columns or df.empty:
114
  return "N/A"
115
  counts = df.groupby(col).size()
116
+ return counts.idxmax() if not counts.empty else "N/A"
 
 
117
 
118
+ calls = get_calls()
119
+ appts = get_appointments()
120
+ leads = get_leads_detail().rename(columns={"Assigned Rep":"Rep"})
 
 
121
 
122
  return pd.DataFrame([
123
+ {"Metric":"Most Calls This Week", "Rep":top_rep(calls, "Rep")},
124
+ {"Metric":"Most Appointments This Week", "Rep":top_rep(appts, "Rep")},
125
+ {"Metric":"Most Leads Allocated", "Rep":top_rep(leads, "Rep")},
126
  ])
127
 
128
  # -------------------- USER MANAGEMENT --------------------
129
  def load_users():
130
+ df = load_sheet_df("Users") # your sheet tab is named "Users"
 
131
  wanted = [
132
  "Id","Email","Name","Business","Role",
133
  "Daily Phone Call Target","Daily Phone Appointment Target",
 
138
  "Monthly Quote Number Target","Monthly Quote Revenue Target",
139
  "Monthly Sales Revenue Target"
140
  ]
141
+ cols = [c for c in wanted if c in df.columns]
142
+ return df[cols]
143
 
144
  def save_users(df):
145
+ ws = client.open_by_url(SHEET_URL).worksheet("Users")
146
  ws.clear()
147
  set_with_dataframe(ws, df)
148
  return "βœ… Users saved!"
149
 
150
  # -------------------- GRADIO UI --------------------
151
+ with gr.Blocks(title="Graffiti Admin Dashboard") as app:
152
+ gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
153
 
154
+ # ─── Calls Report ───────────────────
155
  with gr.Tab("Calls Report"):
156
+ rep_calls = gr.Dropdown("Optional Rep Filter", choices=rep_options("Calls"), allow_custom_value=True)
157
+ calls_btn = gr.Button("Load Current Week Calls")
158
+ calls_sum = gr.Dataframe(label="πŸ“Š Calls by Rep")
159
+ calls_det = gr.Dataframe(label="πŸ”Ž Detailed Calls")
160
+ calls_btn.click(fn=lambda r: (get_calls_summary(r), get_calls(r)),
161
+ inputs=rep_calls, outputs=[calls_sum, calls_det])
162
+
163
+ gr.Markdown("### πŸ” Search Calls by Date")
164
+ y1,m1,d1 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
165
+ rep1 = gr.Dropdown("Optional Rep Filter", choices=rep_options("Calls"), allow_custom_value=True)
166
+ calls_dt_btn = gr.Button("Search")
167
+ calls_dt_tbl = gr.Dataframe()
168
+ calls_dt_btn.click(fn=search_calls_by_date,
169
+ inputs=[y1,m1,d1,rep1],
170
+ outputs=calls_dt_tbl)
171
+
172
+ # ─── Appointments Report ────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  with gr.Tab("Appointments Report"):
174
+ rep_appt = gr.Dropdown("Optional Rep Filter", choices=rep_options("Appointments"), allow_custom_value=True)
175
+ appt_btn = gr.Button("Load Current Week Appts")
176
+ appt_sum = gr.Dataframe(label="πŸ“Š Appts by Rep")
177
+ appt_det = gr.Dataframe(label="πŸ”Ž Detailed Appts")
178
+ appt_btn.click(fn=lambda r: (get_appointments_summary(r), get_appointments(r)),
179
+ inputs=rep_appt, outputs=[appt_sum, appt_det])
180
+
181
+ gr.Markdown("### πŸ” Search Appts by Date")
182
+ y2,m2,d2 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
183
+ rep2 = gr.Dropdown("Optional Rep Filter", choices=rep_options("Appointments"), allow_custom_value=True)
184
+ appt_dt_btn = gr.Button("Search")
185
+ appt_dt_sum = gr.Dataframe(label="πŸ“Š Appts Summary by Rep")
186
+ appt_dt_det = gr.Dataframe(label="πŸ”Ž Detailed Appts")
187
+ appt_dt_btn.click(
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  fn=lambda y,m,d,r: (
189
  (lambda df: df.groupby("Rep").size().reset_index(name="Count"))(search_appointments_by_date(y,m,d,r)),
190
  search_appointments_by_date(y,m,d,r)
191
  ),
192
  inputs=[y2,m2,d2,rep2],
193
+ outputs=[appt_dt_sum, appt_dt_det]
194
  )
195
 
196
+ # ─── Appointed Leads ────────────────
197
  with gr.Tab("Appointed Leads"):
198
+ leads_btn = gr.Button("View Appointed Leads")
199
+ leads_sum = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
200
+ leads_det = gr.Dataframe(label="πŸ”Ž Detailed Leads")
201
+ leads_btn.click(fn=lambda: (get_leads_summary(), get_leads_detail()),
202
+ outputs=[leads_sum, leads_det])
 
 
 
203
 
204
+ # ─── Insights ───────────────────────
205
  with gr.Tab("Insights"):
206
+ ins_btn = gr.Button("Generate Insights")
207
+ ins_tbl = gr.Dataframe()
208
+ ins_btn.click(fn=compute_insights, outputs=ins_tbl)
 
209
 
210
+ # ─── User Management ────────────────
211
  with gr.Tab("User Management"):
212
+ gr.Markdown("## πŸ‘€ Manage Users\nEdit/add/remove rows, then click **Save Users**.")
213
+ users_df = gr.Dataframe(load_users(), interactive=True)
214
  save_btn = gr.Button("Save Users")
215
+ save_stat = gr.Textbox()
216
+ save_btn.click(fn=save_users, inputs=users_df, outputs=save_stat)
 
217
 
 
218
  app.launch()