Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into feat/#46
Browse files Browse the repository at this point in the history
  • Loading branch information
lkhoony committed Sep 9, 2024
2 parents c0bdbfc + b666f74 commit d772584
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 32 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"@tanstack/react-query": "^5.51.23",
"axios": "1.7.3",
"core-js": "^3.28.0",
"echarts": "^5.5.1",
"echarts-for-react": "^3.0.2",
"lucide-react": "^0.435.0",
"p5": "^1.9.4",
"react": "^18.2.0",
Expand Down
24 changes: 23 additions & 1 deletion src/api/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,33 @@ export interface TodayAnalysisData {
}[]
}

export const getTodayAnalysis = async (): Promise<TodayAnalysisData> => {
export interface TotalAnalysisData {
data: TodayAnalysisData[]
page: number
size: number
totalPage: number
totalCount: number
sort: {
empty: boolean
sorted: boolean
unsorted: boolean
}
}

export const getTodayPoseAnalysis = async (): Promise<TodayAnalysisData> => {
try {
const res = await axiosInstance.get("/pose-counts/daily")
return res.data.data
} catch (e) {
throw e
}
}

export const getTotalPoseAnalysis = async (): Promise<TodayAnalysisData[]> => {
try {
const res = await axiosInstance.get("/pose-counts?sort=date,desc")
return res.data.data
} catch (e) {
throw e
}
}
10 changes: 10 additions & 0 deletions src/assets/icons/dash-board-total-count.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions src/components/Dashboard/Chart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import ECharts from "echarts-for-react"

const poseTypeLabels: any = {
TURTLE_NECK: "거북목",
SHOULDER_TWIST: "어깨 틀어짐",
CHIN_UTP: "턱 괴기",
TAILBONE_SIT: "꼬리뼈로 앉기",
}

const PoseAnalysisChart = ({ data }: { data: any[] }) => {
const options = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
legend: {
data: Object.values(poseTypeLabels),
top: 20,
},
grid: {
left: "3%",
right: "3%",
bottom: "5%",
top: "25%",
containLabel: true,
},
xAxis: {
type: "category",
data: data.map((item) => item.date),
},
yAxis: {
type: "value",
minInterval: 1,
axisLabel: {
formatter: "{value}",
},
},
series: Object.keys(poseTypeLabels).map((poseType) => ({
name: poseTypeLabels[poseType],
type: "line",
data: data.map((item) => {
const poseCount = item.count.find((c: any) => c.type === poseType)
return poseCount ? poseCount.count : 0
}),
})),
}

return <ECharts option={options} opts={{ renderer: "svg" }} style={{ height: "100%", width: "100%" }} />
}

export default PoseAnalysisChart
27 changes: 27 additions & 0 deletions src/hooks/useDashBoard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getTodayPoseAnalysis, getTotalPoseAnalysis } from "@/api/analysis"
import { useQueries } from "@tanstack/react-query"

export const usePoseAnalysis = () => {
const results = useQueries({
queries: [
{
queryKey: ["todayAnalysis"],
queryFn: getTodayPoseAnalysis,
},
{
queryKey: ["totalAnalysis"],
queryFn: getTotalPoseAnalysis,
},
],
})

const [todayAnalysis, totalAnalysis] = results

return {
todayAnalysis: todayAnalysis.data,
totalAnalysis: totalAnalysis.data,
isLoading: results.some((result) => result.isLoading),
isError: results.some((result) => result.isError),
errors: results.map((result) => result.error).filter(Boolean),
}
}
2 changes: 1 addition & 1 deletion src/layouts/AnalysisLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Outlet } from "react-router-dom"

