From a84a75476ec4c2e14d3aa1044ab6ca881b1c2ba3 Mon Sep 17 00:00:00 2001 From: Nimit Haria Date: Wed, 27 Mar 2024 12:56:39 +0530 Subject: [PATCH 1/2] feat: added video search --- package.json | 1 + src/app/api/search/route.ts | 65 ++++++++++ src/components/Appbar.tsx | 62 ++++++---- src/components/search/MobileScreenSearch.tsx | 25 ++++ src/components/search/SearchBar.tsx | 118 +++++++++++++++++++ src/components/search/VideoSearchCard.tsx | 31 +++++ src/components/search/VideoSearchInfo.tsx | 15 +++ src/components/search/VideoSearchLoading.tsx | 18 +++ src/hooks/useClickOutside.ts | 21 ++++ 9 files changed, 331 insertions(+), 25 deletions(-) create mode 100644 src/app/api/search/route.ts create mode 100644 src/components/search/MobileScreenSearch.tsx create mode 100644 src/components/search/SearchBar.tsx create mode 100644 src/components/search/VideoSearchCard.tsx create mode 100644 src/components/search/VideoSearchInfo.tsx create mode 100644 src/components/search/VideoSearchLoading.tsx create mode 100644 src/hooks/useClickOutside.ts diff --git a/package.json b/package.json index 2b0e2cf96..90466cf0b 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "dayjs": "^1.11.10", "discord-oauth2": "^2.11.0", "discord.js": "^14.14.1", + "fuse.js": "^7.0.0", "jose": "^5.2.2", "jsonwebtoken": "^9.0.2", "lucide-react": "^0.321.0", diff --git a/src/app/api/search/route.ts b/src/app/api/search/route.ts new file mode 100644 index 000000000..a8cc2938e --- /dev/null +++ b/src/app/api/search/route.ts @@ -0,0 +1,65 @@ +import { Cache } from '@/db/Cache'; +import db from '@/db'; +import { CourseContent } from '@prisma/client'; +import Fuse from 'fuse.js'; +import { NextResponse } from 'next/server'; + +export type TSearchedVideos = { + id: number; + parentId: number | null; + title: string; +} & { + parent: { courses: CourseContent[] } | null; +}; + +const fuzzySearch = (videos: TSearchedVideos[], searchQuery: string) => { + const searchedVideos = new Fuse(videos, { + keys: ['title'], + }).search(searchQuery); + + return searchedVideos.map((video) => video.item); +}; + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url); + const searchQuery = searchParams.get('q'); + + if (searchQuery && searchQuery.length > 2) { + const value: TSearchedVideos[] = await Cache.getInstance().get( + 'getAllVideosForSearch', + [], + ); + + if (value) { + return NextResponse.json(fuzzySearch(value, searchQuery)); + } + + const allVideos = await db.content.findMany({ + where: { + type: 'video', + hidden: false, + }, + select: { + id: true, + parentId: true, + title: true, + parent: { + select: { + courses: true, + }, + }, + }, + }); + + Cache.getInstance().set( + 'getAllVideosForSearch', + [], + allVideos, + 24 * 60 * 60, + ); + + return NextResponse.json(fuzzySearch(allVideos, searchQuery)); + } + + return NextResponse.json({}, { status: 400 }); +} diff --git a/src/components/Appbar.tsx b/src/components/Appbar.tsx index 369e7863b..30a62d316 100644 --- a/src/components/Appbar.tsx +++ b/src/components/Appbar.tsx @@ -1,7 +1,6 @@ 'use client'; import Link from 'next/link'; -import React from 'react'; import { JoinDiscord } from './JoinDiscord'; import { AppbarAuth } from './AppbarAuth'; import { useSession } from 'next-auth/react'; @@ -14,11 +13,14 @@ import { Button } from './ui/button'; import { Sparkles } from 'lucide-react'; import { ThemeToggler } from './ThemeToggler'; import { NavigationMenu } from './landing/appbar/nav-menu'; +import SearchBar from './search/SearchBar'; +import MobileScreenSearch from './search/MobileScreenSearch'; export const Appbar = () => { const session = useSession(); const [sidebarOpen, setSidebarOpen] = useRecoilState(sidebarOpenAtom); const currentPath = usePathname(); + return ( <>