[Portfolio] ๐ŸŽถ FLOrida music

๊น€์ง„์˜ยท2022๋…„ 10์›” 21์ผ
0

Portfolio

๋ชฉ๋ก ๋ณด๊ธฐ
2/6
post-thumbnail

๐Ÿ“‹ FLOrida

๐Ÿ’ก ํŒ€๋ช… : FLOrida

  • ๋ชจํ‹ฐ๋ธŒ๋กœ ํ•œ ์‚ฌ์ดํŠธ : https://www.music-flo.com/
  • FE : ๊น€์ง„์˜ ๊น€์ถฉ๋งŒ ์ž„์ง€์˜ ์ตœ์Šน์ฒ 
  • BE : ๊น€๊ต์€ ์ด์‹ ํฌ
  • ๊ฐœ๋ฐœ๊ธฐ๊ฐ„ : 9/19(์›”) ~ 9/30(๋ชฉ) 14:00 (12์ผ)

์‚ฌ์šฉํ•œ ๊ธฐ์ˆ  ์Šคํƒ
FE : JavaScript React.js styled-component react-h5-audio-player MUI ๋“ฑ
BE :JavaScript Node.js MySQL Express.js jwt bcrypt ๋“ฑ

JUSTCODE ๊ณผ์ •์—์„œ ์ง„ํ–‰๋œ 2์ฐจ ํŒ€ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.

์ด ํ”„๋กœ์ ํŠธ๋Š” ํŒ€์žฅ์€ ๋”ฐ๋กœ ์—†๊ณ  FE ์ด 4๋ช…, BE 2๋ช…์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ํŒ€์œผ๋กœ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฒ˜์Œ์— ์ œ ์ทจ๋ฏธ๊ฐ€ ์Œ์•… ๊ฐ์ƒ์ด๋ผ ์Œ์•… ํ”Œ๋ ˆ์ด์–ด ๋ฐ ๊ฐœ์ธ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ๊ด€๋ฆฌ ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ํ•ด๋ณด๊ณ  ์‹ถ๊ธฐ๋„ ํ•˜๊ณ , 1์ฐจ ํ”„๋กœ์ ํŠธ๋ณด๋‹ค ๊ธฐ๋Šฅ๋„ ๋‹ค์–‘ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ œ์•ˆํ–ˆ๊ณ  ํŒ€์›๋ถ„๋“ค๋„ ๋ชจ๋‘ ๋™์˜ํ•ด ์ฃผ์…”์„œ FLO ์‚ฌ์ดํŠธ๋ฅผ ๋ชจํ‹ฐ๋ธŒ๋กœ ์ œ์ž‘ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ๋ชจํ‹ฐ๋ธŒ๋กœ ์ œ์ž‘ํ•˜์˜€๋‹ค๋Š” ๊ฑด, ๋ˆ„๊ตฐ๊ฐ€์˜ ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌ ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•œ ๊ฒƒ์ด ์•„๋‹Œ ํŽ˜์ด์ง€์˜ ๊ตฌ์กฐ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๊ฒƒ์„ ๋œปํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ”— ๋งํฌ

๐Ÿ’ป GitHub

๐Ÿ“‹ ํšŒ๊ณ ๋ก


๐Ÿ”ง ๋‚ด๊ฐ€ ๊ตฌํ˜„ํ•œ ๊ธฐ๋Šฅ

๐ŸŽฅ ๋‚ด๊ฐ€ ๊ตฌํ˜„ํ•œ ๊ธฐ๋Šฅ ์‹œ์—ฐ ์˜์ƒ

์ œ๊ฐ€ ๋งก์€ ๋ถ€๋ถ„์„ ์„œ๋ฒ„๊ฐ€ ์—ด๋ ค์žˆ์„ ๋•Œ ์ดฌ์˜ํ•˜์—ฌ ์œ ํŠœ๋ธŒ์— ์—…๋กœ๋“œํ–ˆ์Šต๋‹ˆ๋‹ค.

