오늘의 공부
1. 프로젝트 분리 및 연결
-
오늘 아침 결과물들을 어떻게 이어붙여서 디렉토리 구조를 분리/관리 할까에 대해 고민을 하고있었다..
-
그 때 팀원분들 중 한 분이 디렉토리 구조와 스타일을 정리해서 와주셨다!
(협업 유경험자 감사합니다 ㅠㅠ)
만세! 빨리 뜯어서 적용 시켜야지
뜬금 디렉토리 연결용 함수 정리
HTML
<!-- 디렉토리 구조 내의 css파일을 연결-->
<link rel="stylesheet" href="./css/style.css" />
<!-- 디렉토리 구조 내의 js파일을 연결-->
<script src="./js/editMode.js" type="module"></script>
JavaScript
//가져갈 값 지정해주기 (함수도 된다)
export {};
//값 가져오기
import {} from './firebase.js'
- 어제는 GitHub Page 로 빌드하는 것에 고집해서 Jekyll로 이어지게 하려고 했는데..
그냥 index.html에 합쳐져 나오게 만들면 되는 것 이었다..
2. 멤버 소개페이지 프로젝트 방명록 삭제 기능 구현 +@
-
삭제 기능은 그냥 html
<body>
쪽 들어가 remove()만 하면 되는거 아니야?
=> 라는 생각을 했던 때가 있엇죠.. -
사실 페이지만 본다면 틀린말은 아니지만.. 페이지에 댓글들을 저장하기위해 API연동을 시켰기에..
=> 댓글들을 삭제해도 API 서버에 남아있으면 다시 불러와 진다는 것이다! -
그렇게 찾아본 Firebase 함수 deleteDoc()..
deleteDoc(doc(db, "comments", doc.id))
- 어라..? doc의 id를 알아야 삭제가 되네..?
=> 그럼 doc id를 지정할 수 있게 adddoc()을 setdoc()으로 바꾸자!
// doc.id를 특정하기 위한 정보로 "날짜" 와 "작성자 이름" 을 썻다..
await setDoc(doc(db, "comments", name + today), innerDoc)
- 하지만 그렇게 만든 코드는 “같은 날짜”의 “같은 이름”을 쓰면 기록이 덮어진다는 오류를 범하게 된다는 걸 알게되어 팀원분들과 상의를 했다..
=> 그 때 팀원 중 한 분이 “작성된 시간”과 “이름”으로 삭제할 doc를 구별하는건 어떠냐고 조언을 해주셨다..
// comments 라이브러리의 값 가져오기 + orderBy로 정렬
let docs = await getDocs(
query(collection(db, 'comments'), orderBy('createdAt'))
);
// 값 읽어와서 객체에 데이터 저장하기
docs.forEach((docRef) => {
let row = docRef.data();
let name = row['nickName'];
let text = row['comment'];
let Date = row['date'];
let when = row['createdAt'];
//객체 생성
const li = document.createElement('li');
const div = document.createElement('div');
const h3 = document.createElement('h3');
const btn_del = document.createElement('button');
//버튼 name으로 style + 기능 묶기
btn_del.name = 'delete';
btn_del.type = 'button';
//댓글 구분용 데이터 "작성된 시간" 저장
h3.dataset.date = when.toDate();
//들어갈 값 정해주기
btn_del.textContent = '삭제';
h3.textContent = name;
//구조 묶어주기
div.append(h3);
li.append(div);
li.append(btn_del);
//Comment는 붙일 곳을 querySelector로 불러온 것이다.
Comment.prepend(li);
});
// "작성" 버튼 클릭 함수
$("#btn").click(async function () {
// 넣을 값 읽어오기 + 작성된 날짜 기록하기
let name = document.getElementById("ipName").value;
let text = document.getElementById("ipText").value;
let today = new Date().toLocaleDateString();
let now = new Date();
//올릴 값들을 정리하는 곳
const innerDoc = {
nickName: name,
comment: text,
date: today,
createdAt: now,
password: password,
};
//값 올리기
await addDoc(collection(db, "comments"), innerDoc)
});
// 삭제 버튼 클릭 함수
$(document).on("click", "button[name='delete']", async function () {
// 체크용 comments 라이브러리 값 새로 불러오기
let checkDocs = await getDocs(query(collection(db, "comments"), orderBy("createdAt")));
// 삭제 버튼을 누른 댓글에서 비교할 값 가져오기
let nameCheck = $(this).prev().find("h3").text();
// floor 및 0.001 은 날짜 값을 올렸을 때 뒷자리 3자리가 "내림" 당한 값과 비교하기 위함
let dateCheck = Math.floor(new Date($(this).parent().prev().find("h3").data('date')).getTime() * 0.001);
// 라이브러리 속 doc들 순회
checkDocs.forEach((docRef) => {
// 데이터 조리해서 가져오기
let row = docRef.data();
let name = row['nickName'];
let date = Math.floor(row['createdAt'].toDate() * 0.001);
// 이름과 작성된 시간을 비교하여 삭제할 댓글 찾기
if (name === nameCheck && date === dateCheck) {
//댓글을 firebase에서 삭제
deleteDoc(doc(db, "comments", docRef.id))
}
});
});
참고로 위 코드는 최대한 간략화 해서 구조만 보여주도록 리빌딩했다.
- 시행착오들을 간략히 설명하자면
-
데이터 값을 어떻게 요소에 저장시키냐
=> 요소에 dataset 을 이용해 data를 저장시킬 수 있었다! -
데이터 값인 new Date()가 타임스탬프 유형으로 들어가 어떻게 비교하냐
=> 이게 좀 오래걸렸지만 toDate()나 getTime()을 쓰고 뒷자리 3자리를 지웠다
=> 파일이 Firebase에 올라갔다 내려올 때 3자리까지 값이 “내림” 당하는 것 같다. - Firebase에 저장된 데이터들에 작성시간이 포함되어있는데 이를 이용해 정렬할 순 없나..?
=> Firebase 내장함수 query 와 orderBy를 이용했다. - 비밀번호를 입력해서 데이터를 삭제할 수 있는 권한이 부여되면 좋을 것 같다.
=> 값을 받아서 Firebase에 저장하고 위에 2번처럼 비교를 하였다.
(data는 직접 입력하는 값(prompt)과 Firebase에서 직접 가져오게(요소에 저장하면 해킹위험이 있을 것 같았다))
결과다! 뿌듯하다
(디자인은 팀원분이 만져주셧다 + 갓누리님이 디렉토리/스타일 구조 정리 해주신 분)
학습 과정 중 특이사항 / 삽질
- 오늘은 다행히 뻘짓보단 결과가 나오는 일들이 많았다!
관리자 모드 상호작용
발단
- 관리자 모드를 병합시킬 때 세션 스토리지를 사용해서 관리자인 상태를 저장해서 사용한다는 걸 알게 되었다.
=> 관리자 모드가 되면 댓글 삭제는 그냥 가능해야되는거 아냐?
(비밀번호 건너뛰기 기능)
전개
- 세션에서 값을 읽어오는 구문을 분석해서 사용했다.
// 세션에 로그인 상태 저장
sessionStorage.setItem('editMode', 'true');
// 세션 스토리지의 관리자 유무 가져오기
const editMode = sessionStorage.getItem('editMode')
checkDocs.forEach((docRef) => {
// 데이터 조리해서 가져오기
let row = docRef.data();
let name = row['nickName'];
let pswdCheck = row['password'];
// 위 설명대로 뒷자리 3자리 배제
let date = Math.floor(row['createdAt'].toDate() * 0.001);
// 이름과 작성된 날짜를 비교하여 삭제할 댓글 찾기
if (name === nameCheck && date === dateCheck) {
// 비밀번호 비어있는지 + 관리자 모드 확인
if (pswdCheck !== "" && pswdCheck !== undefined && editMode !== 'true') {
// 비밀번호 입력
let key = prompt('비밀번호를 입력해주세요.', '')
if (pswdCheck === key) {
alert('비밀번호 일치')
//댓글을 firebase에서 삭제
deleteDoc(doc(db, "comments", docRef.id))
//댓글을 화면에서 삭제
$(this).parent().parent().remove();
//확인
alert('성공적으로 삭제되었습니다!');
} else {
alert('잘못된 접근입니다.');
}
} else {
//댓글을 firebase에서 삭제
deleteDoc(doc(db, "comments", docRef.id))
//댓글을 화면에서 삭제
$(this).parent().parent().remove();
//확인
alert('성공적으로 삭제되었습니다!');
};
};
});
결말
- 의외로 금방 해냈다.. (비밀번호 설정하는게 더 귀찮았기에..)
멤버 소개페이지 프로젝트 회의
-
내일 있을 발표를 위해 발표자를 선정했다
(방법은 절대 사다리타기가 아닙니다..(아마도)) -
발표자료 예시를 보며 Canva 라는 사이트를 알게되어 거기서 자료를 만들게 되었다.
-
아직 병합되지 않은 기능들이 조금 남아있으나 거의 정리가 다 되서 다행이다!