Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4c9d6fb
Merge branch 'develop' of https://github.com/vecosystem/VECO_Frontend…
sunhwaaRj Jul 14, 2025
bd73a81
Merge branch 'develop' of https://github.com/vecosystem/VECO_Frontend…
sunhwaaRj Jul 14, 2025
c953e5f
#51 [FEAT] 타입 enum 적용
sunhwaaRj Jul 14, 2025
4d1d7be
#51 [FIX] 변경된 변수명 적용
sunhwaaRj Jul 14, 2025
1df89af
#51 [MOD] 버튼 클릭 시 여백 제거
sunhwaaRj Jul 14, 2025
fc1adc2
#51 [FIX] 타입 변수명 적용
sunhwaaRj Jul 14, 2025
6965067
#51 [FIX] 요소 없을 시 '없음' 처리
sunhwaaRj Jul 15, 2025
e3feb1f
#51 [FEAT] 날짜 구조 변경 함수
sunhwaaRj Jul 16, 2025
cf43084
#51 [FEAT] 필터에 따른 더미데이터 생성
sunhwaaRj Jul 16, 2025
3f7a527
#51 [FIX] api 응답구조에 맞춰 수정
sunhwaaRj Jul 16, 2025
985e1de
#51 [FEAT] 공통 api 응답 구조
sunhwaaRj Jul 16, 2025
f2f63ab
#51 [FIX] 체크 기준 추가
sunhwaaRj Jul 16, 2025
4f5cf72
#51 [FEAT] 이슈용 더미데이터
sunhwaaRj Jul 16, 2025
bee17bd
#51 [MOD] 응답값에 따른 구성요소 변경
sunhwaaRj Jul 16, 2025
cda0dcd
#51 [FEAT] 이슈 목록 조회 api 응답 구조
sunhwaaRj Jul 16, 2025
4d2cc87
#51 [MOD] 이슈 interface 변경
sunhwaaRj Jul 16, 2025
834f159
#51 [MOD] 목표, 이슈 페이지 변경구조에 맞게 수정
sunhwaaRj Jul 16, 2025
a015ff2
#51 [DEL] 미사용 함수 제거
sunhwaaRj Jul 16, 2025
516a6fb
#51 [FEAT] 담당자 두 명 이상 시 ui
sunhwaaRj Jul 17, 2025
54defa0
#51 [FEAT] 담당자 두 명 이상 시 ui
sunhwaaRj Jul 17, 2025
8a4f5e2
#51 [MOD] api 구조 재사용
sunhwaaRj Jul 17, 2025
8bb09d8
#51 [MOD] 유형명 정렬
sunhwaaRj Jul 17, 2025
3197b47
#51 [FEAT] 유형명 정렬 함수 분리
sunhwaaRj Jul 17, 2025
a2f3bc1
Merge branch 'develop' into feature/#51-goal_issue_type-refactor
sunhwaaRj Jul 18, 2025
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
87 changes: 40 additions & 47 deletions src/components/ListView/GoalItem.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,50 @@
import type { GoalItemProps } from '../../types/listItem';
import {
PRIORITY_CODES,
PRIORITY_LABELS,
STATUS_CODES,
STATUS_LABELS,
type GoalItemProps,
type PriorityCode,
type StatusCode,
} from '../../types/listItem';
import dateIcon from '../../assets/icons/date.svg';
import grayIcon from '../../assets/icons/gray.svg';
import goalIcon from '../../assets/icons/goal.svg';
import CheckedIcon from '../../assets/icons/check-box-o.svg';
import UncheckedIcon from '../../assets/icons/check-box-x.svg';
import { getFilter, getPriorityIcon, getStatusIcon } from '../../utils/listItemUtils';
import {
formatGoalDate,
getFilter,
getPriorityIcon,
getStatusIcon,
} from '../../utils/listItemUtils';
import ManagerAvatar from './ManagerAvartar';

/*
* 기본값 설정, props 로 전달된 값이 없을 경우 사용
* 추후 백엔드 명세서 확인 후 변수명 등 수정 예정
*/
const defaultData: GoalItemProps = {
showCheckbox: true,
checked: false,
type: 'goal', // 'goal' | 'my-goal'
goalId: 'Veco-g3',
title: '백호를 사용해서 다른 사람들과 협업해보기',
status: '완료',
priority: '보통',
manage: '없음',
filter: '우선순위', // '상태' | '우선순위' | '담당자'
};

