Skip to content

Commit 6a548a3

Browse files
committed
fixes for heatmap data munging
1 parent f417a71 commit 6a548a3

File tree

3 files changed

+103
-20
lines changed

3 files changed

+103
-20
lines changed

packages/common-ui/src/components/HeatMap.vue

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ export default defineComponent({
8989
return 7 * (this.cellSize + this.cellMargin);
9090
},
9191
effectiveActivityRecords(): ActivityRecord[] {
92-
return this.localActivityRecords.length > 0 ? this.localActivityRecords : this.activityRecords;
92+
const useLocal = Array.isArray(this.localActivityRecords) && this.localActivityRecords.length > 0;
93+
const records = useLocal ? this.localActivityRecords : this.activityRecords || [];
94+
console.log('Using effectiveActivityRecords, count:', records.length, 'source:', useLocal ? 'local' : 'prop');
95+
return records;
9396
},
9497
},
9598
@@ -107,12 +110,28 @@ export default defineComponent({
107110
if (this.activityRecordsGetter) {
108111
try {
109112
this.isLoading = true;
110-
this.localActivityRecords = await this.activityRecordsGetter();
113+
console.log('Fetching activity records using getter...');
114+
// Ensure the getter is called safely with proper error handling
115+
const result = await this.activityRecordsGetter();
116+
117+
if (Array.isArray(result)) {
118+
this.localActivityRecords = result;
119+
console.log('Received activity records:', this.localActivityRecords.length);
120+
// Process the loaded records
121+
this.processRecords();
122+
this.createWeeksData();
123+
} else {
124+
console.error('Activity records getter did not return an array:', result);
125+
this.localActivityRecords = [];
126+
}
111127
} catch (error) {
112128
console.error('Error fetching activity records:', error);
129+
this.localActivityRecords = [];
113130
} finally {
114131
this.isLoading = false;
115132
}
133+
} else {
134+
console.log('No activityRecordsGetter provided, using direct activityRecords prop');
116135
}
117136
},
118137
@@ -123,35 +142,67 @@ export default defineComponent({
123142
},
124143
125144
processRecords() {
126-
const records = this.effectiveActivityRecords;
145+
const records = this.effectiveActivityRecords || [];
127146
console.log(`Processing ${records.length} records`);
128147
129148
const data: { [key: string]: number } = {};
130149
150+
if (records.length === 0) {
151+
console.log('No records to process');
152+
this.heatmapData = data;
153+
return;
154+
}
155+
131156
records.forEach((record) => {
132-
const date = moment(record.timeStamp).format('YYYY-MM-DD');
133-
data[date] = (data[date] || 0) + 1;
157+
if (!record || typeof record !== 'object') {
158+
console.warn('Invalid record:', record);
159+
return;
160+
}
161+
162+
if (!record.timeStamp) {
163+
console.warn('Record missing timeStamp:', record);
164+
return;
165+
}
166+
167+
// Make sure timeStamp is properly handled
168+
let date;
169+
try {
170+
// Try to parse the timestamp
171+
const m = moment(record.timeStamp);
172+
if (m.isValid()) {
173+
date = m.format('YYYY-MM-DD');
174+
data[date] = (data[date] || 0) + 1;
175+
} else {
176+
console.warn('Invalid date from record:', record);
177+
}
178+
} catch (e) {
179+
console.error('Error processing record date:', e, record);
180+
}
134181
});
135182
183+
console.log('Processed heatmap data:', Object.keys(data).length, 'unique dates');
136184
this.heatmapData = data;
137185
},
138186
139187
createWeeksData() {
140188
// Reset weeks and max count
141189
this.weeks = [];
142190
this.maxInRange = 0;
143-
191+
144192
const end = moment();
145193
const start = end.clone().subtract(52, 'weeks');
146194
const day = start.clone().startOf('week');
195+
196+
console.log('Creating weeks data from', start.format('YYYY-MM-DD'), 'to', end.format('YYYY-MM-DD'));
147197
148198
while (day.isSameOrBefore(end)) {
149199
const weekData: DayData[] = [];
150200
for (let i = 0; i < 7; i++) {
151201
const date = day.format('YYYY-MM-DD');
202+
const count = this.heatmapData[date] || 0;
152203
const dayData: DayData = {
153204
date,
154-
count: this.heatmapData[date] || 0,
205+
count,
155206
};
156207
weekData.push(dayData);
157208
if (dayData.count > this.maxInRange) {
@@ -162,6 +213,10 @@ export default defineComponent({
162213
}
163214
this.weeks.push(weekData);
164215
}
216+
217+
console.log('Weeks data created, maxInRange:', this.maxInRange);
218+
console.log('First week sample:', this.weeks[0]);
219+
console.log('Last week sample:', this.weeks[this.weeks.length - 1]);
165220
},
166221
167222
getColor(count: number): string {

packages/common-ui/src/components/StudySession.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
Start <a @click="$emit('session-finished')">another study session</a>, or try
2020
<router-link :to="`/edit/${courseID}`">adding some new content</router-link> to challenge yourself and others!
2121
</p>
22-
<heat-map :activity-records-getter="user.getActivityRecords" />
22+
<heat-map :activity-records-getter="() => user.getActivityRecords()" />
2323
</div>
2424

2525
<div v-else ref="shadowWrapper">

packages/db/src/impl/pouch/userDB.ts

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -245,20 +245,48 @@ Currently logged-in as ${this._username}.`
245245
}
246246

247247
public async getActivityRecords(): Promise<ActivityRecord[]> {
248-
const hist = await this.getHistory();
249-
250-
const allRecords: ActivityRecord[] = [];
251-
for (let i = 0; i < hist.length; i++) {
252-
if (hist[i] && hist[i]!.records) {
253-
hist[i]!.records.forEach((record: CardRecord) => {
254-
allRecords.push({
255-
timeStamp: record.timeStamp.toString(),
256-
});
257-
});
248+
try {
249+
const hist = await this.getHistory();
250+
251+
const allRecords: ActivityRecord[] = [];
252+
if (!Array.isArray(hist)) {
253+
console.error('getHistory did not return an array:', hist);
254+
return allRecords;
255+
}
256+
257+
for (let i = 0; i < hist.length; i++) {
258+
try {
259+
if (hist[i] && Array.isArray(hist[i]!.records)) {
260+
hist[i]!.records.forEach((record: CardRecord) => {
261+
try {
262+
// Convert Moment objects to ISO string format for consistency
263+
const timeStamp = record.timeStamp && typeof record.timeStamp.isValid === 'function' && record.timeStamp.isValid()
264+
? record.timeStamp.toISOString()
265+
: new Date().toISOString();
266+
267+
allRecords.push({
268+
timeStamp,
269+
courseID: record.courseID || 'unknown',
270+
cardID: record.cardID || 'unknown',
271+
timeSpent: record.timeSpent || 0,
272+
type: 'card_view'
273+
});
274+
} catch (err) {
275+
console.error('Error processing record:', err, record);
276+
}
277+
});
278+
}
279+
} catch (err) {
280+
console.error('Error processing history item:', err, hist[i]);
281+
}
258282
}
259-
}
260283

261-
return allRecords;
284+
console.log(`Found ${allRecords.length} activity records`);
285+
return allRecords;
286+
} catch (err) {
287+
console.error('Error in getActivityRecords:', err);
288+
return [];
289+
}
262290
}
263291

264292
private async getReviewstoDate(targetDate: Moment, course_id?: string) {

0 commit comments

Comments
 (0)