필터 UI 수정 및 대시보드 연동
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
YAxis
|
||||
} from 'recharts'
|
||||
import { genomeApi, TraitRankDto } from "@/lib/api/genome.api"
|
||||
import { useGlobalFilter } from "@/contexts/GlobalFilterContext"
|
||||
|
||||
// 카테고리 색상 (모던 & 다이나믹 - 생동감 있는 색상)
|
||||
const CATEGORY_COLORS: Record<string, string> = {
|
||||
@@ -184,9 +185,23 @@ export function NormalDistributionChart({
|
||||
chartFilterTrait: externalChartFilterTrait,
|
||||
onChartFilterTraitChange
|
||||
}: NormalDistributionChartProps) {
|
||||
const { filters } = useGlobalFilter()
|
||||
|
||||
// 필터에서 고정된 첫 번째 형질 (없으면 첫 번째 선택된 형질, 없으면 '도체중')
|
||||
const firstPinnedTrait = filters.pinnedTraits?.[0] || selectedTraitData[0]?.name || '도체중'
|
||||
|
||||
// 차트 필터 - 선택된 형질 또는 전체 선발지수 (외부 제어 가능)
|
||||
const [internalChartFilterTrait, setInternalChartFilterTrait] = useState<string>('overall')
|
||||
// 필터 비활성 시 기본값은 첫 번째 고정 형질
|
||||
const [internalChartFilterTrait, setInternalChartFilterTrait] = useState<string>(() => {
|
||||
return filters.isActive ? 'overall' : firstPinnedTrait
|
||||
})
|
||||
|
||||
// 필터 활성 상태 변경 시 기본값 업데이트
|
||||
useEffect(() => {
|
||||
if (!filters.isActive && internalChartFilterTrait === 'overall') {
|
||||
setInternalChartFilterTrait(firstPinnedTrait)
|
||||
}
|
||||
}, [filters.isActive, firstPinnedTrait])
|
||||
|
||||
// 외부에서 제어하면 외부 값 사용, 아니면 내부 상태 사용
|
||||
const chartFilterTrait = externalChartFilterTrait ?? internalChartFilterTrait
|
||||
@@ -366,12 +381,15 @@ export function NormalDistributionChart({
|
||||
<SelectValue placeholder="전체 선발지수" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="overall">전체 선발지수</SelectItem>
|
||||
{selectedTraitData.length > 0 && (
|
||||
{filters.isActive && (
|
||||
<SelectItem value="overall">전체 선발지수</SelectItem>
|
||||
)}
|
||||
{/* 모든 형질 표시 (필터 설정과 무관) */}
|
||||
{allTraits.length > 0 && (
|
||||
<>
|
||||
{/* 카테고리별로 그룹핑 */}
|
||||
{(['성장', '생산', '체형', '무게', '비율'] as const).map((category) => {
|
||||
const categoryTraits = selectedTraitData.filter(t => t.category === category)
|
||||
const categoryTraits = allTraits.filter(t => t.category === category)
|
||||
if (categoryTraits.length === 0) return null
|
||||
return (
|
||||
<div key={category}>
|
||||
|
||||
@@ -193,8 +193,21 @@ export default function CowOverviewPage() {
|
||||
const [highlightMode, setHighlightMode] = useState<'farm' | 'region' | null>(null)
|
||||
const distributionChartRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// 필터에서 고정된 첫 번째 형질 (없으면 '도체중')
|
||||
const firstPinnedTrait = filters.pinnedTraits?.[0] || '도체중'
|
||||
|
||||
// 차트 형질 필터 (전체 선발지수 또는 개별 형질)
|
||||
const [chartFilterTrait, setChartFilterTrait] = useState<string>('overall')
|
||||
// 필터 비활성 시 기본값은 첫 번째 고정 형질
|
||||
const [chartFilterTrait, setChartFilterTrait] = useState<string>(() => {
|
||||
return filters.isActive ? 'overall' : firstPinnedTrait
|
||||
})
|
||||
|
||||
// 필터 활성 상태 변경 시 기본값 업데이트
|
||||
useEffect(() => {
|
||||
if (!filters.isActive && chartFilterTrait === 'overall') {
|
||||
setChartFilterTrait(firstPinnedTrait)
|
||||
}
|
||||
}, [filters.isActive, firstPinnedTrait, chartFilterTrait])
|
||||
|
||||
// 유전자 탭 필터 상태
|
||||
const [geneSearchKeyword, setGeneSearchKeyword] = useState('')
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { apiClient, farmApi } from "@/lib/api"
|
||||
import { DashboardStatsDto, FarmRegionRankingDto, YearlyTraitTrendDto, genomeApi } from "@/lib/api/genome.api"
|
||||
import { useAuthStore } from "@/store/auth-store"
|
||||
import { useGlobalFilter } from "@/contexts/GlobalFilterContext"
|
||||
import {
|
||||
AlertCircle,
|
||||
CheckCircle2,
|
||||
@@ -57,23 +58,50 @@ const TRAIT_CATEGORIES: Record<string, string[]> = {
|
||||
|
||||
export default function DashboardPage() {
|
||||
const { user } = useAuthStore()
|
||||
const { filters } = useGlobalFilter()
|
||||
const [farmNo, setFarmNo] = useState<number | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [stats, setStats] = useState<DashboardStatsDto | null>(null)
|
||||
const [farmRanking, setFarmRanking] = useState<FarmRegionRankingDto | null>(null)
|
||||
|
||||
// 필터에서 고정된 첫 번째 형질 (없으면 '도체중')
|
||||
const firstPinnedTrait = filters.pinnedTraits?.[0] || '도체중'
|
||||
|
||||
// 연도별 육종가 추이 관련 state
|
||||
const [selectedTrait, setSelectedTrait] = useState<string>(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
return localStorage.getItem('dashboard_trait') || '도체중'
|
||||
return localStorage.getItem('dashboard_trait') || firstPinnedTrait
|
||||
}
|
||||
return '도체중'
|
||||
return firstPinnedTrait
|
||||
})
|
||||
const [traitTrendData, setTraitTrendData] = useState<YearlyTraitTrendDto | null>(null)
|
||||
const [traitTrendLoading, setTraitTrendLoading] = useState(false)
|
||||
|
||||
// 보은군 내 농가 위치 차트 분포기준 (선발지수 or 개별 형질)
|
||||
const [distributionBasis, setDistributionBasis] = useState<string>('overall')
|
||||
// 필터 활성 시 'overall', 비활성 시 고정된 첫 번째 형질
|
||||
const [distributionBasis, setDistributionBasis] = useState<string>(() => {
|
||||
return filters.isActive ? 'overall' : firstPinnedTrait
|
||||
})
|
||||
|
||||
// 필터 변경 시 기본값 업데이트
|
||||
useEffect(() => {
|
||||
if (!filters.isActive && distributionBasis === 'overall') {
|
||||
setDistributionBasis(firstPinnedTrait)
|
||||
}
|
||||
}, [filters.isActive, distributionBasis, firstPinnedTrait])
|
||||
|
||||
// 필터에서 고정된 형질이 변경되면 selectedTrait도 업데이트
|
||||
useEffect(() => {
|
||||
if (filters.pinnedTraits && filters.pinnedTraits.length > 0) {
|
||||
const newFirstPinned = filters.pinnedTraits[0]
|
||||
// 첫 번째 고정 형질로 변경
|
||||
setSelectedTrait(newFirstPinned)
|
||||
// distributionBasis가 overall이 아니면 첫 번째 고정 형질로 변경
|
||||
if (distributionBasis !== 'overall') {
|
||||
setDistributionBasis(newFirstPinned)
|
||||
}
|
||||
}
|
||||
}, [filters.pinnedTraits])
|
||||
|
||||
// 모든 형질 목록 (평탄화)
|
||||
const allTraits = Object.entries(TRAIT_CATEGORIES).flatMap(([cat, traits]) =>
|
||||
@@ -431,7 +459,9 @@ export default function DashboardPage() {
|
||||
<SelectValue placeholder="전체 선발지수" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="overall" className="text-sm font-medium">전체 선발지수</SelectItem>
|
||||
{filters.isActive && (
|
||||
<SelectItem value="overall" className="text-sm font-medium">전체 선발지수</SelectItem>
|
||||
)}
|
||||
{Object.entries(TRAIT_CATEGORIES).map(([category, traits]) => (
|
||||
<div key={category}>
|
||||
<div className="px-2 py-1.5 text-sm font-semibold text-slate-500 bg-slate-50">{category}</div>
|
||||
|
||||
Reference in New Issue
Block a user