Skip to content

Commit

Permalink
Merge pull request #40 from DDD-Community/feat/#32
Browse files Browse the repository at this point in the history
[feat/#32] 대시보드 기능 구현
  • Loading branch information
G-hoon authored Aug 29, 2024
2 parents 39a782b + 6c81e72 commit 98c9d8c
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 25 deletions.
Binary file added src/assets/images/chin-up.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/shoulder-twist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/tail-bone-sit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/tutle-neck.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
111 changes: 87 additions & 24 deletions src/pages/AnalysisDashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import React, { useState, useRef, useEffect } from "react"
import { useQuery } from "@tanstack/react-query"
import { getTodayAnalysis, TodayAnalysisData } from "@/api/analysis"
import { poseType } from "@/api/pose"
import { useQuery } from "@tanstack/react-query"
import { Calendar, ChevronLeft, ChevronRight } from "lucide-react"
import { useMemo } from "react"

import TurtleNeckImage from "@/assets/images/tutle-neck.png"
import ShoulderTwistImage from "@/assets/images/shoulder-twist.png"
import ChinUpImage from "@/assets/images/chin-up.png"
import TailBoneSitImage from "@/assets/images/tail-bone-sit.png"

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

const { data, isLoading, isError } = useQuery<TodayAnalysisData>({
queryKey: ["todayAnalysis"],
queryFn: getTodayAnalysis,
Expand All @@ -14,19 +22,51 @@ const AnalysisDashboard = () => {
return data?.count.find((item: any) => item.type === type)?.count || 0
}

const totalCount = useMemo(() => {
return data?.count.reduce((acc, item) => acc + item.count, 0) || 0
}, [data])
const totalCount = data?.count.reduce((acc, item) => acc + item.count, 0) || 0

const carouselItems = [
{ title: "거북목", type: "TURTLE_NECK" as poseType, image: TurtleNeckImage },
{ title: "어깨 틀어짐", type: "SHOULDER_TWIST" as poseType, image: ShoulderTwistImage },
{ title: "턱 괴기", type: "CHIN_UTP" as poseType, image: ChinUpImage },
{ title: "꼬리뼈로 앉기", type: "TAILBONE_SIT" as poseType, image: TailBoneSitImage },
]

const moveCarousel = (direction: "left" | "right") => {
if (direction === "left" && currentIndex > 0) {
setCurrentIndex(currentIndex - 1)
} else if (direction === "right" && currentIndex < carouselItems.length - 3) {
setCurrentIndex(currentIndex + 1)
}
}

useEffect(() => {
if (carouselRef.current) {
const itemWidth = (carouselRef.current as HTMLElement).offsetWidth / 3
;(carouselRef.current as HTMLElement).style.transform = `translateX(-${currentIndex * itemWidth}px)`
}
}, [currentIndex])

return (
<div className="h-full w-full">
<div className="mb-6 flex items-center justify-between">
<h1 className="text-2xl font-bold">오늘의 자세 분석</h1>
<div className="flex space-x-2">
<button className="rounded-full bg-gray-200 p-2">
<button
className={`rounded-full p-2 ${
currentIndex === 0 ? "bg-gray-200 text-gray-400" : "bg-blue-500 text-white"
}`}
onClick={() => moveCarousel("left")}
disabled={currentIndex === 0}
>
<ChevronLeft size={20} />
</button>
<button className="rounded-full bg-blue-500 p-2 text-white">
<button
className={`rounded-full p-2 ${
currentIndex === carouselItems.length - 3 ? "bg-gray-200 text-gray-400" : "bg-blue-500 text-white"
}`}
onClick={() => moveCarousel("right")}
disabled={currentIndex === carouselItems.length - 3}
>
<ChevronRight size={20} />
</button>
</div>
Expand All @@ -35,30 +75,53 @@ const AnalysisDashboard = () => {
{isLoading && <div>로딩 중입니다...</div>}
{isError && <div>데이터를 불러오는 것에 실패했습니다</div>}

{/* 상단 카드 섹션 */}
{!isLoading && !isError && data && (
<>
<div className="mb-8 grid grid-cols-4 gap-4">
<div className="rounded-lg bg-black p-4 text-white">
<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>
{[
{ title: "거북목", type: "TURTLE_NECK" as poseType },
{ title: "어깨 틀어짐", type: "SHOULDER_TWIST" as poseType },
{ title: "턱 괴기", type: "CHIN_UTP" as poseType },
].map(({ title, type }, index) => (
<div key={index} className="rounded-lg bg-gray-100 p-4">
<p className="text-sm text-gray-600">{title}</p>
<p className="mt-2 text-3xl font-bold">{getPoseCount(type)}</p>
<div className="mt-2 h-24 bg-gray-300">{/* 이미지 삽입 */}</div>

{/* 캐러셀 컨테이너 */}
<div className="relative flex w-3/4 overflow-hidden">
{/* 왼쪽 그라디언트 */}
{currentIndex > 0 && (
<div className="absolute left-0 top-0 z-10 h-full w-8 bg-gradient-to-r from-white to-transparent" />
)}

{/* 캐러셀 아이템 */}
<div
ref={carouselRef}
className="flex transition-transform duration-300 ease-in-out"
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 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">
<p className="text-lg font-semibold">{title}</p>
<div className="flex items-center gap-1">
<div className="mb-2 pt-2 text-4xl font-bold">{getPoseCount(type)}</div>
<div className="text-lg"></div>
</div>
</div>
</div>
</div>
))}
</div>
))}
</div>

{/* 오른쪽 그라디언트 */}
{currentIndex < 1 && (
<div className="absolute right-0 top-0 z-10 h-full w-8 bg-gradient-to-l from-white to-transparent" />
)}
</div>
</div>
{/* 차트 섹션 */}
<div className="rounded-lg bg-white p-6 shadow">
<div className="rounded-lg p-6 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>
Expand All @@ -82,7 +145,7 @@ const AnalysisDashboard = () => {
))}
</div>
</div>
</>
</div>
)}
</div>
)
Expand Down
2 changes: 1 addition & 1 deletion src/pages/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const HomePage: React.FC = () => {
}

return (
<div className="w-[1440px]">
<div>
{/* header */}
<div className="flex w-full bg-white px-[120px] py-5">
<div className="flex flex-grow items-center">
Expand Down

0 comments on commit 98c9d8c

Please sign in to comment.