(김유선) 중고거래 사이트를 SPA로 만들기 8일차 - 로그인 후 기능

2024. 4. 16. 17:47프로젝트 일지

우선 편의를 위해 간단하게 로그인하기 전의 기능들부터 해결한다.

 

로그인 전 버튼들 기능 만들기

번개장터도 그렇지만, 보통은 로그인하지 않았을 때 판매하기, 내상점 등이 보이는데, 이 버튼을 누르게 되면

이렇게 로그인창이 뜬다.

즉, 로그인을 하기 전에는 판매하기, 내상점, 로그인/회원가입 버튼이 모두 동일한 기능이라는 것이다.

(사실 이 사실을 미리 알고 있긴 했는데 어떻게 짜야할지 몰라서 일단 만들어뒀다가 지금 수정한다.)

어차피 로그인을 안했을 땐 다 같은 기능이기 때문에 지금 이 가짜 버튼들을 만들어주겠다. 

그래서 모든 버튼의 코드를 이렇게 짰다.

<% if(firstdata.user==undefined){ %> // (1) 유저가 처음 로그인을 하지 않은 상태일 때
        <div class="chatroombtn_fake loginbtn">채팅</div>
        <div class="loginbtn">로그인 / 회원가입</div>
       <div class="myshopbtn_fake loginbtn ">내 상점</div>
        <div class="insertbtn_fake loginbtn ">내 물건 팔기</div>
<% } %>
 
<div class="chatroombtn hide">채팅</div>
<div class="logoutbtn hide ">로그아웃</div>
<div class="myshopbtn hide">내 상점</div>
<div class="insertbtn hide">내 물건 팔기</div>  // (2) 유저가 로그인하기 전에는 없다가 로그인하는 순간 block
 
<% if(firstdata.user!=undefined){ %> // (1) 유저가 처음 로그인을 한 상태일 때
         <div class="chatroombtn">채팅</div>
         <div class="logoutbtn">로그아웃</div>
          <div class="myshopbtn">내 상점</div>
          <div class="insertbtn">내 물건 팔기</div>
<% } %>

(1)번 => 유저가 처음 페이지를 들어왔을 때를 위해.

(2)번 => 유저가 로그인을 해서 변화가 일어났을 때를 위해(안 보이게 숨겨뒀다가 로그인하면 보이게 함, 제 기능도 해야 함)

 

(2)번의 이유는 처음 사이트에 접속했을 때, 로그인을 하면 기능이 동작하지 않던 버튼이 바로 동작할 수 있게 바꿔야 하는데, 유저가 존재하는지에 따라 바꾸기 위해서는 로그인 후 서버를 다시 돌려야 한다. 그렇지 않으면 로그인을 해도 처음 받은 데이터가 유지되기 때문에 버튼의 기능이 남아있지 않는다. 근데 나는 서버를 아끼고 싶으므로 제 기능을 하는 버튼을 따로 만들어서 숨겨뒀다가 로그인이 되면 display=block 처리를 했다. 만약 새로고침이 된다면, display= block처리 된 아이들은 다시 display= none이 되기 때문에 아주 완벽하다.

$('#login_submit').click(function(){ // 로그인 버튼을 눌렀을 때
            if($('#login_id').val()!='' && $('#login_pw').val()!=''){ // 둘다 공백이 아니면
                $.post('/login',{ // login으로 post 요청 보냄
                    username : $('#login_id').val(),
                    password : $('#login_pw').val()
                })
                .done(function(data){
                    alert(data) // 위 코드에서 응답한 json 데이터를 알림창으로 보내줌
                    $('.login_bg').css('display','none')
                    $('.login_container').css('display','none')
                    if(data=='나다장터에 오신 걸 환영합니다.'){ // 로그인되면 바로 변할 것 !!!!!!!!!!!!!!
                        $('.loginbtn').css('display','none')
                        $('.hide').css('display','block')
                    }
                })
            }
            else{alert('아이디 혹은 비밀번호를 입력하지 않았습니다.')} // 둘 중 하나라도 공백이면 이거 띄워줌
        })

