Skip to content

Commit

Permalink
refactor: remove unused card stats modal and associated deps
Browse files Browse the repository at this point in the history
  • Loading branch information
AB1908 committed Nov 12, 2022
1 parent 41887de commit 86326c8
Show file tree
Hide file tree
Showing 4 changed files with 2 additions and 333 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
},
"dependencies": {
"@types/react-dom": "^18.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react": "^18.2.0"
}
}
3 changes: 0 additions & 3 deletions src/declarations.d.ts

This file was deleted.

12 changes: 0 additions & 12 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { FlashcardModal } from "src/ui/modals/flashcard-modal";
import { appIcon } from "src/icons/appicon";
import { t } from "src/lang/helpers";
import { DEFAULT_SETTINGS, SRSettings, SRSettingTab } from "src/settings";
import { StatsModal } from "src/stats-modal";

export interface PluginData {
settings: SRSettings;
Expand Down Expand Up @@ -104,17 +103,6 @@ export default class SRPlugin extends Plugin {
},
});

this.addCommand({
id: "srs-view-stats",
name: t("VIEW_STATS"),
callback: async () => {
// if (!this.syncLock) {
// await this.sync();
new StatsModal(this.app, this).open();
// }
},
});

this.addSettingTab(new SRSettingTab(this.app, this));

