Kerikim commited on
Commit
c378c1e
·
1 Parent(s): 0bef02b

elkay frontend game xp

Browse files
Files changed (1) hide show
  1. phase/Student_view/game.py +58 -36
phase/Student_view/game.py CHANGED
@@ -1,7 +1,9 @@
1
  import streamlit as st
2
  from utils import db as dbapi
3
  import os
 
4
 
 
5
 
6
  # --- Load external CSS (optional) ---
7
  def load_css(file_name: str):
@@ -132,36 +134,40 @@ def _load_leaderboard(user_id: int, limit: int = 10) -> list[dict]:
132
  class_id = st.session_state.get("current_class_id")
133
 
134
  # try to pick a class automatically if none set (optional)
135
- if not class_id and hasattr(dbapi, "list_classes_for_student"):
136
  try:
137
- classes = dbapi.list_classes_for_student(user_id) or []
 
 
 
 
138
  if classes:
139
  class_id = classes[0]["class_id"]
140
  st.session_state.current_class_id = class_id
141
  except Exception:
142
  pass
143
 
144
- # fetch rows from DB
 
145
  try:
146
- if class_id and hasattr(dbapi, "leaderboard_for_class"):
147
  rows = dbapi.leaderboard_for_class(class_id, limit=limit) or []
148
- elif hasattr(dbapi, "leaderboard_global"):
149
  rows = dbapi.leaderboard_global(limit=limit) or []
150
  else:
151
- # fallback using existing function if needed
152
- rows = []
153
- if class_id and hasattr(dbapi, "class_student_metrics"):
154
- for m in dbapi.class_student_metrics(class_id) or []:
155
- xp = int(m.get("total_xp", 0))
156
  rows.append({
157
  "user_id": m.get("student_id"),
158
  "name": m.get("name") or m.get("email") or "Student",
159
- "xp": xp,
160
- "level": dbapi.level_from_xp(xp),
161
  })
162
  except Exception as e:
163
  st.warning(f"Leaderboard error: {e}")
164
- rows = []
165
 
166
  # ensure current user present
167
  if not any(r.get("user_id") == user_id for r in rows):
@@ -250,30 +256,44 @@ def show_games():
250
  )
251
 
252
  with col2:
253
- # pull live XP/level from DB
254
  user_id = st.session_state.user["user_id"]
