diff --git a/apps/app/src/locales/en.json b/apps/app/src/locales/en.json index d16091f..d131934 100644 --- a/apps/app/src/locales/en.json +++ b/apps/app/src/locales/en.json @@ -86,7 +86,13 @@ }, "dashboard": { "login": "Back to Login", - "home": "Back to Home" + "home": "Back to Home", + "chart": { + "total_trash": "Total Trash", + "total_report": "Total Report", + "report_status": "Report Status", + "total_trash_bin": "Total Trash Bin" + } }, "user": { "subtitle": "User", @@ -243,6 +249,7 @@ "view_subtrashbin": "View Sub Trash Bin", "view_trash": "View Trash", "view_history": "View History", + "capacity": "Capacity", "trash": { "subtitle": "Trash", "filter_oldest": "Filter by Oldest", @@ -310,6 +317,7 @@ "status": "Report Status", "photo": "Report Photo", "submitFeedback": "Submit Feedback", + "view_feedback": "Feedback", "action": "Actions", "actions": { "title": "Report Actions", diff --git a/apps/app/src/locales/id.json b/apps/app/src/locales/id.json index e025107..3b5592f 100644 --- a/apps/app/src/locales/id.json +++ b/apps/app/src/locales/id.json @@ -86,7 +86,13 @@ }, "dashboard": { "login": "Kembali ke Login", - "home": "Kembali ke Home" + "home": "Kembali ke Home", + "chart": { + "total_trash": "Total Sampah", + "total_report": "Total Laporan", + "report_status": "Status Laporan", + "total_trash_bin": "Total Tempat Sampah" + } }, "user": { "subtitle": "Pengguna", @@ -243,6 +249,7 @@ "view_subtrashbin": "Lihat Sub Tempat Sampah", "view_trash": "Lihat Sampah", "view_history": "Lihat Riwayat", + "capacity": "Kapasitas", "trash": { "subtitle": "Sampah", "filter_oldest": "Filter Terlama", @@ -310,6 +317,7 @@ "status": "Status Laporan", "photo": "Foto Laporan", "submitFeedback": "Kirim Tanggapan", + "view_feedback": "Tanggapan", "actions": { "title": "Tindakan Laporan", "loading": "Loading...", diff --git a/apps/app/src/pages/complain/form/report-history.tsx b/apps/app/src/pages/complain/form/report-history.tsx index d5036d5..a302758 100644 --- a/apps/app/src/pages/complain/form/report-history.tsx +++ b/apps/app/src/pages/complain/form/report-history.tsx @@ -16,6 +16,7 @@ import { EnumResponseStatus, InterfaceReport } from "../../operator/trash-bin/re import { useGetTrashBinById } from "../../operator/trash-bin/report/get-trash-bin.query"; import { useTranslation } from "react-i18next"; import { t } from "i18next"; +import dayjs from "dayjs"; function ReportStatus({ status }: { status: EnumResponseStatus }) { return ( @@ -105,6 +106,12 @@ export function ComplainReportHistory() { refetch(); }); + function filterAndSortLatest(data: InterfaceReport[]) { + return data + .filter((report) => dayjs(report.createdAt)) + .sort((a, b) => dayjs(b.createdAt).valueOf() - dayjs(a.createdAt).valueOf()); + } + function handleRefresh(event: CustomEvent) { queryClient.invalidateQueries({ queryKey: ["getRepgetReportByNikorts", String(nik)], @@ -114,6 +121,8 @@ export function ComplainReportHistory() { event.detail.complete(); } + const sortedData = reportData ? filterAndSortLatest(reportData.data) : []; + return ( @@ -153,7 +162,7 @@ export function ComplainReportHistory() { ) : ( - reportData.data.map((report: InterfaceReport) => ( + sortedData.map((report: InterfaceReport) => ( history.push(`/complain/tabs/form/report-history/feedback/${report.id}`)} key={report.id} diff --git a/apps/app/src/pages/complain/form/tempat-sampah.tsx b/apps/app/src/pages/complain/form/tempat-sampah.tsx index c414aa9..d36d74c 100644 --- a/apps/app/src/pages/complain/form/tempat-sampah.tsx +++ b/apps/app/src/pages/complain/form/tempat-sampah.tsx @@ -6,6 +6,7 @@ import Fuse from "fuse.js"; import { useTrashBinQuery } from "../../../queries/get-trash-bin-query"; import { useTranslation } from "react-i18next"; +import dayjs from "dayjs"; interface TrashBin { id: number; @@ -13,6 +14,7 @@ interface TrashBin { description: string; latitude: number; longitude: number; + createdAt: string; } export function ComplainFormTempatSampah() { @@ -26,11 +28,19 @@ export function ComplainFormTempatSampah() { threshold: 0.4, }; - const fuse = new Fuse(!isLoading ? (data.data as TrashBin[]) : [], fuseOptions); + function filterAndSortLatest(data: TrashBin[]) { + return data + .filter((trashbin) => dayjs(trashbin.createdAt)) + .sort((a, b) => dayjs(b.createdAt).valueOf() - dayjs(a.createdAt).valueOf()); + } + + const fuse = new Fuse(!isLoading ? (filterAndSortLatest(data.data) as TrashBin[]) : [], fuseOptions); // eslint-disable-next-line @typescript-eslint/no-explicit-any const filteredData: any[] = - !isLoading && searchTerm === "" ? data.data : fuse.search(searchTerm).map((result) => result.item); + !isLoading && searchTerm === "" + ? filterAndSortLatest(data.data) + : fuse.search(searchTerm).map((result) => result.item); return ( diff --git a/apps/app/src/pages/operator/dashboard.tsx b/apps/app/src/pages/operator/dashboard.tsx index 51afa0a..99adcca 100644 --- a/apps/app/src/pages/operator/dashboard.tsx +++ b/apps/app/src/pages/operator/dashboard.tsx @@ -1,18 +1,71 @@ -import { IonContent, IonPage } from "@ionic/react"; -import { Card, CardContent, Button, ChartExample } from "@trashtrack/ui"; +import { CapacitorHttp } from "@capacitor/core"; +import { IonContent, IonPage, IonRefresher, IonRefresherContent, RefresherEventDetail } from "@ionic/react"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { + Card, + CardContent, + Button, + AreaChartTotalTrash, + AreaChartTotalReport, + PieChartReportStatus, +} from "@trashtrack/ui"; import { OperatorContext } from "@trashtrack/ui"; +import { API_URL } from "@trashtrack/utils"; import { t } from "i18next"; import { useContext } from "react"; +import { useTranslation } from "react-i18next"; import { useHistory } from "react-router-dom"; -import { Chart } from "react-google-charts"; + +export const useGetTotalTrashbin = () => { + return useQuery({ + queryKey: ["useGetTotalTrashbin"], + queryFn: () => + CapacitorHttp.request({ + url: API_URL + `/trash-bin/card-chart-total`, + method: "GET", + }).then((res) => res.data), + }); +}; export function OperatorDashboard() { const history = useHistory(); const operator = useContext(OperatorContext); + const { t } = useTranslation(); + const queryClient = useQueryClient(); + + function handleRefresh(event: CustomEvent) { + Promise.all([ + queryClient.invalidateQueries({ + queryKey: ["useGetTotalTrashbin"], + }), + queryClient.invalidateQueries({ + queryKey: ["useGetAreaChartTrashTotal"], + }), + queryClient.invalidateQueries({ + queryKey: ["useGetAreaChartReportTotal"], + }), + queryClient.invalidateQueries({ + queryKey: ["useGetPieChartResponseStatus"], + }), + ]); + + event.detail.complete(); + } + + const { data: totalTrashbin, isLoading } = useGetTotalTrashbin(); + + if (isLoading) { + return
Loading...
; + } return ( + + +

Refreshing...

+
+

TrashTrack

Dashboard

@@ -20,24 +73,30 @@ export function OperatorDashboard() {
- +

+ {t("operator.dashboard.chart.total_trash_bin")}: {totalTrashbin.data} +

- - + +

{t("operator.dashboard.chart.total_trash")}

+
+ + +

{t("operator.dashboard.chart.report_status")}

+ +
+
+ + +

{t("operator.dashboard.chart.total_report")}

+ +
+
+
report.id === Number(report_id)) + : { id: 0, trashBinId: 0, status: "", createdAt: "" }; + + if (isReportsLoading || isTrashBinsLoading) { + console.log("Loading..."); + } else { + filter_report = reports.data.find((report: InterfaceReport) => report.id === Number(report_id)); + } + const { data: feedbackData, isError, error, isLoading, refetch, isRefetching } = useGetFeedbacks(); const filteredData = !isLoading ? feedbackData.data.filter((feedback: InterfaceFeedback) => feedback.reportId === Number(report_id)) @@ -123,6 +136,7 @@ export function FeedbackPage() {
diff --git a/apps/app/src/pages/operator/trash-bin/trashbin/sub-trashbin/history.page.tsx b/apps/app/src/pages/operator/trash-bin/trashbin/sub-trashbin/history.page.tsx index d66597b..9a63d95 100644 --- a/apps/app/src/pages/operator/trash-bin/trashbin/sub-trashbin/history.page.tsx +++ b/apps/app/src/pages/operator/trash-bin/trashbin/sub-trashbin/history.page.tsx @@ -26,7 +26,7 @@ export function TrashPage() { const history = useHistory(); const queryClient = useQueryClient(); const { trashbin_id, subtrashbin_id } = useParams<{ trashbin_id: string; subtrashbin_id: string }>(); - const [filterType, setFilterType] = useState<"latest" | "oldest" | "none">("none"); + const [filterType, setFilterType] = useState<"latest" | "oldest" | "none">("latest"); const { data: historyData, isLoading, isFetching, isError, error, refetch } = useGetHistories(); diff --git a/apps/app/src/pages/operator/trash-bin/trashbin/sub-trashbin/subtrashbin.page.tsx b/apps/app/src/pages/operator/trash-bin/trashbin/sub-trashbin/subtrashbin.page.tsx index de20e33..4b232b3 100644 --- a/apps/app/src/pages/operator/trash-bin/trashbin/sub-trashbin/subtrashbin.page.tsx +++ b/apps/app/src/pages/operator/trash-bin/trashbin/sub-trashbin/subtrashbin.page.tsx @@ -13,6 +13,7 @@ import { useState } from "react"; import Fuse from "fuse.js"; import { useGetSubTrashbins } from "./get-subtrashbins.query"; import { useTranslation } from "react-i18next"; +import dayjs from "dayjs"; export interface InterfaceSubTrashbin { id: number; @@ -20,6 +21,7 @@ export interface InterfaceSubTrashbin { name: string; maxCapacity: number; currentCapacity: number; + createdAt: string; } export function SubTrashbinPage() { @@ -44,13 +46,22 @@ export function SubTrashbinPage() { threshold: 0.4, }; + function filterAndSortLatest(data: InterfaceSubTrashbin[]) { + return data + .filter((subtrashbin) => dayjs(subtrashbin.createdAt)) + .sort((a, b) => dayjs(b.createdAt).valueOf() - dayjs(a.createdAt).valueOf()); + } + const filteredDataForId = !isLoading ? subtrashBinData.data.filter( (subtrashbin: InterfaceSubTrashbin) => subtrashbin.trashBinId === Number(trashbin_id) ) : []; - const fuse = new Fuse(!isLoading ? (filteredDataForId as InterfaceSubTrashbin[]) : [], fuseOptions); + const fuse = new Fuse( + !isLoading ? (filterAndSortLatest(filteredDataForId) as InterfaceSubTrashbin[]) : [], + fuseOptions + ); const filteredData: InterfaceSubTrashbin[] = !isLoading && searchTerm === "" ? filteredDataForId : fuse.search(searchTerm).map((result) => result.item); @@ -132,7 +143,17 @@ export function SubTrashbinPage() {
-

{subtrashbin.name}

+

{subtrashbin.name}

+

+ {t("operator.subtrashbin.capacity")}:{" "} + {subtrashbin?.currentCapacity === 0 + ? 0 + : 100 - + (((subtrashbin?.currentCapacity as number) / + (subtrashbin?.maxCapacity ?? 0)) as number) * + 100} + % / 100% +