Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
81 changes: 24 additions & 57 deletions src/app/shared/components/common/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Image from 'next/image'
import Link from 'next/link'
import { usePathname, useRouter } from 'next/navigation'

import { useDashboard } from '@/app/shared/hooks/useDashboard'
import { useModalStore } from '@/app/shared/store/useModalStore'

import CreateDashboardButton from './CreateDashboardButton'
Expand All @@ -13,55 +14,7 @@ export default function Sidebar(): JSX.Element {
const pathname = usePathname()
const router = useRouter()
const { openCreateDashboardModal } = useModalStore()

// TODO: 목데이터 - API 연동시 삭제예정
const mockDashboards = [
{
id: 1,
title: '비브러리',
color: '#10B981',
createdByMe: true,
createdAt: '',
updatedAt: '',
userId: 1,
},
{
id: 2,
title: '코드잇',
color: '#8B5CF6',
createdByMe: true,
createdAt: '',
updatedAt: '',
userId: 1,
},
{
id: 3,
title: '3분기 계획',
color: '#F59E0B',
createdByMe: false,
createdAt: '',
updatedAt: '',
userId: 2,
},
{
id: 4,
title: '회의록',
color: '#3B82F6',
createdByMe: false,
createdAt: '',
updatedAt: '',
userId: 3,
},
{
id: 5,
title: '중요 문서함',
color: '#EC4899',
createdByMe: false,
createdAt: '',
updatedAt: '',
userId: 4,
},
]
const { dashboards, isLoading, error } = useDashboard()

const handleDashboardClick = (dashboardId: number) => {
router.push(`/dashboard/${dashboardId}`)
Expand Down Expand Up @@ -97,14 +50,28 @@ export default function Sidebar(): JSX.Element {

{/* 대시보드 목록 */}
<div className="space-y-8">
{mockDashboards.map((dashboard) => (
<DashboardItem
key={dashboard.id}
dashboard={dashboard}
isActive={pathname === `/dashboard/${dashboard.id}`}
onClick={handleDashboardClick}
/>
))}
{isLoading ? (
<div className="flex items-center justify-center py-20">
<div className="Text-gray text-14">로딩중...</div>
</div>
) : error ? (
<div className="flex items-center justify-center py-20">
<div className="Text-red text-14">{error}</div>
</div>
) : dashboards.length === 0 ? (
<div className="justify-left flex items-center py-20">
<div className="Text-gray text-14">대시보드가 없습니다.</div>
</div>
) : (
dashboards.map((dashboard) => (
<DashboardItem
key={dashboard.id}
dashboard={dashboard}
isActive={pathname === `/dashboard/${dashboard.id}`}
onClick={handleDashboardClick}
/>
))
)}
</div>
</div>
</aside>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function CreateDashboardModal() {
try {
setIsSubmitting(true)

const response = await api.post(`/dashboards`, formData)
const response = await api.post(`/${process.env.NEXT_PUBLIC_TEAM_ID}/dashboards`, formData)

Comment on lines +49 to 50
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

팀 ID 환경 변수 누락 시 잘못된 엔드포인트 호출 가능성

NEXT_PUBLIC_TEAM_ID가 정의되지 않은 경우 "/undefined/dashboards"로 POST 요청이 전송됩니다.
API 호출 전 유효성을 점검하여 사용자에게 경고하거나 모달을 닫는 등의 처리가 필요합니다.

- const response = await api.post(`/${process.env.NEXT_PUBLIC_TEAM_ID}/dashboards`, formData)
+ if (!process.env.NEXT_PUBLIC_TEAM_ID) {
+   alert('팀 정보가 설정되지 않았습니다.')
+   return
+ }
+ const response = await api.post(
+   `/${process.env.NEXT_PUBLIC_TEAM_ID}/dashboards`,
+   formData,
+ )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const response = await api.post(`/${process.env.NEXT_PUBLIC_TEAM_ID}/dashboards`, formData)
if (!process.env.NEXT_PUBLIC_TEAM_ID) {
alert('팀 정보가 설정되지 않았습니다.')
return
}
const response = await api.post(
`/${process.env.NEXT_PUBLIC_TEAM_ID}/dashboards`,
formData,
)
🤖 Prompt for AI Agents
In src/app/shared/components/common/sidebar/modal/CreateDashboardModal.tsx
around lines 45 to 46, the code uses process.env.NEXT_PUBLIC_TEAM_ID directly in
the API endpoint without checking if it is defined. To fix this, add a
validation step before making the API call to verify that NEXT_PUBLIC_TEAM_ID is
set. If it is undefined, handle the case by showing a user warning or closing
the modal to prevent sending a request to an invalid endpoint.

const data = response.data

Expand Down
Empty file removed src/app/shared/hooks/.gitkeep
Empty file.
37 changes: 37 additions & 0 deletions src/app/shared/hooks/useDashboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use client'

import { useEffect, useState } from 'react'

import api from '../lib/axios'
import { DashboardListResponse } from '../types/dashboard'

export function useDashboard() {
const [dashboards, setDashboards] = useState<
DashboardListResponse['dashboards']
>([])
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(null)

const fetchDashboards = async () => {
try {
setIsLoading(true)
setError(null)

const response = await api.get<DashboardListResponse>(
`/${process.env.NEXT_PUBLIC_TEAM_ID}/dashboards?navigationMethod=infiniteScroll`,
)
setDashboards(response.data.dashboards)
} catch (err) {
console.error('대시보드 목록 조회 실패:', err)
setError('대시보드 목록을 불러오는데 실패했습니다.')
} finally {
setIsLoading(false)
}
}

useEffect(() => {
fetchDashboards()
}, [])

return { dashboards, isLoading, error, refetch: fetchDashboards }
}