diff --git a/app/api/config.ts b/app/api/config.ts
index d3a25d0..a4fc159 100644
--- a/app/api/config.ts
+++ b/app/api/config.ts
@@ -18,6 +18,7 @@ export const ENDPOINTS = {
bookmark: `${API_PREFIX}/profile/list`,
history: `${API_PREFIX}/history`,
favorite: `${API_PREFIX}/favorite`,
+ blocklist: `${API_PREFIX}/profile/blocklist`,
settings: {
my: `${API_PREFIX}/profile/preference/my`,
login: {
diff --git a/app/components/Profile/Profile.BlockedUsersModal.tsx b/app/components/Profile/Profile.BlockedUsersModal.tsx
new file mode 100644
index 0000000..d127a87
--- /dev/null
+++ b/app/components/Profile/Profile.BlockedUsersModal.tsx
@@ -0,0 +1,177 @@
+import { ENDPOINTS } from "#/api/config";
+import { tryCatchAPI, unixToDate, useSWRfetcher } from "#/api/utils";
+import { Avatar, Button, Modal, useThemeMode } from "flowbite-react";
+import { useCallback, useEffect, useState } from "react";
+import useSWRInfinite from "swr/infinite";
+import { Spinner } from "../Spinner/Spinner";
+import { toast } from "react-toastify";
+
+export const ProfileBlockedUsersModal = (props: {
+ isOpen: boolean;
+ setIsOpen: (isOpen: boolean) => void;
+ token: string;
+ profile_id: number;
+}) => {
+ const [currentRef, setCurrentRef] = useState(null);
+ const theme = useThemeMode();
+ const [actionsDisabled, setActionsDisabled] = useState(false);
+ const [unblockedUsers, setUnblockedUsers] = useState([]);
+
+ const modalRef = useCallback((ref) => {
+ setCurrentRef(ref);
+ }, []);
+
+ const getKey = (pageIndex: number, previousPageData: any) => {
+ if (previousPageData && !previousPageData.content.length) return null;
+ let url = `${ENDPOINTS.user.blocklist}/all/${pageIndex}?token=${props.token}`;
+ return url;
+ };
+
+ const { data, error, isLoading, size, setSize } = useSWRInfinite(
+ getKey,
+ useSWRfetcher,
+ { initialSize: 2 }
+ );
+
+ async function _addToBlocklist(profile_id) {
+ setActionsDisabled(true);
+
+ const tid = toast.loading(
+ unblockedUsers.includes(profile_id) ?
+ "Блокируем пользователя..."
+ : "Разблокируем пользователя...",
+ {
+ position: "bottom-center",
+ hideProgressBar: true,
+ closeOnClick: false,
+ pauseOnHover: false,
+ draggable: false,
+ theme: theme.mode == "light" ? "light" : "dark",
+ }
+ );
+
+ let url = `${ENDPOINTS.user.blocklist}`;
+ unblockedUsers.includes(profile_id) ?
+ (url += "/add/")
+ : (url += "/remove/");
+ url += `${profile_id}?token=${props.token}`;
+
+ const { data, error } = await tryCatchAPI(fetch(url));
+ if (error) {
+ toast.update(tid, {
+ render:
+ unblockedUsers.includes(profile_id) ?
+ "Ошибка блокировки"
+ : "Ошибка разблокировки",
+ type: "error",
+ autoClose: 2500,
+ isLoading: false,
+ closeOnClick: true,
+ draggable: true,
+ });
+ setActionsDisabled(false);
+ return;
+ }
+
+ toast.update(tid, {
+ render:
+ unblockedUsers.includes(profile_id) ?
+ "Пользователь заблокирован"
+ : "Пользователь разблокирован",
+ type: "success",
+ autoClose: 2500,
+ isLoading: false,
+ closeOnClick: true,
+ draggable: true,
+ });
+
+ if (unblockedUsers.includes(profile_id)) {
+ setUnblockedUsers((prev) => {
+ return prev.filter((item) => item !== profile_id);
+ });
+ } else {
+ setUnblockedUsers((prev) => {
+ return [...prev, profile_id];
+ });
+ }
+ setActionsDisabled(false);
+ }
+
+ const [content, setContent] = useState([]);
+ useEffect(() => {
+ if (data) {
+ let allReleases = [];
+ for (let i = 0; i < data.length; i++) {
+ allReleases.push(...data[i].content);
+ }
+ setContent(allReleases);
+ }
+ }, [data]);
+
+ const [scrollPosition, setScrollPosition] = useState(0);
+ function handleScroll() {
+ const height = currentRef.scrollHeight - currentRef.clientHeight;
+ const windowScroll = currentRef.scrollTop;
+ const scrolled = (windowScroll / height) * 100;
+ setScrollPosition(Math.floor(scrolled));
+ }
+
+ useEffect(() => {
+ if (scrollPosition >= 95 && scrollPosition <= 96) {
+ setSize(size + 1);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [scrollPosition]);
+ return (
+ <>
+ props.setIsOpen(false)}
+ size={"7xl"}
+ >
+ Заблокированные пользователи
+
+ {content && content.length > 0 ?
+ content.map((user) => {
+ return (
+
+
+
+
+
{user.login}
+
Заблокирован: {unixToDate(user.added_date, "full")}
+
+
+
+
+ );
+ })
+ : "Нет заблокированных пользователей"}
+ {isLoading &&
}
+
+
+ >
+ );
+};
diff --git a/app/components/Profile/Profile.EditModal.tsx b/app/components/Profile/Profile.EditModal.tsx
index 897f3a7..3b01f0b 100644
--- a/app/components/Profile/Profile.EditModal.tsx
+++ b/app/components/Profile/Profile.EditModal.tsx
@@ -14,6 +14,7 @@ import { useSWRConfig } from "swr";
import { useUserStore } from "#/store/auth";
import { ProfileEditLoginModal } from "./Profile.EditLoginModal";
import { toast } from "react-toastify";
+import { ProfileBlockedUsersModal } from "./Profile.BlockedUsersModal";
export const ProfileEditModal = (props: {
isOpen: boolean;
@@ -25,6 +26,7 @@ export const ProfileEditModal = (props: {
const [statusModalOpen, setStatusModalOpen] = useState(false);
const [socialModalOpen, setSocialModalOpen] = useState(false);
const [loginModalOpen, setLoginModalOpen] = useState(false);
+ const [blockedModalOpen, setBlockedModalOpen] = useState(false);
const [privacyModalSetting, setPrivacyModalSetting] = useState("none");
const [privacySettings, setPrivacySettings] = useState({
privacy_stats: 9,
@@ -355,13 +357,18 @@ export const ProfileEditModal = (props: {
}
- {/*
@@ -431,6 +438,12 @@ export const ProfileEditModal = (props: {
setLogin={setLogin}
profile_id={props.profile_id}
/>
+
>
: ""}
>