diff --git a/src/App.tsx b/src/App.tsx index ac771baf..011c3308 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -17,6 +17,7 @@ import { ProfileSettings } from './components/mypage/profile-settings/ProfileSet import IdeaAnalysis from './components/mypage/idea-analysis/IdeaAnalysis' import OngoingProject from './components/mypage/ongoing-project/OngoingProject' import ProfileAnalysis from './components/mypage/profile-analysis/ProfileAnalysis' +import { MatchingStatus } from './components/mypage/matching-status/MatchingStatus' import IdeaAnalyzePage from './pages/IdeaAnalyzePage' import AnalyzeReportPage from './pages/AnalyzeReportPage' import RecruitingProjectsPage from './pages/RecruitingProjectsPage' @@ -95,6 +96,10 @@ const router = createBrowserRouter([ path: 'ongoing', element: , }, + { + path: 'matching', + element: , + }, ], }, { diff --git a/src/assets/icons/mypage/chat.svg b/src/assets/icons/mypage/chat.svg new file mode 100644 index 00000000..8df6b868 --- /dev/null +++ b/src/assets/icons/mypage/chat.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/common/CTAModal.tsx b/src/components/common/CTAModal.tsx index d81e7a0e..cea6644b 100644 --- a/src/components/common/CTAModal.tsx +++ b/src/components/common/CTAModal.tsx @@ -1,10 +1,14 @@ import Button from './Button' -interface ICTAModal { +interface CTAModalProps { message: string subMessage?: string isMessageHighlight?: boolean fixedHeight?: boolean + // 단일 버튼 모드 + buttonMsg?: string + onButtonClick?: () => void + // 이중 버튼 모드 leftButtonMsg?: string rightButtonMsg?: string onLeftClick?: () => void @@ -16,11 +20,13 @@ const CTAModal = ({ subMessage = '', isMessageHighlight = false, fixedHeight = false, + buttonMsg, + onButtonClick, leftButtonMsg, rightButtonMsg, onLeftClick, onRightClick, -}: ICTAModal) => { +}: CTAModalProps) => { // {텍스트} 형식 부분만 보라색으로 하이라이팅 const parseMessage = (text: string) => { const parts = text.split(/(\{[^}]+\})/g) @@ -37,34 +43,49 @@ const CTAModal = ({ }) } + // 단일 버튼 모드인지 확인 + const isSingleButtonMode = !!buttonMsg && !leftButtonMsg && !rightButtonMsg + return (
{/* 타이틀 + 설명글 */}
{parseMessage(message)} - {subMessage ?
{subMessage}
: ''} +
+ {subMessage} +
- {/* 선택용 버튼 2개 */} -
- {leftButtonMsg && ( - - )} +
+ ) : ( + /* 이중 버튼 모드 */ +
+ {leftButtonMsg && ( + + )} - {rightButtonMsg && ( - - )} -
+ {rightButtonMsg && ( + + )} +
+ )}
) diff --git a/src/components/common/ConfirmModal.tsx b/src/components/common/ConfirmModal.tsx deleted file mode 100644 index bab59a63..00000000 --- a/src/components/common/ConfirmModal.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { useEffect } from 'react' -import XIcon from '@/assets/icons/common/X.svg?react' - -interface ConfirmModalProps { - isOpen: boolean - onClose: () => void - title: string - description?: string - cancelText: string - confirmText: string - onCancel: () => void - onConfirm: () => void -} - -const ConfirmModal = ({ - isOpen, - onClose, - title, - description, - cancelText, - confirmText, - onCancel, - onConfirm, -}: ConfirmModalProps) => { - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if (e.key === 'Escape' && isOpen) { - onClose() - } - } - - document.addEventListener('keydown', handleKeyDown) - return () => document.removeEventListener('keydown', handleKeyDown) - }, [isOpen, onClose]) - - // 모달이 열리면 스크롤 방지 - useEffect(() => { - if (isOpen) { - document.body.style.overflow = 'hidden' - } else { - document.body.style.overflow = 'unset' - } - - return () => { - document.body.style.overflow = 'unset' - } - }, [isOpen]) - - if (!isOpen) return null - - return ( -
- {/* 배경 오버레이 */} -
- - {/* 모달 컨텐츠 */} -
- {/* 닫기 버튼 */} - - - {/* 타이틀 */} -

{title}

