갑자기 냅!다 도착하자마자 각자 주제를 정해서 3일만에 웹서비스를 만들라고 한 미니 프로젝트.... 솔직히 진짜 안될 줄 알았는데 의외로 쓸만한 정도로 나왔다.
우리 팀이 정한 주제는 팀플을 위한 스케줄링 앱.
각자가 되는 시간을 입력하면 그 중 가장 많은 사람이 되는 시간을 알려주는 서비스이다.
맨날 리액트만 하고 바닐라 자바스크립트는 제대로 안 한지 일년 가까이 됐더니 우왕좌왕 틀리는 게 많았다. 거기다 웹개발을 한번도 안 해본 팀원들과 팀이 되어서 어쩌다보니 프로 디버거가 되어버렸다... 그래봤자 몇개월 안한 주제에 잘한다고 하기 좀 웃기긴 하지만 그래도 일년 가량을 헛으로 보낸건 아닌것 같아서 좀 뿌듯했다.
간단한 폼 하나에 이렇게 헤맬 줄이야...
처음에 일정 예약에 날짜와 시간 표시를 위해 HTML input
태그의 dateTime-local
속성을 사용했다. 그런데 우리는 한 시간 단위로 일정을 넣고 싶었기 때문에 분 단위는 필요가 없었는데 dataTime-local
에 초는 생략할 수 있지만 분은 생략할 수 없었다. 어쩔 수 없이 input
태그의 date
와 time
으로 따로 나눴다.
그리고는 시작 시간을 선택하고 나면 종료 시간 선택지에서 시작 시간보다 이른 것들은 선택할 수 없도록 disabled
했다. 시간 추가하기 버튼을 누를 때 마다 실행되는 makeTimeLimit
함수 내부에서 추가되는 시간행(사진의 회색 박스 하나!)의 startTime
에 대한 select
태그에 change
이벤트가 발생할 때마다 실행되도록 eventHandler
를 붙였다. startTime
이 바뀌면 같은 넘버를 아이디로 가진 endTime
select
를 가져와서 내부의 option
을 돌면서 startTime
보다 작은 시간은 disable
하도록 짰다. 이 부분은 당시에도 그랬고 지금 쓰면서도 드는 생각이지만 별로 효율적인 코드는 아닌 것 같다. 이왕이면 삭제버튼까지 같이 이벤트 위임을 사용해서 구현하려고 했는데 시간이 없기도 했고, select
태그는 change
이벤트이고 button
태그는 click
이벤트인데 찾아봐도 다른 이벤트끼리는 위임이 안 되는 것 같아 포기했다.
얼추 구현하고 나니 처음 페이지가 로딩되자마자 있는 시간 1과 시간 추가하기 버튼을 눌러 추가되는 시간들의 구현이 중복으로 되어 있다는 걸 깨달았다. 이 중복 구현을 없애기 위해서 처음 페이지 진입하자마자 addTime
함수가 실행되도록 하고 이전 번호가 있으면 추가되는 시간의 넘버를 +1로, 아니면 1로 되게 했다.
그리고 또 한가지 문제가 있었는데, 시작 시간을 먼저 고르고 종료 시간을 고르면 시작 시간 < 종료 시간인 건 맞지만 종료시간 먼저 고른 후에 시작 시간을 고르면 change
이벤트가 발생해 불가능한 종료 시간을 선택하는걸 막아주긴 하지만 이미 선택 된걸 없애주지는 않아서 비정상적인 시간 등록이 가능했다. 이건 기술적으로 해결할 방법은 잘 모르겠어서 비정상적인 시간이 제출되면 사용자에게 alert하고 제출이 되지 않도록만 막았다.
확인 버튼을 만드는 데도 좀 헤맸는데, form
태그 안에는 시간 관련한 input
들만 넣고 싶어서 확인 버튼을 밖으로 뺐더니 제출이 제대로 되지 않았다.
결론은 submit
버튼은 form
태그 내부에 있는 것이 최적의 구조이며, 굳이 밖으로 빼야 한다면 id
값으로 어떤 폼에 대한 버튼인지를 지정해주면 되는 거였다.
<form id="timeForm" onSubmit="submitHandler(event)">
...
</form>
<button type="submit" form="timeForm">확인</button>
그리고 HTML에 바로 단 onSubmit
핸들러에서 preventDefault
를 하려면 e
가 아니라 event
로 이벤트 객체를 받아야만 동작이 가능하다.
난 ajax보다 axios가 좋아!
ajax에서 데이터 전송을 객체 배열 형태([{startTime: Date객체, endTime:Date객체}]
)로 넘겨줬더니 request.form[key]
로 안 받아졌다. 내가 보낸게 객체의 배열이라 안되는건가 싶어서 json.stringify
하고 헤더에도 contentType:json
을 추가해도 failed to decode json object: expecting value: line 1 column 1 (char 0)
이라는 에러 메시지만 떴다.
이것 저것 스택오버플로우에서 하라는거 다 해도 안됐는데 request.form
을 통채로 출력해봤더니 immutableMultiDict
라는게 담겨있는거다?? immutable... 못바꾸는... dict... 딕셔너리....?!?!? 결국은 dict
라는게 맞아서 request.form.to_dict()
하니까 보낸 대로 잘 받아졌다ㅋ..
영국에 살았으면 표준시 그대로 쓸 수 있는 건데!
Date
객체를 쓸 때 넣는 형식에 따라 UTC인지 KST인지 다르다는걸 이제서야 알았다. 출력할 때도 ISO 기준과 한국 표준시 중에 골라서 출력할 수 있다. 그치만 YYYY-MM-DD
형식으로 출력하는 메서드는 없기 때문에 개인적으로 함수를 만들어야 한다. 제일 흔한 형식 아닌가? ECMA야 만들어줘라!
간단한 폼 post
에서도 이렇게 헤멜 줄이야!!
일정을 처음 등록할 때는 괜찮은데, 두번째부터는 등록하면 이전에 등록했던 내용에 덮어씌워져서 이전 일정이 보이지 않는 문제가 있었다. 코드를 따라 올라가다 보니 update_one
으로 [{start, end}]
형식의 새로운 배열을 업데이트했는데, 이게 기존 유저 정보의 available_time
필드에 추가되는게 아니라 대체되기 때문에 기존의 정보가 사라지는 거였다.
해결책은 뭐, 이미 데이터가 있으면 합쳐서 보내는 거였다.
api에서 db에 저장할 때(post) db에서 찾아온 유저 정보에 이미 available_time
필드가 있다면 추가할 데이터 배열에 extend
로 합쳤다.
그런데 여기 또 문제는, 리스트는 중복을 허용하기 때문에 같은 날 같은 시간에 한 사람의 일정이 여러번 추가될 수 있다는 거였다. html에 뿌리는 쪽에서 필터해도 되지만, 근본적인 해결책은 db에 저장하는 쪽이어야 한다고 생각해서 앞에서 extend
한 배열을 set
으로 바꿔서 중복을 제거한 다음에 다시 list
로 바꿔서 update 했다.
사실 말로는 간단하지만 이 6줄짜리 코드 고치는데 몇시간 걸렸다..... 진짜 너무 안돼서 울 뻔함ㅎ 뭐 다른 디버깅 방법이 있는지 모르겠지만 내가 한 방식으로는 플라스크는 안 된다고 에러도 안나고 그냥 그 뒷 블록이 씹히는게 끝이라서 어디서 에러난건지도 모르겠는 총체적 난국이었다. 결국 한줄 한줄 print
해서 안되는 부분 찾았는데 api 쪽에서 timeData
와 userinfo['available_time']
이 둘 다 딕셔너리에 string
으로 저장돼있던 게 문제였다. timeData
는 json.loads
로 변환하니까 됐는데 available_time
은 안돼서 list(eval())
로 바꿨다. 왜 안되는지는 아직도 모르겠음.....ㅎ
엥 전 이런 사진 올린 적 없는데요;;
이건 내 파트는 아니었지만, 막판에 배포 다 했는데 버그나서 다 같이 멘붕왔던 이슈가 있었다. 프로필 사진을 첨부하지 않고 회원가입하면 이전에 등록했던 이미지가 들어갔다. 그것도 무슨 db에서의 마지막 이미지도 아니고 각자 등록했던 마지막 이미지가... 신박한 버그였음
원인은 이미지 업로드 할 때 파일 이름을 img 폴더 안 갯수+1
로 적어서 올렸었는데 그 폴더 안에 기본 프로필을 위한 defualt.jpg
를 같이 넣어놨더니 개수가 하나 더 세진거였다.