Skip to content
This repository has been archived by the owner on Aug 23, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' of github.com:trashtrack-team/trashtrack
Browse files Browse the repository at this point in the history
  • Loading branch information
NotHydra committed Mar 2, 2024
2 parents 3c0affd + 98de031 commit c47d64a
Show file tree
Hide file tree
Showing 17 changed files with 485 additions and 36 deletions.
10 changes: 9 additions & 1 deletion apps/app/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -310,6 +317,7 @@
"status": "Report Status",
"photo": "Report Photo",
"submitFeedback": "Submit Feedback",
"view_feedback": "Feedback",
"action": "Actions",
"actions": {
"title": "Report Actions",
Expand Down
10 changes: 9 additions & 1 deletion apps/app/src/locales/id.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -310,6 +317,7 @@
"status": "Status Laporan",
"photo": "Foto Laporan",
"submitFeedback": "Kirim Tanggapan",
"view_feedback": "Tanggapan",
"actions": {
"title": "Tindakan Laporan",
"loading": "Loading...",
Expand Down
11 changes: 10 additions & 1 deletion apps/app/src/pages/complain/form/report-history.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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<RefresherEventDetail>) {
queryClient.invalidateQueries({
queryKey: ["getRepgetReportByNikorts", String(nik)],
Expand All @@ -114,6 +121,8 @@ export function ComplainReportHistory() {
event.detail.complete();
}

const sortedData = reportData ? filterAndSortLatest(reportData.data) : [];

return (
<IonPage>
<IonContent className="operator-report-action-display ion-padding" fullscreen>
Expand Down Expand Up @@ -153,7 +162,7 @@ export function ComplainReportHistory() {
</CardHeader>
</Card>
) : (
reportData.data.map((report: InterfaceReport) => (
sortedData.map((report: InterfaceReport) => (
<Card
onClick={() => history.push(`/complain/tabs/form/report-history/feedback/${report.id}`)}
key={report.id}
Expand Down
14 changes: 12 additions & 2 deletions apps/app/src/pages/complain/form/tempat-sampah.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ 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;
name: string;
description: string;
latitude: number;
longitude: number;
createdAt: string;
}

export function ComplainFormTempatSampah() {
Expand All @@ -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 (
<IonPage>
Expand Down
91 changes: 75 additions & 16 deletions apps/app/src/pages/operator/dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,102 @@
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<RefresherEventDetail>) {
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 <div>Loading...</div>;
}

return (
<IonPage>
<IonContent className="operator-dashboard ion-padding" fullscreen>
<IonRefresher slot="fixed" onIonRefresh={handleRefresh}>
<IonRefresherContent>
<p className="text-xs text-center">Refreshing...</p>
</IonRefresherContent>
</IonRefresher>
<div className="pt-12">
<h1 className="font-bold text-left text-xl">TrashTrack</h1>
<p className="text-xs text-left text-slate-600">Dashboard</p>
</div>
<div className="flex flex-col pt-8 gap-4">
<Card>
<CardContent className="pt-2 pb-2 pl-0 pr-0">
<ChartExample />
<p className="pl-6 pt-4 mb-4 text-base">
{t("operator.dashboard.chart.total_trash_bin")}: {totalTrashbin.data}
</p>
</CardContent>
</Card>
<Card>
<CardContent>
<Chart
chartType="ScatterChart"
data={[
["Age", "Weight"],
[4, 5.5],
[8, 12],
]}
width="100%"
height="400px"
legendToggle
/>
<CardContent className="pt-2 pb-2 pl-0 pr-0">
<p className="pl-6 pt-4 mb-4 text-base">{t("operator.dashboard.chart.total_trash")}</p>
<AreaChartTotalTrash />
</CardContent>
</Card>
<Card>
<CardContent className="pt-2 pb-2 pl-0 pr-0">
<p className="pl-6 pt-4 mb-4 text-base">{t("operator.dashboard.chart.report_status")}</p>
<PieChartReportStatus />
</CardContent>
</Card>
<Card>
<CardContent className="pt-2 pb-2 pl-0 pr-0">
<p className="pl-6 pt-4 mb-4 text-base">{t("operator.dashboard.chart.total_report")}</p>
<AreaChartTotalReport />
</CardContent>
</Card>

<Card className="flex flex-col mt-8">
<CardContent className="pt-6">
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,11 @@ export function DetailedReportPage() {
<div>
<Button
className="w-full mb-2"
disabled={report?.status !== EnumResponseStatus.ACCEPTED}
onClick={() => history.push(`/trash-bin/tabs/feedback/${report?.id}`)}
>
{t("operator.reports.detailed.input.submitFeedback")}
{report?.status === EnumResponseStatus.COMPLETED
? t("operator.reports.detailed.input.view_feedback")
: t("operator.reports.detailed.input.submitFeedback")}
</Button>
<div className="flex flex-row gap-2">
<ReportStatusAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { CapacitorHttp } from "@capacitor/core";
import { queryClient } from "../../../../../main";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { EnumResponseStatus, InterfaceReport } from "../reports.page";
import { useGetReportsWithTrashBins } from "../get-trash-and-report.query";

export interface InterfaceFeedback {
id: number;
Expand Down Expand Up @@ -99,6 +101,17 @@ export function FeedbackPage() {
const [isOpen, setIsOpen] = useState(false);
const { t } = useTranslation();

const { reports, trashBins, isReportsLoading, isTrashBinsLoading } = useGetReportsWithTrashBins();
let filter_report: InterfaceReport = !isReportsLoading
? reports.data.find((report: InterfaceReport) => 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))
Expand All @@ -123,6 +136,7 @@ export function FeedbackPage() {
<div className="flex flex-col gap-2">
<Button
className="w-full"
disabled={filter_report?.status === EnumResponseStatus.COMPLETED ? true : false}
onClick={() => history.push(`/trash-bin/tabs/feedback/${report_id}/create`)}
>
{t("operator.reports.feedback.delete.create")}
Expand Down Expand Up @@ -179,6 +193,11 @@ export function FeedbackPage() {
<Button
className="w-full mt-4"
variant="destructive"
disabled={
filter_report?.status === EnumResponseStatus.COMPLETED
? true
: false
}
onClick={() => {
setIsOpen(true);
}}
Expand Down
11 changes: 10 additions & 1 deletion apps/app/src/pages/operator/trash-bin/report/reports.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useState } from "react";
import { InterfaceResult, useGetReportsWithTrashBins } from "./get-trash-and-report.query";
import Fuse from "fuse.js";
import { useTranslation } from "react-i18next";
import dayjs from "dayjs";

export enum EnumResponseStatus {
NOT_RESPONDED = "notResponded",
Expand Down Expand Up @@ -105,13 +106,21 @@ export function ReportsPage() {
threshold: 0.4,
};

function filterAndSortLatest(data: InterfaceReport[]) {
return data
.filter((report) => dayjs(report.createdAt))
.sort((a, b) => dayjs(b.createdAt).valueOf() - dayjs(a.createdAt).valueOf());
}

let data: InterfaceResult[] = [];
const fuse = new Fuse(data, fuseOptions);

if (isReportsLoading || isTrashBinsLoading) {
console.log("Loading...");
} else {
data = reports.data.map((re: InterfaceReport) => {
const filter_by_latest_first = filterAndSortLatest(reports.data);

data = filter_by_latest_first.map((re: InterfaceReport) => {
const trashBin = trashBins.data.find((tb: InterfaceTrashbin) => tb.id === re.trashBinId);
return {
...re,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ export function DetailedSubTrashbinPage() {
refetch();
});

const capacity =
subtrashbin?.currentCapacity === 0
? 0
: 100 - (((subtrashbin?.currentCapacity as number) / (subtrashbin?.maxCapacity ?? 0)) as number) * 100;

console.log("capacity", capacity);
console.log("max capacity", subtrashbin?.maxCapacity);
console.log("current capacity", subtrashbin?.currentCapacity);

const { t } = useTranslation();

return (
Expand Down Expand Up @@ -159,12 +168,7 @@ export function DetailedSubTrashbinPage() {
<Label htmlFor="openCount" className="text-xs">
{t("operator.subtrashbin.detailed.capacity")}
</Label>
<Input
readOnly
type="text"
id="openCount"
value={`${subtrashbin?.currentCapacity} / ${subtrashbin?.maxCapacity}`}
/>
<Input readOnly type="text" id="openCount" value={`${capacity}% / 100%`} />
</div>
</div>
<Separator className="my-4" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Loading

0 comments on commit c47d64a

Please sign in to comment.