255
- try:
256
- stats = dbapi.user_xp_and_level(user_id) # {'xp': int, 'level': int, 'streak': int}
257
- total_xp = int(stats.get("xp", 0))
258
- level = int(stats.get("level", 1))
259
- # keep session in sync (optional)
260
- st.session_state.xp = total_xp
261
- st.session_state.streak = stats.get("streak", 0)
262
- except Exception:
263
- # safe fallback if DB hiccups
264
- total_xp = int(st.session_state.get("xp", 0))
265
- level = max(1, (total_xp // 500) + 1)
266
-
267
- # leveling curve: every 500 XP is a level
268
- level_floor = (level - 1) * 500 # XP at start of this level
269
- level_cap = level * 500 # XP needed to reach next level
270
- in_level_xp = max(0, total_xp - level_floor)
271
- span = max(1, level_cap - level_floor) # usually 500
272
- progress_pct = int((in_level_xp / span) * 100)
273
 
274
- st.write(f"Level {level} Experience Points")
275
-
276
- # progress bar shows progress within *current* level
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  st.markdown(f"""
278
  <div style="background:#e0e0e0;border-radius:12px;padding:3px;width:100%;">
279
  <div style="
@@ -281,13 +301,15 @@ def show_games():
281
  background:linear-gradient(135deg,#22c55e,#059669);
282
  height:24px;border-radius:10px;text-align:right;
283
  color:white;font-weight:bold;padding-right:8px;line-height:24px;">
284
- {total_xp:,} / {level_cap:,} XP
285
  </div>
286
  </div>
 
287
  """, unsafe_allow_html=True)
288
 
289
 
290
 
 
291
  st.markdown("---")
292
 
293
  # Game list
 
1
  import streamlit as st
2
  from utils import db as dbapi
3
  import os
4
+ import utils.api as api
5
 
6
+ USE_LOCAL_DB = os.getenv("DISABLE_DB", "1") != "1"
7
 
8
  # --- Load external CSS (optional) ---
9
  def load_css(file_name: str):
 
134
  class_id = st.session_state.get("current_class_id")
135
 
136
  # try to pick a class automatically if none set (optional)
137
+ if not class_id:
138
  try:
139
+ # Prefer backend if DB disabled
140
+ if USE_LOCAL_DB and hasattr(dbapi, "list_classes_for_student"):
141
+ classes = dbapi.list_classes_for_student(user_id) or []
142
+ else:
143
+ classes = api.list_classes_for_student(user_id) or []
144
  if classes:
145
  class_id = classes[0]["class_id"]
146
  st.session_state.current_class_id = class_id
147
  except Exception:
148
  pass
149
 
150
+ # Fetch rows
151
+ rows = []
152
  try:
153
+ if USE_LOCAL_DB and hasattr(dbapi, "leaderboard_for_class") and class_id:
154
  rows = dbapi.leaderboard_for_class(class_id, limit=limit) or []
155
+ elif USE_LOCAL_DB and hasattr(dbapi, "leaderboard_global"):
156
  rows = dbapi.leaderboard_global(limit=limit) or []
157
  else:
158
+ # Backend path: we do not have dedicated leaderboard endpoints,
159
+ # so build from class_student_metrics which includes total_xp.
160
+ if class_id:
161
+ metrics = api.class_student_metrics(class_id) or []
162
+ for m in metrics:
163
  rows.append({
164
  "user_id": m.get("student_id"),
165
  "name": m.get("name") or m.get("email") or "Student",
166
+ "xp": int(m.get("total_xp", 0)),
167
+ "level": int(dbapi.level_from_xp(m.get("total_xp", 0))) if USE_LOCAL_DB else int((int(m.get("total_xp", 0)) // 500) + 1),
168
  })
169
  except Exception as e:
170
  st.warning(f"Leaderboard error: {e}")
 
171
 
172
  # ensure current user present
173
  if not any(r.get("user_id") == user_id for r in rows):
 
256
  )
257
 
258
  with col2:
259
+ # pull live XP/level
260
  user_id = st.session_state.user["user_id"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
+ # Prefer local DB only if enabled. Otherwise call backend.
263
+ if USE_LOCAL_DB and hasattr(dbapi, "user_xp_and_level"):
264
+ stats = dbapi.user_xp_and_level(user_id) # {'xp', 'level', 'streak', maybe 'into','need'}
265
+ else:
266
+ try:
267
+ stats = api.user_stats(user_id) # backend /students/{id}/stats
268
+ except Exception as e:
269
+ # hard fallback so the page still renders
270
+ stats = {"xp": int(st.session_state.get("xp", 0)), "level": 1, "streak": 0}
271
+
272
+ total_xp = int(stats.get("xp", 0))
273
+ level = int(stats.get("level", 1))
274
+ st.session_state.xp = total_xp
275
+ st.session_state.streak = int(stats.get("streak", 0))
276
+
277
+ # Use server-provided per-level values when available
278
+ into = stats.get("into")
279
+ need = stats.get("need")
280
+
281
+ # Fallback if backend has not been updated yet
282
+ if into is None or need in (None, 0):
283
+ base = 500
284
+ level = max(1, total_xp // base + 1)
285
+ start = (level - 1) * base
286
+ into = total_xp - start
287
+ need = base
288
+ if into == need:
289
+ level += 1
290
+ into = 0
291
+
292
+ into = int(max(0, into))
293
+ need = int(max(1, need))
294
+ progress_pct = min(100, int(round((into / need) * 100)))
295
+
296
+ st.write(f"Level {level} Experience Points")
297
  st.markdown(f"""
298
  <div style="background:#e0e0e0;border-radius:12px;padding:3px;width:100%;">
299
  <div style="
 
301
  background:linear-gradient(135deg,#22c55e,#059669);
302
  height:24px;border-radius:10px;text-align:right;
303
  color:white;font-weight:bold;padding-right:8px;line-height:24px;">
304
+ {into:,} / {need:,} XP
305
  </div>
306
  </div>
307
+ <div style="font-size:12px;color:#6b7280;margin-top:6px;">Total XP: {total_xp:,}</div>
308
  """, unsafe_allow_html=True)
309
 
310
 
311
 
312
+
313
  st.markdown("---")
314
 
315
  # Game list