1. ์Œ์•… ํ”Œ๋ ˆ์ด์–ด

์Œ์•… ํ”Œ๋ ˆ์ด์–ด๋Š” react-h5-audio-player ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ž‘์—…ํ–ˆ์Šต๋‹ˆ๋‹ค.

1-1. ํ˜„์žฌ ์žฌ์ƒ๋ชฉ๋ก

ํ˜„์žฌ ์žฌ์ƒ๋ชฉ๋ก์€ state์™€ ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜์—ฌ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€๋กœ๋„ ๊ด€๋ฆฌํ•˜์—ฌ ๋งˆ์šดํŠธ ์‹œ ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€์—์„œ ํ˜„์žฌ ์žฌ์ƒ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์— ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด๋„ ํ˜„์žฌ ์žฌ์ƒ๋ชฉ๋ก์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

1-2. ๊ณก ์…”ํ”Œ ๊ธฐ๋Šฅ

์…”ํ”Œ ๊ธฐ๋Šฅ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์กด์žฌํ•˜์ง€ ์•Š์•„์„œ ์ง์ ‘ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

  const shuffleMusic = () => {
    if (JSON.parse(sessionStorage.getItem('tracks')).length !== 0) {
      const randomTracks = [...musicTracks].sort(() => Math.random() - 0.5);
      if (randomTracks[0] === musicTracks[0]) {
        const lastIndex = randomTracks.length - 1;
        const randomValue = Math.floor(Math.random() * (lastIndex - 1) + 1);
        const temp = randomTracks[0];
        randomTracks[0] = randomTracks[randomValue];
        randomTracks[randomValue] = temp;
      }
      setMusicTracks(randomTracks);
    }
  };

array.sort ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ๋žœ๋คํ•˜๊ฒŒ ํ˜„์žฌ ์žฌ์ƒ๋ชฉ๋ก์„ ๋’ค์„ž๊ณ , ์ฒซ ๋ฒˆ์งธ ๊ณก์ด ๋ฐ”๋€Œ์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ์ฒซ ๋ฒˆ์งธ ๊ณก์„ ๋˜ ๋žœ๋คํ•œ ์ธ๋ฑ์Šค์— ์œ„์น˜ํ•˜๊ฒŒ ํ•˜๋„๋ก ๋กœ์ง์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

1-3. ๊ณก ๋‹ค์ค‘ ์„ ํƒ ๊ธฐ๋Šฅ

๊ณก์„ ๋‹ค์ค‘์œผ๋กœ ์„ ํƒํ•ด ํ˜„์žฌ ์žฌ์ƒ๋ชฉ๋ก์—์„œ ์‚ญ์ œ ๋ฐ ํ”Œ๋ ˆ์ด ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ณก์„ ์„ ํƒํ–ˆ์„ ๋•Œ, ๋ฐฐ์—ด์— ๊ณก์˜ ID๋ฅผ ๋‹ด์•„ state๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ์‚ญ์ œ ๋ฐ ๋ฐฑ์—”๋“œ๋กœ ์ „๋‹ฌ(๋ณด๊ด€ํ•จ์— ์ถ”๊ฐ€) ํ•  ์ˆ˜ ์žˆ๋Š” ๋กœ์ง์ž…๋‹ˆ๋‹ค.

1-4. ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ

์žฌ์ƒ ์ค‘์ธ ๊ณก์„ ๋ฐ”๊พธ๋ ค๋ฉด ์ธ๋ฑ์Šค ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๊ฒ€์ƒ‰์„ ํ•˜๋ฉด ๋ฐฐ์—ด์˜ ๊ธธ์ด๊ฐ€ ์ค„์–ด๋“ค๊ธฐ ๋•Œ๋ฌธ์— ๊ณก์„ ํด๋ฆญํ•˜๋ฉด ์›๋ž˜ ์žฌ์ƒ๋ชฉ๋ก์˜ ์ธ๋ฑ์Šค์— ํ•ด๋‹นํ•˜๋Š” ๊ณก์ด ์‹คํ–‰๋˜์–ด๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ƒ๊ฐํ•œ ๊ฒƒ์ด ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ํ•„ํ„ฐ๋ง๋œ ๊ณก๋“ค์€ ๊ณก url์„ ๋นˆ ๋ฌธ์ž์—ด๋กœ ์„ค์ •ํ•ด๋ฒ„๋ ค ๋นˆ ๋ฌธ์ž์—ด์„ ๊ฐ€์ง„ ๊ณก๋“ค์€ ์ถœ๋ ฅ๋˜์ง€ ์•Š๊ฒŒ ๋กœ์ง์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

2. ๋ณด๊ด€ํ•จ

2-1. ๋ณด๊ด€ํ•จ ๋‹ค์ค‘ ์„ ํƒ ๊ธฐ๋Šฅ

์œ„์˜ ๊ณก ์„ ํƒ ๋กœ์ง๊ณผ ๋˜‘๊ฐ™์Šต๋‹ˆ๋‹ค. ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ID๋ฅผ ๋ฐฐ์—ด์— ์ €์žฅํ•˜์—ฌ state๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

2-2. ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ์žฌ์ƒ ๋กœ์ง

  const playSongs = () => {
    if (playlistSongs[0].songTitle) {
      fetch(`ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์š”์ฒญURL`, {
        headers: {
          Authorization: sessionStorage.getItem('token'),
        },
      })
        .then(res => res.json())
        .then(plData => {
          const musicTracksId = musicTracks.map(el => el.songId);
          const filteredNewTracks = plData.filter(
            (el, i) => musicTracksId.includes(el.songId) === false
          );
          setMusicTracks([...filteredNewTracks, ...musicTracks]);
          setAlertOn('ํ˜„์žฌ ์žฌ์ƒ๋ชฉ๋ก์— ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ค‘๋ณต๋œ ๊ณก์€ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค.');
        })
        .catch(err => {
          if (sessionStorage.getItem('token'))
            setAlertOn(
              '์ด์šฉ๊ถŒ์„ ๊ตฌ๋งคํ•ด์•ผ ์Œ์•… ์žฌ์ƒ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.'
            );
        });
    }
  };

์ „์ฒด ์žฌ์ƒ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์˜ ๊ณก๋“ค์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ๊ณก๋“ค์„ ๋ฐ›์•„ ๋‚ด ํ˜„์žฌ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” ๊ณก๋“ค์„ ์•„์ด๋””๋ฅผ ํ†ตํ•ด ๋น„๊ตํ•ด ์ค‘๋ณต๋˜์ง€ ์•Š๋Š” ๊ณก๋“ค๋งŒ ์ถ”๊ฐ€ํ•˜๋„๋ก ๋กœ์ง์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

2-3. ๊ฐœ๋ณ„ ๊ณก ์žฌ์ƒ ๋กœ์ง

์žฌ์ƒ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ˜„์žฌ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ์ค‘๋ณต๋˜๋Š” ๊ณก์ด ์žˆ๋‹ค๋ฉด ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

3. ๋ณด๊ด€ํ•จ ์ƒ์„ธํŽ˜์ด์ง€

3-1. ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ๋ช… ์ˆ˜์ •

๋ฐ”๋€ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์˜ ๊ฐ’์„ ๋ฐฑ์œผ๋กœ ์ „๋‹ฌํ•˜๊ณ  ๋ฐ”๋กœ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ useRef์™€ focus ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ˆ˜์ • ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ๋ฐ”๋กœ ํฌ์ปค์‹ฑ ๋˜๋„๋ก ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

3-2. ์Œ์•… ํ”Œ๋ ˆ์ด์–ด ์œ„ ์•Œ๋ฆผ์ฐฝ

์•Œ๋ฆผ ์ฐฝ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด setAlert(โ€๋ฉ”์„ธ์ง€โ€) ๋ฅผ ํ†ตํ•ด ์›ํ•˜๋Š” ๋ฉ”์„ธ์ง€๋ฅผ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

