SarahXia0405 commited on
Commit
c6a412f
·
verified ·
1 Parent(s): 5b25a69

Create reviewStar.ts

Browse files
Files changed (1) hide show
  1. web/src/lib/reviewStar.ts +110 -0
web/src/lib/reviewStar.ts ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // web/src/lib/reviewStar.ts
2
+
3
+ export type ReviewEventType = "send_message" | "review_topic" | "review_all";
4
+
5
+ export type ReviewStarState = {
6
+ lastActiveDay: string; // YYYY-MM-DD (local)
7
+ todayCount: number; // today's valid review actions count
8
+ streakDays: number; // consecutive active days
9
+ totalDaysActive: number; // total active days
10
+ };
11
+
12
+ function dayKeyLocal(d = new Date()) {
13
+ const yyyy = d.getFullYear();
14
+ const mm = String(d.getMonth() + 1).padStart(2, "0");
15
+ const dd = String(d.getDate()).padStart(2, "0");
16
+ return `${yyyy}-${mm}-${dd}`;
17
+ }
18
+
19
+ function yesterdayKeyLocal() {
20
+ return dayKeyLocal(new Date(Date.now() - 86400000));
21
+ }
22
+
23
+ export function loadReviewStar(key: string): ReviewStarState | null {
24
+ try {
25
+ const raw = localStorage.getItem(key);
26
+ if (!raw) return null;
27
+ return JSON.parse(raw) as ReviewStarState;
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+
33
+ export function saveReviewStar(key: string, state: ReviewStarState) {
34
+ localStorage.setItem(key, JSON.stringify(state));
35
+ }
36
+
37
+ /**
38
+ * Called when user enters Review section (or on workspace switch while in Review):
39
+ * If day changed, reset today's count to 0 (i.e., dim star until there's real review activity).
40
+ */
41
+ export function normalizeToday(key: string): ReviewStarState | null {
42
+ const cur = loadReviewStar(key);
43
+ if (!cur) return null;
44
+
45
+ const today = dayKeyLocal();
46
+ if (cur.lastActiveDay === today) return cur;
47
+
48
+ const next: ReviewStarState = { ...cur, todayCount: 0 };
49
+ saveReviewStar(key, next);
50
+ return next;
51
+ }
52
+
53
+ /**
54
+ * Mark a valid review activity.
55
+ * - Same day: increment todayCount
56
+ * - New day: todayCount=1, streak updates, totalDaysActive increments
57
+ */
58
+ export function markReviewActive(key: string, _event: ReviewEventType): ReviewStarState {
59
+ const today = dayKeyLocal();
60
+ const prev = loadReviewStar(key);
61
+
62
+ if (!prev) {
63
+ const next: ReviewStarState = {
64
+ lastActiveDay: today,
65
+ todayCount: 1,
66
+ streakDays: 1,
67
+ totalDaysActive: 1,
68
+ };
69
+ saveReviewStar(key, next);
70
+ return next;
71
+ }
72
+
73
+ if (prev.lastActiveDay === today) {
74
+ const next: ReviewStarState = { ...prev, todayCount: prev.todayCount + 1 };
75
+ saveReviewStar(key, next);
76
+ return next;
77
+ }
78
+
79
+ const y = yesterdayKeyLocal();
80
+ const streak = prev.lastActiveDay === y ? prev.streakDays + 1 : 1;
81
+
82
+ const next: ReviewStarState = {
83
+ ...prev,
84
+ lastActiveDay: today,
85
+ todayCount: 1,
86
+ streakDays: streak,
87
+ totalDaysActive: (prev.totalDaysActive ?? 0) + 1,
88
+ };
89
+ saveReviewStar(key, next);
90
+ return next;
91
+ }
92
+
93
+ /**
94
+ * UI mapping: opacity/energy
95
+ * - 0 activity today => dim
96
+ * - 1 activity => medium
97
+ * - 2+ => bright
98
+ * - streak >= 3 => max
99
+ */
100
+ export function starOpacity(state: ReviewStarState | null) {
101
+ if (!state) return 0.15;
102
+ if (state.todayCount <= 0) return 0.15;
103
+ if (state.todayCount === 1) return 0.55;
104
+ if (state.streakDays >= 3) return 1.0;
105
+ return 0.85;
106
+ }
107
+
108
+ export function energyPct(state: ReviewStarState | null) {
109
+ return Math.round(starOpacity(state) * 100);
110
+ }