요 코드를 통해 로그인하면 데이터를 받아서 로그인되면 바로 변할 것 !!!!!!!!!!!!!! < 요 코드 안에 js 코드를 통해 바로 변화가 보이도록 했었다.

 

그래서 위의 1번 2번이 둘다 존재하는 것이다.

 

로그인 후 변화해야 하는 것 (2)

1. 로그인/회원가입 버튼이 로그아웃 버튼으로 바뀔 것 <= 1번을 끝냈다.

2. 내 물건 팔기 버튼이 동작할 것   => '내물건팔기'에 필요한 데이터는 내 아이디이고, post 요청을 받아서 올린 사진과 제목 내용 등을 받아야 한다. 

3. 채팅 기능이 동작할 것 => '채팅'에 필요한 데이터는 내 정보, 주고받은 채팅 내용

4. 찜 버튼이 동작할 것 => '찜'에 필요한 데이터는 내 정보, 물건 정보

5. 내 상점 버튼이 동작할 것 => '내상점'에 필요한 데이터는 내 정보, 내가 올린 물건들, 내가 찜한 물건들

 

지금까지 1번을 끝냈고 이제 2번을 해야 한다.

 

현재 개인 프로젝트가 끝나기 3일 전이므로, 급한 불부터 끄기 위해 디자인은 대충 하는 걸로 하고, 2번 기능을 구현해보겠다. 

 

우선 내 물건 팔기 버튼을 누르면 글을 올릴 수 있는 창이 뜨도록 했다.

 

클라이언트쪽 코드(html)

<div class="insert_bg">
        <div class="insert_container">
            <div class="insert_close"></div>
            <img class="login_img" src="./img/logo.png" alt="">
            <p>간편하게 판매하세요</p>
            <form action="post">
                <input class="id" id="insert_title" type="text" maxlength="10" minlength="1"  placeholder="제목을 작성하세요">
                <input class="pw" id="insert_text" type="text" maxlength="50" minlength="1" placeholder="내용을 작성하세요">
                <input id="insert_img" type="file">
                <input class="submit" id="insert_submit" type="submit" value="올리기">
            </form>
        </div>
    </div>

 

클라이언트 쪽 코드(자바스크립트)

$('.insertbtn').click(function(){ // 물건 올리기 버튼 누르면
            $('.insert_bg').css('display','block')
        })

        $('.insert_close').click(function(){ // 물건 올리기 x 누르면
            $('.insert_bg').css('display','none')
        })

        $('#insert_submit').click(function(){ // 물건 제출 버튼 누르면
            if($('#insert_title').val()!='' && $('#insert_text').val()!=''){ // 둘다 공백이 아니면
                $.post('/insert',{ // insert로 post 요청 보냄
                    title : $('#insert_title').val(),
                    text : $('#insert_text').val(),
                    img : $('#insert_img') // img는 수정해야 함
                })
                .done(function(data){
                    alert('올림')
                    $('.insert_bg').css('display','none')
                })
                .fail(function(){
                    alert('못 올림')
                })
            }
            else{alert('아이디 혹은 비밀번호를 입력하지 않았습니다.')} // 둘 중 하나라도 공백이면 이거 띄워줌
        })

 

서버쪽 코드

app.post('/insert',async(요청,응답)=>{
  await db.collection('products').insertOne({
    user : 요청.user._id,
    title : 요청.body.title,
    text : 요청.body.text,
    img : 요청.body.img <=== 이건 사실 틀렸음, aws를 사용해야 하는데 그거 까먹음
  })
})

 

이렇게 대충 모양은 잡았고(디자인은 나중에 할 거임)

 

이미지 같은 경우엔 하드디스크에 저장해놓고 꺼낼 수도 있긴 하지만 클라우드에 올리다보면 하드디스크 사용이 어려울 수 있기 때문에 s3를 사용할 것이다. 그리고 서버로 이미지를 보내서 s3에 저장하는 걸 multer라는 라이브러리도 사용해서 구현하겠다.

 

< 짧게 관련 단어 정리 >

aws = 아마존 웹 서비스 (파일 저장용 클라우드 서비스)

s3 = aws에서 제공하는 하나의 서비스

