diff --git a/apps/theme-market/package.json b/apps/theme-market/package.json index 78d6b341..b0e4e3c1 100644 --- a/apps/theme-market/package.json +++ b/apps/theme-market/package.json @@ -13,6 +13,7 @@ "next": "14.2.5", "react": "^18", "react-dom": "^18", + "react-intersection-observer": "^9.15.1", "zustand": "^5.0.1" }, "devDependencies": { diff --git a/apps/theme-market/src/app/(routes)/(main)/(bottomsheet)/index.tsx b/apps/theme-market/src/app/(routes)/(main)/(bottomsheet)/index.tsx index bafaf67f..6fc21152 100644 --- a/apps/theme-market/src/app/(routes)/(main)/(bottomsheet)/index.tsx +++ b/apps/theme-market/src/app/(routes)/(main)/(bottomsheet)/index.tsx @@ -1,7 +1,7 @@ "use client"; import { BottomSheet } from "@/app/_components/BottomSheet"; -import { ThemeDetail } from "@/app/_pages/Main/BottomSheet/ThemeDetail"; +import { ThemeDetail } from "@/app/_pages/BottomSheet/ThemeDetail"; import { useThemeStore } from "@/app/_providers/ThemeProvider"; import { useUserStore } from "@/app/_providers/UserProvider"; import { themeService } from "@/services/ThemeService"; diff --git a/apps/theme-market/src/app/(routes)/(main)/download/best/page.tsx b/apps/theme-market/src/app/(routes)/(main)/download/best/page.tsx new file mode 100644 index 00000000..0decf11c --- /dev/null +++ b/apps/theme-market/src/app/(routes)/(main)/download/best/page.tsx @@ -0,0 +1,5 @@ +import { BestPage } from "@/app/_pages/Main/ThemeDownload/Best"; + +export default async function DownloadBestPageRoute() { + return ; +} diff --git a/apps/theme-market/src/app/(routes)/(main)/search/[query]/page.tsx b/apps/theme-market/src/app/(routes)/(main)/search/[query]/page.tsx new file mode 100644 index 00000000..94e6cb73 --- /dev/null +++ b/apps/theme-market/src/app/(routes)/(main)/search/[query]/page.tsx @@ -0,0 +1,10 @@ +import { SearchPage } from "@/app/_pages/Search"; + +interface Props { + params: Promise<{ query: string }>; +} + +export default async function SearchPageRoute({ params }: Props) { + const query = decodeURIComponent((await params).query); + return ; +} diff --git a/apps/theme-market/src/app/_components/Error/NotFound.tsx b/apps/theme-market/src/app/_components/Error/NotFound.tsx index bcdc7037..3776435c 100644 --- a/apps/theme-market/src/app/_components/Error/NotFound.tsx +++ b/apps/theme-market/src/app/_components/Error/NotFound.tsx @@ -2,7 +2,6 @@ import Image from "next/image"; import styles from "./index.module.css"; import SvgCat from "@/assets/icons/svgCat.svg"; -import { ReactNode } from "react"; interface Props { message?: string; diff --git a/apps/theme-market/src/app/_components/Input/index.tsx b/apps/theme-market/src/app/_components/Input/index.tsx index 033d547b..ebc67aec 100644 --- a/apps/theme-market/src/app/_components/Input/index.tsx +++ b/apps/theme-market/src/app/_components/Input/index.tsx @@ -1,11 +1,30 @@ -import { InputHTMLAttributes } from "react"; +"use client"; + +import { InputHTMLAttributes, useState } from "react"; import styles from "./index.module.css"; import classNames from "classnames"; -interface Props extends InputHTMLAttributes {} +interface Props extends InputHTMLAttributes { + onComplete?: (value: string) => void; +} + +export const Input = ({ + onComplete, + className, + defaultValue, + ...props +}: Props) => { + const [value, setValue] = useState((defaultValue || "").toString()); -export const Input = (props: Props) => { return ( - + { + if (e.key === "Enter") onComplete?.(value); + }} + onChange={(e) => setValue(e.target.value)} + /> ); }; diff --git a/apps/theme-market/src/app/_pages/Main/ThemeDownload/ThemeList/ThemeInfo/index.module.css b/apps/theme-market/src/app/_components/Theme/Info/index.module.css similarity index 100% rename from apps/theme-market/src/app/_pages/Main/ThemeDownload/ThemeList/ThemeInfo/index.module.css rename to apps/theme-market/src/app/_components/Theme/Info/index.module.css diff --git a/apps/theme-market/src/app/_pages/Main/ThemeDownload/ThemeList/ThemeInfo/index.tsx b/apps/theme-market/src/app/_components/Theme/Info/index.tsx similarity index 100% rename from apps/theme-market/src/app/_pages/Main/ThemeDownload/ThemeList/ThemeInfo/index.tsx rename to apps/theme-market/src/app/_components/Theme/Info/index.tsx diff --git a/apps/theme-market/src/app/_components/Theme/List/ThemeInfoList.tsx b/apps/theme-market/src/app/_components/Theme/List/ThemeInfoList.tsx new file mode 100644 index 00000000..2a7e6f87 --- /dev/null +++ b/apps/theme-market/src/app/_components/Theme/List/ThemeInfoList.tsx @@ -0,0 +1,19 @@ +"use client"; + +import { ThemeInfo } from "@/app/_components/Theme/Info"; +import { Theme } from "@/entities/Theme"; + +import styles from "./index.module.css"; + +interface Props { + themes: Theme[]; +} +export const ThemeInfoList = ({ themes }: Props) => { + return ( +
+ {themes.map((theme) => { + return ; + })} +
+ ); +}; diff --git a/apps/theme-market/src/app/_components/Theme/List/ThemeListWithInfiniteScroll.tsx b/apps/theme-market/src/app/_components/Theme/List/ThemeListWithInfiniteScroll.tsx new file mode 100644 index 00000000..06f8dead --- /dev/null +++ b/apps/theme-market/src/app/_components/Theme/List/ThemeListWithInfiniteScroll.tsx @@ -0,0 +1,51 @@ +"use client"; + +import { useCallback, useEffect, useState } from "react"; +import { useInView } from "react-intersection-observer"; + +import { ThemeInfo } from "@/app/_components/Theme/Info"; +import { useUserStore } from "@/app/_providers/UserProvider"; +import { themeService } from "@/services/ThemeService"; +import { Theme } from "@/entities/Theme"; + +import styles from "./index.module.css"; + +interface Props { + defaultThemes: Theme[]; +} + +const DEFAULT_PAGE = 2; + +export const ThemeListWithInifiniteScorll = ({ defaultThemes }: Props) => { + const [themes, setThemes] = useState(defaultThemes); + const [page, setPage] = useState(DEFAULT_PAGE); + + const { ref, inView } = useInView(); + + const { accessToken } = useUserStore((state) => state); + + const loadThemes = useCallback(async () => { + const { content: themes } = await themeService.getBestThemes( + page, + accessToken + ); + + setThemes((prev) => [...prev, ...themes]); + setPage((prev) => prev + 1); + }, [accessToken, page]); + + useEffect(() => { + if (inView) loadThemes(); + }, [inView, loadThemes]); + + return ( + <> +
+ {themes.map((theme) => { + return ; + })} +
+
+ + ); +}; diff --git a/apps/theme-market/src/app/_components/Theme/List/index.module.css b/apps/theme-market/src/app/_components/Theme/List/index.module.css new file mode 100644 index 00000000..8687621f --- /dev/null +++ b/apps/theme-market/src/app/_components/Theme/List/index.module.css @@ -0,0 +1,5 @@ +.wrapper { + display: flex; + flex-direction: column; + gap: 10px; +} diff --git a/apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/Preview/Timetable.tsx b/apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/Preview/Timetable.tsx similarity index 100% rename from apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/Preview/Timetable.tsx rename to apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/Preview/Timetable.tsx diff --git a/apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/Preview/index.module.css b/apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/Preview/index.module.css similarity index 100% rename from apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/Preview/index.module.css rename to apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/Preview/index.module.css diff --git a/apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/Preview/index.tsx b/apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/Preview/index.tsx similarity index 100% rename from apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/Preview/index.tsx rename to apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/Preview/index.tsx diff --git a/apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/index.module.css b/apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/index.module.css similarity index 100% rename from apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/index.module.css rename to apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/index.module.css diff --git a/apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/index.tsx b/apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/index.tsx similarity index 100% rename from apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/index.tsx rename to apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/index.tsx index 40d21145..c17a0079 100644 --- a/apps/theme-market/src/app/_pages/Main/BottomSheet/ThemeDetail/index.tsx +++ b/apps/theme-market/src/app/_pages/BottomSheet/ThemeDetail/index.tsx @@ -1,10 +1,10 @@ "use client"; -import { Theme } from "@/entities/Theme"; -import styles from "./index.module.css"; -import { Preview } from "./Preview"; import classNames from "classnames"; +import { Theme } from "@/entities/Theme"; +import { Preview } from "./Preview"; +import styles from "./index.module.css"; interface Props { theme: Theme; isAnonymous: boolean; diff --git a/apps/theme-market/src/app/_pages/Main/Header/MainHeader.tsx b/apps/theme-market/src/app/_pages/Main/Header/MainHeader.tsx new file mode 100644 index 00000000..1d952a02 --- /dev/null +++ b/apps/theme-market/src/app/_pages/Main/Header/MainHeader.tsx @@ -0,0 +1,45 @@ +"use client"; + +import Link from "next/link"; +import { useRouter } from "next/navigation"; + +import { MENU } from "@/entities/Menu"; + +import { TabContent } from "@/app/_components/Tab/TabContent"; +import { Tab } from "@/app/_components/Tab"; +import { Input } from "@/app/_components/Input"; + +import styles from "./index.module.css"; + +interface Props { + menu: MENU; +} + +export const MainHeader = ({ menu }: Props) => { + const router = useRouter(); + + return ( +
+
+ router.push(`/search/${value}`)} + /> +
+ + + + 테마 다운로드 + + + + + 내 테마 올리기 + + + +
+ ); +}; diff --git a/apps/theme-market/src/app/_pages/Main/Header/index.module.css b/apps/theme-market/src/app/_pages/Main/Header/index.module.css new file mode 100644 index 00000000..36ffc212 --- /dev/null +++ b/apps/theme-market/src/app/_pages/Main/Header/index.module.css @@ -0,0 +1,21 @@ +.header { + background-color: var(--color-bg-default); +} + +.inputWrapper { + width: 100%; + height: 80px; + + padding: 20px 18.5px; +} + +.input { + width: 100%; + height: 40px; + + padding-left: 40px; + + background-image: url("/static/icons/svgSearch.svg"); + background-position: 7px 7px; + background-repeat: no-repeat; +} diff --git a/apps/theme-market/src/app/_pages/Main/ThemeDownload/Best/index.module.css b/apps/theme-market/src/app/_pages/Main/ThemeDownload/Best/index.module.css new file mode 100644 index 00000000..f823b2ca --- /dev/null +++ b/apps/theme-market/src/app/_pages/Main/ThemeDownload/Best/index.module.css @@ -0,0 +1,25 @@ +.main { + padding: 17px 18px 0; +} + +.prev { + padding-left: 3px; + + display: flex; + flex-direction: row; + + height: 14px; + font-size: 13px; + font-weight: 400; + line-height: 12.6px; + + color: var(--palette-gray-2); +} + +.themes { + margin-top: 12px; + + display: flex; + flex-direction: column; + gap: 10px; +} diff --git a/apps/theme-market/src/app/_pages/Main/ThemeDownload/Best/index.tsx b/apps/theme-market/src/app/_pages/Main/ThemeDownload/Best/index.tsx new file mode 100644 index 00000000..056f0eb6 --- /dev/null +++ b/apps/theme-market/src/app/_pages/Main/ThemeDownload/Best/index.tsx @@ -0,0 +1,34 @@ +import Image from "next/image"; + +import { cookieService } from "@/services/CookieService"; +import { MainHeader } from "@/app/_pages/Main/Header/MainHeader"; +import { themeService } from "@/services/ThemeService"; +import SvgChevronLeft from "@/assets/icons/svgChevronLeft.svg"; + +import styles from "./index.module.css"; +import { DEFAULT_PAGE } from "@/repositories/ThemeRepository"; +import { ThemeListWithInifiniteScorll } from "@/app/_components/Theme/List/ThemeListWithInfiniteScroll"; +import Link from "next/link"; + +export const BestPage = async () => { + const accessToken = cookieService.getAccessToken(); + const { content: themes } = await themeService.getBestThemes( + DEFAULT_PAGE, + accessToken + ); + + return ( + <> + +
+ + < + 돌아가기 + +
+ +
+
+ + ); +}; diff --git a/apps/theme-market/src/app/_pages/Main/ThemeDownload/ThemeList/index.tsx b/apps/theme-market/src/app/_pages/Main/ThemeDownload/ThemeList/index.tsx index be926c1d..09554b94 100644 --- a/apps/theme-market/src/app/_pages/Main/ThemeDownload/ThemeList/index.tsx +++ b/apps/theme-market/src/app/_pages/Main/ThemeDownload/ThemeList/index.tsx @@ -1,11 +1,14 @@ import Image from "next/image"; import styles from "./index.module.css"; -import { ThemeInfo } from "./ThemeInfo"; +import Link from "next/link"; -import SvgChevronLeft from "@/assets/icons/svgChevronLeft.svg"; import { NotFound } from "@/app/_components/Error/NotFound"; +import { ThemeInfoList } from "@/app/_components/Theme/List/ThemeInfoList"; + import { Theme } from "@/entities/Theme"; +import SvgChevronRight from "@/assets/icons/svgChevronRight.svg"; + interface Props { title: string; themes: Theme[]; @@ -20,14 +23,12 @@ export const ThemeList = ({ title, themes }: Props) => { {themeExists ? ( <>
- {themes.map((theme) => { - return ; - })} +
-
+ 전체 보기 - > -
+ > + ) : (
diff --git a/apps/theme-market/src/app/_pages/Main/ThemeDownload/index.tsx b/apps/theme-market/src/app/_pages/Main/ThemeDownload/index.tsx index 2a663444..c7a65a1d 100644 --- a/apps/theme-market/src/app/_pages/Main/ThemeDownload/index.tsx +++ b/apps/theme-market/src/app/_pages/Main/ThemeDownload/index.tsx @@ -2,11 +2,15 @@ import { themeService } from "@/services/ThemeService"; import { ThemeList } from "./ThemeList"; import { cookieService } from "@/services/CookieService"; +import { DEFAULT_PAGE } from "@/repositories/ThemeRepository"; export const ThemeDownload = async () => { const accessToken = cookieService.getAccessToken(); - const bestThemes = await themeService.getBestThemes(accessToken); + const { content: bestThemes } = await themeService.getBestThemes( + DEFAULT_PAGE, + accessToken + ); const friendsThemes = await themeService.getFriendsThemes(accessToken); return ( diff --git a/apps/theme-market/src/app/_pages/Main/index.module.css b/apps/theme-market/src/app/_pages/Main/index.module.css index ed331e94..974c21bf 100644 --- a/apps/theme-market/src/app/_pages/Main/index.module.css +++ b/apps/theme-market/src/app/_pages/Main/index.module.css @@ -1,25 +1,3 @@ -.header { - background-color: var(--color-bg-default); -} - -.inputWrapper { - width: 100%; - height: 80px; - - padding: 20px 18.5px; -} - -.input { - width: 100%; - height: 40px; - - padding-left: 40px; - - background-image: url("/static/icons/svgSearch.svg"); - background-position: 7px 7px; - background-repeat: no-repeat; -} - .main { - padding: 17px 18px 0; + padding: 21px 18px 0; } diff --git a/apps/theme-market/src/app/_pages/Main/index.tsx b/apps/theme-market/src/app/_pages/Main/index.tsx index 1e9cfcc7..97cf8188 100644 --- a/apps/theme-market/src/app/_pages/Main/index.tsx +++ b/apps/theme-market/src/app/_pages/Main/index.tsx @@ -1,13 +1,10 @@ -import { Input } from "@/app/_components/Input"; -import { Tab } from "@/app/_components/Tab"; -import { TabContent } from "@/app/_components/Tab/TabContent"; import { MENU } from "@/entities/Menu"; import { ThemeDownload } from "./ThemeDownload"; import { MyTheme } from "./MyTheme"; import styles from "./index.module.css"; -import Link from "next/link"; +import { MainHeader } from "@/app/_pages/Main/Header/MainHeader"; interface Props { menu: MENU; @@ -16,27 +13,7 @@ interface Props { export const MainPage = ({ menu }: Props) => { return ( <> -
-
- -
- - - - 테마 다운로드 - - - - - 내 테마 올리기 - - - -
+
{menu === "DOWNLOAD" ? : }
diff --git a/apps/theme-market/src/app/_pages/Search/Header/index.module.css b/apps/theme-market/src/app/_pages/Search/Header/index.module.css new file mode 100644 index 00000000..6495da44 --- /dev/null +++ b/apps/theme-market/src/app/_pages/Search/Header/index.module.css @@ -0,0 +1,19 @@ +.inputWrapper { + position: relative; + z-index: 10; + padding: 20px 19px 0 18px; +} + +.inputWrapper .input { + width: 100%; + height: 40px; + + padding-left: 40px; + + background-image: url("/static/icons/svgSearch.svg"); + background-position: 7px 7px; + background-repeat: no-repeat; + background-color: #ffffff; + + border: 1px solid #f2f2f2; +} diff --git a/apps/theme-market/src/app/_pages/Search/Header/index.tsx b/apps/theme-market/src/app/_pages/Search/Header/index.tsx new file mode 100644 index 00000000..e6ce9fa4 --- /dev/null +++ b/apps/theme-market/src/app/_pages/Search/Header/index.tsx @@ -0,0 +1,27 @@ +"use client"; + +import { useRouter } from "next/navigation"; + +import { Input } from "@/app/_components/Input"; + +import styles from "./index.module.css"; + +interface Props { + defaultValue: string; +} + +export const SearchHeader = ({ defaultValue }: Props) => { + const router = useRouter(); + + return ( +
+ router.replace(`/search/${value}`)} + /> +
+ ); +}; diff --git a/apps/theme-market/src/app/_pages/Search/index.module.css b/apps/theme-market/src/app/_pages/Search/index.module.css new file mode 100644 index 00000000..313e5c01 --- /dev/null +++ b/apps/theme-market/src/app/_pages/Search/index.module.css @@ -0,0 +1,41 @@ +.search { + margin-top: 28px; + padding: 0px 18px 0px; +} + +.notFound { + width: 100%; + height: 100%; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 5; + + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + color: var(--palette-gray-2); +} + +.notFound .text { + margin: 20px 0 8px; + font-size: 16px; + font-weight: 600; + line-height: 22.4px; + text-align: center; + text-underline-position: from-font; + text-decoration-skip-ink: none; +} + +.notFound .subText { + font-size: 14px; + font-weight: 400; + line-height: 19.6px; + text-align: center; + text-underline-position: from-font; + text-decoration-skip-ink: none; +} diff --git a/apps/theme-market/src/app/_pages/Search/index.tsx b/apps/theme-market/src/app/_pages/Search/index.tsx new file mode 100644 index 00000000..58da24ba --- /dev/null +++ b/apps/theme-market/src/app/_pages/Search/index.tsx @@ -0,0 +1,39 @@ +import { cookieService } from "@/services/CookieService"; +import { themeService } from "@/services/ThemeService"; + +import { SearchHeader } from "./Header"; +import { ThemeInfoList } from "@/app/_components/Theme/List/ThemeInfoList"; + +import SvgCat from "@/assets/icons/svgCat.svg"; + +import styles from "./index.module.css"; +import Image from "next/image"; + +interface Props { + query: string; +} + +export const SearchPage = async ({ query }: Props) => { + const accessToken = await cookieService.getAccessToken(); + const themes = await themeService.search(query, accessToken); + + return ( + <> + +
+ {themes.length > 0 ? ( + + ) : ( +
+ not-found + 일치하는 테마가 없습니다. + + 테마명이나 등록자 닉네임으로 검색해보세요. + +
+ )} +
+ ; + + ); +}; diff --git a/apps/theme-market/src/assets/icons/svgChevronLeft.svg b/apps/theme-market/src/assets/icons/svgChevronLeft.svg index e24f0713..8f9c1a58 100644 --- a/apps/theme-market/src/assets/icons/svgChevronLeft.svg +++ b/apps/theme-market/src/assets/icons/svgChevronLeft.svg @@ -1,3 +1,3 @@ - - + + diff --git a/apps/theme-market/src/assets/icons/svgChevronRight.svg b/apps/theme-market/src/assets/icons/svgChevronRight.svg new file mode 100644 index 00000000..e24f0713 --- /dev/null +++ b/apps/theme-market/src/assets/icons/svgChevronRight.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/theme-market/src/repositories/ThemeRepository.ts b/apps/theme-market/src/repositories/ThemeRepository.ts index 8efe450c..2c678af1 100644 --- a/apps/theme-market/src/repositories/ThemeRepository.ts +++ b/apps/theme-market/src/repositories/ThemeRepository.ts @@ -4,6 +4,13 @@ import { PageResponse } from "@/entities/Page"; import { Theme } from "@/entities/Theme"; type ThemeRepository = { + search: ({ + query, + accessToken, + }: { + query: string; + accessToken?: string; + }) => Promise>; getTheme: ({ id, accessToken, @@ -18,7 +25,7 @@ type ThemeRepository = { }: { page?: number; accessToken?: string; - }) => Promise; + }) => Promise>; getFriendsThemes: ({ page, accessToken, @@ -46,9 +53,28 @@ type ThemeRepository = { }) => Promise; }; -const DEFAULT_PAGE = 1; +export const DEFAULT_PAGE = 1; export const themeRepositry: ThemeRepository = { + search: async ({ query, accessToken }) => { + const params = new URLSearchParams({ + query, + }); + + try { + const res = await httpClient.get>( + `/v1/themes/search?${params}`, + accessToken + ); + + return res; + } catch { + return { + content: [], + totalCount: 0, + }; + } + }, getTheme: async ({ id, accessToken }) => { const res = await httpClient.get(`/v1/themes/${id}`, accessToken); @@ -68,7 +94,7 @@ export const themeRepositry: ThemeRepository = { accessToken ); - return res.content; + return res; }, getFriendsThemes: async ({ page, accessToken }) => { const params = new URLSearchParams({ diff --git a/apps/theme-market/src/services/ThemeService.ts b/apps/theme-market/src/services/ThemeService.ts index b313bb0e..5bb3b408 100644 --- a/apps/theme-market/src/services/ThemeService.ts +++ b/apps/theme-market/src/services/ThemeService.ts @@ -1,11 +1,16 @@ +import { PageResponse } from "@/entities/Page"; import { Theme } from "@/entities/Theme"; import { themeRepositry } from "@/repositories/ThemeRepository"; type ThemeService = { + search: (query: string, accessToken?: string) => Promise; getTheme: (id: string, accessToken?: string) => Promise; getMyThemes: (accessToken?: string) => Promise; - getBestThemes: (accessToken?: string) => Promise; + getBestThemes: ( + page?: number, + accessToken?: string + ) => Promise>; getFriendsThemes: (accessToken?: string) => Promise; publishTheme: ( themeId: string, @@ -17,6 +22,9 @@ type ThemeService = { }; export const themeService: ThemeService = { + search: async (query: string, accessToken?: string) => { + return (await themeRepositry.search({ query, accessToken })).content; + }, getTheme: async (id: string, accessToken?: string) => { return await themeRepositry.getTheme({ id, accessToken }); }, @@ -25,8 +33,8 @@ export const themeService: ThemeService = { (theme) => theme.isCustom ); }, - getBestThemes: async (accessToken?: string) => { - return await themeRepositry.getBestThemes({ accessToken }); + getBestThemes: async (page?: number, accessToken?: string) => { + return await themeRepositry.getBestThemes({ page, accessToken }); }, getFriendsThemes: async (accessToken?: string) => { return await themeRepositry.getFriendsThemes({ accessToken }); diff --git a/yarn.lock b/yarn.lock index 1d258c86..818f9895 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9135,6 +9135,11 @@ react-freeze@^1.0.0: resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d" integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g== +react-intersection-observer@^9.15.1: + version "9.15.1" + resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.15.1.tgz#5866b6fdfef24be9f288b74b35b773f63d90c3eb" + integrity sha512-vGrqYEVWXfH+AGu241uzfUpNK4HAdhCkSAyFdkMb9VWWXs6mxzBLpWCxEy9YcnDNY2g9eO6z7qUtTBdA9hc8pA== + "react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"