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 17 commits into
base: main
Choose a base branch
from

Conversation

seong-hui
Copy link
Contributor

@seong-hui seong-hui commented Oct 28, 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. 모달

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

공유과제

제목: 함수형 프로그래밍 찍먹

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


❗️ 내가 새로 알게 된 점

  • 테이블을 렌더링 하는 함수의 매개변수를 data = getMemberData()로 하여 renderTable함수가 호출될 떄 data인자가 제공되지 않을 시 getMemberData()함수를 호출하여 data에 할당하는 방식으로 구현하여 호출인지가 없더라도 기본값으로 잘 동작되도록 하였습니다.
  • document.addEventListener("DOMContentLoaded", () => renderTable()); 는 이벤트 발생 시점에 renderTable이 실행되지만 document.addEventListener("DOMContentLoaded", renderTable());은 이벤트 발생과 상관없이 renderTable이 바로 실행된다는 점을 알게되었습니다. 해당 결과가 다른 이유는 함수 호출 방식과 함수 참조의 차이 때문입니다. () => renderTable()는 화살표 함수이기 때문에 이벤트가 발생할 때 화살표 함수가 실행되고 그 안의 함수가 실행되지만, 후자의 코드는 바로 renderTable()을 호출하는 코드이기 때문에 바로 실행됩니다.

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

  • ~ 부분이 잘 구현한건지 잘 모르겠어요!
  • 기능별로 js파일을 어디까지 분리해야하나에 대해서 고민하였습니다.

🥲 소요 시간

  • 7h

🖼️ 구현 결과물

https://devveb.notion.site/2-12dd9673c22b80ff8fe7c8319aba0585
image

@seong-hui seong-hui self-assigned this Oct 28, 2024
Copy link
Member

@m2na7 m2na7 left a comment

Choose a reason for hiding this comment

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

안녕하세요! 2주차 과제 고생 많으셨습니다 !

전체적으로 정말 깔끔하게 구현 잘 하셨다고 생각해요.
함수별로 기능을 적절하게 잘 나누고, js 파일로 분리한게 인상깊네요 👍👍
공유해주신 아티클도 잘 봤습니다 ! ! !

Comment on lines +5 to +8
const checkEmpty = (fields) => {
return fields.some((field) => field.trim() === "");
};

Copy link
Member

Choose a reason for hiding this comment

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

checkEmpty 까지 따로 분리한게 인상적이네요 👍👍
덕분에 addMember 함수의 역할이 더욱 명확해진 것 같아요 !

Comment on lines +34 to +35
id: Date.now(),
name,
Copy link
Member

Choose a reason for hiding this comment

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

id를 Date.now()로 설정할 생각은 못했네요 대박입니다.
이번 과제서는 id가 충돌할 일이 없으니 좋은 방식인 것 같아요 👍

import { getMemberData, setMemberData } from "./dataUtils.js";

const checkEmpty = (fields) => {
return fields.some((field) => field.trim() === "");
Copy link
Member

Choose a reason for hiding this comment

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

some() 내장함수의 활용 까지 정말 좋네요 👍

Comment on lines +4 to +18
const deleteSelectedRows = () => {
let memberData = getMemberData();

const checkboxes = document.querySelectorAll(".deleteCheckbox:checked");
const idsToDelete = Array.from(checkboxes).map((checkbox) => {
const row = checkbox.closest("tr");
return parseInt(row.getAttribute("memberId"), 10);
});

memberData = memberData.filter((member) => !idsToDelete.includes(member.id));
localStorage.setItem("membersData", JSON.stringify(memberData));

setMemberData(memberData);
renderTable();
};
Copy link
Member

Choose a reason for hiding this comment

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

멤버를 삭제하는 함수, 체크된 체크박스에서 삭제할 id를 가져오는 함수
두 가지로 분리해도 좋아보여요 !

Comment on lines +1 to +7
export const getMemberData = () => {
return JSON.parse(localStorage.getItem("membersData")) || [];
};

export const setMemberData = (data) => {
localStorage.setItem("membersData", JSON.stringify(data));
};
Copy link
Member

Choose a reason for hiding this comment

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

자주 사용되는 부분을 유틸 함수로 분리한게 인상깊네요 👍

Comment on lines +123 to +124
<span class="closeModalBtn">&times;</span>
<div class="modalTitle">새 멤버 추가</div>
Copy link
Member

Choose a reason for hiding this comment

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

HTML 엔티티 사용까지 디테일 대단합니다 ,, 👍
사실 뭔지 몰라서 찾아봤습니다. ㅎ

Comment on lines +122 to +174
<div class="addModal">
<span class="closeModalBtn">&times;</span>
<div class="modalTitle">새 멤버 추가</div>
<form class="modalForm">
<div class="modalLable">이름</div>
<input
type="text"
class="modalName"
placeholder="이름을 입력하세요."
/>
<div class="modalLable">영문 이름</div>
<input
type="text"
class="modalEngName"
placeholder="영문이름을 입력하세요."
/>
<div class="modalLable">GitHub</div>
<input
type="text"
class="modalGit"
placeholder="GitHub ID를 입력하세요."
/>
<div class="modalLable">성별</div>
<select class="modalGender">
<option disabled hidden selected>성별 선택</option>
<option value="male">남자</option>
<option value="female">여자</option>
</select>
<div class="modalLable">역할</div>
<select class="modalRole">
<option disabled hidden selected>YB / OB 선택</option>
<option value="YB">YB</option>
<option value="OB">OB</option>
</select>
<div class="modalLable">1주차 금잔디조</div>
<input
type="number"
placeholder="1주차 금잔디조 (1~9)를 입력하세요"
min="1"
max="9"
class="modalWeek1"
/>
<div class="modalLable">2주차 금잔디조</div>
<input
type="number"
placeholder="2주차 금잔디조 (1~9)를 입력하세요."
min="1"
max="9"
class="modalWeek2"
/>
<button type="submit" class="modalSubmitBtn">추가</button>
</form>
</div>
Copy link
Member

Choose a reason for hiding this comment

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

모달을 dialog가 아닌 div태그로 구현한 이유가 있나요? 궁금합니다 !

Comment on lines +7 to +10
<script
src="https://kit.fontawesome.com/c9218056bf.js"
crossorigin="anonymous"
></script>
Copy link
Member

Choose a reason for hiding this comment

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

해당 script 태그만 head안에 구현한 이유가 있나요 ?

Comment on lines +11 to +12
height: 80px;
padding: 0 20px;
Copy link
Member

Choose a reason for hiding this comment

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

css파일 전부 rem이 아닌 px로 작성하셨는데 이유가 있나요?
px과 rem에 대한 성희님의 의견이 궁금합니다 !

Copy link

@Leeyoonji23 Leeyoonji23 left a comment

Choose a reason for hiding this comment

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

js에 대해서 정말 많이 배우고 갑니다! 아예 모르고 있었던 함수들도 많고 전체적으로 코드가 명확하고 간결해서 보기 너무 편했습니다👍기능별로 정리하신 것도 배우고 갑니다!

z-index: 2;
background-color: burlywood;
display: grid;
grid-template-columns: repeat(3, 1fr);

Choose a reason for hiding this comment

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

오 repeat 함수로 열의 개수랑 각 열의 너비를 반복해서 설정하는 방법 배우고 갑니다!

Comment on lines +22 to +35
.leftHeader {
display: flex;
justify-content: flex-start;
}

.centerHeader {
display: flex;
justify-content: center;
}

.rightHeader {
display: flex;
justify-content: flex-end;
}

Choose a reason for hiding this comment

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

오... 헤더 3등분을 이렇게 left right center 로 나눠서 justify-content 로 정렬해주는 방법이 있었군요...! 눈에 잘 보여서 좋은 것 같아요!

import { getMemberData, setMemberData } from "./dataUtils.js";

const checkEmpty = (fields) => {
return fields.some((field) => field.trim() === "");

Choose a reason for hiding this comment

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

오 some 이라는 내장함수가 있다는 것을 배웠어요. 배열 내에 빈 문자열 또는 공백만 있는 값이 포함되어 있는지 간단히 검사하는 것에 좋겠네요!

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

Successfully merging this pull request may close these issues.

3 participants