export const GoalItem = (props: Partial<GoalItemProps>) => {
const status: StatusCode =
props.status && STATUS_CODES.includes(props.status as StatusCode)
? (props.status as StatusCode)
: ('NONE' as StatusCode);

const priority: PriorityCode =
props.priority && PRIORITY_CODES.includes(props.priority as PriorityCode)
? (props.priority as PriorityCode)
: ('NONE' as PriorityCode);

const {
showCheckbox,
checked,
onCheckChange,
type,
goalId,
name,
title,
status,
priority,
deadline,
manage,
deadline = { start: '', end: '' },
managers = { cnt: 0, info: [] },
filter,
} = {
...defaultData,
...props,
};

Expand All @@ -50,7 +58,7 @@ export const GoalItem = (props: Partial<GoalItemProps>) => {

return (
<div
className={`font-body-r flex justify-between items-center min-w-[110rem] h-[5.6rem] px-[3.2rem] -mx-[3.2rem] ${showCheckbox && checked ? 'bg-gray-300' : ''}`}
className={`font-body-r flex justify-between items-center h-[5.6rem] px-[3.2rem] -mx-[3.2rem] ${showCheckbox && checked ? 'bg-gray-300' : ''}`}
onClick={handleItemClick}
tabIndex={showCheckbox ? 0 : -1}
style={{ cursor: showCheckbox ? 'pointer' : 'default' }}
Expand All @@ -73,10 +81,10 @@ export const GoalItem = (props: Partial<GoalItemProps>) => {
className="w-[1.6rem] h-[1.6rem] pointer-events-none"
/>
</label>
<span className="font-body-b whitespace-nowrap">{goalId}</span>
<span className="font-body-b whitespace-nowrap">{name}</span>
</div>
) : (
<span className="font-body-b ml-[2.4rem] whitespace-nowrap">{goalId}</span>
<span className="font-body-b ml-[2.4rem] whitespace-nowrap">{name}</span>
)}
<div className="flex gap-[0.8rem] items-center">
{/* 목표 아이콘 */}
Expand All @@ -90,38 +98,23 @@ export const GoalItem = (props: Partial<GoalItemProps>) => {
{displayFields.includes('status') && (
<div className="flex gap-[0.8rem] items-center">
{getStatusIcon(status)}
<div className="truncate">{status}</div>
<div className="truncate">{STATUS_LABELS[status]}</div>
</div>
)}
{/* 우선순위 */}
{displayFields.includes('priority') && (
<div className="flex gap-[0.8rem] items-center">
<img src={getPriorityIcon(priority)} alt={priority} className="w-[2.4rem] h-[2.4rem]" />
<div className="truncate">{priority}</div>
<div className="whitespace-nowrap">{PRIORITY_LABELS[priority]}</div>
</div>
)}
{/* 기한 */}
{deadline && deadline !== '없음' && (
<div className="flex gap-[0.8rem] items-center whitespace-nowrap">
<img src={dateIcon} alt="date" className="w-[1.6rem] h-[1.6rem] m-[0.4rem]" />
<div className="">{deadline}</div>
</div>
)}
{/* 담당자/팀명 */}
{/*
* 담당자 1인 기준으로 작성
* 프로필 이미지, 고유 색상 등 추가 예정
*/}
{displayFields.includes('manage') && (
<div className="flex gap-[0.8rem] items-center whitespace-nowrap">
<img
src={type === 'goal' ? grayIcon : grayIcon}
alt="manage"
className="w-[2.0rem] h-[2.0rem]"
/>
<div className="">{manage}</div>
</div>
)}
<div className="flex gap-[0.8rem] items-center whitespace-nowrap">
<img src={dateIcon} alt="date" className="w-[1.6rem] h-[1.6rem] m-[0.4rem]" />
<div>{formatGoalDate(deadline?.start, deadline?.end)}</div>
</div>
{/* 담당자 */}
{displayFields.includes('manage') && <ManagerAvatar managers={managers.info} />}
</div>
</div>
);
Expand Down
6 changes: 3 additions & 3 deletions src/components/ListView/GroupTypeIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ItemFilter, Status } from '../../types/listItem';
import type { ItemFilter, PriorityCode, StatusCode } from '../../types/listItem';
import GoalIcon from '../../assets/icons/goal.svg';
import GoalGrayIcon from '../../assets/icons/goal-gray.svg';
import { getPriorityIcon, getStatusColor } from '../../utils/listItemUtils';
Expand All @@ -14,14 +14,14 @@ const GroupTypeIcon = ({ filter, typeKey, profileImghUrl }: Props) => {
return (
<span
className="inline-block rounded-full w-[1.6rem] h-[1.6rem] mr-[0.8rem]"
style={{ background: getStatusColor(typeKey as Status) }}
style={{ background: getStatusColor(typeKey as StatusCode) }}
/>
);
}
if (filter === '우선순위') {
return (
<img
src={getPriorityIcon(typeKey as any)}
src={getPriorityIcon(typeKey as PriorityCode)}
alt={typeKey}
className="w-[3.2rem] h-[3.2rem] mr-[0.8rem]"
/>
Expand Down
95 changes: 44 additions & 51 deletions src/components/ListView/IssueItem.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,52 @@
import type { IssueItemProps } from '../../types/listItem';
import {
PRIORITY_CODES,
PRIORITY_LABELS,
STATUS_CODES,
STATUS_LABELS,
type IssueItemProps,
type PriorityCode,
type StatusCode,
} from '../../types/listItem';
import dateIcon from '../../assets/icons/date.svg';
import grayIcon from '../../assets/icons/gray.svg';
import goalIcon from '../../assets/icons/goal.svg';
import issueIcon from '../../assets/icons/issue.svg';
import CheckedIcon from '../../assets/icons/check-box-o.svg';
import UncheckedIcon from '../../assets/icons/check-box-x.svg';
import { getFilter, getPriorityIcon, getStatusIcon } from '../../utils/listItemUtils';
import {
formatGoalDate,
getFilter,
getPriorityIcon,
getStatusIcon,
} from '../../utils/listItemUtils';
import ManagerAvatar from './ManagerAvartar';

/*
* 기본값 설정, props 로 전달된 값이 없을 경우 사용
* 추후 백엔드 명세서 확인 후 변수명 등 수정 예정
*/
const defaultData: IssueItemProps = {
showCheckbox: true,
checked: false,
type: 'issue', // 'issue' | 'my-issue'
issueId: 'Veco-i3',
issueTitle: '백호를 사용해서 다른 사람들과 협업해보기',
status: '완료',
priority: '보통',
manage: '없음',
filter: '담당자', // '상태' | '우선순위' | '담당자' | '목표'
};

export const IssueItem = (props: Partial<IssueItemProps>) => {
const status: StatusCode =
props.status && STATUS_CODES.includes(props.status as StatusCode)
? (props.status as StatusCode)
: ('NONE' as StatusCode);

const priority: PriorityCode =
props.priority && PRIORITY_CODES.includes(props.priority as PriorityCode)
? (props.priority as PriorityCode)
: ('NONE' as PriorityCode);

const {
showCheckbox,
checked,
onCheckChange,
type,
issueId,
issueTitle,
goalTitle,
status,
priority,
deadline,
manage,
name,
title,
goalTitle = '없음',
deadline = { start: '', end: '' },
managers = { cnt: 0, info: [] },
filter,
} = {
...defaultData,
...props,
};

Expand All @@ -52,7 +60,7 @@ export const IssueItem = (props: Partial<IssueItemProps>) => {

return (
<div
className={`font-body-r flex justify-between items-center min-w-[110rem] h-[5.6rem] px-[3.2rem] -mx-[3.2rem] ${showCheckbox && checked ? 'bg-gray-300' : ''}`}
className={`font-body-r flex justify-between items-center h-[5.6rem] px-[3.2rem] -mx-[3.2rem] ${showCheckbox && checked ? 'bg-gray-300' : ''}`}
onClick={handleItemClick}
tabIndex={showCheckbox ? 0 : -1}
style={{ cursor: showCheckbox ? 'pointer' : 'default' }}
Expand All @@ -75,34 +83,34 @@ export const IssueItem = (props: Partial<IssueItemProps>) => {
className="w-[1.6rem] h-[1.6rem] pointer-events-none"
/>
</label>
<span className="font-body-b whitespace-nowrap">{issueId}</span>
<span className="font-body-b whitespace-nowrap">{name}</span>
</div>
) : (
<span className="font-body-b ml-[2.4rem] whitespace-nowrap">{issueId}</span>
<span className="font-body-b ml-[2.4rem] whitespace-nowrap">{name}</span>
)}
<div className="flex gap-[0.8rem] items-center">
{/* 이슈 아이콘 */}
<img src={issueIcon} alt="date" className="w-[2.4rem] h-[2.4rem] ml-[1.6rem]" />
{/* 이슈명 */}
<div className="truncate min-w-0 flex-1">{issueTitle}</div>
<div className="truncate min-w-0 flex-1">{title}</div>
</div>
</div>
<div className="flex gap-[3.2rem] items-center">
{/* 상태 */}
{displayFields.includes('status') && (
<div className="flex gap-[0.8rem] items-center">
{getStatusIcon(status)}
<div className="truncate">{status}</div>
<div className="truncate">{STATUS_LABELS[status]}</div>
</div>
)}
{/* 우선순위 */}
{displayFields.includes('priority') && (
<div className="flex gap-[0.8rem] items-center">
<img src={getPriorityIcon(priority)} alt={priority} className="w-[2.4rem] h-[2.4rem]" />
<div className="whitespace-nowrap">{priority}</div>
<div className="whitespace-nowrap">{PRIORITY_LABELS[priority]}</div>
</div>
)}
{displayFields.includes('goal') && goalTitle && goalTitle !== '없음' && (
{displayFields.includes('goal') && goalTitle && (
<div className="flex gap-[0.8rem] items-center">
{/* 목표 아이콘 */}
<img src={goalIcon} alt="date" className="w-[2.4rem] h-[2.4rem]" />
Expand All @@ -112,27 +120,12 @@ export const IssueItem = (props: Partial<IssueItemProps>) => {
)}

{/* 기한 */}
{deadline && deadline !== '없음' && (
<div className="flex gap-[0.8rem] items-center whitespace-nowrap">
<img src={dateIcon} alt="date" className="w-[1.6rem] h-[1.6rem] m-[0.4rem]" />
<div className="">{deadline}</div>
</div>
)}
{/* 담당자/팀명 */}
{/*
* 담당자 1인 기준으로 작성
* 프로필 이미지, 고유 색상 등 추가 예정
*/}
{displayFields.includes('manage') && (
<div className="flex gap-[0.8rem] items-center whitespace-nowrap">
<img
src={type === 'issue' ? grayIcon : grayIcon}
alt="manage"
className="w-[2.0rem] h-[2.0rem]"
/>
<div>{manage}</div>
</div>
)}
<div className="flex gap-[0.8rem] items-center whitespace-nowrap">
<img src={dateIcon} alt="date" className="w-[1.6rem] h-[1.6rem] m-[0.4rem]" />
<div>{formatGoalDate(deadline?.start, deadline?.end)}</div>
</div>
{/* 담당자 */}
{displayFields.includes('manage') && <ManagerAvatar managers={managers.info} />}
</div>
</div>
);
Expand Down
11 changes: 6 additions & 5 deletions src/components/ListView/ListViewToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ const ListViewToolbar = ({
<div className="flex gap-[2.4rem] items-center">
{/* 필터영역 */}
<div className="relative">
<div
className="flex gap-[0.8rem] items-center cursor-pointer relative"
onClick={onFilterClick}
>
<div className="flex items-center cursor-pointer relative" onClick={onFilterClick}>
{/* 드롭다운 */}
<img src={FilterIcon} className="inline-block w-[2.4rem] h-[2.4rem]" alt="" />
<img
src={FilterIcon}
className="inline-block w-[2.4rem] h-[2.4rem] mr-[0.8rem]"
alt=""
/>
<span className="font-body-r">필터</span>
{dropdownProps.isOpen && dropdownProps.content && (
<div onClick={(e) => e.stopPropagation()}>
Expand Down
Loading