export default function AnalysisLayout() {
return (
<div className="h-full bg-[#F9F9FD] p-12">
<div className="h-full bg-[#F9F9FD] px-28 py-12">
<Outlet />
</div>
)
Expand Down
60 changes: 30 additions & 30 deletions src/pages/AnalysisDashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { useState, useRef, useEffect } from "react"
import { useQuery } from "@tanstack/react-query"
import { getTodayAnalysis, TodayAnalysisData } from "@/api/analysis"
import { poseType } from "@/api/pose"
import { Calendar, ChevronLeft, ChevronRight } from "lucide-react"
import { useEffect, useRef, useState } from "react"
import { usePoseAnalysis } from "@/hooks/useDashBoard"

import TurtleNeckImage from "@/assets/images/tutle-neck.png"
import ShoulderTwistImage from "@/assets/images/shoulder-twist.png"
import TotalCountChartIcon from "@/assets/icons/dash-board-total-count.svg?react"
import ChinUpImage from "@/assets/images/chin-up.png"
import ShoulderTwistImage from "@/assets/images/shoulder-twist.png"
import TailBoneSitImage from "@/assets/images/tail-bone-sit.png"
import TurtleNeckImage from "@/assets/images/tutle-neck.png"
import PoseAnalysisChart from "@/components/Dashboard/Chart"

const AnalysisDashboard = () => {
const [currentIndex, setCurrentIndex] = useState(0)
const carouselRef = useRef(null)

const { data, isLoading, isError } = useQuery<TodayAnalysisData>({
queryKey: ["todayAnalysis"],
queryFn: getTodayAnalysis,
})
const { todayAnalysis, totalAnalysis, isLoading, isError } = usePoseAnalysis()

console.log("totalAnalysis: ", totalAnalysis)

const getPoseCount = (type: poseType) => {
return data?.count.find((item: any) => item.type === type)?.count || 0
return todayAnalysis?.count.find((item: any) => item.type === type)?.count || 0
}

const totalCount = data?.count.reduce((acc, item) => acc + item.count, 0) || 0
const totalCount = todayAnalysis?.count.reduce((acc, item) => acc + item.count, 0) || 0

const carouselItems = [
{ title: "거북목", type: "TURTLE_NECK" as poseType, image: TurtleNeckImage },
Expand Down Expand Up @@ -75,14 +75,19 @@ const AnalysisDashboard = () => {
{isLoading && <div>로딩 중입니다...</div>}
{isError && <div>데이터를 불러오는 것에 실패했습니다</div>}

{!isLoading && !isError && data && (
{!isLoading && !isError && todayAnalysis && (
<div className="relative mb-8 overflow-hidden">
<div className="flex">
{/* 고정된 전체 틀어짐 횟수 카드 */}
<div className="mr-4 w-1/4 flex-shrink-0 rounded-lg bg-black p-4 text-white">
<p className="text-sm text-blue-400">전체 틀어짐 횟수</p>
<p className="mt-2 text-3xl font-bold">{totalCount}</p>
<div className="mt-2 h-24 bg-gray-700">{/* 차트 이미지 삽입 */}</div>
<div className="relative mr-3 flex w-60 flex-col items-center rounded-lg bg-black text-white">
<p className="mt-8 text-sm text-[#5A9CFF]">전체 틀어짐 횟수</p>
<div className="mt-2 flex items-center">
<span className="text-4xl font-bold">{totalCount}</span>
<span className="ml-1 text-sm"></span>
</div>
<div className="absolute bottom-[25px] flex h-24 justify-center">
<TotalCountChartIcon />
</div>
</div>

{/* 캐러셀 컨테이너 */}
Expand All @@ -99,7 +104,7 @@ const AnalysisDashboard = () => {
style={{ width: `${(carouselItems.length / 3) * 100}%` }}
>
{carouselItems.map(({ title, type, image }, index) => (
<div key={index} className="w-1/3 flex-shrink-0 px-2">
<div key={index} className="mr-3 w-1/5 flex-shrink-0">
<div className="relative overflow-hidden rounded-lg bg-gray-100">
<img src={image} alt={title} className="h-full w-full" />
<div className="absolute inset-0 flex flex-col items-center pt-8 text-black">
Expand All @@ -120,29 +125,24 @@ const AnalysisDashboard = () => {
)}
</div>
</div>
<div className="mb-12 mt-8">
<hr />
</div>
{/* 차트 섹션 */}
<div className="rounded-lg p-6 shadow">
<div className="rounded-lg shadow">
<div className="mb-4 flex items-center justify-between">
<div className="flex items-center space-x-2">
<button className="rounded-full bg-gray-800 px-4 py-2 text-sm text-white">7월 첫째주</button>
<ChevronLeft size={20} />
<span className="rounded-full bg-zinc-800 px-4 py-2 text-white">7월 첫째주 추이</span>
<ChevronRight size={20} />
</div>
<div className="flex items-center text-sm text-gray-600">
<Calendar size={16} className="mr-2" />
{data?.date}
{"2024-09-09"}
</div>
</div>
<div className="h-64 bg-gray-100">{/* 실제 차트 컴포넌트 삽입 */}</div>
<div className="mt-4 flex justify-center space-x-4">
{["거북목", "어깨 틀어짐", "턱 괴기", "고개숙여 보기"].map((item, index) => (
<div key={index} className="flex items-center">
<div
className={`mr-2 h-3 w-3 rounded-full bg-${["red", "blue", "green", "purple"][index]}-500`}
></div>
<span className="text-sm">{item}</span>
</div>
))}
<div className="h-[340px] rounded-[10px] border-[1px] border-solid border-gray-200 bg-white">
{totalAnalysis && <PoseAnalysisChart data={totalAnalysis} />}
</div>
</div>
</div>
Expand Down
33 changes: 33 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,22 @@ eastasianwidth@^0.2.0:
resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz"
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==

echarts-for-react@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/echarts-for-react/-/echarts-for-react-3.0.2.tgz#ac5859157048a1066d4553e34b328abb24f2b7c1"
integrity sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==
dependencies:
fast-deep-equal "^3.1.3"
size-sensor "^1.0.1"

echarts@^5.5.1:
version "5.5.1"
resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.5.1.tgz#8dc9c68d0c548934bedcb5f633db07ed1dd2101c"
integrity sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==
dependencies:
tslib "2.3.0"
zrender "5.6.0"

electron-to-chromium@^1.5.4:
version "1.5.6"
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.6.tgz"
Expand Down Expand Up @@ -3001,6 +3017,11 @@ signal-exit@^4.0.1:
resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz"
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==

size-sensor@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/size-sensor/-/size-sensor-1.0.2.tgz#b8f8da029683cf2b4e22f12bf8b8f0a1145e8471"
integrity sha512-2NCmWxY7A9pYKGXNBfteo4hy14gWu47rg5692peVMst6lQLPKrVjhY+UTEsPI5ceFRJSl3gVgMYaUi/hKuaiKw==

slash@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
Expand Down Expand Up @@ -3289,6 +3310,11 @@ tsconfig-paths@^3.15.0:
minimist "^1.2.6"
strip-bom "^3.0.0"

[email protected]:
version "2.3.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==

tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
Expand Down Expand Up @@ -3556,6 +3582,13 @@ yocto-queue@^0.1.0:
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==

[email protected]:
version "5.6.0"
resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.6.0.tgz#01325b0bb38332dd5e87a8dbee7336cafc0f4a5b"
integrity sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==
dependencies:
tslib "2.3.0"

zustand@^4.5.5:
version "4.5.5"
resolved "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz"
Expand Down

0 comments on commit d772584

Please sign in to comment.