Implement routing and search functionality enhancements

- Wrapped the main application in a BrowserRouter to enable routing.
- Integrated react-router-dom for managing search parameters in the Search component.
- Updated search functionality to initialize from URL parameters and reflect changes in the URL when the search query is modified.
- Added logic to filter templates based on search query and selected tags, improving user experience.
This commit is contained in:
Mauricio Siu
2025-03-30 21:44:23 -06:00
parent a22c638f82
commit fa3a75a9ba
4 changed files with 120 additions and 10 deletions

View File

@@ -3,16 +3,19 @@ import Navigation from "./components/Navigation";
import Search from "./components/Search";
import { useStore } from "@/store";
import "./App.css";
import { BrowserRouter } from "react-router-dom";
function App() {
const view = useStore((state) => state.view);
return (
<div className="min-h-screen">
<Navigation />
<Search />
<TemplateGrid view={view} />
</div>
<BrowserRouter>
<div className="min-h-screen">
<Navigation />
<Search />
<TemplateGrid view={view} />
</div>
</BrowserRouter>
);
}

View File

@@ -16,9 +16,10 @@ import { Check, ChevronsUpDown } from "lucide-react";
import React from "react";
import { Tabs, TabsList, TabsTrigger } from "./ui/tabs";
import SelectedTags from "./SelectedTags";
import { useSearchParams } from "react-router-dom";
const Search = () => {
const { templates, searchQuery, setSearchQuery, setView, templatesCount } =
const { templates, searchQuery, setSearchQuery, setView, templatesCount, setFilteredTemplates, setTemplatesCount } =
useStore();
const selectedTags = useStore((state) => state.selectedTags);
const addSelectedTag = useStore((state) => state.addSelectedTag);
@@ -26,6 +27,7 @@ const Search = () => {
const [open, setOpen] = React.useState(false);
const [tagSearch, setTagSearch] = React.useState("");
const view = useStore((state) => state.view);
const [searchParams, setSearchParams] = useSearchParams();
// Get all unique tags, safely handle empty templates
const uniqueTags = React.useMemo(() => {
@@ -43,6 +45,53 @@ const Search = () => {
);
}, [uniqueTags, tagSearch]);
// Initialize search query from URL params and apply filters
React.useEffect(() => {
const queryFromUrl = searchParams.get("q") || "";
if (queryFromUrl !== searchQuery) {
setSearchQuery(queryFromUrl);
}
// Apply filters whenever templates, search query or selected tags change
if (templates) {
const filtered = templates.filter((template) => {
// Filter by search query
const matchesSearch = template.name
.toLowerCase()
.includes(queryFromUrl.toLowerCase());
// Filter by selected tags
const matchesTags =
selectedTags.length === 0 ||
selectedTags.every((tag) => template.tags.includes(tag));
return matchesSearch && matchesTags;
});
setFilteredTemplates(filtered);
setTemplatesCount(filtered.length);
}
}, [searchParams, templates, selectedTags, setSearchQuery, setFilteredTemplates, setTemplatesCount]);
// Update URL params when search query changes
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newQuery = e.target.value;
setSearchQuery(newQuery);
if (newQuery) {
setSearchParams({ q: newQuery });
} else {
searchParams.delete("q");
setSearchParams(searchParams);
}
};
// Clear search and URL params
const handleClearSearch = () => {
setSearchQuery("");
searchParams.delete("q");
setSearchParams(searchParams);
};
return (
<div className=" mx-auto p-4 lg:p-12 border-b w-full">
{/* <h1 className="text-2xl md:text-3xl xl:text-4xl font-bold text-center mb-8">
@@ -63,11 +112,11 @@ const Search = () => {
type="text"
placeholder="Search templates..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onChange={handleSearchChange}
className="w-full p-6"
/>
{searchQuery.length > 0 ? (
<div className="cursor-pointer" onClick={() => setSearchQuery("")}>
<div className="cursor-pointer" onClick={handleClearSearch}>
<XIcon className="absolute end-3 translate-y-3.5 top-1/2 h-5 w-5 text-gray-400" />
</div>
) : (