-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: #15 profile/edit : 미니프로필 수정 ui
- Loading branch information
Showing
2 changed files
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import ProfileEditBasic from '@/features/profile/edit/basic/components/ProfileEditBasic' | ||
|
||
export default function ProfileEditBasicPage() { | ||
return ( | ||
<div className="pl-[4.25rem] pr-[8.69rem] pt-[3.75rem]"> | ||
<label className="text-xl font-bold">미니 프로필</label> | ||
|
||
<div className="mt-5 rounded-xl"> | ||
<ProfileEditBasic /> | ||
</div> | ||
</div> | ||
) | ||
} |
187 changes: 187 additions & 0 deletions
187
src/features/profile/edit/basic/components/ProfileEditBasic.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
'use client' | ||
import { addressData } from '@/shared/data/addressSelectData' | ||
import { Button } from '@/shared/ui/Button/Button' | ||
import Input from '@/shared/ui/Input/Input' | ||
import Radio from '@/shared/ui/Radio/Radio' | ||
import Select from '@/shared/ui/Select/Select' | ||
import Image from 'next/image' | ||
import { useState } from 'react' | ||
|
||
export default function ProfileEditBasic() { | ||
const [selectedCity, setSelectedCity] = useState('') | ||
const [selectedStatuses, setSelectedStatuses] = useState<string[]>([]) | ||
const [selectedOption, setSelectedOption] = useState<string>('option1') | ||
|
||
const options = [ | ||
{ label: '전체공개', value: '전체공개' }, | ||
{ label: '비공개', value: '비공개' }, | ||
] | ||
|
||
// Select 컴포넌트에 표시할 대분류 옵션을 구성합니다. | ||
const mainOptions = addressData.map((city) => ({ | ||
label: city.name, | ||
value: city.name, | ||
})) | ||
|
||
// 선택된 대분류에 따라 하위 옵션을 구성합니다. | ||
const subOptions = | ||
addressData | ||
.find((city) => city.name === selectedCity) | ||
?.subArea.map((area) => ({ | ||
label: area, | ||
value: area, | ||
})) || [] | ||
|
||
const statusOptions = [ | ||
'팀원 찾는 중', | ||
'팀 찾는 중', | ||
'대회 준비 중', | ||
'공모전 준비 중', | ||
'포폴 쌓는 중', | ||
'둘러보는 중', | ||
'프로젝트 진행 중', | ||
'아이디어 찾는 중', | ||
'투자 유치 중', | ||
] | ||
|
||
const handleStatusClick = (status: string) => { | ||
setSelectedStatuses((prev) => (prev.includes(status) ? prev.filter((s) => s !== status) : [...prev, status])) | ||
} | ||
|
||
const handleRemoveStatus = (status: string) => { | ||
setSelectedStatuses((prev) => prev.filter((s) => s !== status)) | ||
} | ||
|
||
return ( | ||
<> | ||
<div className="flex flex-col gap-10 rounded-xl bg-white px-[2.88rem] py-10"> | ||
{/* 프로필 사진 */} | ||
<div className="flex flex-col"> | ||
<div className="flex w-full justify-between"> | ||
<span className="text-grey80">프로필 사진</span> | ||
<span className="flex items-center text-xs text-grey50"> | ||
<p className="text-main">*</p>은 필수항목입니다 | ||
</span> | ||
</div> | ||
|
||
<div className="mt-3 flex gap-8"> | ||
<Image src="/common/default_profile.svg" width={150} height={150} alt="profile" /> | ||
|
||
<div className="flex flex-col justify-end"> | ||
<p className="text-xs text-grey50">*10MB 이하의 PNG, JPG, GIF, SVG 파일을 업로드 해주세요</p> | ||
<div className="flex items-end gap-4"> | ||
<Button className="mt-2 rounded-xl" animationMode="main" mode="main"> | ||
사진 업로드 | ||
</Button> | ||
<p className="cursor-pointer text-xs text-grey50 underline">삭제하기</p> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
{/* 이름 */} | ||
<div className="flex flex-col gap-3"> | ||
<span className="flex text-grey80"> | ||
이름<p className="text-main">*</p> | ||
</span> | ||
<Input placeholder="이름을 입력해주세요" /> | ||
<span className="text-xs text-grey50">*이름은 계정 관리 - 계정 설정에서 변경할 수 있어요</span> | ||
</div> | ||
|
||
{/* 포지션 */} | ||
<div className="flex flex-col gap-3"> | ||
<span className="flex text-grey80"> | ||
포지션(데이터 넣어야함) <p className="text-main">*</p> | ||
</span> | ||
|
||
<div className="flex w-full gap-[1.38rem]"> | ||
<div className="flex w-[48%] flex-col gap-2"> | ||
<span className="text-sm text-grey70">대분류</span> | ||
<Select options={mainOptions} placeholder="도/광역시 선택" onChange={(value) => setSelectedCity(value)} /> | ||
</div> | ||
|
||
{selectedCity && ( | ||
<div className="flex w-[48%] flex-col gap-2"> | ||
<span className="text-sm text-grey70">소분류</span> | ||
<Select options={subOptions} placeholder="구/군 선택" /> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
|
||
{/* 활동 지역 */} | ||
<div className="flex flex-col gap-3"> | ||
<span className="flex text-grey80"> | ||
활동 지역 <p className="text-main">*</p> | ||
</span> | ||
|
||
<div className="flex w-full gap-[1.38rem]"> | ||
<div className="flex w-[48%] flex-col gap-2"> | ||
<span className="text-sm text-grey70">시/도</span> | ||
<Select options={mainOptions} placeholder="도/광역시 선택" onChange={(value) => setSelectedCity(value)} /> | ||
</div> | ||
|
||
{selectedCity && ( | ||
<div className="flex w-[48%] flex-col gap-2"> | ||
<span className="text-sm text-grey70">시/군/구</span> | ||
<Select options={subOptions} placeholder="구/군 선택" /> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
|
||
<div className="flex flex-col gap-4"> | ||
{/* 현재 상태 - 선택된 상태들 */} | ||
<div className="flex flex-col gap-3"> | ||
<span className="flex text-grey80">현재 상태</span> | ||
|
||
<div className="flex flex-wrap gap-2"> | ||
{selectedStatuses.map((status) => ( | ||
<div | ||
onClick={() => handleRemoveStatus(status)} | ||
key={status} | ||
className="flex cursor-pointer items-center rounded-lg border border-main bg-[#EEF4FF] px-4 py-3 text-sm text-main" | ||
> | ||
<span>{status}</span> | ||
<button className="ml-2 text-main">✕</button> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
|
||
{/* 현재 상태 - 옵션 선택 */} | ||
<div className="flex w-full flex-wrap gap-3 rounded-xl bg-grey10 px-6 py-7"> | ||
{statusOptions.map((status) => ( | ||
<span | ||
key={status} | ||
onClick={() => handleStatusClick(status)} | ||
className={`cursor-pointer rounded-lg border px-4 py-3 text-sm ${ | ||
selectedStatuses.includes(status) | ||
? 'border-main bg-[#EEF4FF] text-main' // 선택된 상태의 스타일 | ||
: 'border-grey40 bg-[#FCFCFD] text-grey50' // 기본 상태의 스타일 | ||
}`} | ||
> | ||
{status} | ||
</span> | ||
))} | ||
</div> | ||
</div> | ||
|
||
{/* 프로필 공개 여부 */} | ||
<div className="flex flex-col gap-3"> | ||
<span className="flex text-grey80"> | ||
프로필 공개 여부 <p className="text-main">*</p> | ||
</span> | ||
|
||
<Radio options={options} selectedValue={selectedOption} onChange={setSelectedOption} labelClassName="" /> | ||
</div> | ||
</div> | ||
|
||
<div className="mt-[1.31rem] flex w-full justify-end"> | ||
<Button className="rounded-xl px-5 py-[0.38rem]" animationMode="main" mode="main"> | ||
저장하기 | ||
</Button> | ||
</div> | ||
</> | ||
) | ||
} |