Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/api/user/getUserList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type UserListResponseType = {
export default async function getUserList(params: ListParams) {
const { page, perPage } = params.pagination;
const keyword = params.filter?.keyword || "";
const filter = "all";
const filter = params.filter?.status;

const url = keyword
? `/admin-management/users/search/${keyword}`
Expand Down
27 changes: 27 additions & 0 deletions src/components/SortSelect/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Meta, StoryObj } from "@storybook/react";

import SortSelect from ".";

const meta: Meta<typeof SortSelect> = {
title: "components/sortSelect",
component: SortSelect,
tags: ["autodocs"],
argTypes: {
onChange: { action: "changed" },
},
};

export default meta;

type SortSelectStory = StoryObj<typeof SortSelect>;

export const Default: SortSelectStory = {
args: {
options: [
{ value: "name", label: "이름순" },
{ value: "date", label: "날짜순" },
{ value: "price", label: "가격순" },
],
defaultValue: "name",
},
};
36 changes: 36 additions & 0 deletions src/components/SortSelect/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
interface SortOption {
value: string;
label: string;
}

interface SortSelectProps {
options: SortOption[];
onChange: (value: string) => void;
defaultValue?: string;
}

export default function SortSelect({
options,
onChange,
defaultValue,
}: SortSelectProps) {
const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
onChange(event.target.value);
};

return (
<div className="relative inline-block w-48">
<select
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
onChange={handleChange}
defaultValue={defaultValue}
>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
);
}
59 changes: 59 additions & 0 deletions src/hooks/useQueryParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useLocation } from "react-router-dom";

const useQueryParams = () => {
const location = useLocation();
const searchParams = new URLSearchParams(location.search);

const addKeyValue = (key: string, value: string) => {
searchParams.append(key, value);
return searchParams.toString();
};
const replaceValue = (key: string, value: string) => {
searchParams.set(key, value);
return searchParams.toString();
};

const removeKeyValue = (key: string, value: string) => {
const values = searchParams.getAll(key);
searchParams.delete(key);

values.forEach((val) => {
if (val !== value) {
searchParams.append(key, val);
}
});

return searchParams.toString();
};

const removeAllValues = (key: string) => {
searchParams.delete(key);

return searchParams.toString();
};

const hasValue = (key: string) => {
return searchParams.has(key);
};

const getValue = (key: string) => searchParams.get(key);
const getAllValue = (key: string) => searchParams.getAll(key);

const hasKeyValueSet = (key: string, value: string) => {
const values = getAllValue(key);
return values.includes(value);
};

return {
getValue,
getAllValue,
addKeyValue,
replaceValue,
removeKeyValue,
removeAllValues,
hasValue,
hasKeyValueSet,
};
};

export default useQueryParams;
40 changes: 31 additions & 9 deletions src/pages/user/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Link } from "react-router-dom";
import List from "../../components/List";
import LoadingFallback from "../../components/fallback/LoadingFallback";
import Pagination from "../../components/Pagination";
import SortSelect from "../../components/SortSelect";
import UIErrorBoundary from "../../components/fallback/UIErrorBoundary";
import { UserType } from "../../api/user";
import usePagination from "../../components/Pagination/usePagination";
Expand All @@ -27,17 +28,29 @@ const userListColumns = [
"사용자 상태",
"가입날짜",
];

const USER_FILTER = [
{ value: "all", label: "전체보기" },
{ value: "monitored", label: "monitored" },
{ value: "activeSubscription", label: "구독자만 보기" },
];

const UserListContent = () => {
const [userSearchKeyword, setUserSearchKeyword] = useState("");
const [userFilter, setUserFilter] = useState(USER_FILTER[0].value);
const { currentPage, handlePaginationEvent } = usePagination();

const { data, error, isLoading } = useQuery({
...userQueryOptions.getUserList({
pagination: { page: currentPage, perPage: 10 },
filter: { keyword: userSearchKeyword },
filter: { keyword: userSearchKeyword, status: userFilter },
}),
});

const changeUserFilter = (filter: string) => {
setUserFilter(filter);
};

if (isLoading) {
return <LoadingFallback />;
}
Expand All @@ -52,17 +65,26 @@ const UserListContent = () => {
return (
<List>
<List.Header totalCount={data.total} label="사용자">
<KeywordSearch
placeholder="이메일을 입력하세요"
keyword={userSearchKeyword}
onKeywordChange={setUserSearchKeyword}
/>
<div className="flex gap-[20px]">
<SortSelect
options={USER_FILTER}
onChange={changeUserFilter}
defaultValue={USER_FILTER[0].value}
/>
<KeywordSearch
placeholder="이메일을 입력하세요"
keyword={userSearchKeyword}
onKeywordChange={setUserSearchKeyword}
/>
</div>
</List.Header>
<List.ColumnContainer headers={userListColumns} row={5} />
<List.RowContainer row={10}>
{data.users.map((user) => (
<UserListItem key={user.id} {...user} />
))}
{!data.users || data.users.length === 0 ? (
<Blank />
) : (
data.users.map((user) => <UserListItem key={user.id} {...user} />)
)}
</List.RowContainer>
<Pagination
totalPages={data.totalPage}
Expand Down
8 changes: 1 addition & 7 deletions src/queries/userQueryOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@ import { queryOptions } from "@tanstack/react-query";
const userQueryOptions = {
getUserList: (params: ListParams) =>
queryOptions({
queryKey: [
"user",
"list",
params.pagination.page,
params.pagination.perPage,
params.filter?.keyword || "",
],
queryKey: ["user", "list", params],
queryFn: () => getUserList(params),
}),
getUserDetail: (params: DetailParams) =>
Expand Down
Loading