Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2주차 기본/심화/공유 과제] 관리자 페이지 #3

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

KIMGEONHWI
Copy link
Member

@KIMGEONHWI KIMGEONHWI commented Oct 29, 2024

✨ 구현 기능 명세

💡 기본 과제

  • 바닐라 JavaScript 사용. (React 등 라이브러리 사용 X)
  1. 데이터

    • 초기 데이터는 데이터 파일을 별도로 생성해서 저장
    • 이 데이터를 불러와서 localStorage에 저장(이미 localStorage에 값이 있으면 안 불러옴).
    • localStorage 데이터를 이용해서 테이블을 렌더링(HTML에 데이터를 직접 넣는 하드코딩 x)
  2. 헤더

    • 왼쪽엔 아이콘 1개 (종류는 상관 x)
    • 가운데에는 타이틀(아무거나)
    • 오른쪽에는 긴 컨텐츠(텍스트, 아이콘 등 아무거나)
    • 좌측/우측 컨텐츠의 길이가 달라도 헤더가 정확히 3등분 되어 정렬되어야 함.
  3. 필터

    • 7개의 검색필터, 2개의 버튼으로 구성
    • 검색필터를 배치할때는 반드시 display: grid 속성 사용
    • 속성이 4줄에 각각 1개, 1개, 3개, 2개 배치 되어야 함(속성의 내용은 상관 x)
    • 필터링 할 값을 input에 입력
      (기본과제에서는 7개 모두 input으로 구현해도 괜찮음)
    • 7개의 속성 모두 필터링이 동작해야 함(포함하는 값으로 필터링)
    • (기본) 1번에 1개씩 입력하고 검색 필터 적용
    • 우측 상단에는 선택삭제, 추가 버튼이 위치
    • 상단 필터에서 필터링 된 값만 나타남
    • 반드시 HTML의 table 태그를 사용해서 구현
    • 체크박스 기능
    • 선택삭제 버튼 클릭 시, 체크된 항목들 삭제
    • 추가 버튼 클릭 시, 항목 추가 모달 등장
  4. 모달

    • 필터링, 테이블에 사용되는 7개의 항목을 입력 가능
    • 우측 상단에 모달 닫기 버튼
    • 하단에 추가 버튼 클릭 시, 모달 닫히면 데이터 추가
    • 1개라도 비어있는 상태로 추가 시, alert 창 띄워주기

🔥 심화 과제

  1. 필터

    • 필터에 dropdown을 1개 이상 사용
    • 초기화 버튼을 누르면 모든 필드가 비워짐
    • (심화) 여러 조건들을 모두 만족하도록(and) 검색 필터 적용
    • 한 개 이상의 열에는, 눌렀을 때 해당 칸의 값을 이용해서 링크 이동
    • 전체 체크박스 기능 (전체가 체크되면 맨위 체크박스도 자동으로 체크, 하나라도 해제되면 같이 해제)
  2. 모달

    • 백드롭(모달 주변 어두운 배경 부분) 클릭 시 모달 닫힘

공유과제

제목: Webpack & Babel

링크 첨부 : https://wave-web.tistory.com/60


❗️ 내가 새로 알게 된 점

삭제 로직에서 index를 기준으로 처리하게되면, 순차적으로 삭제를 하는 상황이면 괜찮은데 중간에 있는 데이터를 삭제하게 되는 경우 index가 꼬여서 원치 않는 데이터가 삭제되고 삭제하고 싶은 데이터는 그대로 남아있는 문제가 발생할 수 있다.
=> 각 데이터 객체에 고유한 ID. 즉, ID 값을 사용해 정확한 데이터를 삭제하는 방식으로 진행하여야한다.


❓ 구현 과정에서의 어려웠던/고민했던 부분

멤버 데이터 삭제후, 다른 멤버 추가로 삭제시 처음에 삭제했던 데이터가 다시 불러와지는 문제

export function deleteCheckedRows(data, tbody, renderTable) {
  const rowCheckboxes = tbody.querySelectorAll(
    'input[type="checkbox"]:checked'
  );

  // 체크된 행들의 ID 수집
  const idsToDelete = Array.from(rowCheckboxes).map((checkbox) => {
    return parseInt(checkbox.dataset.id, 10); // data-id 속성에서 ID 추출
  });

  // ID와 일치하는 데이터 삭제
  const updatedData = data.filter((item) => !idsToDelete.includes(item.id));

  // 로컬 스토리지 업데이트 및 테이블 재렌더링
  localStorage.setItem("infoData", JSON.stringify(updatedData));
  renderTable(updatedData, tbody);
}

