mirror of
https://github.com/Radiquum/AniX.git
synced 2025-05-03 03:19:41 +05:00
feat(deploy): allow deploying on deta.space
- **BREAKING CHANGE**: Api url now /api/v1 \n **Fix**: Frontend build. \n **Fix**: errors about unknown styles BREAKING CHANGE:
This commit is contained in:
parent
d85ce45989
commit
d97ad7dbfe
19 changed files with 504 additions and 412 deletions
|
@ -56,8 +56,8 @@ export const App = (props) => {
|
|||
|
||||
return (
|
||||
<body>
|
||||
<div style={{ display: "flex", "flex-direction": "row" }}>
|
||||
<div style={{ "padding-inline-start": "0" }}>
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<div style={{ paddingInlineStart: "0" }}>
|
||||
<NavigationRail
|
||||
colorPicker={colorPicker}
|
||||
settingsPopup={settingsPopup}
|
||||
|
@ -89,7 +89,7 @@ export const App = (props) => {
|
|||
>
|
||||
<div
|
||||
className="border round padding"
|
||||
style={{ height: "calc(100vh - 2rem)", "overflow-y": "scroll" }}
|
||||
style={{ height: "calc(100vh - 2rem)", overflowY: "scroll" }}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export const API_URL = "/api";
|
||||
export let API_URL = "/api/v1";
|
||||
|
||||
export const endpoints = {
|
||||
index: {
|
||||
|
|
|
@ -1,122 +1,11 @@
|
|||
"use client";
|
||||
|
||||
import { getData } from "@/app/api/api-utils";
|
||||
import { endpoints } from "@/app/api/config";
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import ReleasesOverview from "@/app/components/ReleasesOverview/ReleasesOverview";
|
||||
import { useUserStore } from "@/app/store/user-store";
|
||||
import { LogInNeeded } from "@/app/components/LogInNeeded/LogInNeeded";
|
||||
import BookmarksPage from "../components/Pages/BookmarksPage";
|
||||
|
||||
export default function Bookmarks() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const [list, setList] = useState();
|
||||
const [releases, setReleases] = useState();
|
||||
const [page, setPage] = useState(0);
|
||||
|
||||
const [isNextPage, setIsNextPage] = useState(true);
|
||||
|
||||
const searchParams = useSearchParams();
|
||||
const createQueryString = useCallback(
|
||||
(name, value) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set(name, value);
|
||||
|
||||
return params.toString();
|
||||
},
|
||||
[searchParams],
|
||||
);
|
||||
|
||||
// set list on initial page load
|
||||
useEffect(() => {
|
||||
const query = searchParams.get("list");
|
||||
if (query) {
|
||||
setList(query);
|
||||
} else {
|
||||
setList("watching");
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function fetchData(list, page = 0) {
|
||||
if (userStore.token) {
|
||||
const url = `${endpoints.user.bookmarks[list]}?page=${page}&token=${userStore.token}`;
|
||||
const data = await getData(url);
|
||||
|
||||
if (data.content.length < 25) {
|
||||
setIsNextPage(false);
|
||||
} else {
|
||||
setIsNextPage(true);
|
||||
}
|
||||
|
||||
// Handle initial load (page 0) or subsequent pagination
|
||||
if (page === 0) {
|
||||
setReleases(data.content);
|
||||
} else {
|
||||
setReleases([...releases, ...data.content]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (list) {
|
||||
router.push(pathname + "?" + createQueryString("list", list));
|
||||
setReleases(null);
|
||||
setPage(0);
|
||||
fetchData(list); // Call fetchData here
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [list, userStore.token]);
|
||||
|
||||
useEffect(() => {
|
||||
if (list && releases) {
|
||||
fetchData(list, page); // Use fetchData for pagination
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [page]);
|
||||
|
||||
const chips = [
|
||||
{
|
||||
title: "Смотрю",
|
||||
list: "watching",
|
||||
},
|
||||
{
|
||||
title: "В планах",
|
||||
list: "planned",
|
||||
},
|
||||
{
|
||||
title: "Просмотрено",
|
||||
list: "watched",
|
||||
},
|
||||
{
|
||||
title: "Отложено",
|
||||
list: "delayed",
|
||||
},
|
||||
{
|
||||
title: "Заброшено",
|
||||
list: "abandoned",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{!userStore.isAuth ? (
|
||||
<LogInNeeded />
|
||||
) : (
|
||||
<ReleasesOverview
|
||||
chips={chips}
|
||||
setList={setList}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
list={list}
|
||||
releases={releases}
|
||||
isNextPage={isNextPage}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
return <>{!userStore.isAuth ? <LogInNeeded /> : <BookmarksPage />}</>;
|
||||
}
|
||||
|
|
|
@ -47,13 +47,13 @@ export const NavigationRail = (props) => {
|
|||
<nav
|
||||
className="left border round margin"
|
||||
style={{
|
||||
"inline-size": "unset",
|
||||
inlineSize: "unset",
|
||||
position: "sticky",
|
||||
top: "1rem",
|
||||
left: "0",
|
||||
"min-height": "calc(100vh - (var(---margin) * 2))",
|
||||
"background-color": "var(--surface)",
|
||||
"padding-block": "1rem",
|
||||
minHeight: "calc(100vh - (var(---margin) * 2))",
|
||||
backgroundColor: "var(--surface)",
|
||||
paddingBlock: "1rem",
|
||||
}}
|
||||
>
|
||||
{userStore.isAuth && userStore.user ? (
|
||||
|
|
117
frontend/app/components/Pages/BookmarksPage.jsx
Normal file
117
frontend/app/components/Pages/BookmarksPage.jsx
Normal file
|
@ -0,0 +1,117 @@
|
|||
"use client";
|
||||
|
||||
import { getData } from "@/app/api/api-utils";
|
||||
import { endpoints } from "@/app/api/config";
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import ReleasesOverview from "@/app/components/ReleasesOverview/ReleasesOverview";
|
||||
import { useUserStore } from "@/app/store/user-store";
|
||||
|
||||
export default function BookmarksPage() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const [list, setList] = useState();
|
||||
const [releases, setReleases] = useState();
|
||||
const [page, setPage] = useState(0);
|
||||
|
||||
const [isNextPage, setIsNextPage] = useState(true);
|
||||
|
||||
const searchParams = useSearchParams();
|
||||
const createQueryString = useCallback(
|
||||
(name, value) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set(name, value);
|
||||
|
||||
return params.toString();
|
||||
},
|
||||
[searchParams],
|
||||
);
|
||||
|
||||
// set list on initial page load
|
||||
useEffect(() => {
|
||||
const query = searchParams.get("list");
|
||||
if (query) {
|
||||
setList(query);
|
||||
} else {
|
||||
setList("watching");
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function fetchData(list, page = 0) {
|
||||
if (userStore.token) {
|
||||
const url = `${endpoints.user.bookmarks[list]}?page=${page}&token=${userStore.token}`;
|
||||
const data = await getData(url);
|
||||
|
||||
if (data.content.length < 25) {
|
||||
setIsNextPage(false);
|
||||
} else {
|
||||
setIsNextPage(true);
|
||||
}
|
||||
|
||||
// Handle initial load (page 0) or subsequent pagination
|
||||
if (page === 0) {
|
||||
setReleases(data.content);
|
||||
} else {
|
||||
setReleases([...releases, ...data.content]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (list) {
|
||||
router.push(pathname + "?" + createQueryString("list", list));
|
||||
setReleases(null);
|
||||
setPage(0);
|
||||
fetchData(list); // Call fetchData here
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [list, userStore.token]);
|
||||
|
||||
useEffect(() => {
|
||||
if (list && releases) {
|
||||
fetchData(list, page); // Use fetchData for pagination
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [page]);
|
||||
|
||||
const chips = [
|
||||
{
|
||||
title: "Смотрю",
|
||||
list: "watching",
|
||||
},
|
||||
{
|
||||
title: "В планах",
|
||||
list: "planned",
|
||||
},
|
||||
{
|
||||
title: "Просмотрено",
|
||||
list: "watched",
|
||||
},
|
||||
{
|
||||
title: "Отложено",
|
||||
list: "delayed",
|
||||
},
|
||||
{
|
||||
title: "Заброшено",
|
||||
list: "abandoned",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<ReleasesOverview
|
||||
chips={chips}
|
||||
setList={setList}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
list={list}
|
||||
releases={releases}
|
||||
isNextPage={isNextPage}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
107
frontend/app/components/Pages/IndexPage.jsx
Normal file
107
frontend/app/components/Pages/IndexPage.jsx
Normal file
|
@ -0,0 +1,107 @@
|
|||
"use client";
|
||||
|
||||
import { getData } from "@/app/api/api-utils";
|
||||
import { endpoints } from "@/app/api/config";
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import ReleasesOverview from "@/app/components/ReleasesOverview/ReleasesOverview";
|
||||
|
||||
export default function IndexPage() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const [list, setList] = useState();
|
||||
const [releases, setReleases] = useState();
|
||||
const [page, setPage] = useState(0);
|
||||
|
||||
const [isNextPage, setIsNextPage] = useState(true);
|
||||
|
||||
const searchParams = useSearchParams();
|
||||
const createQueryString = useCallback(
|
||||
(name, value) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set(name, value);
|
||||
|
||||
return params.toString();
|
||||
},
|
||||
[searchParams],
|
||||
);
|
||||
|
||||
// set list on initial page load
|
||||
useEffect(() => {
|
||||
const query = searchParams.get("list");
|
||||
if (query) {
|
||||
setList(query);
|
||||
} else {
|
||||
setList("last");
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function fetchData(list, page = 0) {
|
||||
const url = `${endpoints.index[list]}?page=${page}`;
|
||||
const data = await getData(url);
|
||||
|
||||
if (data.content.length < 25) {
|
||||
setIsNextPage(false);
|
||||
} else {
|
||||
setIsNextPage(true);
|
||||
}
|
||||
|
||||
// Handle initial load (page 0) or subsequent pagination
|
||||
if (page === 0) {
|
||||
setReleases(data.content);
|
||||
} else {
|
||||
setReleases([...releases, ...data.content]);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (list) {
|
||||
router.push(pathname + "?" + createQueryString("list", list));
|
||||
setReleases(null);
|
||||
setPage(0);
|
||||
fetchData(list); // Call fetchData here
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [list]);
|
||||
|
||||
useEffect(() => {
|
||||
if (list && releases) {
|
||||
fetchData(list, page); // Use fetchData for pagination
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [page]);
|
||||
|
||||
const chips = [
|
||||
{
|
||||
title: "последнее",
|
||||
list: "last",
|
||||
},
|
||||
{
|
||||
title: "в эфире",
|
||||
list: "ongoing",
|
||||
},
|
||||
{
|
||||
title: "анонсировано",
|
||||
list: "announce",
|
||||
},
|
||||
{
|
||||
title: "завершено",
|
||||
list: "finished",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<ReleasesOverview
|
||||
chips={chips}
|
||||
setList={setList}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
list={list}
|
||||
releases={releases}
|
||||
isNextPage={isNextPage}
|
||||
/>
|
||||
);
|
||||
}
|
150
frontend/app/components/Pages/SearchPage.jsx
Normal file
150
frontend/app/components/Pages/SearchPage.jsx
Normal file
|
@ -0,0 +1,150 @@
|
|||
"use client";
|
||||
|
||||
import { getData } from "@/app/api/api-utils";
|
||||
import { endpoints } from "@/app/api/config";
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import ReleasesOverview from "@/app/components/ReleasesOverview/ReleasesOverview";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
function saveSearches(search) {
|
||||
localStorage.setItem("searches", search);
|
||||
}
|
||||
function getSearches() {
|
||||
return localStorage.getItem("searches");
|
||||
}
|
||||
|
||||
export default function SearchPage() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const [releases, setReleases] = useState();
|
||||
const [page, setPage] = useState(0);
|
||||
const [query, setQuery] = useState("");
|
||||
const [isNextPage, setIsNextPage] = useState(true);
|
||||
|
||||
const [searches, setSearches] = useState(JSON.parse(getSearches()));
|
||||
|
||||
const searchParams = useSearchParams();
|
||||
const createQueryString = useCallback(
|
||||
(name, value) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set(name, value);
|
||||
|
||||
return params.toString();
|
||||
},
|
||||
[searchParams],
|
||||
);
|
||||
|
||||
async function fetchData(query, page = 0) {
|
||||
const url = `${endpoints.search}?query=${query}&page=${page}`;
|
||||
const data = await getData(url);
|
||||
|
||||
if (data.content.length < 25) {
|
||||
setIsNextPage(false);
|
||||
} else {
|
||||
setIsNextPage(true);
|
||||
}
|
||||
|
||||
// Handle initial load (page 0) or subsequent pagination
|
||||
if (page === 0) {
|
||||
setReleases(data.content);
|
||||
} else {
|
||||
setReleases([...releases, ...data.content]);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const query = searchParams.get("query");
|
||||
if (query) {
|
||||
setQuery(query);
|
||||
fetchData(query, 0);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (releases) {
|
||||
fetchData(query, page); // Use fetchData for pagination
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [page]);
|
||||
|
||||
const handleInput = (e) => {
|
||||
setQuery(e.target.value);
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
if (query != "") {
|
||||
router.push(pathname + "?" + createQueryString("query", query));
|
||||
setReleases(null);
|
||||
setPage(0);
|
||||
fetchData(query);
|
||||
|
||||
// save searches and update search history
|
||||
if (!searches) {
|
||||
setSearches([query]);
|
||||
saveSearches(JSON.stringify([query]));
|
||||
} else {
|
||||
console.log(searches);
|
||||
if (!searches.find((element) => element == query)) {
|
||||
setSearches([query, ...searches.slice(0, 5)]);
|
||||
saveSearches(JSON.stringify([query, ...searches.slice(0, 5)]));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<form className="field large prefix round fill" onSubmit={handleSubmit}>
|
||||
<i className="front">search</i>
|
||||
<input name="query" onInput={handleInput} value={query} />
|
||||
<menu className="min" style={{ marginTop: "64px" }}>
|
||||
{searches
|
||||
? searches.map((item) => {
|
||||
return (
|
||||
<a
|
||||
key={item}
|
||||
onClick={() => {
|
||||
setQuery(item);
|
||||
}}
|
||||
className="row"
|
||||
>
|
||||
<i>history</i>
|
||||
<div>{item}</div>
|
||||
</a>
|
||||
);
|
||||
})
|
||||
: ""}
|
||||
</menu>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{releases ? (
|
||||
releases.length > 0 ? (
|
||||
<ReleasesOverview
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
releases={releases}
|
||||
isNextPage={isNextPage}
|
||||
/>
|
||||
) : (
|
||||
<div className="absolute padding primary center middle small-round">
|
||||
<i className="extra">search</i>
|
||||
<h5>Ничего не найдено.</h5>
|
||||
<p>Введите другой поисковой запрос.</p>
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<div className="absolute padding primary center middle small-round">
|
||||
<i className="extra">search</i>
|
||||
<h5>Здесь пока ничего нет.</h5>
|
||||
<p>Введите поисковой запрос для начала поиска.</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1,107 +1,14 @@
|
|||
"use client";
|
||||
|
||||
import { getData } from "./api/api-utils";
|
||||
import { endpoints } from "./api/config";
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import ReleasesOverview from "./components/ReleasesOverview/ReleasesOverview";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
const IndexPage = dynamic(() => import("./components/Pages/IndexPage"), {
|
||||
ssr: false,
|
||||
});
|
||||
export default function Home() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const [list, setList] = useState();
|
||||
const [releases, setReleases] = useState();
|
||||
const [page, setPage] = useState(0);
|
||||
|
||||
const [isNextPage, setIsNextPage] = useState(true);
|
||||
|
||||
const searchParams = useSearchParams();
|
||||
const createQueryString = useCallback(
|
||||
(name, value) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set(name, value);
|
||||
|
||||
return params.toString();
|
||||
},
|
||||
[searchParams],
|
||||
);
|
||||
|
||||
// set list on initial page load
|
||||
useEffect(() => {
|
||||
const query = searchParams.get("list");
|
||||
if (query) {
|
||||
setList(query);
|
||||
} else {
|
||||
setList("last");
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function fetchData(list, page = 0) {
|
||||
const url = `${endpoints.index[list]}?page=${page}`;
|
||||
const data = await getData(url);
|
||||
|
||||
if (data.content.length < 25) {
|
||||
setIsNextPage(false);
|
||||
} else {
|
||||
setIsNextPage(true);
|
||||
}
|
||||
|
||||
// Handle initial load (page 0) or subsequent pagination
|
||||
if (page === 0) {
|
||||
setReleases(data.content);
|
||||
} else {
|
||||
setReleases([...releases, ...data.content]);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (list) {
|
||||
router.push(pathname + "?" + createQueryString("list", list));
|
||||
setReleases(null);
|
||||
setPage(0);
|
||||
fetchData(list); // Call fetchData here
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [list]);
|
||||
|
||||
useEffect(() => {
|
||||
if (list && releases) {
|
||||
fetchData(list, page); // Use fetchData for pagination
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [page]);
|
||||
|
||||
const chips = [
|
||||
{
|
||||
title: "последнее",
|
||||
list: "last",
|
||||
},
|
||||
{
|
||||
title: "в эфире",
|
||||
list: "ongoing",
|
||||
},
|
||||
{
|
||||
title: "анонсировано",
|
||||
list: "announce",
|
||||
},
|
||||
{
|
||||
title: "завершено",
|
||||
list: "finished",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<ReleasesOverview
|
||||
chips={chips}
|
||||
setList={setList}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
list={list}
|
||||
releases={releases}
|
||||
isNextPage={isNextPage}
|
||||
/>
|
||||
<>
|
||||
<IndexPage />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,150 +1,13 @@
|
|||
"use client";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import { getData } from "@/app/api/api-utils";
|
||||
import { endpoints } from "@/app/api/config";
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import ReleasesOverview from "../components/ReleasesOverview/ReleasesOverview";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
function saveSearches(search) {
|
||||
localStorage.setItem("searches", search);
|
||||
}
|
||||
function getSearches() {
|
||||
return localStorage.getItem("searches");
|
||||
}
|
||||
const SearchPage = dynamic(() => import("../components/Pages/SearchPage"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
export default function Search() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const [releases, setReleases] = useState();
|
||||
const [page, setPage] = useState(0);
|
||||
const [query, setQuery] = useState("");
|
||||
const [isNextPage, setIsNextPage] = useState(true);
|
||||
|
||||
const [searches, setSearches] = useState(JSON.parse(getSearches()));
|
||||
|
||||
const searchParams = useSearchParams();
|
||||
const createQueryString = useCallback(
|
||||
(name, value) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set(name, value);
|
||||
|
||||
return params.toString();
|
||||
},
|
||||
[searchParams],
|
||||
);
|
||||
|
||||
async function fetchData(query, page = 0) {
|
||||
const url = `${endpoints.search}?query=${query}&page=${page}`;
|
||||
const data = await getData(url);
|
||||
|
||||
if (data.content.length < 25) {
|
||||
setIsNextPage(false);
|
||||
} else {
|
||||
setIsNextPage(true);
|
||||
}
|
||||
|
||||
// Handle initial load (page 0) or subsequent pagination
|
||||
if (page === 0) {
|
||||
setReleases(data.content);
|
||||
} else {
|
||||
setReleases([...releases, ...data.content]);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const query = searchParams.get("query");
|
||||
if (query) {
|
||||
setQuery(query);
|
||||
fetchData(query, 0);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (releases) {
|
||||
fetchData(query, page); // Use fetchData for pagination
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [page]);
|
||||
|
||||
const handleInput = (e) => {
|
||||
setQuery(e.target.value);
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
if (query != "") {
|
||||
router.push(pathname + "?" + createQueryString("query", query));
|
||||
setReleases(null);
|
||||
setPage(0);
|
||||
fetchData(query);
|
||||
|
||||
// save searches and update search history
|
||||
if (!searches) {
|
||||
setSearches([query]);
|
||||
saveSearches(JSON.stringify([query]));
|
||||
} else {
|
||||
console.log(searches);
|
||||
if (!searches.find((element) => element == query)) {
|
||||
setSearches([query, ...searches.slice(0, 5)]);
|
||||
saveSearches(JSON.stringify([query, ...searches.slice(0, 5)]));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<form className="field large prefix round fill" onSubmit={handleSubmit}>
|
||||
<i className="front">search</i>
|
||||
<input name="query" onInput={handleInput} value={query} />
|
||||
<menu className="min" style={{ marginTop: "64px" }}>
|
||||
{searches
|
||||
? searches.map((item) => {
|
||||
return (
|
||||
<a
|
||||
key={item}
|
||||
onClick={() => {
|
||||
setQuery(item);
|
||||
}}
|
||||
className="row"
|
||||
>
|
||||
<i>history</i>
|
||||
<div>{item}</div>
|
||||
</a>
|
||||
);
|
||||
})
|
||||
: ""}
|
||||
</menu>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{releases ? (
|
||||
releases.length > 0 ? (
|
||||
<ReleasesOverview
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
releases={releases}
|
||||
isNextPage={isNextPage}
|
||||
/>
|
||||
) : (
|
||||
<div className="absolute padding primary center middle small-round">
|
||||
<i className="extra">search</i>
|
||||
<h5>Ничего не найдено.</h5>
|
||||
<p>Введите другой поисковой запрос.</p>
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<div className="absolute padding primary center middle small-round">
|
||||
<i className="extra">search</i>
|
||||
<h5>Здесь пока ничего нет.</h5>
|
||||
<p>Введите поисковой запрос для начала поиска.</p>
|
||||
</div>
|
||||
)}
|
||||
<SearchPage />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue