diff --git a/enjoy/src/api/client.ts b/enjoy/src/api/client.ts index adc1ff522..7f40ffa15 100644 --- a/enjoy/src/api/client.ts +++ b/enjoy/src/api/client.ts @@ -247,6 +247,10 @@ export class Client { }); } + usages(): Promise<{ label: string; data: number[] }[]> { + return this.api.get("/api/mine/usages"); + } + syncAudio(audio: Partial) { return this.api.post("/api/mine/audios", decamelizeKeys(audio)); } diff --git a/enjoy/src/i18n/en.json b/enjoy/src/i18n/en.json index 177bab95a..a0bd93573 100644 --- a/enjoy/src/i18n/en.json +++ b/enjoy/src/i18n/en.json @@ -718,5 +718,6 @@ "audioInput": "Audio input", "textInput": "Text input", "increasePlaybackRate": "Increase playback rate", - "descreasePlaybackRate": "Descrease playback rate" + "descreasePlaybackRate": "Descrease playback rate", + "usage": "Usage" } diff --git a/enjoy/src/i18n/zh-CN.json b/enjoy/src/i18n/zh-CN.json index fb77a819d..80f9166ba 100644 --- a/enjoy/src/i18n/zh-CN.json +++ b/enjoy/src/i18n/zh-CN.json @@ -718,5 +718,6 @@ "audioInput": "语音输入", "textInput": "文字输入", "increasePlaybackRate": "加快播放速度", - "decreasePlaybackRate": "减慢播放速度" + "decreasePlaybackRate": "减慢播放速度", + "usage": "使用情况" } diff --git a/enjoy/src/renderer/components/preferences/balance-settings.tsx b/enjoy/src/renderer/components/preferences/balance-settings.tsx index c6c985945..b90e2e3e2 100644 --- a/enjoy/src/renderer/components/preferences/balance-settings.tsx +++ b/enjoy/src/renderer/components/preferences/balance-settings.tsx @@ -1,6 +1,6 @@ import { t } from "i18next"; import { AppSettingsProviderContext } from "@renderer/context"; -import { useContext, useState, useEffect } from "react"; +import { useContext, useState, useEffect, useRef } from "react"; import { Button, Dialog, @@ -24,6 +24,7 @@ import { import { LoaderSpin } from "@renderer/components"; import { LoaderIcon } from "lucide-react"; import { formatDateTime } from "@/renderer/lib/utils"; +import Chart from "chart.js/auto"; export const BalanceSettings = () => { const { webApi, EnjoyApp } = useContext(AppSettingsProviderContext); @@ -32,6 +33,7 @@ export const BalanceSettings = () => { const [loading, setLoading] = useState(false); const [paymentCreated, setPaymentCreated] = useState(false); const [payments, setPayments] = useState([]); + const [displayUsage, setDisplayUsage] = useState(false); const refreshPayments = () => { webApi @@ -88,150 +90,234 @@ export const BalanceSettings = () => {
${balance}
- { - if (value) { - refreshPayments(); - } else { - setPaymentCreated(false); - refreshBalance(); - } - }} - > - - - - - - - {t("deposit")} - {t("depositDescription")} - - - {paymentCreated ? ( - <> - -
- {t("pleaseCompletePaymentInPopupWindow")} -
- - ) : ( - <> -
- {[1, 2, 5, 10].map((amount) => ( -
setDepositAmount(amount)} - > - ${amount} -
- ))} -
-
{t("depositDisclaimer")}
- - )} - - - -
-
- - - - - - -
- +
+ { + if (value) { + refreshPayments(); + } else { + setPaymentCreated(false); + refreshBalance(); + } + }} + > + -
- -
-
- - - - - -
- -
+ - + + + {t("deposit")} + {t("depositDescription")} + - - - - - - - {payments.length > 0 && ( -
- - {t("recentDeposits")} - - - ID - {t("amount")} - {t("status")} - - {t("processor")} - - {t("date")} - - - - {payments.map((payment) => ( - - - - {payment.id.split("-").shift()} - - - ${payment.amount} - {payment.status} - - {payment.processor} - - - {formatDateTime(payment.createdAt)} - - + {paymentCreated ? ( + <> + +
+ {t("pleaseCompletePaymentInPopupWindow")} +
+ + ) : ( + <> +
+ {[1, 2, 5, 10].map((amount) => ( +
setDepositAmount(amount)} + > + ${amount} +
))} - -
+
+
{t("depositDisclaimer")}
+ + )} + + + +
+
+ + + + + + +
+ + +
+ +
+
+ + + + + +
+
- )} -
-
+ + + + + + + + + + {payments.length > 0 && ( +
+ + {t("recentDeposits")} + + + ID + + {t("amount")} + + + {t("status")} + + + {t("processor")} + + {t("date")} + + + + {payments.map((payment) => ( + + + + {payment.id.split("-").shift()} + + + ${payment.amount} + {payment.status} + + {payment.processor} + + + {formatDateTime(payment.createdAt)} + + + ))} + +
+
+ )} + + + + + + + + + + {t("usage")} + + Usage rencently + + {displayUsage && } + + + + + + ); +}; + +const UsageChart = () => { + const { webApi, EnjoyApp } = useContext(AppSettingsProviderContext); + const [usages, setUsages] = useState<{ label: string; data: number[] }[]>([]); + const chartRef = useRef(null); + + const fetchUsages = () => { + webApi + .usages() + .then((usages) => { + setUsages(usages); + }) + .catch((error) => { + toast.error(error.message); + }); + }; + + const renderUsageChart = () => { + if (!chartRef.current) return; + if (!usages.length) return; + + new Chart(chartRef.current, { + type: "bar", + data: { + labels: Object.keys(usages[0].data), + datasets: usages.map((usage) => ({ + label: usage.label, + data: Object.values(usage.data), + })), + }, + options: { + scales: { + y: { + beginAtZero: true, + }, + }, + }, + }); + }; + + useEffect(() => { + fetchUsages(); + }, []); + + useEffect(() => { + renderUsageChart(); + }, [usages, chartRef.current]); + + return ( +
+
); };