기존 코드에서는 멤버를 삭제할 때는 updatedData로 필터링하여 렌더링하고 로컬 스토리지를 갱신하고 있는데, data 변수는 여전히 초기 상태를 참조하고 있기 때문에 이후 삭제 시 문제가 발생하고 있었다.

해결 방법

export function deleteCheckedRows(tbody, renderTable) {
  const rowCheckboxes = tbody.querySelectorAll(
    'input[type="checkbox"]:checked'
  );

  // 체크된 행들의 ID 수집
  const idsToDelete = Array.from(rowCheckboxes).map((checkbox) =>
    parseInt(checkbox.dataset.id, 10)
  );

  // 로컬 스토리지에서 최신 데이터 가져오기 (변수 이름을 변경)
  const latestData = JSON.parse(localStorage.getItem("infoData")) || [];

  // ID와 일치하는 데이터 삭제
  const updatedData = latestData.filter((item) => !idsToDelete.includes(item.id));

  // 로컬 스토리지 업데이트
  localStorage.setItem("infoData", JSON.stringify(updatedData));

  // 테이블 재렌더링
  renderTable(updatedData, tbody);
}
  • 삭제 후 항상 로컬 스토리지에서 최신 데이터를 가져오도록 수정.
  • data 변수를 삭제 후 최신 상태로 동기화

🥲 소요 시간

  • 12h

🖼️ 구현 결과물

스크린샷 2024-10-29 오후 3 34 07

https://living-headstand-8f1.notion.site/2-12e205f6a105800c95b6c196eb1f1605

@import url("https://fonts.googleapis.com/css2?family=Jua&display=swap");

* {
font-family: "Jua", sans-serif;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 폰트가 귀여워요 👍

} from "./modules/checkboxHandlers.js";
import { setupModalHandlers, closeModal } from "./modules/modalHandlers.js";
import { setupFormHandler } from "./modules/modalFormHandlers.js";
import { deleteCheckedRows } from "./modules/deleteHandler.js";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 저는 js를 하나의 파일에 다 작성했는데, 건휘님처럼 modules 폴더에 각각의 기능에 맞게 나누어 작성한 게 정말 좋은 것 같아요! 보기에도 훨씬 깔끔하고, 나중에 코드 유지 보수하기에도 더 편리할 것 같습니다.

}

const englishName = document.getElementById("englishName").value;
if (!englishRegex.test(englishName)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 영문이름과 깃허브에서 유효성 검사를 수행하는 섬세함이 돋보입니당

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그러게요 ! 유효성 검사까지 신경 쓰신 부분 .... 디테일하셔라 ......🫠🫠👍

Comment on lines +48 to +51
firstWeekGroup: parseInt(
document.getElementById("firstWeekGroup").value,
10
),
Copy link

@hansoojeongsj hansoojeongsj Oct 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: firstWeekGroup과 secondWeekGroup의 값을 parseInt를 사용하여 정수로 변환한 점이 인상적인 것 같아요. 사용자가 입력한 값을 안전하게 정수형으로 변환함으로써, 이후의 계산이나 비교에 문제가 발생하지 않도록 해주고 있는 거 겠죠..? 사람 수는 소수점으로 나올 수 없으니까, 세심하게 모든 부분을 고려하신 것 같아요 !!

Copy link

@maylh maylh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 ~ 건휘님 !

2주차 과제 너무 고생 많으셨습니다 🍀
폼의 유효성 검사까지 꼼꼼히 챙기신 부분이 인상 깊었고, every나 test 같이 다양한 메서드들을 잘 활용하셔서 많이 배우고 갑니다 !!

그리고 PR에 남겨주신 멤버 데이터 삭제후, 다른 멤버 추가 시 처음에 삭제했던 데이터가 다시 불러와지는 문제가 아직도 발생하고 있는 것 같습니다. 관련 로직 한번 더 체크해보시면 좋을 것 같습니다 😮
저도 코드를 보긴 했는데 이유를 모르겠습니다 ......... ㅎ.ㅎ

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모든 로직은 각 파일 내에서 담당하고, index.js에는 핸들러 함수를 불러와서 사용하는 식으로 하셨네요 !
가독성 측면에서 좋은 것 같습니다 👍

@@ -0,0 +1,18 @@
export function openModal(modal) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 코드에는 모달을 열 때 입력된 필드 값을 초기화하는 부분이 없는 것 같아요. 이 부분 때문에 멤버를 추가한 뒤 다시 모달을 열어서 다른 멤버 데이터를 추가하고자 할 때 이전에 입력했던 내용이 그대로 남아 있는 것 같아요 ..!

  1. openModal 함수 안에 모달 열기 전에 폼을 초기화하는 로직을 추가해주기
  2. 별도의 초기화 함수로 분리한 후 setupModalHandlers에서 모달을 열 때마다 호출되도록 하기

두 가지 방법으로 해당 이슈를 해결할 수 있을 것 같습니다 !

}

