File size: 3,106 Bytes
fdb7c58
 
 
 
 
 
20faa99
 
fdb7c58
d088c21
fdb7c58
 
d088c21
fdb7c58
 
 
2b529d5
 
 
 
 
fdb7c58
2b529d5
 
 
 
fdb7c58
66f319d
fdb7c58
66f319d
fdb7c58
 
 
d088c21
fdb7c58
66f319d
 
 
 
 
 
 
 
 
 
 
 
 
fdb7c58
20faa99
fdb7c58
 
 
 
 
 
d088c21
66f319d
 
 
 
 
 
 
 
 
 
20faa99
fdb7c58
 
 
 
 
 
 
 
 
 
2b529d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fdb7c58
 
 
2b529d5
 
 
fdb7c58
 
 
2b529d5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import {
  ModelData,
  ProviderInfo,
  CalendarData,
  Activity,
} from "../types/heatmap";

export const generateCalendarData = (
  modelData: ModelData[],
  providers: ProviderInfo[]
): CalendarData => {
  const data: Record<string, Activity[]> = Object.fromEntries(
    providers.map((provider) => [provider.authors[0], []]),
  );

  const today = new Date();

  // Calculate the first date to display GitHub-style:
  // 1. Go back 52 weeks (364 days) from today so we cover the last year.
  // 2. Shift further back to the previous Sunday (if necessary) so that
  //    the first column of the heatmap always begins on a Sunday.
  const startDate = new Date(today);
  startDate.setDate(startDate.getDate() - 364);
  
  const dayOfWeek = startDate.getDay();
  startDate.setDate(startDate.getDate() - dayOfWeek);

  // create a map to store counts and item names for each provider and date
  const countMap: Record<string, Record<string, number>> = {};
  const itemsMap: Record<string, Record<string, string[]>> = {};

  modelData.forEach((item) => {
    const dateString = item.createdAt.split("T")[0];
    providers.forEach(({ authors }) => {
      if (authors.some((author) => item.id.startsWith(author))) {
        const providerKey = authors[0];
        
        // Initialize maps if needed
        countMap[providerKey] = countMap[providerKey] || {};
        itemsMap[providerKey] = itemsMap[providerKey] || {};
        
        // Increment count
        countMap[providerKey][dateString] =
          (countMap[providerKey][dateString] || 0) + 1;
          
        // Add item name to the list
        itemsMap[providerKey][dateString] = itemsMap[providerKey][dateString] || [];
        itemsMap[providerKey][dateString].push(item.id);
      }
    });
  });

  // fill in with 0s for days with no activity
  for (let d = new Date(startDate); d <= today; d.setDate(d.getDate() + 1)) {
    const dateString = d.toISOString().split("T")[0];

    providers.forEach(({ authors }) => {
      const providerKey = authors[0];
      const count = countMap[providerKey]?.[dateString] || 0;
      const items = itemsMap[providerKey]?.[dateString] || [];
      
      data[providerKey].push({ 
        date: dateString, 
        count, 
        level: 0, 
        items 
      });
    });
  }

  // calculate average counts for each provider
  const avgCounts = Object.fromEntries(
    Object.entries(data).map(([provider, days]) => [
      provider,
      days.reduce((sum, day) => sum + day.count, 0) / days.length || 0,
    ]),
  );

  const calculateLevel = (count: number, avgCount: number): number => {
    if (count === 0) {
      return 0;
    }
    if (count <= avgCount * 0.5) {
      return 1;
    }
    if (count <= avgCount) {
      return 2;
    }
    if (count <= avgCount * 1.5) {
      return 3;
    }
    return 4;
  };

  // assign levels based on count relative to average
  Object.entries(data).forEach(([provider, days]) => {
    const avgCount = avgCounts[provider];
    for (const day of days) {
      day.level = calculateLevel(day.count, avgCount);
    }
  });

  return data;
};