alert ์ปดํฌ๋„ŒํŠธ๋Š” ๋‚˜ํƒ€๋‚œ ๋’ค 3์ดˆ ํ›„์— ์ž๋™์œผ๋กœ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

๊ทธ ์™ธ ํ˜„์žฌ ์žฌ์ƒ๋ชฉ๋ก ์ค‘๋ณต ๋ฐฉ์ง€ ๋ฐ ๋‹ค์ค‘ ์„ ํƒ ๊ธฐ๋Šฅ์€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

4. ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ

๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์ „๊นŒ์ง€ ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋นˆ ํ™”๋ฉด ๋Œ€์‹  ์ถœ๋ ฅ๋˜๋„๋ก ํ•˜๊ณ  ๋‹ค๋ฅธ ๋ชจ๋“  ํŽ˜์ด์ง€์— ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜์ค‘์— ์‹œ๊ฐ„์ด ๋œ๋‹ค๋ฉด ์Šค์ผˆ๋ ˆํ†ค์œผ๋กœ๋„ ๊ตฌํ˜„ํ•ด ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.


๐Ÿ’ช ๋‚ด๊ฐ€ ์„ฑ์žฅํ•œ ๋ถ€๋ถ„

1. ์†Œํ†ต์˜ ์ค‘์š”์„ฑ์„ ๊นจ๋‹ซ๋‹ค

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ ์ดˆ๋ฐ˜์— ํŒ€์›์˜ ์‚ฌ์ •์œผ๋กœ ์ธํ•ด ์—ฐ๋ฝ์ด ๋˜์ง€ ์•Š์•„ ํŒ€ ํ˜‘์—… ๊ฐ„์— ํŠธ๋Ÿฌ๋ธ”์ด ์ƒ๊ธธ๋ป” ํ•œ ์ƒํ™ฉ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ทธ ์ดํ›„ ํšŒ์˜๋ฅผ ํ†ตํ•ด ์ฃผ๊ธฐ์ ์ธ ํšŒ์˜ ์‹œ๊ฐ„์„ ์ •ํ•ด๋†“๊ณ , Slack (ํ˜‘์—… ๋ฉ”์‹ ์ €) ์•Œ๋ฆผ๋„ ํ•ญ์ƒ ์ผœ๋†“๊ธฐ๋กœ ํ–ˆ๋”๋‹ˆ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ์ผ์„ ํ†ตํ•ด ํŒ€์› ๊ฐ„์˜ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์ด ์–ผ๋งˆ๋‚˜ ์ค‘์š”ํ•œ์ง€ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ๋‹ค์Œ์—” ์ด๋Ÿฐ ์ผ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋„๋ก ๋ฐฉ์ง€ํ•ด์•ผ๊ฒ ๋‹ค๊ณ  ๋‹ค์งํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

2. ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ์˜ ๋ฌธ์ œ์  ํŒŒ์•…

์‚ฌ์‹ค ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๊นŒ์ง€๋Š” ์˜ค๋กœ์ง€ ๊ธฐ๋Šฅ์ด ์ž‘๋™ํ•˜๋Š” ๋ฐ์—๋งŒ ์˜์˜๋ฅผ ๋‘์–ด์„œ ๊ฐ€๋…์„ฑ์„ ๊ณ ๋ คํ•˜์ง€ ๋ชปํ•˜๊ณ  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋๋‚˜๊ณ  ์ œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋‹ˆ ํ•œ๋ˆˆ์— ๋“ค์–ด์˜ค์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ํ”„๋กœ์ ํŠธ๊ฐ€ ๋๋‚˜๊ณ  ํด๋ฆฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณต๋ถ€ํ–ˆ๊ณ  ์ ์  ๊ฐ€๋…์„ฑ๋„ ๊ณ ๋ คํ•˜๋ฉฐ ์ฝ”๋”ฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๊ฐ€๊ณ  ์žˆ๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€