const englishName = document.getElementById("englishName").value;
if (!englishRegex.test(englishName)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그러게요 ! 유효성 검사까지 신경 쓰신 부분 .... 디테일하셔라 ......🫠🫠👍

if (event.target.type === "checkbox") {
const allChecked = Array.from(
tbody.querySelectorAll('input[type="checkbox"]')
).every((checkbox) => checkbox.checked);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 체크박스 로직이 과제에서 가장 어려운 부분이었는데요 ..
갯수 비교를 통해 전체 체크박스의 on off를 체크했는데 every 메서드를 사용할 수도 있었네요 ..!!

}

.btn-container button {
width: 49%;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

width를 49%로 지정해서 버튼 간의 갭을 주는 것 보다, width: 100%로 지정하고 flex-grow 속성을 준 뒤 gap을 직접적으로 지정하는 게 반응형에서 더 유연하게 반응할 것 같습니당 !

Comment on lines +18 to +19
display: grid;
grid-template-columns: 1fr 1fr 1fr;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 저는 display:flex;를 써서 했는데, grid-template-columns: 1fr 1fr 1fr;라고 설정하면 총 가용 공간이 3개의 열로 동일하게 나뉘어 각 열이 전체 공간의 1/3을 차지하게 되므로 gird로 주는 게 정확히 3등분 하는 데에 더 적합한 것 같네요 ! 배웠습니당

@@ -0,0 +1,22 @@
export function handleCheckAll(checkAll, tbody) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: 전체 선택 체크박스가 선택된 이후, 검색, 새멤버추가, 삭제를 해도 전체 선택 체크박스가 리셋이 되지 않고 있습니당..! 전체 선택 체크박스가 체크된 채로 남아있는데, 전체 체크박스가 false되는 방향으로 수정해주시면 좋을 것 같습니당
image

justify-content: center;
width: 8rem;
height: 3rem;
flex-shrink: 0;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 아직은 저에게 조금 낯선 스타일이라 건휘님 코드에서 보고 한 번 더 공부할 수 있었습니다 !!
여기서 이 스타일을 주신 이유가 있을까요..?

left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 소소한 궁금증이 있는데 어떨 때 px를 쓰고 어떨 때 rem을 쓰는지 알 수 있을까요? 지난주에는 reset.css에서 font-size를 62.5%로 설정하고 단위를 rem으로 통일해 달라고 하셨는데, 통일하다 보니 어느 정도의 단위까지 rem을 사용하는 게 좋을지 고민되더라고요. 저번 프로젝트에서는 어떤 방법으로 단위 사용을 통일하셨었는지 궁금합니당

@hansoojeongsj
Copy link

안녕하세요 건휘님!
멤버 데이터 삭제 후 다른 멤버를 추가로 삭제할 때 처음 삭제했던 데이터가 다시 불러와지는 문제에 대해, 문제 코드와 해결 방법을 잘 정리해주셔서 천천히 읽어 볼 수 있었습니다. 다만, 여전히 데이터가 다시 불러와지는 부분에서 문제가 발생하고 있어 이 점과 더불어 전체 선택 체크박스 초기화 부분만 다시 봐주시면 정말 좋을 것 같습니다!

그리고 건휘님이 JS 파일을 모듈로 나누어 관리하셔서 코드 가독성도 훨씬 좋고 파일 구조도 깔끔해진 것 같아요! 또, 저는 아직도 커밋 메시지를 고민하다가 적곤 하는데, 건휘님 커밋 메시지는 정말 알아보기 쉽게 쓰여 있는 것 같아서 OB의 노련함이 엿보입니다 !!ㅎㅎㅎ 금잔디 조장님이자 나리스 조장님, 앞으로도 많이 배우겠습니다! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants