Skip to content

Commit

Permalink
feat: connect questions to video
Browse files Browse the repository at this point in the history
  • Loading branch information
ezhil56x committed Oct 5, 2024
1 parent 54dd562 commit fb94b30
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 8 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.1",
"@radix-ui/react-tooltip": "^1.0.7",
"@tabler/icons-react": "^3.14.0",
"@types/bcrypt": "^5.0.2",
Expand Down
32 changes: 32 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 23 additions & 2 deletions src/app/(main)/(pages)/question/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ import {
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';

import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@/components/ui/tabs";

import { Button } from '@/components/ui/button';
import { QueryParams, TabType } from '@/actions/types';
import { getDisabledFeature, getUpdatedUrl, paginationData } from '@/lib/utils';
Expand All @@ -24,6 +31,7 @@ import { authOptions } from '@/lib/auth';
import PostCard from '@/components/posts/PostCard';
import Pagination from '@/components/Pagination';
import { redirect } from 'next/navigation';
import SearchQuestionByVideo from '@/components/search/SearchQuestionByVideo';

type QuestionsResponse = {
data: ExtendedQuestion[] | null;
Expand Down Expand Up @@ -164,8 +172,21 @@ export default async function QuestionsPage({
{/* Next question button */}
<NewPostDialog />
<div className="flex w-full flex-col gap-4">
<div className="flex flex-col justify-between gap-4 md:flex-row">
<Search />
<div className="flex flex-col md:flex-row justify-between gap-4 items-end">
<Tabs defaultValue="searchQuestion" className="w-full md:w-[400px]">
<TabsList className='mb-1 bg-primary/5'>
<TabsTrigger value="searchQuestion">Search by question</TabsTrigger>
<TabsTrigger value="searchVideo">Search by video</TabsTrigger>
</TabsList>
<TabsContent value="searchQuestion">
<div className="flex flex-col justify-between gap-4 md:flex-row">
<Search />
</div>
</TabsContent>
<TabsContent value="searchVideo">
<SearchQuestionByVideo />
</TabsContent>
</Tabs>
<div className="flex items-center justify-between gap-2">
<DropdownMenu>
<DropdownMenuTrigger asChild>
Expand Down
6 changes: 3 additions & 3 deletions src/components/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ const Search = () => {
router.push(getUpdatedUrl(path, paramsObj, { search }));
};
return (
<div className="relative flex h-10 w-full items-center md:w-[300px] lg:w-[400px] xl:w-[500px]">
<SearchIcon className="absolute left-5 top-1/2 h-4 w-4 -translate-y-1/2 transform text-gray-500" />
<div className="relative flex h-10 w-full items-center md:w-[300px] lg:w-[400px] xl:w-[500px] gap-2">
<SearchIcon className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 transform text-primary/80" />
<Input
aria-label="Search Input"
className="focus:ring-none rounded-lg border-none bg-primary/5 px-10 text-base focus:outline-none"
placeholder="Search..."
placeholder="Search by question"
type="search"
value={search}
onChange={(e) => setSearch(e.target.value)}
Expand Down
8 changes: 5 additions & 3 deletions src/components/search/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function SearchBar({
onCardClick,
shouldRedirect = true,
disableCmdK = false,
placeholder = 'Search for videos...',
}: {
onCardClick?: (
videoUrl?: string,
Expand All @@ -28,6 +29,7 @@ export function SearchBar({
) => void;
shouldRedirect?: boolean;
disableCmdK?: boolean;
placeholder?: string;
}) {
const [searchTerm, setSearchTerm] = useState('');
const [searchedVideos, setSearchedVideos] = useState<TSearchedVideos[]>([]);
Expand Down Expand Up @@ -130,7 +132,7 @@ export function SearchBar({
{/* Search Input Bar */}
<SearchIcon className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 transform text-primary/80" />
<Input
placeholder="Search for videos..."
placeholder={placeholder}
className="focus:ring-none rounded-lg border-none bg-primary/5 px-10 text-base focus:outline-none"
value={searchTerm}
onChange={handleInputChange}
Expand Down Expand Up @@ -208,7 +210,7 @@ export function SearchBar({
<Command onClick={() => setDialogOpen(true)}>
<div className="flex items-center justify-between border-2">
<CommandInput
placeholder="Search video..."
placeholder={placeholder}
value={searchTerm}
onValueChange={(search) => setSearchTerm(search)}
/>
Expand All @@ -224,7 +226,7 @@ export function SearchBar({
onOpenChange={() => setDialogOpen((prev) => !prev)}
>
<CommandInput
placeholder="Search video..."
placeholder={placeholder}
value={searchTerm}
onValueChange={(search) => setSearchTerm(search)}
/>
Expand Down
74 changes: 74 additions & 0 deletions src/components/search/SearchQuestionByVideo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
'use client';

import React, { useState } from 'react';
import { SearchBar } from '@/components/search/SearchBar';
import { useRouter } from 'next/navigation';
import { Button } from '../ui/button';
import { FormPostInput } from '../posts/form/form-input';

interface SearchQuestionByVideoProps {
onCardClick?: (
videoUrl?: string,
videoId?: number,
videoTitle?: string,
) => void;
shouldRedirect?: boolean;
disableCmdK?: boolean;
placeholder?: string;
}

const SearchQuestionByVideo: React.FC<SearchQuestionByVideoProps> = (props) => {
const [videoId, setVideoId] = useState<string>('');
const [videoTitle, setVideoTitle] = useState<string>('');
const router = useRouter();

const handleSearch = (
videoUrl?: string,
videoId?: number,
videoTitle?: string,
) => {
router.push(`/question?videoId=${videoId}`);
if (videoUrl && videoId && videoTitle) {
setVideoId(videoId.toString());
setVideoTitle(videoTitle);
}
};

return (
<div className='relative flex h-10 w-full items-center md:w-[300px] lg:w-[400px] xl:w-[500px] gap-2'>
{videoId ? (
<div className="flex w-full items-center gap-2">
<FormPostInput
id="videoTitle"
placeholder="Select a video from the search"
value={videoTitle}
className="w-full"
disabled={true}
/>
<Button
type="button"
className="flex-shrink-0"
onClick={() => {
setVideoId('');
setVideoTitle('');
router.push('/question');
}}
>
Clear
</Button>
</div>
) : (
<SearchBar
{...props}
shouldRedirect={false}
disableCmdK={true}
onCardClick={handleSearch}
placeholder="Search by video"
/>
)}
</div>

);
};

export default SearchQuestionByVideo;
55 changes: 55 additions & 0 deletions src/components/ui/tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"use client"

import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"

import { cn } from "@/lib/utils"

const Tabs = TabsPrimitive.Root

const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
className
)}
{...props}
/>
))
TabsList.displayName = TabsPrimitive.List.displayName

const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
className
)}
{...props}
/>
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName

const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className
)}
{...props}
/>
))
TabsContent.displayName = TabsPrimitive.Content.displayName

export { Tabs, TabsList, TabsTrigger, TabsContent }

0 comments on commit fb94b30

Please sign in to comment.