iam = aws 엑세스 관리, 관리자 같은 거 만드는 곳 (몽고디비의 user 포럼 같다) 

arn = 몽고디비에서의 _id 같은 것, 포럼에도 있고 사용자에게도 있다.

 

 

근데 사실 사진을 post하는 건 csr 방법으로 하기 너무 힘들 것 같아서 시간 관계상 요 기능은 ssr로 만들기로 했다. 내일 코드를 작성할 것이다.

 

로그인 후 변화해야 하는 것(3)

3. 채팅 기능이 동작할 것 => '채팅'에 필요한 데이터는 내 정보, 주고받은 채팅 내용

 

<소켓 통신 배우고 할 것임 ㅜㅜ>

 

로그인 후 변화해야 하는 것(4)

4. 찜 버튼이 동작할 것 => '찜'에 필요한 데이터는 내 정보, 물건 정보

 

클라이언트 코드(html)

<div class="products">
            <% if(firstdata.user==undefined){ %>
                <% firstdata.products.forEach(function(a,i){ %>
                    <div class="product_container nouser">
                        <img class="product_img" src=<%=firstdata.products[i].img%>>
                        <p class="product_title"><%=firstdata.products[i].title%></p>
                        <div class="product_boxing">
                            <p class="product_price"><%=firstdata.products[i].price%></p>
                            <img class="heart_fake loginbtn" src="./img/heart-empty.png" alt="">
                        </div>
                    </div>
                <% }) %>
            <% } %>

            <% firstdata.products.forEach(function(a,i){ %>
                <div class="product_container hide">
                    <img class="product_img" src=<%=firstdata.products[i].img%>>
                    <p class="product_title"><%=firstdata.products[i].title%></p>
                    <div class="product_boxing">
                        <p class="product_price"><%=firstdata.products[i].price%></p>
                        <img class="heart" src="./img/heart-empty.png" alt="">
                    </div>
                </div>
            <% }) %>

            <% if(firstdata.user!=undefined){ %>
                <% firstdata.products.forEach(function(a,i){ %>
                    <div class="product_container">
                        <img class="product_img" src=<%=firstdata.products[i].img%>>
                        <p class="product_title"><%=firstdata.products[i].title%></p>
                        <div class="product_boxing">
                            <p class="product_price"><%=firstdata.products[i].price%></p>
                            <img class="heart" src="./img/heart-empty.png" alt="">
                        </div>
                    </div>
                <% }) %>
            <% } %>
        </div>

 

클라이언트 코드(js)

$('#login_submit').click(function(){ // 로그인 버튼을 눌렀을 때
            if($('#login_id').val()!='' && $('#login_pw').val()!=''){ // 둘다 공백이 아니면
                $.post('/login',{ // login으로 post 요청 보냄
                    username : $('#login_id').val(),
                    password : $('#login_pw').val()
                })
                .done(function(data){
                    alert(data) // 위 코드에서 응답한 json 데이터를 알림창으로 보내줌
                    $('.login_bg').css('display','none')
                    $('.login_container').css('display','none')
                    if(data=='나다장터에 오신 걸 환영합니다.'){ // 로그인되면 바로 변할 것!!!!!
                        $('.nouser').css('display','none')
                        $('.hide').css('display','block')
                    }
                })
            }
            else{alert('아이디 혹은 비밀번호를 입력하지 않았습니다.')} // 둘 중 하나라도 공백이면 이거 띄워줌
        })

 

다른 버튼과 마찬가지로 찜 버튼도 로그인 안했을 때 보일 fake, 로그인하면 바로 보이게 할 hide, 로그인한 상태면 보일 heart버튼을 만들어줬다. 

