์ด๋ฒ์๋ ๋ ๊ฐ์ง ๊ธฐ๋ฅ์ ์๋กญ๊ฒ ์ถ๊ฐํ๋ค:
- ๋ค๋ฅธ ์ฌ์ฉ์์ ํ๋กํ์ ๊ฐํธํ๊ฒ ํ์ธํ ์ ์๋ FollowProfile
- ์์ฃผ ์ฐ๋ ๋ฌธ์ฅ์ ๋ฑ๋กํ๊ณ ํ๊ธ ์์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํด์ ๋ณผ ์ ์๋ Shortcut ๊ธฐ๋ฅ
- ๋จ์ํ UI๋ง ๊ตฌ์ฑํ ๊ฒ ์๋๋ผ, ์ค์ API ์ฐ๋๋ถํฐ ์ ๋ ฌ ๋ก์ง, ์ํ ์ ์ฅ๊น์ง ๊ฝค ๋ค์ํ ๊ฐ๋ ์ ํจ๊ป ๋ค๋ค๋ค.
ํ๋ก์ํ ์ ์ ๋ฅผ ๋๋ ์ ๋, ํด๋น ์ ์ ์ ํ๋กํ ์ ๋ณด๋ฅผ ํ์ ํ์์ผ๋ก ๋ถ๋ฌ์ค๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์๋ค. ํต์ฌ์ ๋ค์๊ณผ ๊ฐ์ ํ๋ฆ์ด๋ค:
const profileWing = GetProfileByUserIDGameIDWing(userId, MAPLEGAMEID);
const profileResponse = await shootingStar.launch<ProfileData>(profileWing);
Wing์ผ๋ก API ์์ฒญ ์ ๋ณด๋ฅผ ๊ตฌ์ฑํ๊ณ , ShootingStar๋ก ์ค์ ์์ฒญ์ ๋ณด๋ธ๋ค
๋ฐ์ ๋ฐ์ดํฐ๋ ProfileData ํ์ ์ผ๋ก ๊ตฌ์กฐํ๋์ด ๋ค์ด์จ๋ค
ํ๋กํ ์ด๋ฆ, ๊ฐฑ์ ์ผ, ๋ํ ์บ๋ฆญํฐ์ ๋ ๋ฒจ, ์ ํฌ๋ ฅ, ์ ๋์จ ๋ฑ์ ์ถ์ถ
getImagePathFromProfile ์ ํธ ํจ์๋ก ์บ๋ฆญํฐ ์ด๋ฏธ์ง ๊ฒฐ์
formatPower()๋ก ์ ํฌ๋ ฅ ์ซ์๋ฅผ ์ต, ์ฒ๋ง ๋จ์๋ก ํฌ๋งทํ
Popup์ ํ๋ฉด ํ๋จ์ ๊ณ ์ ๋ ํํ๋ก ๋จ๋๋ก position: fixed
์ฌ๋ผ์ด๋ ์ /๋ค์ด ์ ๋๋ฉ์ด์ ์ transform: translateY()์ transition์ผ๋ก ์ ์ด
์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋ฌธ๊ตฌ(input)์ ๋จ์ถ์ด(output)์ ์ ์ฅํ๊ณ ์ถ์๊ธฐ ๋๋ฌธ์,
๊ธฐ์กด์ ํ๋กํ ์ ๋ณด์ shortcut_words ๋ฐฐ์ด์ ์ถ๊ฐํด์ ์ ์ฅํ๋ค.
const updatedShortcuts = [
...(myProfile.shortcut_words || []),
{ input: text, output: shortcut }
];
await updateMyProfile({ shortcut_words: updatedShortcuts });
์ด ์์ ์ AddShortcutContainer.tsx์์ ์ฒ๋ฆฌ๋๋ฉฐ, ์ ์ฅ ๋ฒํผ ํด๋ฆญ ์ ์คํ๋จ
์๋ฒ์๋ updateMyProfile ์ ํธํจ์๋ฅผ ์ฌํ์ฉํด์ ์ ์ก
const getHangulInitial = (char) => {
const initialLetters = ["ใฑ", "ใฒ", "ใด", ...];
const code = char.charCodeAt(0);
if (code >= 0xAC00 && code <= 0xD7A3) {
const index = Math.floor((code - 0xAC00) / 588);
return initialLetters[index];
}
return char;
};
ํ๊ธ ์์ ์ ์ ๋์ฝ๋ ์์์ ์ด์ฑ/์ค์ฑ/์ข ์ฑ์ผ๋ก ์กฐํฉ๋์ด ์๊ณ ,
์ด์ฑ ํ๋์ ๋จ์๋ 588๊ฐ์ ๋ธ๋ก๋ง๋ค ๋ฐ๋ณต๋๊ธฐ ๋๋ฌธ์ Math.floor((code - 0xAC00) / 588)๋ก ์ด์ฑ์ ๊ณ์ฐํจ
์ด ๋ฐฉ์์ผ๋ก ๋จ์ถ์ด๋ค์ ใฑ ~ ใ ์์๋ก ๊ทธ๋ฃนํ ๊ฐ๋ฅํจ
const groupedShortcuts = shortcutList.reduce((acc, shortcut) => {
const firstChar = getHangulInitial(shortcut.output[0]);
if (!acc[firstChar]) acc[firstChar] = [];
acc[firstChar].push(shortcut);
return acc;
}, {});
๋จ์ถ์ด ์ถ๋ ฅ๊ฐ์ ์ฒซ ๊ธ์๋ฅผ ๊ธฐ์ค์ผ๋ก ์ด์ฑ์ ๊ตฌ๋ถํ๊ณ ,
๊ทธ ์ด์ฑ์ ํค๋ก ํด์ ๋ฌถ์ด ๋ ๋๋งํ ์ ์๋๋ก ๊ตฌ์ฑ
๊ทธ๋ฃน ์ด๋ฆ(์ด์ฑ)์ ํฌ๊ฒ ๋ณด์ฌ์ฃผ๊ณ ,
๊ฐ ๋จ์ถ์ด๋ ์ข์ธก์ output, ์ฐ์ธก์ input์ผ๋ก ๋ณด์ฌ์ฃผ๋ ์๊ฐ์ ๊ตฌ์ฑ
๊ธฐ๋ฅ ๊ธฐ์ ํฌ์ธํธ
FollowProfile Wing + ShootingStar ์กฐํฉ์ผ๋ก ์ ์ ๋ฐ์ดํฐ ์์ฒญ ํ์
์ ๋๋ฉ์ด์
๊ตฌํ (translateY + transition)
Shortcut ๋ฑ๋ก ๊ธฐ์กด ํ๋กํ ๊ตฌ์กฐ ์ฌ์ฌ์ฉ (updateMyProfile๋ก ์ ์ฅ)
์ ๋ ฌ ์ ๋์ฝ๋ ๊ธฐ๋ฐ ์ด์ฑ ์ถ์ถ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ใฑ~ใ
์ ๋ ฌ ๊ตฌํ
ํ์ฌ๋ ๋จ์ถ์ด ๋ชฉ๋ก๋ง ํ์ธ ๊ฐ๋ฅํ ์ํ์ง๋ง,
ํฅํ์๋ ์ฑํ ์ ๋ ฅ๋์์ ๋จ์ถ์ด๋ฅผ ์๋์ผ๋ก ํ์ฅํ๊ฑฐ๋,
๋จ์ถ์ด ์ถ์ฒ ๊ธฐ๋ฅ์ฒ๋ผ ์ฐ๊ฒฐํด์ ์ค์๊ฐ ์นํ ๊ธฐ๋ฅ์ ๋ฃ๋ ๊ฑธ ๋ชฉํ๋ก ํ๊ณ ์๋ค
์: "ใฑใ " ์ ๋ ฅ ์ ์๋์ผ๋ก "๊ฐ์ฌํฉ๋๋ค"๋ก ๋ณํ๋๋๋ก ๊ตฌํ ์์
ํ์ฌ FollowProfile์ ํ์ ์ผ๋ก ์ ๋ณด๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ฐ์ ๊ทธ์น์ง๋ง,
์ ์ ์ด๋ฆ์ ํด๋ฆญํ๋ฉด ํด๋น ์ ์ ์ ์ ์ฒด ํ๋กํ ํ๋ฉด์ผ๋ก ๋ผ์ฐํ ๋๋๋ก ๊ตฌํ๋์ด ์๋ค
onClick={() => navigate(`/trade-profile?userID=${userId}&title=${nickname}`)}
์ด๋ ๊ฒ ํ๋ฉด ํ์ ์์ ์ ์ฒด ํ์ด์ง๋ก ์์ฐ์ค๋ฝ๊ฒ ์ฐ๊ฒฐ๋๋ UX ํ๋ฆ์ด ์์ฑ๋๋ค
FollowProfile์ UI/UX ์ธก๋ฉด์์ ์ฌ์ฉ์ ์ ๋ณด ์ ๊ทผ์ฑ์ ํฅ์์์ผฐ๊ณ ,
Shortcut์ ์ค์ฌ์ฉ์๊ฐ ์์ฃผ ์ฐ๋ ๋ฌธ์ฅ์ ๋น ๋ฅด๊ฒ ๋ฑ๋กํ๊ณ ํ์ธํ ์ ์๋๋ก ํ๋ ์ค์ ์ ์ฉํ ๊ธฐ๋ฅ์ด์๋ค
ํนํ ํ๊ธ ์ ๋ ฌ์ ๊ตฌํํ๋ฉด์ ์ ๋์ฝ๋์ ๊ตฌ์กฐ๋ฅผ ์ง์ ๋ค๋ค๋ณธ ๊ฒ ํฐ ํ์ต์ด์๊ณ , ๋จ์ํ ์ ๋ ฌ ํจ์๊ฐ ์๋ ํ๊ตญ์ด์ ํนํ๋ ์ฌ์ฉ์ ๊ฒฝํ์ ์ด๋ป๊ฒ ์ ๊ณตํ ์ ์์์ง ๊ณ ๋ฏผํ๋ ๊ณ๊ธฐ๊ฐ ๋์๋ค.
๋จ์ํ ๊ธฐ๋ฅ ํ๋์๋ API ์ค๊ณ, ์ํ ์ฒ๋ฆฌ, ํ ์คํธ ๋ถํด ์๊ณ ๋ฆฌ์ฆ๊น์ง ๋ค์ํ ๊ธฐ์ ์ด ์ค๋ฉฐ๋ ๋ค๋ ๊ฑธ ๋ค์ ์ฒด๊ฐํ ์์ ์ด์๋ค.