-
Notifications
You must be signed in to change notification settings - Fork 2
✨ Feat: 대시보드 상세 페이지 #37
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
Changes from 5 commits
05e79f6
500b31c
4b821b7
ba6b128
cc344ca
a69970c
769c5b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,17 @@ | ||
| /** @type {import('next').NextConfig} */ | ||
| const nextConfig = { | ||
| output: 'standalone', | ||
|
|
||
| images: { | ||
| remotePatterns: [ | ||
| { | ||
| protocol: 'https', | ||
| hostname: 'sprint-fe-project.s3.ap-northeast-2.amazonaws.com', | ||
| port: '', | ||
| pathname: '/**', | ||
| }, | ||
| ], | ||
| }, | ||
| } | ||
|
|
||
| export default nextConfig | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import axios from 'axios' | ||
|
|
||
| const axiosClient = axios.create({ | ||
| baseURL: 'https://sp-taskify-api.vercel.app', | ||
| }) | ||
|
|
||
| // 작업용 임시 토큰 | ||
| const TEMP_TOKEN = | ||
| 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NTc4NiwidGVhbUlkIjoiNy02IiwiaWF0IjoxNzQ5MzEyOTI3LCJpc3MiOiJzcC10YXNraWZ5In0.JFrNYvsX_b5-yCMm-Nsmp56gaVwzJ7JfBqYirBR3qw0' | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| axiosClient.interceptors.request.use((config) => { | ||
| if (TEMP_TOKEN) { | ||
| config.headers['Authorization'] = `Bearer ${TEMP_TOKEN}` | ||
| } | ||
|
|
||
| return config | ||
| }) | ||
|
Comment on lines
+10
to
+16
This comment was marked as resolved.
Sorry, something went wrong. |
||
|
|
||
| export default axiosClient | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| //Colums id: 50923,50924,50925,50926 | ||
| //나중에는 fetchColumns의 결과로 받은 컬럼 아이디를 모아서 넣어야할듯. | ||
| //size일단 10으로 하고, 나중에 커서아이디 받아서 무한 스크롤 구현해야 함. | ||
| import { useQuery } from '@tanstack/react-query' | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tanStack Query 사용하셨군용!! |
||
|
|
||
| import axiosClient from './axiosClient' | ||
|
|
||
| export interface Assignee { | ||
| id: number | ||
| nickname: string | ||
| profileImageUrl: string | null | ||
| } | ||
| export interface Card { | ||
| id: number | ||
| title: string | ||
| description: string | ||
| tags: string[] | ||
| dueDate: string | ||
| assignee: Assignee | ||
| imageUrl: string | ||
| teamId: string | ||
| dashboardId: number | ||
| columnId: number | ||
| createdAt: string | ||
| updatedAt: string | ||
| } | ||
| export interface CardResponse { | ||
| cards: Card[] | ||
| totalCount: number | ||
| cursorId: number | ||
| } | ||
|
|
||
| export async function fetchCards(columnId: number): Promise<CardResponse> { | ||
| const res = await axiosClient.get<CardResponse>( | ||
| `/7-6/cards?size=10&columnId=${columnId}`, | ||
| ) | ||
| return res.data | ||
| } | ||
|
||
|
|
||
| export default function useCards(column: number) { | ||
| return useQuery<CardResponse>({ | ||
| queryKey: ['columnId', column], | ||
| queryFn: () => fetchCards(column), | ||
| }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import { useQuery } from '@tanstack/react-query' | ||
|
|
||
| import axiosClient from './axiosClient' | ||
|
|
||
| //타입 | ||
| export interface Column { | ||
| id: number | ||
| title: string | ||
| teamId: string | ||
| dashboardId: number | ||
| createdAt: string | ||
| updatedAt: string | ||
| } | ||
| export interface ColumnsResponse { | ||
| data: Column[] | ||
| } | ||
|
|
||
| //fetch 함수 (API 호출 전용) | ||
| export async function fetchColums(dashboardId: number): Promise<Column[]> { | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const res = await axiosClient.get<ColumnsResponse>( | ||
| `/7-6/columns?dashboardId=${dashboardId}`, | ||
| ) | ||
| return res.data.data | ||
| } | ||
|
|
||
| //useQuery | ||
| export default function useColumns(dashboardId: number) { | ||
| return useQuery<Column[]>({ | ||
| queryKey: ['columns', dashboardId], | ||
| queryFn: () => fetchColums(dashboardId), | ||
| }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import Image from 'next/image' | ||
|
|
||
| import type { Card } from '@/app/api/useCards' | ||
|
|
||
| import Tags from './Tags' | ||
|
|
||
| export default function Card({ card }: { card: Card }) { | ||
| const { imageUrl, title, tags, dueDate, assignee } = card | ||
| return ( | ||
| <div className="BG-white Border-section relative w-314 rounded-6 border-solid px-20 py-16"> | ||
| Todo Card | ||
| {imageUrl && ( | ||
| <Image | ||
| src={imageUrl} | ||
| alt="카드 이미지" | ||
| width={400} | ||
| height={600} | ||
| className="h-auto w-full rounded-6 object-contain" | ||
| priority | ||
| /> | ||
| )} | ||
| <p>{title}</p> | ||
| <Tags tags={tags} /> | ||
| <p>{dueDate}</p> | ||
| <p>프로필</p> | ||
| </div> | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| export default function Tags({ tags }: { tags: string[] }) { | ||
| //태그 컬러 - 랜덤 배정 | ||
| //카드 생성 시 - 동일 태그 입력 불가하도록 | ||
| return ( | ||
| <div className="flex gap-6"> | ||
| {tags.map((tag) => ( | ||
| <span | ||
| key={tag} | ||
| className="inline-block whitespace-nowrap rounded-4 px-9 pb-3 pt-5" | ||
| style={{ backgroundColor: '#F7DBF0', color: '#D549B6' }} | ||
| > | ||
| {tag} | ||
| </span> | ||
| ))} | ||
| </div> | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import Image from 'next/image' | ||
|
|
||
| import useCards from '@/app/api/useCards' | ||
| import type { Column } from '@/app/api/useColumns' | ||
|
|
||
| import Card from '../Card/Card' | ||
| export default function Column({ column }: { column: Column }) { | ||
| const { id, title }: { id: number; title: string } = column | ||
| const { data, isLoading, error } = useCards(id) | ||
|
|
||
| if (isLoading) return <p>loading...</p> | ||
| if (error) return <p>error...{error.message}</p> | ||
|
|
||
| return ( | ||
| <div className="BG-gray Border-column flex w-354 shrink-0 flex-col gap-16 p-20"> | ||
| <div className="mb-24 flex items-center justify-between"> | ||
| <div className="flex items-center"> | ||
| <div className="mb-7 mr-8 size-8 rounded-25 bg-blue-500"></div> | ||
| <h2 className="mr-12 text-18 font-bold leading-none">{title}</h2> | ||
| <span className="Text-gray block size-20 rounded-4 bg-[#EEEEEE] pt-3 text-center text-12 font-medium leading-tight dark:bg-[#2E2E2E]"> | ||
| {data?.totalCount} | ||
| </span> | ||
| </div> | ||
| <Image | ||
| src={'/images/config.svg'} | ||
| alt="컬럼 설정" | ||
| width={20} | ||
| height={20} | ||
| /> | ||
| </div> | ||
| <button className="BG-white Border-btn rounded-6 px-146 py-9"> | ||
| <div className="flex h-22 w-22 items-center justify-center rounded-4 bg-blue-100"> | ||
| <Image | ||
| src={'/images/plus.svg'} | ||
| alt="추가하기" | ||
| width={10} | ||
| height={10} | ||
| /> | ||
| </div> | ||
| </button> | ||
| {data?.cards.map((card) => <Card key={card.id} card={card} />)} | ||
| </div> | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| 'use client' | ||
|
|
||
| import Image from 'next/image' | ||
|
|
||
| import useColumns from '@/app/api/useColumns' | ||
|
|
||
| import Column from './Column/Column' | ||
| export default function DashboardID() { | ||
| const dashboard = 15120 | ||
This comment was marked as resolved.
Sorry, something went wrong. |
||
| const { data: columns, isLoading, error } = useColumns(dashboard) | ||
| if (isLoading) return <p>loading...</p> | ||
| if (error) return <p>error...{error.message}</p> | ||
|
|
||
| return ( | ||
| <> | ||
| <div className="fixed left-0 h-1080 w-300 bg-gray-100">사이드바</div> | ||
| <div className="ml-300"> | ||
| <div className="flex"> | ||
| {columns?.map((column) => <Column key={column.id} column={column} />)} | ||
| <div className="BG-gray Border-column p-20"> | ||
| <button className="BG-white Border-btn flex items-center gap-12 whitespace-nowrap rounded-8 px-85 pb-20 pt-24 text-18 font-bold"> | ||
| <span>새로운 컬럼 추가하기</span> | ||
| <div className="flex h-22 w-22 items-center justify-center rounded-4 bg-blue-100"> | ||
| <Image | ||
| src={'/images/plus.svg'} | ||
| alt="플러스 아이콘" | ||
| width={10} | ||
| height={10} | ||
| /> | ||
| </div> | ||
| </button> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </> | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,21 @@ | ||
| 'use client' | ||
|
|
||
| import { QueryClient, QueryClientProvider } from '@tanstack/react-query' | ||
| import { ThemeProvider } from 'next-themes' | ||
| import { ReactNode } from 'react' | ||
| import { ReactNode, useState } from 'react' | ||
|
|
||
| export function Providers({ children }: { children: ReactNode }) { | ||
| const [queryClient] = useState(() => new QueryClient()) | ||
|
|
||
| return ( | ||
| <ThemeProvider attribute="class" defaultTheme="system" enableSystem={true}> | ||
| {children} | ||
| </ThemeProvider> | ||
| <QueryClientProvider client={queryClient}> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tanStack Query의 경우도 provider로 감싸줘야 하는군용 |
||
| <ThemeProvider | ||
| attribute="class" | ||
| defaultTheme="system" | ||
| enableSystem={true} | ||
| > | ||
| {children} | ||
| </ThemeProvider> | ||
| </QueryClientProvider> | ||
| ) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 코드를 추가 하신 이유가 무엇인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
외부 이미지를 사용하기 위해 추가한 설정입니다.
Next.js의
Image컴포넌트는 보안상의 이유로 외부 도메인의 이미지를 기본적으로 차단합니다.받아온 이미지 URL을 보면
이렇고, 외부 API에서 데이터를 받아올때. 이미지 URL은 AWS S3에 저장해서 제공하고 있습니다.(amazonaws)
Next.js에서 이 이미지를 표시하려면 S3 도메인을 허용해야 했습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
답변 감사합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
외부 도메인의 이미지를 차단하는 지는 처음 알았네용 😮