diff --git a/app/api/utils.ts b/app/api/utils.ts index b7c1e8f..aa03c14 100644 --- a/app/api/utils.ts +++ b/app/api/utils.ts @@ -288,13 +288,6 @@ export function minutesToTime(min: number) { if (minutes > 0) return minuteDisplay; } -const StatusList: Record = { - last: null, - finished: 1, - ongoing: 2, - announce: 3, -}; - export const FilterCountry = ["Япония", "Китай", "Южная Корея"]; export const FilterCategoryIdToString: Record = { 1: "Сериал", diff --git a/app/components/Discovery/Modal/FiltersGenreModal.tsx b/app/components/Discovery/Modal/FiltersGenreModal.tsx new file mode 100644 index 0000000..98ad180 --- /dev/null +++ b/app/components/Discovery/Modal/FiltersGenreModal.tsx @@ -0,0 +1,124 @@ +"use client"; + +import { FilterGenre } from "#/api/utils"; +import { + Button, + Checkbox, + Label, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + ToggleSwitch, +} from "flowbite-react"; +import { useEffect, useState } from "react"; + +type Props = { + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + genres: string[]; + exclusionMode: boolean; + save: (genres, exclusionMode) => void; +}; +export const FiltersGenreModal = ({ + isOpen, + setIsOpen, + genres, + exclusionMode, + save, +}: Props) => { + const [newGenres, setNewGenres] = useState(genres); + const [newExclusionMode, setNewExclusionMode] = useState(exclusionMode); + + function toggleGenre(string: string) { + if (newGenres.includes(string)) { + setNewGenres(newGenres.filter((genre) => genre != string)); + } else { + setNewGenres([...newGenres, string]); + } + } + + useEffect(() => { + setNewGenres(genres); + setNewExclusionMode(exclusionMode); + }, [genres, exclusionMode]); + + return ( + setIsOpen(false)} dismissible> + Жанры + +
+ {Object.entries(FilterGenre).map(([key, value]) => { + return ( +
+

{value.name}

+ {value.genres.map((genre) => { + return ( +
+ toggleGenre(genre)} + checked={newGenres.includes(genre)} + color="blue" + /> + +
+ ); + })} +
+ ); + })} +
+
+ +
+
+
+

Режим исключения

+

+ Фильтр будет искать релизы не содержащие ни один из указанных + выше жанров +

+
+ setNewExclusionMode(!newExclusionMode)} + checked={newExclusionMode} + /> +
+
+ + +
+
+
+
+ ); +}; diff --git a/app/components/Discovery/Modal/FiltersListExcludeModal.tsx b/app/components/Discovery/Modal/FiltersListExcludeModal.tsx new file mode 100644 index 0000000..3ea2229 --- /dev/null +++ b/app/components/Discovery/Modal/FiltersListExcludeModal.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { FilterProfileListIdToString } from "#/api/utils"; +import { + Button, + Checkbox, + Label, + Modal, + ModalBody, + ModalFooter, + ModalHeader +} from "flowbite-react"; +import { useEffect, useState } from "react"; + +type Props = { + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + lists: number[]; + setLists: (lists: number[]) => void; +}; + +export const FiltersListExcludeModal = ({ + isOpen, + setIsOpen, + lists, + setLists, +}: Props) => { + const [newList, setNewList] = useState(lists); + + function toggleList(number: number) { + if (newList.includes(number)) { + setNewList(newList.filter((list) => list != number)); + } else { + setNewList([...newList, number]); + } + } + + useEffect(() => { + setNewList(lists); + }, [lists]); + + return ( + setIsOpen(false)} dismissible> + Выберите списки + + {Object.entries(FilterProfileListIdToString).map(([key, value]) => { + return ( +
+ toggleList(Number(key))} + checked={newList.includes(Number(key))} + color="blue" + /> + +
+ ); + })} +
+ + + + +
+ ); +} diff --git a/app/components/Discovery/Modal/FiltersModal.tsx b/app/components/Discovery/Modal/FiltersModal.tsx new file mode 100644 index 0000000..56380f2 --- /dev/null +++ b/app/components/Discovery/Modal/FiltersModal.tsx @@ -0,0 +1,172 @@ +"use client"; + +import { + Filter, + FilterCategoryIdToString, + FilterCountry, + FilterDefault, + FilterProfileListIdToString, +} from "#/api/utils"; +import { + Button, + Dropdown, + DropdownItem, + Modal, + ModalBody, + ModalFooter, + ModalHeader, +} from "flowbite-react"; +import { useState } from "react"; +import { FiltersGenreModal } from "./FiltersGenreModal"; +import { useUserStore } from "#/store/auth"; +import { FiltersListExcludeModal } from "./FiltersListExcludeModal"; + +type ModalProps = { + isOpen: boolean; + setIsOpen: (value: boolean) => void; + filter?: Filter; +}; + +export const FiltersModal = ({ isOpen, setIsOpen, filter }: ModalProps) => { + const userStore = useUserStore(); + + const [newFilter, setNewFilter] = useState(filter || FilterDefault); + const [isGenreModalOpen, setIsGenreModalOpen] = useState(false); + const [isListExcludeModalOpen, setIsListExcludeModalOpen] = useState(false); + + function saveGenres(genres, is_genres_exclude_mode_enabled) { + setNewFilter({ ...newFilter, genres, is_genres_exclude_mode_enabled }); + } + + return ( + <> + setIsOpen(false)} + size="4xl" + dismissible + > + Фильтр + +
+
+

Страна

+ + setNewFilter({ ...newFilter, country: null })} + > + Неважно + + {FilterCountry.map((item) => { + return ( + + setNewFilter({ ...newFilter, country: item }) + } + > + {item} + + ); + })} + +
+
+

Категория

+ + + setNewFilter({ ...newFilter, category_id: null }) + } + > + Неважно + + {Object.entries(FilterCategoryIdToString).map( + ([key, value]) => { + return ( + + setNewFilter({ + ...newFilter, + category_id: Number(key), + }) + } + > + {value} + + ); + } + )} + +
+
+

Жанры

+ +

+ Будет искать релизы, содержащие каждый из указанных жанров. + Рекомендуется выбирать не более 3 жанров +

+
+ {userStore.isAuth ?
+

Исключить закладки

+ +

+ Исключит из выдачи релизы, входящие в указанные закладки +

+
: ""} +
+
+ +
+ + + setNewFilter({ ...newFilter, profile_list_exclusions }) + } + /> + + ); +}; diff --git a/app/components/Navbar/NavBarMobile.tsx b/app/components/Navbar/NavBarMobile.tsx index 3937c86..6108483 100644 --- a/app/components/Navbar/NavBarMobile.tsx +++ b/app/components/Navbar/NavBarMobile.tsx @@ -69,7 +69,7 @@ export const NavBarMobile = (props: { setIsSettingModalOpen: any }) => {