added next-intl, composed next-auth and next-intl in middleware, fixed some bugs, completed details page, added google auth

This commit is contained in:
Alibek committed 2024-02-29 14:09:37 +06:00
1 parent 9cd7b2a67d
commit 6637ab4eae
172 files changed
+1772 -502

No files matched your search

@@ -0,0 +1,137 @@
.profile-table {
display: flex;
flex-direction: column;
gap: 30px;
&__wrapper {
overflow: hidden;
overflow-x: auto;
&::-webkit-scrollbar {
display: none;
}
}
table {
width: 100%;
thead {
padding: 0 40px;
width: 100%;
height: 68px;
display: flex;
align-items: center;
background-color: rgb(244, 244, 244);
tr {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 160px 271px 300px 164px 100px;
justify-content: space-between;
td {
display: flex;
align-items: center;
height: 100%;
background-color: rgb(244, 244, 244);
}
td,
button {
font-size: 16px;
font-weight: 400;
line-height: 18px;
color: rgb(102, 112, 133);
}
button {
display: flex;
align-items: center;
}
}
}
tbody {
display: flex;
flex-direction: column;
tr {
padding: 0 40px;
height: 80px;
display: grid;
grid-template-columns: 160px 271px 300px 164px 100px;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid rgb(241, 244, 249);
td {
font-size: 18px;
font-weight: 500;
line-height: 20px;
}
#my-report-date {
color: rgb(102, 112, 133);
}
#my-report-location {
a {
display: flex;
font-size: 20px;
color: rgb(50, 48, 58);
}
}
#my-report-status {
font-size: 20px;
}
#my-report-reviews {
color: rgb(72, 159, 225);
}
#my-report-likes {
color: rgb(74, 192, 63);
}
}
}
}
&__message {
font-size: 18px;
font-weight: 500;
line-height: 22px;
color: rgb(102, 102, 102);
}
#my-reports-link {
display: none;
padding: 10px;
border-radius: 8px;
background-color: rgb(57, 152, 232);
font-size: 16px;
font-weight: 800;
line-height: 19px;
color: rgb(255, 255, 255);
}
}
.no-reports-in-profile {
border: 1px solid rgb(197, 198, 197);
border-radius: 10px;
width: 100%;
height: 150px;
display: flex;
align-items: center;
justify-content: center;
}
@media screen and (max-width: 550px) {
.profile-table {
a {
display: flex;
align-self: center;
}
}
}
@@ -0,0 +1,197 @@
"use client";
import Image from "next/image";
import "./ProfileTable.scss";
import arrows from "@/shared/icons/arrows.svg";
import {
REPORT_STATUS,
REPORT_STATUS_COLORS,
} from "@/shared/variables/report-status";
import Pagination from "@/features/Pagination/Pagination";
import { useEffect, useState } from "react";
import { useSession } from "next-auth/react";
import { sliceDate } from "./helpers";
import { useProfileReportsStore } from "./profile-reports.store";
import { Link, useRouter } from "@/shared/config/navigation";
interface IProfileTableProps {
searchParams: { ["страница-обращений"]: string };
}
const ProfileTable: React.FC<IProfileTableProps> = ({
searchParams,
}: IProfileTableProps) => {
const {
getMyReports,
data: reports,
isLoading,
error,
} = useProfileReportsStore();
const session = useSession();
const router = useRouter();
const [filter, setFilter] = useState({
option: "date",
toggle: true,
});
const [activePage, setActivePage] = useState<number>(
+searchParams["страница-обращений"] || 1
);
const params = [
{
param: "Дата",
handleClick() {
if (filter.option !== "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: "Статус" },
{
param: "Комментарии",
handleClick() {
if (filter.option !== "count_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: "Рейтинг",
handleClick() {
if (filter.option !== "total_likes") {
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
);
},
},
];
useEffect(() => {
if (session.status === "loading") return;
getMyReports(
filter,
activePage,
session.data?.access_token as string
);
}, [session]);
useEffect(() => {
router.push(
`/profile/my-reports?страница-обращений=${activePage}`,
{ scroll: false }
);
getMyReports(
filter,
activePage,
session.data?.access_token as string
);
}, [activePage]);
return (
<div className="profile-table">
<div
className={`profile-table__wrapper ${
reports.results.length ? "" : "no-reports-in-profile"
}`}
>
{reports.results.length ? (
<table>
<thead>
<tr>
{params.map((p) => (
<td key={p.param}>
{p.handleClick ? (
<button onClick={p.handleClick}>
{p.param}{" "}
<Image src={arrows} alt="Arrows Icon" />
</button>
) : (
p.param
)}
</td>
))}
</tr>
</thead>
<tbody>
{reports.results.map((report) => (
<tr key={report.id}>
<td id="my-report-date">
{sliceDate(report.created_at)}
</td>
<td id="my-report-location">
{report.status === 2 ? (
<Link href={`/report/${report.id}`}>
{report.location[0].address}
</Link>
) : (
report.location[0].address
)}
</td>
<td
id="my-report-status"
style={{
color: `${REPORT_STATUS_COLORS[report.status]}`,
}}
>
{REPORT_STATUS[report.status]}
</td>
<td id="my-report-reviews">
{report.count_reviews}
</td>
<td id="my-report-likes">{report.total_likes}</td>
</tr>
))}
</tbody>
</table>
) : (
<p className="profile-table__message">
Вы пока не оставили ни одного обращения.
</p>
)}
</div>
<Pagination
activePage={activePage}
setActivePage={setActivePage}
count={reports.count as number}
prev={reports.previous}
next={reports.next}
current_count={reports.results.length}
limit={8}
/>
<Link id="my-reports-link" href="/create-report">
Написать обращение
</Link>
</div>
);
};
export default ProfileTable;
@@ -0,0 +1,6 @@
export const sliceDate = (date: string) => {
return `${date.slice(8, 10)}.${date.slice(5, 7)}.${date.slice(
0,
4
)}`;
};
@@ -0,0 +1,106 @@
import { apiInstance } from "@/shared/config/apiConfig";
import { IFetch } from "@/shared/types/fetch-type";
import {
IMyReports,
IMyReportsList,
} from "@/shared/types/my-reports";
import { AxiosError } from "axios";
import { create } from "zustand";
const filterCategories: Record<string, string> = {
count_reviews: "count_reviews",
total_likes: "total_likes",
};
interface IProfileReportsStore extends IFetch {
data: IMyReportsList;
getMyReports: (
filter: { option: string; toggle: boolean },
page: number,
access_token: string
) => void;
}
export const useProfileReportsStore = create<IProfileReportsStore>(
(set) => ({
isLoading: false,
error: "",
data: {
count: 0,
previous: null,
next: null,
results: [],
},
getMyReports: async (
filter: {
option: string;
toggle: boolean;
},
page: number,
access_token: string
) => {
try {
const Authorization = `Bearer ${access_token}`;
const config = {
headers: {
Authorization,
},
};
set({ isLoading: true });
const res = await apiInstance.get<IMyReportsList>(
`/users/reports/?page=${page}`,
config
);
let data = res.data;
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 === 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 });
} catch (error: unknown) {
if (error instanceof AxiosError) {
set({ error: error.message });
} else {
set({ error: "an error ocured" });
}
} finally {
set({ isLoading: false });
}
},
})
);
@@ -0,0 +1,121 @@
@import "@/shared/ui/variables.scss";
.statistics-table {
position: relative;
&__popup {
width: 123px;
position: absolute;
top: 58%;
left: 2%;
display: flex;
flex-direction: column;
background-color: #fff;
border-radius: 8px;
border: 1px solid rgb(255, 255, 255);
box-shadow: 0px 4px 6px -2px rgba(16, 24, 40, 0.03),
0px 12px 16px -4px rgba(16, 24, 40, 0.08);
button {
padding: 10px 14px;
display: flex;
align-items: center;
font-size: 14px;
font-weight: 500;
line-height: 24px;
color: $gray-900;
}
button:hover {
background-color: #f5f5f5;
}
&-current {
background-color: #f5f5f5;
}
}
&__wrapper {
border: 1px solid rgb(213, 213, 213);
border-radius: 12px;
overflow: hidden;
overflow-x: auto;
&::-webkit-scrollbar {
display: none;
}
table {
width: 100%;
thead {
width: 100%;
padding: 0 20px;
height: 76px;
display: flex;
background-color: rgb(244, 244, 244);
align-items: center;
tr {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 100px 167px 186px 188px 263px 170px 151px;
align-items: center;
td {
display: flex;
align-items: center;
height: 100%;
background-color: rgb(244, 244, 244);
}
td,
button {
font-size: 14px;
font-weight: 500;
line-height: 18px;
color: rgb(102, 112, 133);
}
button {
display: flex;
align-items: center;
}
}
}
tbody {
padding: 0 20px;
tr {
display: grid;
grid-template-columns: 100px 167px 186px 188px 263px 170px 151px;
align-items: center;
width: 100%;
height: 80px;
border-bottom: 1px solid rgb(241, 244, 249);
td {
font-size: 20px;
font-weight: 500;
line-height: 20px;
color: rgb(102, 112, 133);
}
#statistics-table-stat-name {
color: black;
}
}
#statistics-table__no-data-warning {
grid-template-columns: 1fr;
justify-content: center;
td {
text-align: center;
}
}
}
}
}
}
@@ -0,0 +1,258 @@
"use client";
import "./StatisticsTable.scss";
import { useStatisticsStore } from "./statistics.store";
import { useShallow } from "zustand/react/shallow";
import SearchForm from "@/features/SearchForm/SearchForm";
import chevron_down from "./icons/chevron-down.svg";
import arrows from "@/shared/icons/arrows.svg";
import Image from "next/image";
import { useEffect, useState } from "react";
import { useDebounce } from "use-debounce";
import { useRouter } from "@/shared/config/navigation";
interface IStatisticsTableProps {
searchParams: {
["поиск-населенного-пункта"]: string;
};
}
const StatisticsTable: React.FC<IStatisticsTableProps> = ({
searchParams,
}: IStatisticsTableProps) => {
const router = useRouter();
const [location, setLocation] = useState<string>("city");
const [queryStatistics, setQueryStatistics] = useState<string>(
searchParams["поиск-населенного-пункта"] || ""
);
const [query] = useDebounce(queryStatistics, 500);
const {
error,
isLoading,
getStatistics,
data: statistics,
} = useStatisticsStore(useShallow((state) => state));
const [filter, setFilter] = useState({
option: "broken_road",
toggle: false,
});
const [openPopup, setOpenPopup] = useState<boolean>(false);
const handleSubmit = () => {};
const params = [
{
param: "Добавлено дорог",
async handleClick() {
if (filter.option !== "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: "Локальных дефектов",
async handleClick() {
if (filter.option !== "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: "Очагов аварийности",
async handleClick() {
if (filter.option !== "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: "Локальных дефектов исправлено",
async handleClick() {
if (filter.option !== "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: "В планах ремонта",
async handleClick() {
if (filter.option !== "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: "Отремонтировано",
async handleClick() {
if (filter.option !== "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) => {
setLocation(location);
getStatistics(location, filter, query);
console.error("Error fetching statistics:", error);
};
useEffect(() => {
getStatistics(location, filter, query);
router.push(`/statistics?поиск-населенного-пункта=${query}`);
}, [query]);
return (
<div className="statistics-table">
<SearchForm
onChange={(e) => setQueryStatistics(e.target.value)}
value={queryStatistics}
placeholder="Введите населенный пункт"
style={{ width: "100%" }}
handleSubmit={handleSubmit}
/>
{openPopup && (
<div className="statistics-table__popup">
<button
className={
location === "state"
? "statistics-table__popup-current"
: ""
}
onClick={() => getStatsByLocation("state")}
>
Область
</button>
<button
className={
location === "city"
? "statistics-table__popup-current"
: ""
}
onClick={() => getStatsByLocation("city")}
>
Город
</button>
<button
className={
location === "village"
? "statistics-table__popup-current"
: ""
}
onClick={() => getStatsByLocation("village")}
>
Деревня
</button>
</div>
)}
<div className="statistics-table__wrapper">
<table>
<thead>
<tr>
<td>
<button onClick={() => setOpenPopup((prev) => !prev)}>
Город
<Image src={chevron_down} alt=" Chevron Icon" />
</button>
</td>
{params.map((param) => (
<td key={param.param}>
<button onClick={param.handleClick}>
{param.param}
<Image src={arrows} alt=" Arrows Icon" />
</button>
</td>
))}
</tr>
</thead>
<tbody>
{statistics.length ? (
statistics.map((stat) => (
<tr key={stat.name}>
<td id="statistics-table-stat-name">{stat.name}</td>
<td>{stat.broken_road_1}</td>
<td>{stat.local_defect_3}</td>
<td>{stat.hotbed_of_accidents_2}</td>
<td>{stat.local_defect_fixed_6}</td>
<td>{stat.repair_plans_4}</td>
<td>{stat.repaired_5}</td>
</tr>
))
) : (
<tr id="statistics-table__no-data-warning">
<td>
{error
? error
: "Oops, looks like there is no data"}
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
);
};
export default StatisticsTable;
@@ -0,0 +1,7 @@
<svg width="9.000000" height="6.000000" viewBox="0 0 9 6" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<desc>
Created with Pixso.
</desc>
<defs/>
<path id="Vector" d="M8.25 0L0.75 0C0.609375 0 0.46875 0.0410156 0.347656 0.117188C0.226562 0.193359 0.132812 0.302734 0.0703125 0.431641C0.0117188 0.561523 -0.0117188 0.705078 0.0078125 0.84668C0.0234375 0.988281 0.0820312 1.12109 0.175781 1.23047L3.92578 5.73047C3.99609 5.81543 4.08203 5.88281 4.18359 5.92969C4.28125 5.97656 4.39062 6 4.5 6C4.60938 6 4.71875 5.97656 4.81641 5.92969C4.91797 5.88281 5.00781 5.81543 5.07812 5.73047L8.82812 1.23047C8.91797 1.12109 8.97656 0.988281 8.99609 0.84668C9.01172 0.705078 8.99219 0.561523 8.92969 0.431641C8.87109 0.302734 8.77344 0.193359 8.65234 0.117188C8.53125 0.0410156 8.39453 0 8.25 0ZM4.5 4.07812L2.35156 1.5L6.64844 1.5L4.5 4.07812Z" fill="#667085" fill-opacity="1.000000" fill-rule="nonzero"/>
</svg>

After

Width:  |  Height:  |  Size: 955 B

@@ -0,0 +1,76 @@
import { apiInstance } from "@/shared/config/apiConfig";
import { IFetch } from "@/shared/types/fetch-type";
import { IList } from "@/shared/types/list-type";
import { IStatistics } from "@/shared/types/statistics-type";
import { AxiosError } from "axios";
import { create } from "zustand";
const filterCategories: Record<string, string> = {
broken_road_1: "broken_road_1",
hotbed_of_accidents_2: "hotbed_of_accidents_2",
local_defect_3: "local_defect_3",
repair_plans_4: "repair_plans_4",
repaired_5: "repaired_5",
local_defect_fixed_6: "local_defect_fixed_6",
};
interface IStatisticsStore extends IFetch {
data: IStatistics[];
getStatistics: (
endpoint: string,
filter: { option: string; toggle: boolean },
query: string
) => void;
}
export const useStatisticsStore = create<IStatisticsStore>((set) => ({
isLoading: false,
error: "",
data: [],
getStatistics: async (
endpoint: string,
filter: { option: string; toggle: boolean },
query: string = ""
) => {
try {
set({ isLoading: true });
const response = await apiInstance.get<IStatistics[]>(
`/report/${endpoint}/stats`
);
let data = response.data.filter((loc) =>
loc.name.toLowerCase().includes(query.toLowerCase())
);
if (
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 });
} catch (error: unknown) {
if (error instanceof AxiosError) {
set({ error: error.message });
} else {
set({ error: "an error ocured" });
}
} finally {
set({ isLoading: false });
}
},
}));
@@ -0,0 +1,73 @@
.volunteers-table {
overflow: hidden;
overflow-x: auto;
&::-webkit-scrollbar {
display: none;
}
border: 1px solid rgb(213, 213, 213);
border-radius: 6px;
table {
width: 100%;
thead {
width: 100%;
padding: 0 20px;
height: 76px;
display: flex;
background-color: rgb(244, 244, 244);
align-items: center;
tr {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 100px 320px 210px 213px 222px 92px;
align-items: center;
td {
display: flex;
align-items: center;
height: 100%;
background-color: rgb(244, 244, 244);
}
td,
button {
font-size: 16px;
font-weight: 500;
line-height: 18px;
color: rgb(102, 112, 133);
}
button {
display: flex;
align-items: center;
}
}
}
tbody {
padding: 0 20px;
tr {
display: grid;
grid-template-columns: 100px 320px 210px 213px 222px 92px;
align-items: center;
width: 100%;
height: 80px;
border-bottom: 1px solid rgb(241, 244, 249);
td {
font-size: 20px;
font-weight: 500;
line-height: 20px;
}
#volunteers-user-cell {
color: rgb(72, 159, 225);
}
}
}
}
}
@@ -0,0 +1,139 @@
"use client";
import "./VolunteersTable.scss";
import Image from "next/image";
import arrows from "@/shared/icons/arrows.svg";
import { useEffect, useState } from "react";
import { useVolunteersStore } from "./volunteers.store";
const VolunteersTable = () => {
const { data, isLoading, error, getVolunteers } =
useVolunteersStore();
const [filter, setFilter] = useState({
option: "report_count",
toggle: true,
});
const params = [
{ param: "№" },
{ param: "Активист" },
{
param: "Добавлено дорог",
handleClick() {
if (filter.option !== "report_count") {
return setFilter({
option: "report_count",
toggle: false,
});
}
setFilter((prev) => {
return { option: "report_count", toggle: !prev.toggle };
});
getVolunteers(filter);
},
},
{
param: "Получено голосов",
handleClick() {
if (filter.option !== "likes_given_count") {
return setFilter({
option: "likes_given_count",
toggle: false,
});
}
setFilter((prev) => {
return {
option: "likes_given_count",
toggle: !prev.toggle,
};
});
getVolunteers(filter);
},
},
{
param: "Оставлено голосов",
handleClick() {
if (filter.option !== "likes_received_count") {
return setFilter({
option: "likes_received_count",
toggle: false,
});
}
setFilter((prev) => {
return {
option: "likes_received_count",
toggle: !prev.toggle,
};
});
getVolunteers(filter);
},
},
{
param: "Рейтинг",
handleClick() {
if (filter.option !== "average_rating") {
return setFilter({
option: "average_rating",
toggle: false,
});
}
setFilter((prev) => {
return { option: "average_rating", toggle: !prev.toggle };
});
getVolunteers(filter);
},
},
];
const hideEmail = (email: string) => {
return `${email.slice(0, 3)}*****@****.com`;
};
useEffect(() => {
getVolunteers(filter);
}, []);
return (
<div className="volunteers-table">
<table>
<thead>
<tr>
{params.map((param) => (
<td key={param.param}>
{param.handleClick ? (
<button onClick={param.handleClick}>
{param.param}
<Image src={arrows} alt="Arrows Icon" />
</button>
) : (
<>{param.param}</>
)}
</td>
))}
</tr>
</thead>
<tbody>
{data.map((user, index) => (
<tr key={user.user_id}>
<td>{index + 1}</td>
<td id="volunteers-user-cell">
{hideEmail(user.username)}
</td>
<td>{user.report_count}</td>
<td>{user.likes_received_count}</td>
<td>{user.likes_given_count}</td>
<td>{user.average_rating}</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default VolunteersTable;
@@ -0,0 +1,71 @@
import { apiInstance } from "@/shared/config/apiConfig";
import { IFetch } from "@/shared/types/fetch-type";
import { IList } from "@/shared/types/list-type";
import { IStatistics } from "@/shared/types/statistics-type";
import { IUserRatings } from "@/shared/types/user-rating-type";
import { AxiosError } from "axios";
import { create } from "zustand";
const filterCategories: Record<string, string> = {
report_count: "report_count",
likes_given_count: "likes_given_count",
likes_received_count: "likes_received_count",
average_rating: "average_rating",
};
interface IVolunteersStore extends IFetch {
data: IUserRatings[];
getVolunteers: (filter: {
option: string;
toggle: boolean;
}) => void;
}
export const useVolunteersStore = create<IVolunteersStore>((set) => ({
isLoading: false,
error: "",
data: [],
getVolunteers: async (filter: {
option: string;
toggle: boolean;
}) => {
try {
set({ isLoading: true });
const response = await apiInstance.get<IUserRatings[]>(
`/report/user_ratings/`
);
let data = response.data;
if (
filter.option === filterCategories[filter.option] &&
filter.toggle === false
) {
data = data.sort((a, b) => {
const optionKey = filter.option as keyof IUserRatings;
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 IUserRatings;
return (Number(a[optionKey]) -
Number(b[optionKey])) as number;
});
}
set({ data: data });
} catch (error: unknown) {
if (error instanceof AxiosError) {
set({ error: error.message });
} else {
set({ error: "an error ocured" });
}
} finally {
set({ isLoading: false });
}
},
}));