forked from Transparency/kgroad-frontend2
fixed bugs with sort
This commit is contained in:
parent
bcc7279d39
commit
74b15060a1
@ -182,5 +182,11 @@
|
|||||||
"invalid_activation_code_reset": "Invalid activation code for reset.",
|
"invalid_activation_code_reset": "Invalid activation code for reset.",
|
||||||
"invalid_password_reset_code": "Invalid password reset code.",
|
"invalid_password_reset_code": "Invalid password reset code.",
|
||||||
"invalid_code": "Invalid code."
|
"invalid_code": "Invalid code."
|
||||||
|
},
|
||||||
|
"disclaimer": {
|
||||||
|
"text": "This website is funded by the European Union. Its contents are the sole responsibility of Transparency International Kyrgyzstan and do not necessarily reflect the views of the European Union."
|
||||||
|
},
|
||||||
|
"rights": {
|
||||||
|
"text": "All rights reserved"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,5 +182,11 @@
|
|||||||
"invalid_activation_code_reset": "Сыр сөздү калыпта тапшыруу үчүн четке калган иштеш коду.",
|
"invalid_activation_code_reset": "Сыр сөздү калыпта тапшыруу үчүн четке калган иштеш коду.",
|
||||||
"invalid_password_reset_code": "Сыр сөздү өзгөртүү коду четке калган эмес.",
|
"invalid_password_reset_code": "Сыр сөздү өзгөртүү коду четке калган эмес.",
|
||||||
"invalid_code": "Четке калган иштеш коду."
|
"invalid_code": "Четке калган иштеш коду."
|
||||||
|
},
|
||||||
|
"disclaimer": {
|
||||||
|
"text": "Бул веб-сайт Европа Биримдиги тарабынан каржыланат. Анын мазмуну үчүн Трансперенси Интернешнл Кыргызстан гана жоопкерчиликтүү жана ал Европа Биримдигинин көз карашын сөзсүз түрдө чагылдырбайт."
|
||||||
|
},
|
||||||
|
"rights": {
|
||||||
|
"text": "Бардык укуктар корголгон"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,5 +182,11 @@
|
|||||||
"invalid_activation_code_reset": "Код активации не действителен.",
|
"invalid_activation_code_reset": "Код активации не действителен.",
|
||||||
"invalid_password_reset_code": "Код сброса пароля не действителен.",
|
"invalid_password_reset_code": "Код сброса пароля не действителен.",
|
||||||
"invalid_code": "Неверный код."
|
"invalid_code": "Неверный код."
|
||||||
|
},
|
||||||
|
"disclaimer": {
|
||||||
|
"text": "Этот веб-сайт финансируется Европейским Союзом. Ответственность за его содержание лежит исключительно на Трансперенси Интернешнл Кыргызстан и не обязательно отражает точку зрения Европейского Союза."
|
||||||
|
},
|
||||||
|
"rights": {
|
||||||
|
"text": "Все права защищены"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start -p 8004",
|
"start": "next start -p 3000",
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -15,3 +15,17 @@ export interface IReport {
|
|||||||
total_likes: number;
|
total_likes: number;
|
||||||
count_reviews: number;
|
count_reviews: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IRatingReport {
|
||||||
|
created_at: string;
|
||||||
|
category: null;
|
||||||
|
author: {
|
||||||
|
id: number;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
govern_status: null;
|
||||||
|
};
|
||||||
|
total_likes: number;
|
||||||
|
count_reviews: number;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
@ -4,6 +4,19 @@
|
|||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
background-color: rgb(15, 23, 42);
|
background-color: rgb(15, 23, 42);
|
||||||
|
|
||||||
|
&__logo {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: white;
|
||||||
|
font-family: "Inter", sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
a,
|
a,
|
||||||
li,
|
li,
|
||||||
h4 {
|
h4 {
|
||||||
|
@ -13,11 +13,17 @@ import NetKgTracker from "@/widgets/NetKgTracker/NetKgTracker";
|
|||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
const t = useTranslations("general");
|
const t = useTranslations("general");
|
||||||
|
const tDisclaimer = useTranslations("disclaimer");
|
||||||
|
const tRights = useTranslations("rights");
|
||||||
return (
|
return (
|
||||||
<footer className="footer">
|
<footer className="footer">
|
||||||
<Link href="/">
|
<div className="footer__logo">
|
||||||
<Image src={logo} alt="Logo" />
|
<Link href="/">
|
||||||
</Link>
|
<Image src={logo} alt="Logo" />
|
||||||
|
</Link>
|
||||||
|
<p>© {tRights("text")}</p>
|
||||||
|
<p>{tDisclaimer("text")}</p>
|
||||||
|
</div>
|
||||||
<div className="footer__links">
|
<div className="footer__links">
|
||||||
<h4>{t("navigation")}</h4>
|
<h4>{t("navigation")}</h4>
|
||||||
<ul>
|
<ul>
|
||||||
@ -45,8 +51,8 @@ const Footer = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</li>
|
</li>
|
||||||
|
<li>Photo By ThomasG, CC BY-SA 3.0</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p className="text-white">Photo By ThomasG, CC BY-SA 3.0</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="footer__apps">
|
<div className="footer__apps">
|
||||||
|
@ -11,6 +11,18 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
|
||||||
|
&__logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
&_last {
|
||||||
|
min-width: 78px;
|
||||||
|
max-width: 78px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__links {
|
&__links {
|
||||||
height: 40%;
|
height: 40%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -46,6 +58,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1220px) {
|
||||||
|
.navbar {
|
||||||
|
padding: 0 60px;
|
||||||
|
|
||||||
|
&__links {
|
||||||
|
gap: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1024px) {
|
@media screen and (max-width: 1024px) {
|
||||||
.navbar {
|
.navbar {
|
||||||
padding: 0 30px;
|
padding: 0 30px;
|
||||||
@ -60,7 +82,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 900px) {
|
||||||
.navbar {
|
.navbar {
|
||||||
height: 72px;
|
height: 72px;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import "./Navbar.scss";
|
import "./Navbar.scss";
|
||||||
import Image from "next/image";
|
import Image, { StaticImageData } from "next/image";
|
||||||
import { Link } from "@/shared/config/navigation";
|
import { Link } from "@/shared/config/navigation";
|
||||||
import { usePathname } from "@/shared/config/navigation";
|
import { usePathname } from "@/shared/config/navigation";
|
||||||
import logo from "@/shared/assets/logo.svg";
|
import logo from "@/shared/assets/logo.svg";
|
||||||
@ -12,16 +12,34 @@ import menu from "./icons/menu.svg";
|
|||||||
import cross from "./icons/cross.svg";
|
import cross from "./icons/cross.svg";
|
||||||
import NavMenu from "./NavMenu/NavMenu";
|
import NavMenu from "./NavMenu/NavMenu";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import founded_ru from "./assets/founded-ru.png";
|
||||||
|
import founded_en from "./assets/founded-en.png";
|
||||||
|
import founded_kg from "./assets/founded-kg.png";
|
||||||
|
import { useParams } from "next/navigation";
|
||||||
|
|
||||||
const Navbar = () => {
|
const Navbar = () => {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const [openMenu, setOpenMenu] = useState<boolean>(false);
|
const [openMenu, setOpenMenu] = useState<boolean>(false);
|
||||||
|
const { locale } = useParams();
|
||||||
|
|
||||||
|
const FOUNDED: Record<string, StaticImageData> = {
|
||||||
|
ru: founded_ru,
|
||||||
|
kg: founded_kg,
|
||||||
|
en: founded_en,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="navbar">
|
<section className="navbar">
|
||||||
<Link href="/">
|
<div className="navbar__logo">
|
||||||
<Image src={logo} alt="Logo" />
|
<Link href="/">
|
||||||
</Link>
|
<Image src={logo} alt="Logo" />
|
||||||
|
</Link>
|
||||||
|
<Image
|
||||||
|
className="navbar__logo_last"
|
||||||
|
src={FOUNDED[locale as string]}
|
||||||
|
alt="Founded by EU Image"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<nav className="navbar__links">
|
<nav className="navbar__links">
|
||||||
{LINKS().map((link) => (
|
{LINKS().map((link) => (
|
||||||
|
BIN
src/widgets/Navbar/assets/founded-en.png
Normal file
BIN
src/widgets/Navbar/assets/founded-en.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
BIN
src/widgets/Navbar/assets/founded-kg.png
Normal file
BIN
src/widgets/Navbar/assets/founded-kg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
BIN
src/widgets/Navbar/assets/founded-ru.png
Normal file
BIN
src/widgets/Navbar/assets/founded-ru.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
@ -39,10 +39,7 @@ const RatingSection: React.FC<IRatingSectionProps> = ({
|
|||||||
const [activePage, setActivePage] = useState<number>(
|
const [activePage, setActivePage] = useState<number>(
|
||||||
+searchParams["страница-рейтинга"] || 1
|
+searchParams["страница-рейтинга"] || 1
|
||||||
);
|
);
|
||||||
const [filter, setFilter] = useState({
|
const [sort, setSort] = useState<string>("");
|
||||||
option: "date",
|
|
||||||
toggle: false,
|
|
||||||
});
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const reports = useRatingStore(useShallow((state) => state.data));
|
const reports = useRatingStore(useShallow((state) => state.data));
|
||||||
@ -51,8 +48,8 @@ const RatingSection: React.FC<IRatingSectionProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getReports(ratingSearch, activePage, filter);
|
getReports(ratingSearch, activePage, sort);
|
||||||
}, []);
|
}, [sort]);
|
||||||
|
|
||||||
const handleSubmit: React.FormEventHandler<
|
const handleSubmit: React.FormEventHandler<
|
||||||
HTMLFormElement
|
HTMLFormElement
|
||||||
@ -74,7 +71,7 @@ const RatingSection: React.FC<IRatingSectionProps> = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
getReports(ratingSearch, activePage, filter);
|
getReports(ratingSearch, activePage, sort);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
reports.results.length < 8 &&
|
reports.results.length < 8 &&
|
||||||
@ -98,7 +95,7 @@ const RatingSection: React.FC<IRatingSectionProps> = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
getReports(ratingSearch, activePage, filter);
|
getReports(ratingSearch, activePage, sort);
|
||||||
}, [activePage]);
|
}, [activePage]);
|
||||||
|
|
||||||
const params = [
|
const params = [
|
||||||
@ -106,14 +103,7 @@ const RatingSection: React.FC<IRatingSectionProps> = ({
|
|||||||
id: 1,
|
id: 1,
|
||||||
name: tGeneral("date"),
|
name: tGeneral("date"),
|
||||||
handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "date") {
|
setSort("");
|
||||||
return setFilter({ option: "date", toggle: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "date", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
getReports(ratingSearch, activePage, filter);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ id: 2, name: tGeneral("address") },
|
{ id: 2, name: tGeneral("address") },
|
||||||
@ -123,28 +113,14 @@ const RatingSection: React.FC<IRatingSectionProps> = ({
|
|||||||
id: 5,
|
id: 5,
|
||||||
name: tGeneral("reviews"),
|
name: tGeneral("reviews"),
|
||||||
handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "reviews") {
|
setSort("reviews");
|
||||||
return setFilter({ option: "reviews", toggle: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "reviews", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
getReports(ratingSearch, activePage, filter);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 6,
|
id: 6,
|
||||||
name: tGeneral("rating"),
|
name: tGeneral("rating"),
|
||||||
handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "rating") {
|
setSort("likes");
|
||||||
return setFilter({ option: "rating", toggle: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "rating", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
getReports(ratingSearch, activePage, filter);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -13,7 +13,7 @@ interface IRatingStore extends IFetch {
|
|||||||
getReports: (
|
getReports: (
|
||||||
categories: string,
|
categories: string,
|
||||||
page: number,
|
page: number,
|
||||||
filter: { option: string; toggle: boolean }
|
sort: string
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,14 +29,14 @@ export const useRatingStore = create<IRatingStore>((set) => ({
|
|||||||
getReports: async (
|
getReports: async (
|
||||||
query: string = "",
|
query: string = "",
|
||||||
page: number = 1,
|
page: number = 1,
|
||||||
filter: { option: string; toggle: boolean }
|
sort: string = ""
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
set({ isLoading: true });
|
set({ isLoading: true });
|
||||||
|
|
||||||
const data = (
|
const data = (
|
||||||
await apiInstance.get<IFetchReports>(
|
await apiInstance.get<IFetchReports>(
|
||||||
`/report/?page=${page}&page_size=${8}`
|
`/report/list_sort?sort_by=${sort}&page=${page}`
|
||||||
)
|
)
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
@ -50,46 +50,6 @@ export const useRatingStore = create<IRatingStore>((set) => ({
|
|||||||
|
|
||||||
data.results = [...searched];
|
data.results = [...searched];
|
||||||
|
|
||||||
if (filter.option === "date" && filter.toggle === false) {
|
|
||||||
data.results = data.results.sort((a, b) => {
|
|
||||||
const dateA = new Date(a.created_at) as unknown as number;
|
|
||||||
const dateB = new Date(b.created_at) as unknown as number;
|
|
||||||
return dateA - dateB;
|
|
||||||
});
|
|
||||||
} else if (filter.option === "date" && filter.toggle === true) {
|
|
||||||
data.results = data.results.sort((a, b) => {
|
|
||||||
const dateA = new Date(a.created_at) as unknown as number;
|
|
||||||
const dateB = new Date(b.created_at) as unknown as number;
|
|
||||||
return dateB - dateA;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter.option === "reviews" && filter.toggle === false) {
|
|
||||||
data.results = data.results.sort(
|
|
||||||
(a, b) => a.count_reviews - b.count_reviews
|
|
||||||
);
|
|
||||||
} else if (
|
|
||||||
filter.option === "reviews" &&
|
|
||||||
filter.toggle === true
|
|
||||||
) {
|
|
||||||
data.results = data.results.sort(
|
|
||||||
(a, b) => b.count_reviews - a.count_reviews
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter.option === "rating" && filter.toggle === false) {
|
|
||||||
data.results = data.results.sort(
|
|
||||||
(a, b) => a.total_likes - b.total_likes
|
|
||||||
);
|
|
||||||
} else if (
|
|
||||||
filter.option === "rating" &&
|
|
||||||
filter.toggle === true
|
|
||||||
) {
|
|
||||||
data.results = data.results.sort(
|
|
||||||
(a, b) => b.total_likes - a.total_likes
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
set({ data: data });
|
set({ data: data });
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
set({ error: error.message });
|
set({ error: error.message });
|
||||||
|
@ -29,10 +29,7 @@ const ProfileTable: React.FC<IProfileTableProps> = ({
|
|||||||
} = useProfileReportsStore();
|
} = useProfileReportsStore();
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [filter, setFilter] = useState({
|
const [sort, setSort] = useState("date");
|
||||||
option: "date",
|
|
||||||
toggle: true,
|
|
||||||
});
|
|
||||||
const [activePage, setActivePage] = useState<number>(
|
const [activePage, setActivePage] = useState<number>(
|
||||||
+searchParams["страница-обращений"] || 1
|
+searchParams["страница-обращений"] || 1
|
||||||
);
|
);
|
||||||
@ -40,18 +37,7 @@ const ProfileTable: React.FC<IProfileTableProps> = ({
|
|||||||
{
|
{
|
||||||
param: "Дата",
|
param: "Дата",
|
||||||
handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "date") {
|
setSort("date");
|
||||||
return setFilter({ option: "date", toggle: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "date", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
getMyReports(
|
|
||||||
filter,
|
|
||||||
activePage,
|
|
||||||
session.data?.access_token as string
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ param: "Адрес" },
|
{ param: "Адрес" },
|
||||||
@ -59,38 +45,13 @@ const ProfileTable: React.FC<IProfileTableProps> = ({
|
|||||||
{
|
{
|
||||||
param: "Комментарии",
|
param: "Комментарии",
|
||||||
handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "count_reviews") {
|
setSort("reviews");
|
||||||
return setFilter({
|
|
||||||
option: "count_reviews",
|
|
||||||
toggle: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "count_reviews", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
getMyReports(
|
|
||||||
filter,
|
|
||||||
activePage,
|
|
||||||
session.data?.access_token as string
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
param: "Рейтинг",
|
param: "Рейтинг",
|
||||||
handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "total_likes") {
|
setSort("rating");
|
||||||
return setFilter({ option: "total_likes", toggle: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "total_likes", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
getMyReports(
|
|
||||||
filter,
|
|
||||||
activePage,
|
|
||||||
session.data?.access_token as string
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -98,7 +59,7 @@ const ProfileTable: React.FC<IProfileTableProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session.status === "loading") return;
|
if (session.status === "loading") return;
|
||||||
getMyReports(
|
getMyReports(
|
||||||
filter,
|
sort,
|
||||||
activePage,
|
activePage,
|
||||||
session.data?.access_token as string
|
session.data?.access_token as string
|
||||||
);
|
);
|
||||||
@ -110,11 +71,11 @@ const ProfileTable: React.FC<IProfileTableProps> = ({
|
|||||||
{ scroll: false }
|
{ scroll: false }
|
||||||
);
|
);
|
||||||
getMyReports(
|
getMyReports(
|
||||||
filter,
|
sort,
|
||||||
activePage,
|
activePage,
|
||||||
session.data?.access_token as string
|
session.data?.access_token as string
|
||||||
);
|
);
|
||||||
}, [activePage]);
|
}, [activePage, sort]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="profile-table">
|
<div className="profile-table">
|
||||||
|
@ -15,7 +15,7 @@ const filterCategories: Record<string, string> = {
|
|||||||
interface IProfileReportsStore extends IFetch {
|
interface IProfileReportsStore extends IFetch {
|
||||||
data: IMyReportsList;
|
data: IMyReportsList;
|
||||||
getMyReports: (
|
getMyReports: (
|
||||||
filter: { option: string; toggle: boolean },
|
filter: string,
|
||||||
page: number,
|
page: number,
|
||||||
access_token: string
|
access_token: string
|
||||||
) => void;
|
) => void;
|
||||||
@ -32,10 +32,7 @@ export const useProfileReportsStore = create<IProfileReportsStore>(
|
|||||||
results: [],
|
results: [],
|
||||||
},
|
},
|
||||||
getMyReports: async (
|
getMyReports: async (
|
||||||
filter: {
|
sort: string,
|
||||||
option: string;
|
|
||||||
toggle: boolean;
|
|
||||||
},
|
|
||||||
page: number,
|
page: number,
|
||||||
access_token: string
|
access_token: string
|
||||||
) => {
|
) => {
|
||||||
@ -47,48 +44,27 @@ export const useProfileReportsStore = create<IProfileReportsStore>(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
set({ isLoading: true });
|
set({ isLoading: true });
|
||||||
const res = await apiInstance.get<IMyReportsList>(
|
const data = await apiInstance
|
||||||
`/users/reports/?page=${page}`,
|
.get<IMyReportsList>(
|
||||||
config
|
`/users/reports/?page=${page}&page_size=8`,
|
||||||
);
|
config
|
||||||
|
)
|
||||||
|
.then((res) => res.data);
|
||||||
|
|
||||||
let data = res.data;
|
if (sort === "date") {
|
||||||
|
|
||||||
if (filter.option === "date" && filter.toggle === false) {
|
|
||||||
data.results = data.results.sort((a, b) => {
|
data.results = data.results.sort((a, b) => {
|
||||||
const dateA = new Date(a.created_at) as unknown as number;
|
const dateA = new Date(b.created_at) as unknown as number;
|
||||||
const dateB = new Date(b.created_at) as unknown as number;
|
const dateB = new Date(a.created_at) as unknown as number;
|
||||||
return dateA - dateB;
|
return dateA - dateB;
|
||||||
});
|
});
|
||||||
} else if (
|
} else if (sort === "reviews") {
|
||||||
filter.option === "date" &&
|
data.results = data.results.sort(
|
||||||
filter.toggle === true
|
(a, b) => b.count_reviews - a.count_reviews
|
||||||
) {
|
);
|
||||||
data.results = data.results.sort((a, b) => {
|
} else if (sort === "rating") {
|
||||||
const dateA = new Date(a.created_at) as unknown as number;
|
data.results = data.results.sort(
|
||||||
const dateB = new Date(b.created_at) as unknown as number;
|
(a, b) => b.total_likes - a.total_likes
|
||||||
return dateB - dateA;
|
);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
filter.option === filterCategories[filter.option] &&
|
|
||||||
filter.toggle === false
|
|
||||||
) {
|
|
||||||
data.results = data.results.sort((a, b) => {
|
|
||||||
const optionKey = filter.option as keyof IMyReports;
|
|
||||||
return (Number(a[optionKey]) -
|
|
||||||
Number(b[optionKey])) as number;
|
|
||||||
});
|
|
||||||
} else if (
|
|
||||||
filter.option === "rating" &&
|
|
||||||
filter.toggle === true
|
|
||||||
) {
|
|
||||||
data.results = data.results.sort((a, b) => {
|
|
||||||
const optionKey = filter.option as keyof IMyReports;
|
|
||||||
return (Number(a[optionKey]) -
|
|
||||||
Number(b[optionKey])) as number;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set({ data: data });
|
set({ data: data });
|
||||||
|
@ -32,10 +32,7 @@ const StatisticsTable: React.FC<IStatisticsTableProps> = ({
|
|||||||
getStatistics,
|
getStatistics,
|
||||||
data: statistics,
|
data: statistics,
|
||||||
} = useStatisticsStore(useShallow((state) => state));
|
} = useStatisticsStore(useShallow((state) => state));
|
||||||
const [filter, setFilter] = useState({
|
const [sort, setSort] = useState<string>("broken_road_1");
|
||||||
option: "broken_road",
|
|
||||||
toggle: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const [openPopup, setOpenPopup] = useState<boolean>(false);
|
const [openPopup, setOpenPopup] = useState<boolean>(false);
|
||||||
|
|
||||||
@ -44,122 +41,54 @@ const StatisticsTable: React.FC<IStatisticsTableProps> = ({
|
|||||||
const params = [
|
const params = [
|
||||||
{
|
{
|
||||||
param: "Добавлено дорог",
|
param: "Добавлено дорог",
|
||||||
async handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "broken_road_1") {
|
setSort("broken_road_1");
|
||||||
return setFilter({
|
|
||||||
option: "broken_road_1",
|
|
||||||
toggle: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "broken_road_1", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
|
|
||||||
getStatistics(location, filter, query);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
param: "Локальных дефектов",
|
param: "Локальных дефектов",
|
||||||
async handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "local_defect_3") {
|
setSort("local_defect_3");
|
||||||
return setFilter({
|
|
||||||
option: "local_defect_3",
|
|
||||||
toggle: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "local_defect_3", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
|
|
||||||
getStatistics(location, filter, query);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
param: "Очагов аварийности",
|
param: "Очагов аварийности",
|
||||||
async handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "hotbed_of_accidents_2") {
|
setSort("hotbed_of_accidents_2");
|
||||||
return setFilter({
|
|
||||||
option: "hotbed_of_accidents_2",
|
|
||||||
toggle: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return {
|
|
||||||
option: "hotbed_of_accidents_2",
|
|
||||||
toggle: !prev.toggle,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
getStatistics(location, filter, query);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
param: "Локальных дефектов исправлено",
|
param: "Локальных дефектов исправлено",
|
||||||
async handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "local_defect_fixed_6") {
|
setSort("local_defect_fixed_6");
|
||||||
return setFilter({
|
|
||||||
option: "local_defect_fixed_6",
|
|
||||||
toggle: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return {
|
|
||||||
option: "local_defect_fixed_6",
|
|
||||||
toggle: !prev.toggle,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
getStatistics(location, filter, query);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
param: "В планах ремонта",
|
param: "В планах ремонта",
|
||||||
async handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "repair_plans_4") {
|
setSort("repair_plans_4");
|
||||||
return setFilter({
|
|
||||||
option: "repair_plans_4",
|
|
||||||
toggle: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "repair_plans_4", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
|
|
||||||
getStatistics(location, filter, query);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
param: "Отремонтировано",
|
param: "Отремонтировано",
|
||||||
async handleClick() {
|
handleClick() {
|
||||||
if (filter.option !== "repaired_5") {
|
setSort("repaired_5");
|
||||||
return setFilter({ option: "repaired_5", toggle: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
setFilter((prev) => {
|
|
||||||
return { option: "repaired_5", toggle: !prev.toggle };
|
|
||||||
});
|
|
||||||
|
|
||||||
getStatistics(location, filter, query);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const getStatsByLocation = async (location: string) => {
|
const getStatsByLocation = async (location: string) => {
|
||||||
setLocation(location);
|
setLocation(location);
|
||||||
getStatistics(location, filter, query);
|
getStatistics(location, sort, query);
|
||||||
console.error("Error fetching statistics:", error);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getStatistics(location, filter, query);
|
getStatistics(location, sort, query);
|
||||||
|
|
||||||
router.push(`/statistics?поиск-населенного-пункта=${query}`);
|
router.push(`/statistics?поиск-населенного-пункта=${query}`, {
|
||||||
}, [query]);
|
scroll: false,
|
||||||
|
});
|
||||||
|
}, [query, sort]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="statistics-table">
|
<div className="statistics-table">
|
||||||
@ -241,11 +170,7 @@ const StatisticsTable: React.FC<IStatisticsTableProps> = ({
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<tr id="statistics-table__no-data-warning">
|
<tr id="statistics-table__no-data-warning">
|
||||||
<td>
|
<td>{error ? error : "Данных не найдено"}</td>
|
||||||
{error
|
|
||||||
? error
|
|
||||||
: "Oops, looks like there is no data"}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -18,7 +18,7 @@ interface IStatisticsStore extends IFetch {
|
|||||||
data: IStatistics[];
|
data: IStatistics[];
|
||||||
getStatistics: (
|
getStatistics: (
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
filter: { option: string; toggle: boolean },
|
sort: string,
|
||||||
query: string
|
query: string
|
||||||
) => void;
|
) => void;
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ export const useStatisticsStore = create<IStatisticsStore>((set) => ({
|
|||||||
data: [],
|
data: [],
|
||||||
getStatistics: async (
|
getStatistics: async (
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
filter: { option: string; toggle: boolean },
|
sort: string,
|
||||||
query: string = ""
|
query: string = ""
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
@ -42,27 +42,9 @@ export const useStatisticsStore = create<IStatisticsStore>((set) => ({
|
|||||||
loc.name.toLowerCase().includes(query.toLowerCase())
|
loc.name.toLowerCase().includes(query.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
const sorted = data.sort((a: any, b: any) => a[sort] - b[sort]);
|
||||||
filter.option === filterCategories[filter.option] &&
|
|
||||||
filter.toggle === false
|
|
||||||
) {
|
|
||||||
data = data.sort((a, b) => {
|
|
||||||
const optionKey = filter.option as keyof IStatistics;
|
|
||||||
return (Number(a[optionKey]) -
|
|
||||||
Number(b[optionKey])) as number;
|
|
||||||
});
|
|
||||||
} else if (
|
|
||||||
filter.option === "rating" &&
|
|
||||||
filter.toggle === true
|
|
||||||
) {
|
|
||||||
data = data.sort((a, b) => {
|
|
||||||
const optionKey = filter.option as keyof IStatistics;
|
|
||||||
return (Number(a[optionKey]) -
|
|
||||||
Number(b[optionKey])) as number;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
set({ data: data });
|
set({ data: sorted });
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof AxiosError) {
|
if (error instanceof AxiosError) {
|
||||||
set({ error: error.message });
|
set({ error: error.message });
|
||||||
|
Loading…
Reference in New Issue
Block a user