Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat/#28] 스냅샷 저장 및 조회 기능 추가, 저장된 스냅샷이 있는 경우 해당 스냅샷 사용 #30

Merged
merged 2 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/api/axiosInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ const axiosInstance = axios.create({
// localStorage에서 토큰 가져오기
const token = localStorage.getItem("accessToken")
if (token) {
axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${token}`
axiosInstance.defaults.headers.common["X-HERO-AUTH-TOKEN"] = token
}

// 엑세스 토큰 설정 함수
export const setAccessToken = (token: string) => {
axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${token}`
localStorage.setItem("accessToken", token)
export const setAccessToken = (_token: string): void => {
axiosInstance.defaults.headers.common["X-HERO-AUTH-TOKEN"] = _token
// localStorage.setItem("accessToken", token)
}

// 엑세스 토큰 제거 함수
export const clearAccessToken = () => {
delete axiosInstance.defaults.headers.common["Authorization"]
localStorage.removeItem("accessToken")
export const clearAccessToken = (): void => {
delete axiosInstance.defaults.headers.common["X-HERO-AUTH-TOKEN"]
// localStorage.removeItem("accessToken")
}

export default axiosInstance
1 change: 1 addition & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./auth"
export * from "./snapshot"
64 changes: 64 additions & 0 deletions src/api/snapshot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import axiosInstance from "./axiosInstance"

export type position =
| "NOSE"
| "LEFT_EYE"
| "RIGHT_EYE"
| "LEFT_EAR"
| "RIGHT_EAR"
| "LEFT_SHOULDER"
| "RIGHT_SHOULDER"
| "LEFT_ELBOW"
| "RIGHT_ELBOW"
| "LEFT_WRIST"
| "RIGHT_WRIST"
| "LEFT_HIP"
| "RIGHT_HIP"
| "LEFT_KNEE"
| "RIGHT_KNEE"
| "LEFT_ANKLE"
| "RIGHT_ANKLE"

export interface point {
position: position
x: number
y: number
}

export interface snapshot {
id?: number
points: point[]
}

export interface createSnapshotRes {
id: string
}

export const createSnapshot = async (snapshot: snapshot): Promise<createSnapshotRes> => {
try {
const res = await axiosInstance.post(`/pose-layouts`, { snapshot })
const { id } = res.data.data

return { id }
} catch (e) {
throw e
}
}

export const getSnapshots = async (id: string): Promise<snapshot> => {
try {
const res = await axiosInstance.get(`/pose-layouts/${id}`)
return res.data.data
} catch (e) {
throw e
}
}

export const getRecentSnapshot = async (): Promise<snapshot> => {
try {
const res = await axiosInstance.get(`/pose-layouts/recent`)
return res.data.data
} catch (e) {
throw e
}
}
35 changes: 35 additions & 0 deletions src/components/PoseDetector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { worker } from "@/utils/worker"
import { useCallback, useEffect, useRef, useState } from "react"
import Camera from "./Camera"
import GuidePopup from "./Posture/GuidePopup"
import { useSnapshotStore } from "@/store/SnapshotStore"
import { useCreateSnaphot } from "@/hooks/useSnapshotMutation"
import { position } from "@/api"
import PostureCheckIcon from "@assets/icons/good-posture-check-button-icon.svg?react"
import GuideIcon from "@assets/icons/posture-guide-button-icon.svg?react"

Expand All @@ -24,6 +27,10 @@ const PoseDetector: React.FC = () => {
const timer = useRef<any>(null)
const canvasRef = useRef<HTMLCanvasElement>(null)

const snapshot = useSnapshotStore((state) => state.snapshot)
const createSnapMutation = useCreateSnaphot()
const setSnap = useSnapshotStore((state) => state.setSnapshot)

const { requestNotificationPermission, showNotification } = usePushNotification()

const requestApi = (delay: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, delay))
Expand Down Expand Up @@ -115,6 +122,30 @@ const PoseDetector: React.FC = () => {
const getInitSnap = (): void => {
if (modelRef && modelRef.current) {
snapRef.current = resultRef.current
if (snapshot === null) {
if (snapRef.current) {
const req = snapRef.current[0].keypoints.map((p) => ({
position: p.name.toUpperCase() as position,
x: p.x,
y: p.y,
}))
createSnapMutation.mutate(
{ points: req },
{
onSuccess: (data: any) => {
setSnap(data)
},
}
)
}
}
setIsSnapSaved(true)
}
}

const getUserSnap = (): void => {
if (snapshot) {
snapRef.current = [{ keypoints: snapshot }]
setIsSnapSaved(true)
}
}
Expand All @@ -138,6 +169,10 @@ const PoseDetector: React.FC = () => {
}
}, [isModelLoaded, detectStart])

useEffect(() => {
getUserSnap()
}, [snapshot])

// const initializePoseMonitoring = () => {
// setIsTextNeck(null)
// setSlope(null)
Expand Down
35 changes: 35 additions & 0 deletions src/hooks/useSnapshotMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { createSnapshot, createSnapshotRes, getRecentSnapshot, getSnapshots, snapshot } from "@/api"
import { useMutation, UseMutationResult } from "@tanstack/react-query"

export const useCreateSnaphot = (): UseMutationResult<createSnapshotRes, unknown, snapshot, unknown> => {
return useMutation({
mutationFn: (snapshot: snapshot) => {
return createSnapshot(snapshot)
},
onSuccess: (data) => {
console.log(data)
},
})
}

export const useGetSnapshot = (): UseMutationResult<snapshot, unknown, string, unknown> => {
return useMutation({
mutationFn: (id: string) => {
return getSnapshots(id)
},
onSuccess: (data) => {
console.log(data)
},
})
}

export const useGetRecentSnapshot = (): UseMutationResult<snapshot, unknown, void, unknown> => {
return useMutation({
mutationFn: () => {
return getRecentSnapshot()
},
onSuccess: (data) => {
console.log(data)
},
})
}
12 changes: 12 additions & 0 deletions src/pages/AuthPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Login from "@/components/Login"
import { useOauth, useSignUp, useSignIn, useGetIsSignUp } from "@/hooks/useAuthMutation"
import RoutePath from "@/constants/routes.json"
import { useAuthStore } from "@/store/AuthStore"
import { useSnapshotStore } from "@/store/SnapshotStore"
import { useGetRecentSnapshot } from "@/hooks/useSnapshotMutation"

const AuthPage: React.FC = () => {
const navigate = useNavigate()
Expand All @@ -12,11 +14,13 @@ const AuthPage: React.FC = () => {
const getIsSignUpMutation = useGetIsSignUp()
const signUpMutation = useSignUp()
const signInMutation = useSignIn()
const getRecentSnapMutation = useGetRecentSnapshot()

const [isLoading, setIsLoading] = useState(true)
const [isError, setIsError] = useState(false)

const setUser = useAuthStore((state) => state.setUser)
const setSnap = useSnapshotStore((state) => state.setSnapshot)

useEffect(() => {
const authenticate = async (): Promise<void> => {
Expand All @@ -41,6 +45,14 @@ const AuthPage: React.FC = () => {
// AuthStore에 사용자 정보와 토큰 저장
setUser({ uid, nickname }, accessToken)

// 최근 스냅샷을 가져오기
const userSnap = await getRecentSnapMutation.mutateAsync()

// 스냅샷이 있으면 store에 저장
if (userSnap.id !== -1) {
setSnap(userSnap.points.map((p) => ({ name: p.position.toLocaleLowerCase(), x: p.x, y: p.y, confidence: 1 })))
}

setIsLoading(false)
navigate(RoutePath.MONITORING)
} catch (error) {
Expand Down
8 changes: 4 additions & 4 deletions src/routes/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BrowserRouter, Route, Routes, Navigate } from "react-router-dom"
import { AuthPage, MonitoringPage, HomePage } from "@/pages"
import { Layout } from "@/layouts"
import RoutePath from "@/constants/routes.json"
// import AuthRoute from "@/routes/AuthRoute" // ToDo: 로그인 정상화 될때까지 routing 보호하지 않도록 수정
import AuthRoute from "@/routes/AuthRoute"

const Router: React.FC = () => {
return (
Expand All @@ -13,9 +13,9 @@ const Router: React.FC = () => {
<Route path="/" element={<HomePage />} />
<Route path="/" element={<Layout />}>
{/* AuthRoute로 보호된 경로를 감쌉니다 */}
{/* <Route element={<AuthRoute />}> */}
<Route path={RoutePath.MONITORING} element={<MonitoringPage />} />
{/* </Route> */}
<Route element={<AuthRoute />}>
<Route path={RoutePath.MONITORING} element={<MonitoringPage />} />
</Route>
<Route path="*" element={<Navigate to="/" replace />} />
</Route>
</Routes>
Expand Down
12 changes: 12 additions & 0 deletions src/store/SnapshotStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { keypoint } from "@/utils"
import { create } from "zustand"

interface SnapshotState {
snapshot: keypoint[] | null
setSnapshot: (snapshot: keypoint[]) => void
}

export const useSnapshotStore = create<SnapshotState>((set) => ({
snapshot: null,
setSnapshot: (snapshot: keypoint[]) => set({ snapshot }),
}))
40 changes: 20 additions & 20 deletions src/utils/detector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,26 @@ export interface box {
// 포즈 객체의 타입 정의
export interface pose {
keypoints: keypoint[]
box: box
score: number
id: number
nose: keypoint
left_eye: keypoint
right_eye: keypoint
left_ear: keypoint
right_ear: keypoint
left_shoulder: keypoint
right_shoulder: keypoint
left_elbow: keypoint
right_elbow: keypoint
left_wrist: keypoint
right_wrist: keypoint
left_hip: keypoint
right_hip: keypoint
left_knee: keypoint
right_knee: keypoint
left_ankle: keypoint
right_ankle: keypoint
box?: box
score?: number
id?: number
nose?: keypoint
left_eye?: keypoint
right_eye?: keypoint
left_ear?: keypoint
right_ear?: keypoint
left_shoulder?: keypoint
right_shoulder?: keypoint
left_elbow?: keypoint
right_elbow?: keypoint
left_wrist?: keypoint
right_wrist?: keypoint
left_hip?: keypoint
right_hip?: keypoint
left_knee?: keypoint
right_knee?: keypoint
left_ankle?: keypoint
right_ankle?: keypoint
}

/**
Expand Down
Loading