- - {/* 설명 */} - {description &&

{description}

} - - {/* 버튼 영역 */} -
- - -
-
-
- ) -} - -export default ConfirmModal diff --git a/src/components/mypage/SegmentTabButton.tsx b/src/components/mypage/SegmentTabButton.tsx new file mode 100644 index 00000000..c07baa2a --- /dev/null +++ b/src/components/mypage/SegmentTabButton.tsx @@ -0,0 +1,42 @@ +import { cn } from '@/utils/cn' + +interface SegmentTabButtonProps { + /** 탭 텍스트 */ + label: string + /** 카운트 (Count 타입일 때 표시) */ + count?: number + /** 활성화 여부 */ + isActive: boolean + /** 클릭 핸들러 */ + onClick?: () => void + /** 추가 클래스명 */ + className?: string +} + +const SegmentTabButton = ({ label, count, isActive, onClick, className }: SegmentTabButtonProps) => { + return ( + + ) +} + +export default SegmentTabButton diff --git a/src/components/mypage/idea-analysis/IdeaAnalysis.tsx b/src/components/mypage/idea-analysis/IdeaAnalysis.tsx index 58b69594..7d147b57 100644 --- a/src/components/mypage/idea-analysis/IdeaAnalysis.tsx +++ b/src/components/mypage/idea-analysis/IdeaAnalysis.tsx @@ -8,7 +8,7 @@ import Section02TeamComposition from './sections/Section02TeamComposition' import Section03Improvements from './sections/Section03Improvements' import Section04Roadmap from './sections/Section04Roadmap' import type { IdeaAnalysisData } from '@/types/mypage/ideaAnalysis' -import CTAModal from '../../common/CTAModal' +import CTAModal from '@/components/common/CTAModal' import { useNavigate } from 'react-router' import { useCTAModal } from '@/stores/useCTAModal' diff --git a/src/components/mypage/matching-status/MatchingNotice.tsx b/src/components/mypage/matching-status/MatchingNotice.tsx new file mode 100644 index 00000000..e630085a --- /dev/null +++ b/src/components/mypage/matching-status/MatchingNotice.tsx @@ -0,0 +1,64 @@ +import { cn } from '@/utils/cn' +import type { NoticeItem } from '@/constants/matchingNotice' + +interface MatchingNoticeProps { + /** 유의사항 항목 목록 */ + items: NoticeItem[] + /** 추가 클래스명 */ + className?: string +} + +const MatchingNotice = ({ items, className }: MatchingNoticeProps) => { + return ( +
+ {items.map((item, index) => ( +
+ {/* 규칙 메인 텍스트 */} +

+ {item.number}. + {/* 텍스트 내부의 "/" 처리 */} + {item.text.split(/(\/)/).map((part, partIndex) => { + if (part === '/') { + return {part} + } + return {part} + })} +

+ + {/* 규칙 하위 설명 텍스트 */} + {item.subText && ( +
+ {item.subText.split('\n').map((line, lineIndex) => ( +

+ {line.split(/(\*\*.*?\*\*)/).map((segment, segIndex) => { + if (segment.startsWith('**') && segment.endsWith('**')) { + return ( + + {segment.slice(2, -2)} + + ) + } + return {segment} + })} +

+ ))} +
+ )} +
+ ))} +
+ ) +} + +export default MatchingNotice diff --git a/src/components/mypage/matching-status/MatchingStatus.tsx b/src/components/mypage/matching-status/MatchingStatus.tsx new file mode 100644 index 00000000..5029c0c2 --- /dev/null +++ b/src/components/mypage/matching-status/MatchingStatus.tsx @@ -0,0 +1,433 @@ +import { useState } from 'react' +import { MyPageHeader } from '../MyPageHeader' +import ProjectCard from './ProjectCard' +import ProfileCard from './ProfileCard' +import MatchingTimerCard from './MatchingTimerCard' +import MatchingNotice from './MatchingNotice' +import RoleTagChip from '@/components/mission-modal/RoleTagChip' +import { RECEIVED_REQUEST_NOTICES, SENT_REQUEST_NOTICES } from '@/constants/matchingNotice' +import CTAModal from '@/components/common/CTAModal' +import SegmentTabButton from '../SegmentTabButton' + +type TabType = 'received' | 'sent' + +interface MatchingStatusProps { + receivedCount?: number + sentCount?: number +} + +// 역할 이름을 roleId로 매핑 +const getRoleIdByName = (roleName: string): number => { + const roleMap: Record = { + PM: 1, + Design: 2, + Frontend: 3, + Backend: 4, + } + return roleMap[roleName] || 1 +} + +export const MatchingStatus = ({ receivedCount = 6, sentCount = 5 }: MatchingStatusProps) => { + const [activeTab, setActiveTab] = useState('received') + const [modalType, setModalType] = useState<'reject' | 'rejectSuccess' | 'accept' | 'acceptSuccess' | 'cancel' | 'cancelSuccess' | null>(null) + + // 받은 요청 데이터 (임시) + const receivedProjects = [ + { + id: 1, + projectName: 'MoneyLog', + category: '금융 · 핀테크', + description: '하루의 소비를 기록해, 나의 돈 흐름을 이해하는 금융 다이어리', + currentMembers: 4, + totalMembers: 10, + timerText: '09:58:29', + }, + ] + + const receivedTeamMembers = [ + { + part: 'Design', + partColor: 'bg-roletag-pink', + members: [ + { + id: 1, + nickname: '김넥트', + part: 'Design', + introduction: 'UX.UI 어쩌고 한줄 소개 ~~~~', + timerText: '01:27:00', + }, + { + id: 2, + nickname: '윤다', + part: 'Design', + introduction: '인터렉티브 디자인 전공으로 인터렉션에 강합니다 !', + timerText: '07:14:00', + }, + ], + }, + { + part: 'Backend', + partColor: 'bg-roletag-blue', + members: [ + { + id: 3, + nickname: '러핑', + part: 'Backend', + introduction: '프로필 소개 (첫 문장까지 미리보기됨)', + timerText: '04:08:00', + }, + { + id: 4, + nickname: '리뮤딘', + part: 'Backend', + introduction: '프로필 소개 (첫 문장까지 미리보기됨)', + timerText: '06:32:00', + }, + { + id: 5, + nickname: '이경', + part: 'Backend', + introduction: '프로필 소개 (첫 문장까지 미리보기됨)', + timerText: '07:54:00', + }, + { + id: 6, + nickname: '루트', + part: 'Backend', + introduction: '프로필 소개 (첫 문장까지 미리보기됨)', + timerText: '00:00:00', + status: 'accepted' as const, + }, + ], + }, + ] + + // 보낸 요청 데이터 (임시) + const sentProjects = [ + { + id: 1, + projectName: 'NECT 웹사이트', + category: 'IT · 웹/모바일 서비스', + description: '크리에이터를 위한 사이드 프로젝트 매칭 & 협업 플랫폼', + currentMembers: 6, + totalMembers: 10, + timerText: '12:34:56', + }, + ] + + const sentTeamMembers = [ + { + part: 'Frontend', + partColor: 'bg-roletag-green', + members: [ + { + id: 1, + nickname: '김개발', + part: 'Frontend', + introduction: 'React/Next.js 개발 경험이 있습니다!', + timerText: '05:20:00', + }, + { + id: 2, + nickname: '박프론트', + part: 'Frontend', + introduction: '프로필 소개 (첫 문장까지 미리보기됨)', + timerText: '08:15:30', + }, + ], + }, + { + part: 'PM', + partColor: 'bg-roletag-purple', + members: [ + { + id: 3, + nickname: '최기획', + part: 'PM', + introduction: '프로젝트 관리 경험이 풍부합니다', + timerText: '03:45:00', + }, + ], + }, + ] + + return ( +
+ + + {/* 전체 컨테이너 */} +
+ {/* 탭 영역 */} +
+ setActiveTab('received')} + /> + setActiveTab('sent')} + /> +
+ + {/* 탭 컨텐츠 */} +
+ {activeTab === 'received' && ( + <> + {/* 프로젝트 섹션 */} +
+
+
+

프로젝트

+
+
+
+ {receivedProjects.map(project => ( +
+ + setModalType('accept')} + onReject={() => setModalType('reject')} + /> +
+ ))} +
+
+ + {/* 넥트 팀원 섹션 */} +
+
+
+

넥트 팀원

+
+
+
+ {receivedTeamMembers.map((partGroup, partIndex) => ( +
+ +
+ {partGroup.members.map(member => ( +
+ console.log(`${member.nickname}에게 메시지 보내기`)} + /> + setModalType('accept')} + onReject={() => setModalType('reject')} + /> +
+ ))} +
+
+ ))} +
+
+ + {/* 유의사항 섹션 */} +
+
+
+