this.app.workspace.onLayoutReady(() => {
Expand Down
317 changes: 1 addition & 316 deletions src/stats-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,322 +1,7 @@
import { Modal, App, Platform } from "obsidian";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import h from "vhtml";
import {
Chart,
BarElement,
BarController,
Legend,
Title,
Tooltip,
SubTitle,
ChartTypeRegistry,
CategoryScale,
LinearScale,
PieController,
ArcElement,
} from "chart.js";

import type SRPlugin from "src/main";
import { getKeysPreserveType, getTypedObjectEntries } from "src/utils";
import { textInterval } from "src/scheduling";
import { t } from "src/lang/helpers";

Chart.register(
BarElement,
BarController,
Legend,
Title,
Tooltip,
SubTitle,
CategoryScale,
LinearScale,
PieController,
ArcElement
);

export interface Stats {
eases: Record<number, number>;
intervals: Record<number, number>;
newCount: number;
youngCount: number;
matureCount: number;
}

export class StatsModal extends Modal {
private plugin: SRPlugin;

constructor(app: App, plugin: SRPlugin) {
super(app);

this.plugin = plugin;

this.titleEl.setText(`${t("STATS_TITLE")} `);
this.titleEl.innerHTML += (
<select id="chartPeriod">
<option value="month" selected>
{t("MONTH")}
</option>
<option value="quarter">{t("QUARTER")}</option>
<option value="year">{t("YEAR")}</option>
<option value="lifetime">{t("LIFETIME")}</option>
</select>
);

this.modalEl.style.height = "100%";
this.modalEl.style.width = "100%";

if (Platform.isMobile) {
this.contentEl.style.display = "block";
}
}

onOpen(): void {
const { contentEl } = this;
contentEl.style.textAlign = "center";

// Add forecast
let maxN: number = Math.max(...getKeysPreserveType(this.plugin.dueDatesFlashcards));
for (let dueOffset = 0; dueOffset <= maxN; dueOffset++) {
if (!Object.prototype.hasOwnProperty.call(this.plugin.dueDatesFlashcards, dueOffset)) {
this.plugin.dueDatesFlashcards[dueOffset] = 0;
}
}

const dueDatesFlashcardsCopy: Record<number, number> = { 0: 0 };
for (const [dueOffset, dueCount] of getTypedObjectEntries(this.plugin.dueDatesFlashcards)) {
if (dueOffset <= 0) {
dueDatesFlashcardsCopy[0] += dueCount;
} else {
dueDatesFlashcardsCopy[dueOffset] = dueCount;
}
}

const cardStats: Stats = this.plugin.cardStats;
const scheduledCount: number = cardStats.youngCount + cardStats.matureCount;
maxN = Math.max(maxN, 1);

contentEl.innerHTML += (
<div>
<canvas id="forecastChart"></canvas>
<span id="forecastChartSummary"></span>
<p></p>
<canvas id="intervalsChart"></canvas>
<span id="intervalsChartSummary"></span>
<p></p>
<canvas id="easesChart"></canvas>
<span id="easesChartSummary"></span>
<p></p>
<div style="width: 50%; margin: auto;">
<canvas id="cardTypesChart"></canvas>
</div>
<span id="cardTypesChartSummary"></span>
</div>
);

createStatsChart(
"bar",
"forecastChart",
t("FORECAST"),
t("FORECAST_DESC"),
Object.keys(dueDatesFlashcardsCopy),
Object.values(dueDatesFlashcardsCopy),
t("REVIEWS_PER_DAY", { avg: (scheduledCount / maxN).toFixed(1) }),
t("SCHEDULED"),
t("DAYS"),
t("NUMBER_OF_CARDS")
);

maxN = Math.max(...getKeysPreserveType(cardStats.intervals));
for (let interval = 0; interval <= maxN; interval++) {
if (!Object.prototype.hasOwnProperty.call(cardStats.intervals, interval)) {
cardStats.intervals[interval] = 0;
}
}

// Add intervals
const average_interval: string = textInterval(
Math.round(
(getTypedObjectEntries(cardStats.intervals)
.map(([interval, count]) => interval * count)
.reduce((a, b) => a + b, 0) /
scheduledCount) *
10
) / 10 || 0,
false
),
longest_interval: string = textInterval(
Math.max(...getKeysPreserveType(cardStats.intervals)) || 0,
false
);

createStatsChart(
"bar",
"intervalsChart",
t("INTERVALS"),
t("INTERVALS_DESC"),
Object.keys(cardStats.intervals),
Object.values(cardStats.intervals),
t("INTERVALS_SUMMARY", { avg: average_interval, longest: longest_interval }),
t("COUNT"),
t("DAYS"),
t("NUMBER_OF_CARDS")
);

// Add eases
const eases: number[] = getKeysPreserveType(cardStats.eases);
for (let ease = Math.min(...eases); ease <= Math.max(...eases); ease++) {
if (!Object.prototype.hasOwnProperty.call(cardStats.eases, ease)) {
cardStats.eases[ease] = 0;
}
}
const average_ease: number =
Math.round(
getTypedObjectEntries(cardStats.eases)
.map(([ease, count]) => ease * count)
.reduce((a, b) => a + b, 0) / scheduledCount
) || 0;

createStatsChart(
"bar",
"easesChart",
t("EASES"),
"",
Object.keys(cardStats.eases),
Object.values(cardStats.eases),
t("EASES_SUMMARY", { avgEase: average_ease }),
t("COUNT"),
t("EASES"),
t("NUMBER_OF_CARDS")
);

// Add card types
const totalCardsCount: number = this.plugin.deckTree.totalFlashcards;
createStatsChart(
"pie",
"cardTypesChart",
t("CARD_TYPES"),
t("CARD_TYPES_DESC"),
[
`${t("CARD_TYPE_NEW")} - ${Math.round(
(cardStats.newCount / totalCardsCount) * 100
)}%`,
`${t("CARD_TYPE_YOUNG")} - ${Math.round(
(cardStats.youngCount / totalCardsCount) * 100
)}%`,
`${t("CARD_TYPE_MATURE")} - ${Math.round(
(cardStats.matureCount / totalCardsCount) * 100
)}%`,
],
[cardStats.newCount, cardStats.youngCount, cardStats.matureCount],
t("CARD_TYPES_SUMMARY", { totalCardsCount })
);
}

onClose(): void {
const { contentEl } = this;
contentEl.empty();
}
}

function createStatsChart(
type: keyof ChartTypeRegistry,
canvasId: string,
title: string,
subtitle: string,
labels: string[],
data: number[],
summary: string,
seriesTitle = "",
xAxisTitle = "",
yAxisTitle = ""
) {
let scales = {},
backgroundColor = ["#2196f3"];
if (type !== "pie") {
scales = {
x: {
title: {
display: true,
text: xAxisTitle,
},
},
y: {
title: {
display: true,
text: yAxisTitle,
},
},
};
} else {
backgroundColor = ["#2196f3", "#4caf50", "green"];
}

const shouldFilter = canvasId === "forecastChart" || canvasId === "intervalsChart";

const statsChart = new Chart(document.getElementById(canvasId) as HTMLCanvasElement, {
type,
data: {
labels: shouldFilter ? labels.slice(0, 31) : labels,
datasets: [
{
label: seriesTitle,
backgroundColor,
data: shouldFilter ? data.slice(0, 31) : data,
},
],
},
options: {
scales,
plugins: {
title: {
display: true,
text: title,
font: {
size: 22,
},
},
subtitle: {
display: true,
text: subtitle,
font: {
size: 16,
},
},
legend: {
display: false,
},
},
},
});

if (shouldFilter) {
const chartPeriodEl = document.getElementById("chartPeriod") as HTMLSelectElement;
chartPeriodEl.addEventListener("click", () => {
let filteredLabels, filteredData;
const chartPeriod = chartPeriodEl.value;
if (chartPeriod === "month") {
filteredLabels = labels.slice(0, 31);
filteredData = data.slice(0, 31);
} else if (chartPeriod === "quarter") {
filteredLabels = labels.slice(0, 91);
filteredData = data.slice(0, 91);
} else if (chartPeriod === "year") {
filteredLabels = labels.slice(0, 366);
filteredData = data.slice(0, 366);
} else {
filteredLabels = labels;
filteredData = data;
}

statsChart.data.labels = filteredLabels;
statsChart.data.datasets[0] = {
label: seriesTitle,
backgroundColor,
data: filteredData,
};
statsChart.update();
});
}

document.getElementById(`${canvasId}Summary`).innerText = summary;
}
}

0 comments on commit 86326c8

Please sign in to comment.