그리고 nouser라는 걸 추가해줘서 로그인했을 때  $('.loginbtn').css('display','none'했던 것을 삭제하고 로그인 안했을 때만 보이는 것들에 nouser를 추가해줬다.

<% if(firstdata.user==undefined){ %>
                <div class="chatroombtn_fake loginbtn nouser">채팅</div>
                <div class="loginbtn nouser">로그인 / 회원가입</div>
                <div class="myshopbtn_fake loginbtn nouser">내 상점</div>
                <div class="insertbtn_fake loginbtn nouser">내 물건 팔기</div>
            <% } %>

요렇게 nouser를 추가해줬다.

$('.heart').click(function(){ // 하트 버튼 누르면
            alert('기능 동작')
        })

그리고 검사용 코드 한번 작성해줌

로그인 안한 상태에서 하트를 누르면 이렇게 로그인 창이 뜨고,

 

로그인 했을 때 하트 누르면 이렇게 된다.

 

그럼 이제 하트를 누르면 누른 유저 정보, 눌린 물건 정보를 가져와서 heart 컬렉션에 유저 _id, 물건 _id 값을 사용해서 다음과 같은 document 하나를 insert한다. (forum > collection > document)

{

_id : 자동생성

user_id : 

product_id : 

}

만약에 하트를 취소하게 된다면 product_id와 사용자의 아이디가 있는 문서 하나를 delete 하면 된다. 

 

< 서버에서 지켜야 할 것 >

1. user_id와 product_id 모두가 동일한 것을 이미 인서트한 기록이 있다면 insert가 아니라 delete를 한다.

( db에 넣기 전에 먼저 데이터가 있는지 확인하고, 있으면 delete, 없으면 insert를 하면 되겠다)

 

< 클라이언트에서 지켜야 할 것 >

1. 인서트를 했다면 하트가 채워진 상태로 보여야 한다.

2. 채워진 하트를 한번 더 누르면 하트가 취소되어야 한다.

 

그리고 이 모든 것은 새로고침해도 똑같이 유지가 되어야 한다.

그러니 처음 데이터를 뿌릴 때, 찜을 했는지가 반영이 되어서 뿌려져야 한다.

 

<순서>

1. 사이트에 접속하면 요청.유저의 아이디를 따와서, 하트 컬렉션에서 요청.유저가 있는 도큐먼트들을 찾아낸다.

2. 찾은 도큐먼트의 product_id를 통해서 products 컬렉션의 _id가 일치하는 것들의 데이터 하트를 채워준다.

3. 이벤트리스너로 즉석에서 클릭을 하면 하트가 채워졌다 비었다 하는 걸 보여준다(동시에 서버에 한번씩 왔다갔다 하면서 데이터 하트가 비었으면 채워주고 차있으면 비워준다).

 

 

 

<이거 시간 남으면 할랭>

 

로그인 후 변화해야 하는 것(5)

5. 내 상점 버튼이 동작할 것 => '내상점'에 필요한 데이터는 내 정보, 내가 올린 물건들, 내가 찜한 물건들

 

<이건 마지막에 하는 게 편할 듯>

 

오늘의 감상 : 코드를 짜면서 생각했는데, 난 아직 처음부터 모든 것을 기획할 능력은 없는 것 같다. 처음에 기획을 하려고 하면 뭘 기획해야 할지 잘 모르겠는데 직접 디자인하고 눈으로 보면서 만들어가야 이런 저런 걸 '고쳐야'겠다는 생각이 든다. 그래서 이렇게 직접 코드를 짜고 분석하다보면 점점 살이 붙어간다. 근데 결국 완성도 높게 만드는 내가 대단하다고 느낀다. ㅎㅎ 이렇게 여러번 하면서 점점 깨닫다보면 나중엔 처음 기획 한번만으로 줄줄이 만들 수 있는 날이 오지 않을까?

 

오늘 하루 알게 된 작은 꿀팁 :

<form>
            <input id="register_id" type="text">
            <input id="register_pw" type="password">
            <input id="register_submit" type="submit">
</form>

html을 이렇게 작성하고(인풋을 form태그로 감싸고)

ajax로 #register_submit를 click하면 post 요청이 가게 작성했을 때, 

#register_pw를 작성하고 엔터를 쳐도 post 요청이 들어간다.

근데 form 태그를 지워버린다면 엔터로는 post 요청이 안 가고  #register_submit를 직접 클릭해줘야 post 요청이 들어간다.

엔터를 쳐서 넘어가게 하고 싶다면 form 태그 쓰는 게 꿀팁!!