유의사항

+
+
+
+ +
+
+ + )} + {activeTab === 'sent' && ( + <> + {/* 프로젝트 섹션 */} +
+
+
+

프로젝트

+
+
+
+ {sentProjects.map(project => ( +
+ + setModalType('cancel')} + /> +
+ ))} +
+
+ + {/* 넥트 팀원 섹션 */} +
+
+
+

넥트 팀원

+
+
+
+ {sentTeamMembers.map((partGroup, partIndex) => ( +
+ +
+ {partGroup.members.map(member => ( +
+ console.log(`${member.nickname}에게 메시지 보내기`)} + /> + setModalType('cancel')} + /> +
+ ))} +
+
+ ))} +
+
+ + {/* 유의사항 섹션 */} +
+
+
+

유의사항

+
+
+
+ +
+
+ + )} +
+
+ + {/* 매칭 거절 확인 모달 */} + {modalType === 'reject' && ( + setModalType(null)} + onRightClick={() => { + console.log('매칭 거절 확인') + setModalType('rejectSuccess') + }} + /> + )} + + {/* 매칭 거절 성공 모달 */} + {modalType === 'rejectSuccess' && ( + { + console.log('매칭 거절 성공 확인') + setModalType(null) + }} + /> + )} + + {/* 매칭 수락 확인 모달 */} + {modalType === 'accept' && ( + setModalType(null)} + onRightClick={() => { + console.log('매칭 수락 확인') + setModalType('acceptSuccess') + }} + /> + )} + + {/* 매칭 수락 성공 모달 */} + {modalType === 'acceptSuccess' && ( + { + console.log('매칭 수락 성공 확인') + setModalType(null) + }} + /> + )} + + {/* 매칭 취소 확인 모달 */} + {modalType === 'cancel' && ( + setModalType(null)} + onRightClick={() => { + console.log('매칭 취소 확인') + setModalType('cancelSuccess') + }} + /> + )} + + {/* 매칭 취소 성공 모달 */} + {modalType === 'cancelSuccess' && ( + { + console.log('매칭 취소 성공 확인') + setModalType(null) + }} + /> + )} +
+ ) +} diff --git a/src/components/mypage/matching-status/MatchingTimerCard.tsx b/src/components/mypage/matching-status/MatchingTimerCard.tsx new file mode 100644 index 00000000..ee9fa057 --- /dev/null +++ b/src/components/mypage/matching-status/MatchingTimerCard.tsx @@ -0,0 +1,132 @@ +import { cn } from '@/utils/cn' + +type MatchingStatus = 'default' | 'auto-rejected' | 'accepted' +type RequestType = 'received' | 'sent' + +interface MatchingTimerCardProps { + /** 요청 타입 (받은 요청 / 보낸 요청) */ + requestType: RequestType + /** 매칭 상태 */ + status?: MatchingStatus + /** 타이머 값 (초 단위) */ + timerSeconds?: number + /** 타이머 표시 텍스트 (HH:MM:SS 형식, 예: "09:58:29") */ + timerText?: string + /** 수락 버튼 클릭 핸들러 (받은 요청일 때만) */ + onAccept?: () => void + /** 거절 버튼 클릭 핸들러 (받은 요청일 때만) */ + onReject?: () => void + /** 매칭 취소 버튼 클릭 핸들러 (보낸 요청일 때만) */ + onCancel?: () => void + /** 추가 클래스명 */ + className?: string +} + +/** + * 타이머를 HH:MM:SS 형식으로 포맷팅 + */ +const formatTimer = (seconds: number): string => { + const hours = Math.floor(seconds / 3600) + const minutes = Math.floor((seconds % 3600) / 60) + const secs = seconds % 60 + return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}` +} + +const MatchingTimerCard = ({ + requestType, + status = 'default', + timerSeconds, + timerText, + onAccept, + onReject, + onCancel, + className, +}: MatchingTimerCardProps) => { + const isAutoRejected = status === 'auto-rejected' + const isAccepted = status === 'accepted' + const isReceived = requestType === 'received' + const isSent = requestType === 'sent' + + // 타이머 텍스트 결정 + const displayTimer = timerText || (timerSeconds !== undefined ? formatTimer(timerSeconds) : '00:00:00') + + // 상태에 따른 텍스트와 색상 + const statusText = isAutoRejected + ? '자동 거절 되었습니다.' + : isAccepted + ? '매칭 수락 되었습니다.' + : '대기 만료까지' + const statusTextColor = isAutoRejected + ? 'text-semantic-700' + : isAccepted + ? 'text-primary-500-normal' + : 'text-neutral-500' + const timerColor = isAutoRejected || isAccepted ? 'text-neutral-200' : 'text-primary-500-normal' + + return ( +
+
+ {/* 타이머 영역 */} +
+

{statusText}

+

{displayTimer}

+
+ + {/* 버튼 영역 */} + {status === 'default' && ( +
+ {/* 받은 요청: 거절/수락 버튼 */} + {isReceived && ( + <> + + + + )} + + {/* 보낸 요청: 매칭 취소 버튼 */} + {isSent && ( + + )} +
+ )} +
+
+ ) +} + +export default MatchingTimerCard diff --git a/src/components/mypage/matching-status/ProfileCard.tsx b/src/components/mypage/matching-status/ProfileCard.tsx new file mode 100644 index 00000000..462c2831 --- /dev/null +++ b/src/components/mypage/matching-status/ProfileCard.tsx @@ -0,0 +1,74 @@ +import { cn } from '@/utils/cn' +import ChatIcon from '@/assets/icons/mypage/chat.svg?react' + +interface ProfileCardProps { + /** 프로필 이미지 URL */ + imageUrl?: string + /** 사용자 닉네임 */ + nickname: string + /** 사용자 파트 (예: Design, Frontend, Backend) */ + part: string + /** 프로필 소개 텍스트 */ + introduction?: string + /** 메시지 버튼 클릭 핸들러 */ + onMessageClick?: () => void + /** 추가 클래스명 */ + className?: string +} + +const ProfileCard = ({ imageUrl, nickname, part, introduction, onMessageClick, className }: ProfileCardProps) => { + return ( +
+
+ {/* 프로필 이미지 */} +
+
+ {imageUrl ? ( + {nickname} + ) : ( +
+ )} +
+
+ + {/* 텍스트 영역 */} +
+
+ {/* 닉네임 | Part */} +
+
+

{nickname}

+
+

{part}

+
+
+ {/* 프로필 소개 */} +

+ {introduction || '프로필 소개 (첫 문장까지 미리보기됨)'} +

+
+
+ + {/* 메시지 아이콘 버튼 */} + +
+
+ ) +} + +export default ProfileCard diff --git a/src/components/mypage/matching-status/ProjectCard.tsx b/src/components/mypage/matching-status/ProjectCard.tsx new file mode 100644 index 00000000..f5b2df17 --- /dev/null +++ b/src/components/mypage/matching-status/ProjectCard.tsx @@ -0,0 +1,63 @@ +import { cn } from '@/utils/cn' + +interface ProjectCardProps { + /** 프로젝트 이름 */ + projectName: string + /** 프로젝트 카테고리 (예: "금융 · 핀테크") */ + category: string + /** 프로젝트 설명 */ + description: string + /** 현재 팀원 수 */ + currentMembers: number + /** 전체 팀원 수 */ + totalMembers: number + /** 클릭 핸들러 */ + onClick?: () => void + /** 추가 클래스명 */ + className?: string +} + +const ProjectCard = ({ projectName, category, description, currentMembers, totalMembers, onClick, className }: ProjectCardProps) => { + return ( +
+
+ {/* 상단: 프로젝트 이름 + 카테고리 */} +
+
+ {/* 프로젝트 이름 | 카테고리 */} +
+

+ {projectName} +

+
+

{category}

+
+ {/* 프로젝트 설명 */} +

+ {description} +

+
+
+ + {/* 하단: 팀원 수 */} +
+

+ 팀원 + {` ${currentMembers}`} + / + {totalMembers} +

+
+
+
+ ) +} + +export default ProjectCard diff --git a/src/components/mypage/ongoing-project/OngoingProject.tsx b/src/components/mypage/ongoing-project/OngoingProject.tsx index 1cca6a5f..d26db187 100644 --- a/src/components/mypage/ongoing-project/OngoingProject.tsx +++ b/src/components/mypage/ongoing-project/OngoingProject.tsx @@ -2,14 +2,14 @@ import { useState, useCallback, useEffect } from 'react' import Button from '@/components/common/Button' import { MyPageHeader } from '../MyPageHeader' import HamburgerIcon from '@/assets/icons/common/hamburger.svg?react' -import Tabbar from './Tabbar' +import SegmentTabButton from '../SegmentTabButton' import ProjectManagementView from './tab1-project-setting/ProjectManagementView' import TeamManagementView from './tab2-team-management/TeamManagementView' import { useNavigationBlocker } from '@/hooks/mypage/useNavigationBlocker' import { useOngoingProjectForm } from '@/hooks/mypage/useOngoingProjectForm' import type { TabType } from '@/types/mypage/ongoindProject' -import CTAModal from '../../common/CTAModal' +import CTAModal from '@/components/common/CTAModal' import PartSettingsModal from './PartSettingsModal' import { useNavigate } from 'react-router' import type { ProjectSettingsType } from '@/utils/schemas/projectSchema' @@ -212,7 +212,18 @@ const OngoingProject = () => {
{/* 탭바 */} - +
+ handleActivateTab('프로젝트 설정')} + /> + handleActivateTab('팀원 관리')} + /> +
{/* 탭 01. 프로젝트 설정 */} {activeTab === '프로젝트 설정' && ( diff --git a/src/components/mypage/ongoing-project/Tabbar.tsx b/src/components/mypage/ongoing-project/Tabbar.tsx deleted file mode 100644 index cade4af4..00000000 --- a/src/components/mypage/ongoing-project/Tabbar.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import type { TabType } from '@/types/mypage/ongoindProject' - -interface ITabbar { - currentTab: string - onClick: (tabName: TabType) => void -} - -const Tabbar = ({ currentTab, onClick }: ITabbar) => { - return ( -
- - - -
- ) -} - -export default Tabbar diff --git a/src/components/mypage/profile-analysis/ProfileAnalysis.tsx b/src/components/mypage/profile-analysis/ProfileAnalysis.tsx index 4e2d7dd3..7abbb594 100644 --- a/src/components/mypage/profile-analysis/ProfileAnalysis.tsx +++ b/src/components/mypage/profile-analysis/ProfileAnalysis.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import CTAModal from '../../common/CTAModal' +import CTAModal from '@/components/common/CTAModal' import EmptyProfileAnalysis from './EmptyProfileAnalysis' import { useCollaboStore, useGrowGuideStore, useRoleRecommendStore, useSkillStore } from '@/stores/profileAnalysisStore' import ProfileRadarChart from '@/components/profile-analysis/ProfileRadarChart' diff --git a/src/components/mypage/profile-settings/ProfileSettings.tsx b/src/components/mypage/profile-settings/ProfileSettings.tsx index bffdccbe..d4597096 100644 --- a/src/components/mypage/profile-settings/ProfileSettings.tsx +++ b/src/components/mypage/profile-settings/ProfileSettings.tsx @@ -6,7 +6,7 @@ import { useProfileSettingsForm } from '@/hooks/mypage/useProfileSettingsForm' import { useCTAModal } from '@/stores/useCTAModal' import type { ProfileFormDataType } from '@/utils/schemas/profileSchema' -import CTAModal from '../../common/CTAModal' +import CTAModal from '@/components/common/CTAModal' import { MyPageHeader } from '../MyPageHeader' import ProfileBasicInfo from './ProfileBasicInfo' import Section01Introduction from './sections/Section01Introduction' diff --git a/src/constants/matchingNotice.ts b/src/constants/matchingNotice.ts new file mode 100644 index 00000000..0f7ee4a5 --- /dev/null +++ b/src/constants/matchingNotice.ts @@ -0,0 +1,42 @@ +export interface NoticeItem { + /** 규칙 번호 */ + number: number + /** 규칙 메인 텍스트 */ + text: string + /** 규칙 하위 설명 텍스트 (선택, 여러 줄은 \n으로 구분) */ + subText?: string +} + +/** 받은 요청 유의사항 */ +export const RECEIVED_REQUEST_NOTICES: NoticeItem[] = [ + { + number: 1, + text: '대기 만료 시, 매칭이 자동 거절 처리', + }, + { + number: 2, + text: '24시간 동안의 매칭 취소 / 거절 / 수락은 번복 불가', + }, + { + number: 3, + text: '리더가 직접 보내는 요청은 파트당 최대 3명까지 가능 (24시간 동안)', + subText: '리더는 24시간동안 한 프로젝트의 파트당 최대 3명에게 **매칭 요청을 직접 보낼 수 있습니다.**\n이때, 유저가 보내오는 프로젝트 매칭 요청은 포함되지 않습니다.', + }, +] + +/** 보낸 요청 유의사항 */ +export const SENT_REQUEST_NOTICES: NoticeItem[] = [ + { + number: 1, + text: '대기 만료 시, 매칭이 자동 거절 처리', + }, + { + number: 2, + text: '24시간 동안의 매칭 취소 / 거절 / 수락은 번복 불가', + }, + { + number: 3, + text: '매칭 신청 후 대기 중인 24시간동안 다른 프로젝트에 신청할 수 없습니다.', + subText: '이때, 타 유저로 부터 받은 요청은 포함되지 않습니다.', + }, +]