File size: 2,998 Bytes
22aa376
 
 
 
715230e
22aa376
 
c798beb
715230e
 
 
 
 
 
 
 
c798beb
22aa376
eda28cd
22aa376
 
eda28cd
22aa376
 
 
c4f22f9
22aa376
c4f22f9
 
 
22aa376
 
 
 
 
eda28cd
22aa376
eda28cd
 
 
22aa376
c798beb
22aa376
 
 
 
eda28cd
 
 
c798beb
22aa376
 
 
 
 
 
 
 
 
 
 
c4f22f9
 
 
22aa376
 
 
c4f22f9
715230e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import {
  ModelData,
  ProviderInfo,
  CalendarData,
  CompactCalendarData,
  Activity,
} from "../types/heatmap";

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;
};

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();

  const startDate = new Date(today);
  startDate.setDate(startDate.getDate() - 364);
  const dayOfWeek = startDate.getDay();
  startDate.setDate(startDate.getDate() - dayOfWeek);

  const countMap: Record<string, Record<string, number>> = {};

  modelData.forEach((item) => {
    const dateString = item.createdAt.split("T")[0];
    providers.forEach(({ authors }) => {
      if (authors.some((author) => item.id.startsWith(author))) {
        countMap[authors[0]] = countMap[authors[0]] || {};
        countMap[authors[0]][dateString] =
          (countMap[authors[0]][dateString] || 0) + 1;
      }
    });
  });

  for (let d = new Date(startDate); d <= today; d.setDate(d.getDate() + 1)) {
    const dateString = d.toISOString().split("T")[0];
    providers.forEach(({ authors }) => {
      const count = countMap[authors[0]]?.[dateString] || 0;
      data[authors[0]].push({ date: dateString, count, level: 0 });
    });
  }

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

  Object.entries(data).forEach(([provider, days]) => {
    const avgCount = avgCounts[provider];
    for (const day of days) {
      day.level = calculateLevel(day.count, avgCount);
    }
  });

  return data;
};

export const compactCalendarData = (data: CalendarData): CompactCalendarData => {
  const compact: CompactCalendarData = {};
  for (const [key, activities] of Object.entries(data)) {
    if (activities.length > 0) {
      compact[key] = {
        startDate: activities[0].date,
        counts: activities.map((a) => a.count),
      };
    }
  }
  return compact;
};

export const expandCalendarData = (compact: CompactCalendarData): CalendarData => {
  const data: CalendarData = {};
  for (const [key, { startDate, counts }] of Object.entries(compact)) {
    const total = counts.reduce((sum, c) => sum + c, 0);
    const avg = total / counts.length || 0;
    const start = new Date(startDate + "T00:00:00");

    const activities: Activity[] = counts.map((count, i) => {
      const date = new Date(start);
      date.setDate(date.getDate() + i);
      return {
        date: date.toISOString().split("T")[0],
        count,
        level: calculateLevel(count, avg),
      };
    });

    data[key] = activities;
  }
  return data;
};