Skip to content

Commit cf77158

Browse files
committed
feat: sync search params and version filter with URL parameters - Add URL parameter synchronization using useSearchParams hook - Search term synced with 'q' URL parameter - Version filter synced with 'filter' URL parameter - Auto-search when package name is present in URL on page load - Update SearchBox and VersionFilterInput components to support URL state - Maintain input field state separate from applied filter for better UX
1 parent aa9c76f commit cf77158

File tree

3 files changed

+71
-15
lines changed

3 files changed

+71
-15
lines changed

src/App.tsx

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1-
import React, { useState } from "react";
1+
import React, { useEffect } from "react";
22
import { ThemeProvider } from "./contexts/ThemeContext";
33
import AntdProvider from "./contexts/AntdProvider";
44
import AppLayout from "./components/AppLayout";
55
import SearchBox from "./components/SearchBox";
66
import PackageResults from "./components/PackageResults";
77
import ErrorDisplay from "./components/ErrorDisplay";
88
import { usePackageSearch } from "./hooks/usePackageSearch";
9+
import { useSearchParams } from "./hooks/useSearchParams";
910
import "./App.css";
1011

1112
const AppContent: React.FC = () => {
13+
// URL params state management
14+
const { params, setParam, resetParams } = useSearchParams({
15+
q: "",
16+
filter: "",
17+
});
18+
1219
const {
1320
searchTerm,
1421
setSearchTerm,
@@ -20,29 +27,61 @@ const AppContent: React.FC = () => {
2027
resetSearch,
2128
} = usePackageSearch();
2229

23-
// State for version filter
24-
const [versionFilter, setVersionFilter] = useState("");
30+
// Sync URL params with local state
31+
useEffect(() => {
32+
if (params.q && params.q !== searchTerm) {
33+
setSearchTerm(params.q);
34+
// Auto-search if there's a package name in URL
35+
if (params.q.trim()) {
36+
searchPackage(params.q);
37+
}
38+
}
39+
}, [params.q, searchTerm, setSearchTerm, searchPackage]);
40+
41+
// Update URL when search term changes
42+
useEffect(() => {
43+
if (searchTerm !== params.q) {
44+
setParam("q", searchTerm);
45+
}
46+
}, [searchTerm, params.q, setParam]);
47+
48+
// Handle search term changes
49+
const handleSearchTermChange = (value: string) => {
50+
setSearchTerm(value);
51+
setParam("q", value);
52+
};
53+
54+
// Handle version filter changes
55+
const handleVersionFilterChange = (filter: string) => {
56+
setParam("filter", filter);
57+
};
2558

2659
// Handle logo click to reset the app to home state
2760
const handleLogoClick = () => {
2861
resetSearch();
2962
setSearchTerm("");
30-
setVersionFilter("");
63+
resetParams();
3164
};
3265

3366
const renderContent = () => {
3467
if (error) {
3568
return (
36-
<ErrorDisplay errorMessage={error} onReset={() => setSearchTerm("")} />
69+
<ErrorDisplay
70+
errorMessage={error}
71+
onReset={() => {
72+
setSearchTerm("");
73+
setParam("q", "");
74+
}}
75+
/>
3776
);
3877
}
3978

4079
if (packageInfo) {
4180
return (
4281
<PackageResults
4382
packageInfo={packageInfo}
44-
versionFilter={versionFilter}
45-
onVersionFilterChange={setVersionFilter}
83+
versionFilter={params.filter}
84+
onVersionFilterChange={handleVersionFilterChange}
4685
/>
4786
);
4887
}
@@ -59,11 +98,12 @@ const AppContent: React.FC = () => {
5998
<AppLayout onLogoClick={handleLogoClick}>
6099
<SearchBox
61100
searchTerm={searchTerm}
62-
onSearchTermChange={setSearchTerm}
101+
onSearchTermChange={handleSearchTermChange}
63102
onSearch={searchPackage}
64103
isLoading={loading}
65104
isCompact={showCompactSearch}
66-
onVersionFilter={packageInfo ? setVersionFilter : undefined}
105+
onVersionFilter={packageInfo ? handleVersionFilterChange : undefined}
106+
versionFilter={params.filter}
67107
/>
68108
{renderContent()}
69109
</AppLayout>

src/components/SearchBox.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface SearchBoxProps {
1212
isLoading: boolean;
1313
isCompact?: boolean;
1414
onVersionFilter?: (filter: string) => void;
15+
versionFilter?: string;
1516
}
1617

1718
const SearchBox: React.FC<SearchBoxProps> = ({
@@ -21,6 +22,7 @@ const SearchBox: React.FC<SearchBoxProps> = ({
2122
isLoading,
2223
isCompact = false,
2324
onVersionFilter,
25+
versionFilter,
2426
}) => {
2527
if (isCompact) {
2628
return (
@@ -44,6 +46,7 @@ const SearchBox: React.FC<SearchBoxProps> = ({
4446
{onVersionFilter && (
4547
<VersionFilterInput
4648
onVersionFilter={onVersionFilter}
49+
versionFilter={versionFilter}
4750
isLoading={isLoading}
4851
style={{ flex: "1 0 200px", maxWidth: "300px", marginLeft: "auto" }}
4952
/>

src/components/VersionFilterInput.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,45 @@
1-
import React, { useState } from "react";
1+
import React, { useState, useEffect } from "react";
22
import { Input, Button, Space, Tooltip } from "antd";
33
import { FilterOutlined } from "@ant-design/icons";
44

55
// Version Filter Input Component interface
66
interface VersionFilterInputProps {
77
onVersionFilter: (filter: string) => void;
8+
versionFilter?: string;
89
isLoading: boolean;
910
style?: React.CSSProperties;
1011
}
1112

1213
const VersionFilterInput: React.FC<VersionFilterInputProps> = ({
1314
onVersionFilter,
15+
versionFilter = "",
1416
isLoading,
1517
style,
1618
}) => {
17-
const [versionFilter, setVersionFilter] = useState("");
19+
const [inputValue, setInputValue] = useState(versionFilter);
20+
21+
// Sync input value with prop when it changes externally
22+
useEffect(() => {
23+
setInputValue(versionFilter);
24+
}, [versionFilter]);
1825

1926
const handleFilterChange = (e: React.ChangeEvent<HTMLInputElement>) => {
20-
setVersionFilter(e.target.value);
27+
setInputValue(e.target.value);
2128
};
2229

2330
const handleFilterKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
2431
if (e.key === "Enter") {
25-
onVersionFilter(versionFilter);
32+
onVersionFilter(inputValue);
2633
}
2734
};
2835

2936
const applyFilter = () => {
30-
onVersionFilter(versionFilter);
37+
onVersionFilter(inputValue);
38+
};
39+
40+
const handleClear = () => {
41+
setInputValue("");
42+
onVersionFilter("");
3143
};
3244

3345
return (
@@ -36,10 +48,11 @@ const VersionFilterInput: React.FC<VersionFilterInputProps> = ({
3648
<Input
3749
size="middle"
3850
placeholder="Version filter (e.g., ^3.0.0)"
39-
value={versionFilter}
51+
value={inputValue}
4052
onChange={handleFilterChange}
4153
onKeyDown={handleFilterKeyDown}
4254
allowClear
55+
onClear={handleClear}
4356
disabled={isLoading}
4457
/>
4558
</Tooltip>

0 commit comments

Comments
 (0)