1+ import { useState } from 'react' ;
2+
3+ import { Flex , Text , theme , WidthFitFlex } from '@duri-fe/ui' ;
4+ import styled from '@emotion/styled' ;
5+ import { ResponsivePie } from '@nivo/pie' ;
6+ import { PET_STATISTIC_MENT } from '@salon/constants/statistic' ;
7+
8+ import { TabBarItem } from '../quotation/TabBarItem' ;
9+
110interface PetStatisticProps {
211 agePetStatistic ?: {
312 standard : string ;
@@ -18,11 +27,144 @@ interface PetStatisticProps {
1827 } [ ] ;
1928}
2029
30+ const colorScheme = [
31+ `${ theme . palette . Normal200 } ` ,
32+ `${ theme . palette . Normal500 } ` ,
33+ `${ theme . palette . Normal600 } ` ,
34+ `${ theme . palette . Normal800 } ` ,
35+ `${ theme . palette . Normal900 } ` ,
36+ `${ theme . palette . Gray300 } ` ,
37+ ] ;
38+
2139export const PetStatistic = ( {
2240 agePetStatistic,
2341 characterPetStatistic,
2442 diseasePetStatistic,
2543} : PetStatisticProps ) => {
26- console . log ( agePetStatistic , diseasePetStatistic , characterPetStatistic ) ;
27- return < div > PetStatistic</ div > ;
44+ const [ selectedTab , setSelectedTab ] = useState < '나이' | '질환' | '성격' > (
45+ '나이' ,
46+ ) ;
47+ // 각 탭에 해당하는 데이터 (Props로 전달된 데이터를 사용)
48+ const dataMap = {
49+ 나이 : agePetStatistic ,
50+ 질환 : diseasePetStatistic ,
51+ 성격 : characterPetStatistic ,
52+ } ;
53+
54+ // 선택된 탭에 맞는 데이터가 없으면 빈 배열 반환
55+ const chartData = ( dataMap [ selectedTab ] ?? [ ] ) . map ( ( item , index ) => ( {
56+ id : item . standard ,
57+ label : item . standard ,
58+ value : item . count ,
59+ ratio : item . ratio ,
60+ color : colorScheme [ index % colorScheme . length ] , // 순환하여 색상 적용
61+ } ) ) ;
62+
63+ const handleToggleTab = ( currTab : '나이' | '질환' | '성격' ) => {
64+ setSelectedTab ( currTab ) ;
65+ } ;
66+
67+ return (
68+ < Flex direction = "column" >
69+ < Flex direction = "column" align = "flex-start" gap = { 8 } padding = "0 20px" >
70+ < Text typo = "Title2" > 반려견 통계</ Text >
71+ < Text typo = "Caption1" > 우리 매장에는 이런 아이들이 자주 왔어요.</ Text >
72+ </ Flex >
73+ < Flex
74+ height = { 37 }
75+ justify = "flex-start"
76+ backgroundColor = { theme . palette . White }
77+ margin = "24px 0 0"
78+ >
79+ < TabBarItem
80+ label = "나이"
81+ selected = { selectedTab === '나이' }
82+ typo = { selectedTab === '나이' ? 'Title3' : 'Label3' }
83+ onClick = { ( ) => handleToggleTab ( '나이' ) }
84+ />
85+ < TabBarItem
86+ label = "질환"
87+ selected = { selectedTab === '질환' }
88+ typo = { selectedTab === '질환' ? 'Title3' : 'Label3' }
89+ onClick = { ( ) => handleToggleTab ( '질환' ) }
90+ />
91+ < TabBarItem
92+ label = "성격"
93+ selected = { selectedTab === '성격' }
94+ typo = { selectedTab === '성격' ? 'Title3' : 'Label3' }
95+ onClick = { ( ) => handleToggleTab ( '성격' ) }
96+ />
97+ </ Flex >
98+
99+ { /* 통계 상단 타이틀 */ }
100+ < Flex justify = "flex-start" padding = "0 20px" margin = "24px 0 0" >
101+ { dataMap [ selectedTab ] && dataMap [ selectedTab ] ?. length > 0 ? (
102+ < RelativeText typo = "Title3" >
103+ { PET_STATISTIC_MENT [ selectedTab ] ?. [
104+ dataMap [ selectedTab ] [ 0 ] . standard
105+ ] ?? '다양한 아이들이 자주 와요!' }
106+ < TextHighlight width = { selectedTab === '성격' ? '50px' : '62px' } />
107+ </ RelativeText >
108+ ) : (
109+ < Text typo = "Title3" > 아직 방문한 고객이 없어요😞</ Text >
110+ ) }
111+ </ Flex >
112+
113+ < Flex padding = "0 20px" margin = "28px 0 0" gap = { 48 } >
114+ < Flex width = { 150 } height = { 150 } >
115+ < ResponsivePie
116+ data = { chartData }
117+ innerRadius = { 0.9 } // 파이 차트 안쪽 반지름 크기
118+ padAngle = { 1 } // 조각 간의 간격
119+ cornerRadius = { 1 } // 조각 모서리의 둥글기
120+ colors = { ( { data } ) => data . color }
121+ enableArcLinkLabels = { false } // 링크 레이블 표시 여부
122+ enableArcLabels = { true } // 차트 안에 레이블 표시 여부
123+ arcLinkLabelsSkipAngle = { 10 } // 링크 레이블이 보이려면 이 각도 이상일 때만 표시
124+ arcLabelsRadiusOffset = { 0.5 } // 레이블이 원에서 떨어지는 거리
125+ arcLinkLabelsThickness = { 2 } // 링크 레이블 두께
126+ arcLinkLabelsColor = { { from : 'color' , modifiers : [ [ 'darker' , 0.6 ] ] } } // 링크 레이블 색상
127+ arcLabelsTextColor = "transparent" // 레이블 텍스트 색상
128+ tooltip = { ( ) => null } // 툴팁 비활성화
129+ />
130+ </ Flex >
131+ < WidthFitFlex direction = "column" gap = { 6 } >
132+ { chartData &&
133+ chartData . map ( ( item ) => (
134+ < BarColorFlex
135+ justify = "space-between"
136+ color = { item . color }
137+ key = { item . label }
138+ width = { 130 }
139+ height = { 22 }
140+ padding = "10px 10px 10px 16px"
141+ >
142+ < Text typo = "Label3" > { item . label } </ Text >
143+ < Text typo = "Label2" colorCode = { theme . palette . Gray300 } >
144+ { item . ratio } %
145+ </ Text >
146+ </ BarColorFlex >
147+ ) ) }
148+ </ WidthFitFlex >
149+ </ Flex >
150+ </ Flex >
151+ ) ;
28152} ;
153+
154+ const BarColorFlex = styled ( Flex ) < { color : string } > `
155+ border-left: 3px solid ${ ( { color } ) => color } ;
156+ ` ;
157+
158+ const RelativeText = styled ( Text ) `
159+ position: relative;
160+ ` ;
161+
162+ const TextHighlight = styled . div < { width : string } > `
163+ position: absolute;
164+ width: ${ ( { width } ) => ( width ? width : '62px' ) } ;
165+ height: 9px;
166+ background-color: ${ theme . palette . Normal500 } ;
167+ opacity: 0.5;
168+ left: -3px;
169+ top: 8px;
170+ ` ;
0 commit comments