|
| 1 | +import { useState } from "react"; |
| 2 | +import { useLocation } from "react-router-dom"; |
| 3 | +import FormButton from "@/components/button/FormButton"; |
| 4 | +import Header from "@/components/Header"; |
| 5 | + |
1 | 6 | const SelectInfo = () => { |
2 | | - return <div>빠른 대화 설정 및 친구 저장 페이지 </div>; |
| 7 | + const location = useLocation(); |
| 8 | + const mode = location.state; // mode: fastFriend, virtualFriend 두 종류 존재 |
| 9 | + const isNameRequired = mode === "virtualFriend"; |
| 10 | + const headerTitle = mode === 'fastFriend' ? "상대방 정보선택" : "친구 저장하기"; |
| 11 | + |
| 12 | + const [selectedMBTI, setSelectedMBTI] = useState<{ |
| 13 | + [key: string]: string | null; |
| 14 | + }>({ |
| 15 | + E: null, |
| 16 | + N: null, |
| 17 | + F: null, |
| 18 | + P: null |
| 19 | + }); |
| 20 | + const [name, setName] = useState<string>(""); |
| 21 | + const [age, setAge] = useState<string | null>(null); |
| 22 | + const [gender, setGender] = useState<string | null>(null); |
| 23 | + const [relationship, setRelationship] = useState<string | null>(null); |
| 24 | + const [interest, setInterest] = useState<string[]>([]); |
| 25 | + |
| 26 | + const mbtiOptions = ["E", "N", "F", "P", "I", "S", "T", "J"]; |
| 27 | + const ageOptions = ["10대", "20대", "30대 이상"]; |
| 28 | + const genderOptions = ["여자", "남자"]; |
| 29 | + const relationshipOptions = [ |
| 30 | + "부모", |
| 31 | + "자녀", |
| 32 | + "친구", |
| 33 | + "짝사랑", |
| 34 | + "이별", |
| 35 | + "연인", |
| 36 | + "선생님", |
| 37 | + "직장동료" |
| 38 | + ]; |
| 39 | + const interestOptions = [ |
| 40 | + "연애", |
| 41 | + "결혼", |
| 42 | + "취미", |
| 43 | + "사회생활", |
| 44 | + "여행", |
| 45 | + "운동", |
| 46 | + "심리", |
| 47 | + "뷰티/패션", |
| 48 | + "음식", |
| 49 | + "인간관계" |
| 50 | + ]; |
| 51 | + |
| 52 | + const handleMBTISelect = (option: string) => { |
| 53 | + const group = getMBTIgroup(option); |
| 54 | + setSelectedMBTI((prevState) => ({ |
| 55 | + ...prevState, |
| 56 | + [group]: prevState[group] === option ? null : option |
| 57 | + })); |
| 58 | + }; |
| 59 | + |
| 60 | + const getMBTIgroup = (option: string) => { |
| 61 | + if (["E", "I"].includes(option)) return "E"; |
| 62 | + if (["N", "S"].includes(option)) return "N"; |
| 63 | + if (["F", "T"].includes(option)) return "F"; |
| 64 | + if (["P", "J"].includes(option)) return "P"; |
| 65 | + return ""; |
| 66 | + }; |
| 67 | + |
| 68 | + const isMBTISelected = (option: string) => { |
| 69 | + const group = getMBTIgroup(option); |
| 70 | + return selectedMBTI[group] === option; |
| 71 | + }; |
| 72 | + |
| 73 | + const handleInterestSelect = (option: string) => { |
| 74 | + if (interest.includes(option)) { |
| 75 | + setInterest((prevInterests) => |
| 76 | + prevInterests.filter((item) => item !== option) |
| 77 | + ); |
| 78 | + } else { |
| 79 | + setInterest((prevInterests) => [...prevInterests, option]); |
| 80 | + } |
| 81 | + }; |
| 82 | + |
| 83 | + const isInterestSelected = (option: string) => { |
| 84 | + return interest.includes(option); |
| 85 | + }; |
| 86 | + |
| 87 | + const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => { |
| 88 | + const value = e.target.value; |
| 89 | + if (value.length > 6) { |
| 90 | + const truncatedValue = value.substring(0, 6); |
| 91 | + setName(truncatedValue); |
| 92 | + } else { |
| 93 | + setName(value); |
| 94 | + } |
| 95 | + }; |
| 96 | + |
| 97 | + const handleButtonClick = (value: string, setter: (val: string | null) => void, state: string | null) => { |
| 98 | + setter(state === value ? null : value); |
| 99 | + }; |
| 100 | + |
| 101 | + const handleStartChat = () => { |
| 102 | + const isEGroupSelected = selectedMBTI.E !== null; |
| 103 | + const isNGroupSelected = selectedMBTI.N !== null; |
| 104 | + const isFGroupSelected = selectedMBTI.F !== null; |
| 105 | + const isPGroupSelected = selectedMBTI.P !== null; |
| 106 | + |
| 107 | + // 선택한 MBTI값이 하나라도 부재할 경우 |
| 108 | + if ( |
| 109 | + !isEGroupSelected || |
| 110 | + !isNGroupSelected || |
| 111 | + !isFGroupSelected || |
| 112 | + !isPGroupSelected |
| 113 | + ) { |
| 114 | + return alert("각 MBTI 그룹에서 하나의 값을 선택해주세요."); // TODO: Toast popup UI 완료 시 반영 예정 |
| 115 | + } |
| 116 | + |
| 117 | + // 이름 필수 && 이름이 입력되지 않았을 경우 |
| 118 | + if (isNameRequired && !name) { |
| 119 | + return alert("이름을 입력해주세요."); // TODO: Toast popup UI 완료 시 반영 예정 |
| 120 | + } |
| 121 | + |
| 122 | + alert("대화 시작 API 연결하기."); // TODO: API 연동 예정 |
| 123 | + }; |
| 124 | + |
| 125 | + return ( |
| 126 | + <div className="flex w-[360px] flex-col bg-white md:w-[375px] lg:w-[500px]"> |
| 127 | + <Header title={headerTitle} /> |
| 128 | + |
| 129 | + <div className="w-[320px] mx-auto"> |
| 130 | + {/* MBTI 선택 */} |
| 131 | + <div className="mb-[40px] pt-[48px]"> |
| 132 | + <p className="font-bold text-[20px] leading-[30px] tracking-[-0.01em]"> |
| 133 | + 상대방의 MBTI를 선택하면 <br /> |
| 134 | + 대화를 시뮬레이션 해볼 수 있어요 |
| 135 | + </p> |
| 136 | + |
| 137 | + <div className="pt-[24px] grid grid-cols-4 gap-[24px_13px]"> |
| 138 | + {mbtiOptions.map((option) => ( |
| 139 | + <FormButton |
| 140 | + key={option} |
| 141 | + size="md" |
| 142 | + selected={isMBTISelected(option)} |
| 143 | + onClick={() => handleMBTISelect(option)} |
| 144 | + > |
| 145 | + {option} |
| 146 | + </FormButton> |
| 147 | + ))} |
| 148 | + </div> |
| 149 | + </div> |
| 150 | + </div> |
| 151 | + |
| 152 | + <div className="w-full h-[8px] bg-[#EEF0F3]" /> |
| 153 | + |
| 154 | + <div className="w-[320px] mx-auto"> |
| 155 | + <div className="pt-[40px]"> |
| 156 | + <p className="font-bold text-[20px] leading-[30px] tracking-[-0.01em]"> |
| 157 | + 정보 추가 입력 |
| 158 | + </p> |
| 159 | + |
| 160 | + {/* 이름 입력 */} |
| 161 | + <div className="pt-[32px] flex flex-col gap-2"> |
| 162 | + <label |
| 163 | + htmlFor="name" |
| 164 | + className="font-bold text-2lg leading-[24px] tracking-[0em] text-gray-600" |
| 165 | + > |
| 166 | + 이름 |
| 167 | + {isNameRequired && <span className="text-red-500">*</span>} |
| 168 | + </label> |
| 169 | + <input |
| 170 | + id="name" |
| 171 | + type="text" |
| 172 | + value={name} |
| 173 | + onChange={handleNameChange} |
| 174 | + className="w-full h-[56px] px-4 border border-gray-200 rounded-lg focus:outline-none focus:ring-primary-light focus:border-primary-light" |
| 175 | + placeholder="이름" |
| 176 | + maxLength={6} |
| 177 | + /> |
| 178 | + </div> |
| 179 | + |
| 180 | + {/* 나이 선택 */} |
| 181 | + <div className="pt-[20px] pb-[12px]"> |
| 182 | + <p className="font-bold text-2lg leading-[24px] tracking-[0em] text-gray-600"> |
| 183 | + 나이 |
| 184 | + </p> |
| 185 | + <div className="pt-[16px] flex gap-[16px]"> |
| 186 | + {ageOptions.map((option) => ( |
| 187 | + <FormButton |
| 188 | + key={option} |
| 189 | + size="sm" |
| 190 | + selected={age === option} |
| 191 | + onClick={() => handleButtonClick(option, setAge, age)} |
| 192 | + > |
| 193 | + {option} |
| 194 | + </FormButton> |
| 195 | + ))} |
| 196 | + </div> |
| 197 | + </div> |
| 198 | + |
| 199 | + {/* 성별 선택 */} |
| 200 | + <div className="pt-[20px] pb-[12px]"> |
| 201 | + <p className="font-bold text-2lg leading-[24px] tracking-[0em] text-gray-600"> |
| 202 | + 성별 |
| 203 | + </p> |
| 204 | + <div className="pt-[16px] flex gap-[16px]"> |
| 205 | + {genderOptions.map((option) => ( |
| 206 | + <FormButton |
| 207 | + key={option} |
| 208 | + size="sm" |
| 209 | + selected={gender === option} |
| 210 | + onClick={() => handleButtonClick(option, setGender, gender)} |
| 211 | + > |
| 212 | + {option} |
| 213 | + </FormButton> |
| 214 | + ))} |
| 215 | + </div> |
| 216 | + </div> |
| 217 | + |
| 218 | + {/* 관계 선택 */} |
| 219 | + <div className="pt-[20px] pb-[20px]"> |
| 220 | + <p className="font-bold text-2lg leading-[24px] tracking-[0em] text-gray-600"> |
| 221 | + 상대방과 나의 관계 |
| 222 | + </p> |
| 223 | + <div className="pt-[16px] grid grid-cols-4 gap-[16px]"> |
| 224 | + {relationshipOptions.map((option) => ( |
| 225 | + <FormButton |
| 226 | + key={option} |
| 227 | + size="sm" |
| 228 | + selected={relationship === option} |
| 229 | + onClick={() => handleButtonClick(option, setRelationship, relationship)} |
| 230 | + > |
| 231 | + {option} |
| 232 | + </FormButton> |
| 233 | + ))} |
| 234 | + </div> |
| 235 | + </div> |
| 236 | + |
| 237 | + {/* 관심사 선택 */} |
| 238 | + <div className="pt-[20px] pb-[26px]"> |
| 239 | + <p className="font-bold text-2lg leading-[24px] tracking-[0em] text-gray-600"> |
| 240 | + 관심사 |
| 241 | + </p> |
| 242 | + <div className="pt-[16px] grid grid-cols-4 gap-[16px]"> |
| 243 | + {interestOptions.map((option) => ( |
| 244 | + <FormButton |
| 245 | + key={option} |
| 246 | + size="sm" |
| 247 | + selected={isInterestSelected(option)} |
| 248 | + onClick={() => handleInterestSelect(option)} |
| 249 | + > |
| 250 | + {option} |
| 251 | + </FormButton> |
| 252 | + ))} |
| 253 | + </div> |
| 254 | + </div> |
| 255 | + </div> |
| 256 | + |
| 257 | + {/* 대화 시작 버튼 */} |
| 258 | + <button |
| 259 | + className="w-full my-[22px] h-[60px] bg-primary-normal text-white rounded-[8px] font-bold" |
| 260 | + onClick={handleStartChat} |
| 261 | + > |
| 262 | + 대화 시작하기 |
| 263 | + </button> |
| 264 | + </div> |
| 265 | + </div> |
| 266 | + ); |
3 | 267 | }; |
4 | 268 |
|
5 | 269 | export default SelectInfo; |
0 commit comments