2025-08-26 14:23:22 +09:00
|
|
|
import { Search, Plus, ChevronDown, ChevronUp } from "lucide-react";
|
2025-08-21 09:41:46 +09:00
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { Input } from "@/components/ui/input";
|
|
|
|
|
import { UserSearchFilter } from "@/types/user";
|
2025-08-26 14:23:22 +09:00
|
|
|
import { useState } from "react";
|
2025-08-21 09:41:46 +09:00
|
|
|
|
|
|
|
|
interface UserToolbarProps {
|
|
|
|
|
searchFilter: UserSearchFilter;
|
|
|
|
|
totalCount: number;
|
|
|
|
|
isSearching?: boolean;
|
|
|
|
|
onSearchChange: (searchFilter: Partial<UserSearchFilter>) => void;
|
|
|
|
|
onCreateClick: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 사용자 관리 툴바 컴포넌트
|
2025-08-26 14:23:22 +09:00
|
|
|
* 통합 검색 + 고급 검색 옵션 지원
|
2025-08-21 09:41:46 +09:00
|
|
|
*/
|
|
|
|
|
export function UserToolbar({
|
|
|
|
|
searchFilter,
|
|
|
|
|
totalCount,
|
|
|
|
|
isSearching = false,
|
|
|
|
|
onSearchChange,
|
|
|
|
|
onCreateClick,
|
|
|
|
|
}: UserToolbarProps) {
|
2025-08-26 14:23:22 +09:00
|
|
|
const [showAdvancedSearch, setShowAdvancedSearch] = useState(false);
|
|
|
|
|
|
|
|
|
|
// 통합 검색어 변경
|
|
|
|
|
const handleUnifiedSearchChange = (value: string) => {
|
|
|
|
|
onSearchChange({
|
|
|
|
|
searchValue: value,
|
|
|
|
|
// 통합 검색 시 고급 검색 필드들 클리어
|
|
|
|
|
searchType: undefined,
|
|
|
|
|
search_sabun: undefined,
|
|
|
|
|
search_companyName: undefined,
|
|
|
|
|
search_deptName: undefined,
|
|
|
|
|
search_positionName: undefined,
|
|
|
|
|
search_userId: undefined,
|
|
|
|
|
search_userName: undefined,
|
|
|
|
|
search_tel: undefined,
|
|
|
|
|
search_email: undefined,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 고급 검색 필드 변경
|
|
|
|
|
const handleAdvancedSearchChange = (field: string, value: string) => {
|
|
|
|
|
onSearchChange({
|
|
|
|
|
[field]: value,
|
|
|
|
|
// 고급 검색 시 통합 검색어 클리어
|
|
|
|
|
searchValue: undefined,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 고급 검색 모드인지 확인
|
|
|
|
|
const isAdvancedSearchMode = !!(
|
|
|
|
|
searchFilter.search_sabun ||
|
|
|
|
|
searchFilter.search_companyName ||
|
|
|
|
|
searchFilter.search_deptName ||
|
|
|
|
|
searchFilter.search_positionName ||
|
|
|
|
|
searchFilter.search_userId ||
|
|
|
|
|
searchFilter.search_userName ||
|
|
|
|
|
searchFilter.search_tel ||
|
|
|
|
|
searchFilter.search_email
|
|
|
|
|
);
|
|
|
|
|
|
2025-08-21 09:41:46 +09:00
|
|
|
return (
|
|
|
|
|
<div className="space-y-4">
|
2025-10-22 14:52:13 +09:00
|
|
|
{/* 검색 및 액션 영역 */}
|
|
|
|
|
<div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
|
|
|
|
{/* 검색 영역 */}
|
|
|
|
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-center">
|
|
|
|
|
<div className="w-full sm:w-[400px]">
|
2025-08-26 14:23:22 +09:00
|
|
|
<div className="relative">
|
|
|
|
|
<Search
|
2025-10-22 14:52:13 +09:00
|
|
|
className={`absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 ${
|
|
|
|
|
isSearching ? "animate-pulse text-primary" : "text-muted-foreground"
|
2025-08-26 14:23:22 +09:00
|
|
|
}`}
|
|
|
|
|
/>
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="통합 검색..."
|
|
|
|
|
value={searchFilter.searchValue || ""}
|
|
|
|
|
onChange={(e) => handleUnifiedSearchChange(e.target.value)}
|
|
|
|
|
disabled={isAdvancedSearchMode}
|
2025-10-22 14:52:13 +09:00
|
|
|
className={`h-10 pl-10 text-sm ${
|
|
|
|
|
isSearching ? "border-primary ring-2 ring-primary/20" : ""
|
|
|
|
|
} ${isAdvancedSearchMode ? "cursor-not-allowed bg-muted text-muted-foreground" : ""}`}
|
2025-08-26 14:23:22 +09:00
|
|
|
/>
|
|
|
|
|
</div>
|
2025-10-22 14:52:13 +09:00
|
|
|
{isSearching && <p className="mt-1.5 text-xs text-primary">검색 중...</p>}
|
2025-08-26 14:23:22 +09:00
|
|
|
{isAdvancedSearchMode && (
|
2025-10-22 14:52:13 +09:00
|
|
|
<p className="mt-1.5 text-xs text-warning">
|
2025-08-26 14:23:22 +09:00
|
|
|
고급 검색 모드가 활성화되어 있습니다. 통합 검색을 사용하려면 고급 검색 조건을 초기화하세요.
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 고급 검색 토글 버튼 */}
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
2025-10-22 14:52:13 +09:00
|
|
|
size="default"
|
2025-08-26 14:23:22 +09:00
|
|
|
onClick={() => setShowAdvancedSearch(!showAdvancedSearch)}
|
2025-10-22 14:52:13 +09:00
|
|
|
className="h-10 gap-2 text-sm font-medium"
|
2025-08-21 09:41:46 +09:00
|
|
|
>
|
2025-10-22 14:52:13 +09:00
|
|
|
고급 검색
|
2025-08-26 14:23:22 +09:00
|
|
|
{showAdvancedSearch ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
|
|
|
|
|
</Button>
|
2025-08-21 09:41:46 +09:00
|
|
|
</div>
|
|
|
|
|
|
2025-10-22 14:52:13 +09:00
|
|
|
{/* 액션 버튼 영역 */}
|
|
|
|
|
<div className="flex items-center gap-4">
|
|
|
|
|
{/* 조회 결과 정보 */}
|
|
|
|
|
<div className="text-sm text-muted-foreground">
|
|
|
|
|
총 <span className="font-semibold text-foreground">{totalCount.toLocaleString()}</span> 명
|
|
|
|
|
</div>
|
2025-08-26 14:23:22 +09:00
|
|
|
|
2025-10-22 14:52:13 +09:00
|
|
|
{/* 사용자 등록 버튼 */}
|
|
|
|
|
<Button onClick={onCreateClick} size="default" className="h-10 gap-2 text-sm font-medium">
|
|
|
|
|
<Plus className="h-4 w-4" />
|
|
|
|
|
사용자 등록
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-08-26 14:23:22 +09:00
|
|
|
|
2025-10-22 14:52:13 +09:00
|
|
|
{/* 고급 검색 옵션 */}
|
|
|
|
|
{showAdvancedSearch && (
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<h4 className="text-sm font-semibold">고급 검색 옵션</h4>
|
|
|
|
|
<p className="text-xs text-muted-foreground">각 필드별로 개별 검색 조건을 설정할 수 있습니다</p>
|
|
|
|
|
</div>
|
2025-08-26 14:23:22 +09:00
|
|
|
|
2025-10-22 14:52:13 +09:00
|
|
|
{/* 고급 검색 필드들 */}
|
|
|
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="회사명 검색"
|
|
|
|
|
value={searchFilter.search_companyName || ""}
|
|
|
|
|
onChange={(e) => handleAdvancedSearchChange("search_companyName", e.target.value)}
|
|
|
|
|
className="h-10 text-sm"
|
|
|
|
|
/>
|
2025-08-26 14:23:22 +09:00
|
|
|
|
2025-10-22 14:52:13 +09:00
|
|
|
<Input
|
|
|
|
|
placeholder="부서명 검색"
|
|
|
|
|
value={searchFilter.search_deptName || ""}
|
|
|
|
|
onChange={(e) => handleAdvancedSearchChange("search_deptName", e.target.value)}
|
|
|
|
|
className="h-10 text-sm"
|
|
|
|
|
/>
|
2025-08-26 14:23:22 +09:00
|
|
|
|
2025-10-22 14:52:13 +09:00
|
|
|
<Input
|
|
|
|
|
placeholder="직책 검색"
|
|
|
|
|
value={searchFilter.search_positionName || ""}
|
|
|
|
|
onChange={(e) => handleAdvancedSearchChange("search_positionName", e.target.value)}
|
|
|
|
|
className="h-10 text-sm"
|
|
|
|
|
/>
|
2025-08-26 14:23:22 +09:00
|
|
|
|
2025-10-22 14:52:13 +09:00
|
|
|
<Input
|
|
|
|
|
placeholder="사용자 ID 검색"
|
|
|
|
|
value={searchFilter.search_userId || ""}
|
|
|
|
|
onChange={(e) => handleAdvancedSearchChange("search_userId", e.target.value)}
|
|
|
|
|
className="h-10 text-sm"
|
|
|
|
|
/>
|
2025-08-26 14:23:22 +09:00
|
|
|
|
2025-10-22 14:52:13 +09:00
|
|
|
<Input
|
|
|
|
|
placeholder="사용자명 검색"
|
|
|
|
|
value={searchFilter.search_userName || ""}
|
|
|
|
|
onChange={(e) => handleAdvancedSearchChange("search_userName", e.target.value)}
|
|
|
|
|
className="h-10 text-sm"
|
|
|
|
|
/>
|
2025-08-26 14:23:22 +09:00
|
|
|
|
2025-10-22 14:52:13 +09:00
|
|
|
<Input
|
|
|
|
|
placeholder="전화번호/휴대폰 검색"
|
|
|
|
|
value={searchFilter.search_tel || ""}
|
|
|
|
|
onChange={(e) => handleAdvancedSearchChange("search_tel", e.target.value)}
|
|
|
|
|
className="h-10 text-sm"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="이메일 검색"
|
|
|
|
|
value={searchFilter.search_email || ""}
|
|
|
|
|
onChange={(e) => handleAdvancedSearchChange("search_email", e.target.value)}
|
|
|
|
|
className="h-10 text-sm"
|
|
|
|
|
/>
|
2025-08-26 14:23:22 +09:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 고급 검색 초기화 버튼 */}
|
|
|
|
|
{isAdvancedSearchMode && (
|
2025-10-22 14:52:13 +09:00
|
|
|
<div>
|
2025-08-26 14:23:22 +09:00
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
2025-10-22 14:52:13 +09:00
|
|
|
size="sm"
|
2025-08-26 14:23:22 +09:00
|
|
|
onClick={() =>
|
|
|
|
|
onSearchChange({
|
|
|
|
|
search_sabun: undefined,
|
|
|
|
|
search_companyName: undefined,
|
|
|
|
|
search_deptName: undefined,
|
|
|
|
|
search_positionName: undefined,
|
|
|
|
|
search_userId: undefined,
|
|
|
|
|
search_userName: undefined,
|
|
|
|
|
search_tel: undefined,
|
|
|
|
|
search_email: undefined,
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-10-22 14:52:13 +09:00
|
|
|
className="h-9 text-sm text-muted-foreground hover:text-foreground"
|
2025-08-26 14:23:22 +09:00
|
|
|
>
|
|
|
|
|
고급 검색 조건 초기화
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-08-21 09:41:46 +09:00
|
|
|
</div>
|
2025-08-26 14:23:22 +09:00
|
|
|
)}
|
2025-08-21 09:41:46 +09:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|