committed by
GitHub
9 changed files with 210 additions and 10 deletions
|
After Width: | Height: | Size: 585 B |
|
Before Width: | Height: | Size: 327 B After Width: | Height: | Size: 120 B |
|
After Width: | Height: | Size: 253 B |
@ -0,0 +1,21 @@ |
|||
|
|||
|
|||
export default function CreatorCard({ creator }) { |
|||
const handleClick = () => { |
|||
window.location.href = `/manage-channel/${creator.id}`; |
|||
}; |
|||
|
|||
return ( |
|||
<div className="flex flex-col glassmorphism w-full p-6 cursor-pointer" onClick={handleClick}> |
|||
<img |
|||
src={creator.profilePicture} |
|||
alt={creator.name} |
|||
className="w-[128px] aspect-square object-cover rounded-full mx-auto" |
|||
/> |
|||
<h2 className="text-2xl font-medium font-inter mt-3 text-white">{creator.name}</h2> |
|||
<div className="text-sm text-gray-400 mt-1"> |
|||
{creator.subscribers} abonné(e)s |
|||
</div> |
|||
</div> |
|||
); |
|||
} |
|||
@ -0,0 +1,128 @@ |
|||
import Navbar from "../components/Navbar.jsx"; |
|||
import {useEffect, useState} from "react"; |
|||
import {search} from "../services/search.service.js" |
|||
import VideoCard from "../components/VideoCard.jsx"; |
|||
import CreatorCard from "../components/CreatorCard.jsx"; |
|||
import {useSearchParams} from "react-router-dom"; |
|||
|
|||
export default function Search() { |
|||
|
|||
const [searchParams, setSearchParams] = useSearchParams(); |
|||
const queryFromUrl = searchParams.get('q') || ''; |
|||
const typeFromUrl = searchParams.get('type') || 'videos'; |
|||
|
|||
const [filter, setFilter] = useState(typeFromUrl); |
|||
const [searchQuery, setSearchQuery] = useState(queryFromUrl); |
|||
|
|||
const [results, setResults] = useState({}); |
|||
|
|||
useEffect(() => { |
|||
async function fetchData() { |
|||
if (searchParams) { |
|||
setResults(await search(queryFromUrl, typeFromUrl, 0, 20)); |
|||
} |
|||
} |
|||
fetchData(); |
|||
}, [searchParams]); |
|||
useEffect(() => { |
|||
async function fetchData() { |
|||
if (searchQuery) { |
|||
setResults(await search(searchQuery, filter, 0, 20)); |
|||
} |
|||
} |
|||
fetchData(); |
|||
}, [filter]); |
|||
|
|||
const handleKeyPress = async (e) => { |
|||
if (e.key === 'Enter') { |
|||
setResults(await search(e.target.value, filter, 0, 20)); |
|||
} |
|||
} |
|||
|
|||
return ( |
|||
<div className="min-w-screen min-h-screen bg-linear-to-br from-left-gradient to-right-gradient"> |
|||
<Navbar isSearchPage={true} /> |
|||
|
|||
<main className="px-36 pt-[118px]"> |
|||
|
|||
{/* MEGA SEARCH BAR */} |
|||
<div className="flex items-center w-full gap-8" > |
|||
<div className="glassmorphism text-white font-montserrat text-2xl font-black cursor-pointer flex-1 h-[50px] px-3 flex items-center justify-center"> |
|||
<input |
|||
type="text" |
|||
name="search" |
|||
id="searchbar" |
|||
placeholder="Rechercher" |
|||
className="font-inter text-2xl font-normal focus:outline-none bg-transparent w-full" |
|||
value={searchQuery} |
|||
onChange={(e) => setSearchQuery(e.target.value)} |
|||
onKeyPress={(e) => handleKeyPress(e) } |
|||
/> |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="32" viewBox="0 0 32 32" fill="none" className="h-6 w-6"> |
|||
<circle cx="18.381" cy="13.619" r="12.119" stroke="white" strokeWidth="3"/> |
|||
<line x1="9.63207" y1="22.2035" x2="1.06064" y2="30.7749" stroke="white" strokeWidth="3"/> |
|||
</svg> |
|||
</div> |
|||
|
|||
{/* FILTERS */} |
|||
<form action="" className="flex w-max gap-4 items-center h-full"> |
|||
<label |
|||
htmlFor="videos" |
|||
className={"p-3 " + (filter === "videos" ? "bg-white rounded-full fill-black border-2 border-white" : "glassmorphism-rounded-full") + " cursor-pointer"} |
|||
> |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className={(filter === "videos") ? "fill-black" : "fill-white"} ><path d="M7 6v12l10-6z"></path></svg> |
|||
</label> |
|||
<input |
|||
type="radio" |
|||
name="filter" |
|||
id="videos" |
|||
className="hidden" |
|||
onClick={() => setFilter("videos")} |
|||
/> |
|||
|
|||
<label |
|||
htmlFor="channel" |
|||
className={"p-3 " + (filter === "channel" ? "bg-white rounded-full fill-black border-2 border-white" : "glassmorphism-rounded-full") + " cursor-pointer"} |
|||
> |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className={(filter === "channel") ? "fill-black" : "fill-white"} ><path d="M12 2a5 5 0 1 0 5 5 5 5 0 0 0-5-5zm0 8a3 3 0 1 1 3-3 3 3 0 0 1-3 3zm9 11v-1a7 7 0 0 0-7-7h-4a7 7 0 0 0-7 7v1h2v-1a5 5 0 0 1 5-5h4a5 5 0 0 1 5 5v1z"></path></svg> |
|||
</label> |
|||
<input |
|||
type="radio" |
|||
name="filter" |
|||
id="channel" |
|||
className="hidden" |
|||
onClick={() => setFilter("channel")} |
|||
/> |
|||
|
|||
</form> |
|||
|
|||
</div> |
|||
|
|||
{/* RESULTS */} |
|||
<div className="grid grid-cols-4 gap-8 mt-8"> |
|||
{results && results.length > 0 ? ( |
|||
results.map((result, index) => { |
|||
if (result.type === "video") { |
|||
return ( |
|||
<VideoCard key={index} video={result} /> |
|||
); |
|||
} else if (result.type === "channel") { |
|||
return ( |
|||
<CreatorCard key={index} creator={result} /> |
|||
); |
|||
} |
|||
}) |
|||
) : ( |
|||
|
|||
<div className="text-white text-center mt-10 col-span-4"> |
|||
<h2 className="text-3xl font-bold">Aucun résultat trouvé</h2> |
|||
<p className="mt-4">Essayez de modifier votre recherche ou d'utiliser un autre filtre.</p> |
|||
</div> |
|||
|
|||
)} |
|||
</div> |
|||
|
|||
</main> |
|||
</div> |
|||
) |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
|
|||
|
|||
export function search(query, filter, offset, limit) { |
|||
return fetch(`https://localhost/api/search?q=${encodeURIComponent(query)}&type=${filter}&offset=${offset}&limit=${limit}`) |
|||
.then((response) => { |
|||
if (!response.ok) { |
|||
throw new Error("Network response was not ok"); |
|||
} |
|||
return response.json(); |
|||
}) |
|||
.catch((error) => { |
|||
console.error("There was a problem with the fetch operation:", error); |
|||
throw error; |
|||
}); |
|||
} |
|||
Loading…
Reference in new issue