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

Implement and fixes final day issues #37

Merged
merged 14 commits into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading