Skip to content

Commit eb3d41b

Browse files
committed
queryで検索可能になった
1 parent 9a35810 commit eb3d41b

File tree

4 files changed

+101
-58
lines changed

4 files changed

+101
-58
lines changed

web/app/search/layout.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import BottomBar from "~/components/BottomBar";
22
import Header from "~/components/Header";
3-
import { NavigateByAuthState } from "~/components/common/NavigateByAuthState";
43

54
export default function HomePageLayout({
65
children,
76
}: {
87
children: React.ReactNode;
98
}) {
109
return (
11-
<NavigateByAuthState type="toLoginForUnauthenticated">
10+
<>
1211
<Header title="検索/Search" />
1312
<div className="absolute top-14 right-0 bottom-14 left-0 overflow-y-auto sm:top-16">
1413
{children}
1514
</div>
1615
<BottomBar activeTab="2_search" />
17-
</NavigateByAuthState>
16+
</>
1817
);
1918
}

web/app/search/page.tsx

Lines changed: 12 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,24 @@
11
"use client";
22

3-
import type { User } from "common/types";
43
import type React from "react";
5-
import { useEffect, useState } from "react";
6-
import { useAll } from "~/api/user";
4+
import Search from "~/components/search/search";
5+
import Table from "~/components/search/table";
76

8-
import { useModal } from "~/components/common/modal/ModalProvider";
9-
import { HumanListItem } from "~/components/human/humanListItem";
10-
11-
export default function SearchPage() {
12-
const [searchWord, setSearchWord] = useState("");
13-
const {
14-
state: { data },
15-
} = useAll();
16-
const { openModal } = useModal();
17-
const [users, setUsers] = useState<User[] | null>(null);
18-
19-
useEffect(() => {
20-
if (data) {
21-
setUsers(data);
22-
}
23-
}, [data]);
24-
25-
function searchByUserName() {
26-
const filteredUsers = data?.filter((user) =>
27-
user.name.toLowerCase().includes(searchWord.toLowerCase()),
28-
);
29-
setUsers(filteredUsers || null);
30-
}
7+
export default function SearchPage(props: {
8+
searchParams?: {
9+
query?: string;
10+
page?: string;
11+
};
12+
}) {
13+
const searchParams = props.searchParams;
14+
const query = searchParams?.query || "";
3115

3216
return (
3317
<div className="flex min-h-screen items-center justify-center bg-gray-100">
3418
<div className="card w-96 bg-white p-6 shadow-md">
3519
<h2 className="mb-4 font-bold text-2xl">Search</h2>
36-
<div className="form-control mb-4">
37-
<label htmlFor="searchInput" className="label">
38-
<span className="label-text">Enter search term</span>
39-
</label>
40-
<input
41-
type="text"
42-
value={searchWord}
43-
onChange={(e) => setSearchWord(e.target.value)}
44-
placeholder="Type here"
45-
className="input input-bordered w-full"
46-
/>
47-
</div>
48-
<button
49-
type="button"
50-
onClick={searchByUserName}
51-
className="btn btn-primary w-full"
52-
>
53-
Search
54-
</button>
55-
{users?.map((user) => (
56-
<HumanListItem
57-
key={user.id}
58-
id={user.id}
59-
name={user.name}
60-
pictureUrl={user.pictureUrl}
61-
onOpen={() => openModal(user)}
62-
hasDots
63-
/>
64-
))}
20+
<Search placeholder="検索" />
21+
<Table query={query} />
6522
</div>
6623
</div>
6724
);

web/components/search/search.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"use client";
2+
3+
import { usePathname, useRouter, useSearchParams } from "next/navigation";
4+
import { MdOutlineSearch } from "react-icons/md";
5+
6+
export default function Search({ placeholder }: { placeholder: string }) {
7+
const searchParams = useSearchParams();
8+
const pathname = usePathname();
9+
const { replace } = useRouter();
10+
11+
function handleSearch(term: string) {
12+
const params = new URLSearchParams(searchParams);
13+
if (term) {
14+
params.set("query", term);
15+
} else {
16+
params.delete("query");
17+
}
18+
replace(`${pathname}?${params.toString()}`);
19+
}
20+
21+
return (
22+
<div className="relative flex flex-1 flex-shrink-0">
23+
<label htmlFor="search" className="sr-only">
24+
Search
25+
</label>
26+
<input
27+
className="peer block w-full rounded-md border border-gray-200 py-[9px] pl-10 text-sm outline-2 placeholder:text-gray-500"
28+
placeholder={placeholder}
29+
onChange={(e) => {
30+
handleSearch(e.target.value);
31+
}}
32+
defaultValue={searchParams.get("query")?.toString()}
33+
/>
34+
<MdOutlineSearch className="-translate-y-1/2 absolute top-1/2 left-3 h-[18px] w-[18px] text-gray-500 peer-focus:text-gray-900" />
35+
</div>
36+
);
37+
}

web/components/search/table.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"use client";
2+
import type { User } from "common/types";
3+
import { useEffect, useState } from "react";
4+
import { useAll } from "~/api/user";
5+
import { useModal } from "../common/modal/ModalProvider";
6+
import { HumanListItem } from "../human/humanListItem";
7+
8+
export default function UserTable({ query }: { query: string }) {
9+
const { openModal } = useModal();
10+
const {
11+
state: { data },
12+
} = useAll();
13+
14+
const [users, setUsers] = useState<User[] | null>(null);
15+
16+
useEffect(() => {
17+
if (data) {
18+
setUsers(data);
19+
}
20+
}, [data]);
21+
22+
useEffect(() => {
23+
function searchByUserName(query: string) {
24+
const filteredUsers = data?.filter((user) =>
25+
user.name.toLowerCase().includes(query.toLowerCase()),
26+
);
27+
setUsers(filteredUsers || null);
28+
}
29+
if (query === "") {
30+
setUsers(data);
31+
}
32+
if (query) {
33+
searchByUserName(query);
34+
}
35+
}, [query, data]);
36+
37+
return (
38+
<div>
39+
{users?.map((user) => (
40+
<HumanListItem
41+
key={user.id}
42+
id={user.id}
43+
name={user.name}
44+
pictureUrl={user.pictureUrl}
45+
onOpen={() => openModal(user)}
46+
/>
47+
))}
48+
</div>
49+
);
50+
}

0 commit comments

Comments
 (0)