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

KDT0_ParkSungHoo 아즈카반 죄수 관리 시스템 #45

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

Conversation

HOOOO98
Copy link

@HOOOO98 HOOOO98 commented Aug 18, 2023

          🪄AZKABAN🦉

👇서비스 링크👇

AZKABAN

ID : aaa

PW : bbb

(전체화면은 F11키를 누르시면 됩니다.)



👻아즈카반

아즈카반은 해리포터 시리즈에서 등장한 마법사들의 감옥으로 영국 북해 어딘가에 있다고 전해집니다.

아즈카반은 원래부터 감옥은 아니었고, 오래전에 어둠의 마법사인 에크리즈디스가 살던 탑입니다.

그를 디멘터라는 종족이 따르게 되면서 아즈카반은 디멘터로 가득 차게 됩니다.

그리고 그가 죽고 난 후 감옥으로 사용하게 된 지금까지도 디멘터가 간수로서 죄수를 괴롭히고 있습니다.



⚙️사용한 스택



Static Badge
Static BadgeStatic Badge



👤유저플로우

유저플로우

로그인

정해진 ID와 PW로만 로그인 가능합니다.

이후에 DB를 이용해 로그인을 구현해보겠습니다.

로그인

검색

이름으로 검색을 할 수 있습니다.

검색

  • search.js
function handleInputChange() {
    const searchPrisonerInput = document.querySelector('.searchPrisoner');
    const searchText = searchPrisonerInput.value.toLowerCase().trim();
    
    const prisonCells = document.querySelectorAll('.prisonCell');
    
    prisonCells.forEach(cell => {
        const cellId = cell.id.toLowerCase();
        
        if (cellId.includes(searchText)) {
            cell.style.display = 'flex';
        } else {
            cell.style.display = 'none';
        }
    });
}
  • main.html

<input oninput="handleInputChange()" placeholder="Looking for Prisoner?" class="searchPrisoner">
input 태그의 oninput 속성을 사용해서 값이 달라짐을 감지해서 함수가 동작하도록 했습니다.

업데이트

외부에서 데이터를 변경하고 다시 새로고침하면 최신의 데이터로 업데이트가 가능합니다.

업데이트

추가

새로운 데이터를 DB와 sotrage에 저장합니다.

추가

변경

이름, 등급, 이미지를 변경할 수 있습니다.

변경

삭제

UX적인 부분을 고려해서 삭제 시 한번 더 물어보는 단계를 추가해보겠습니다.

삭제



커서 이미지 입히기

html {
  cursor: url(../icon/cursor50-brown.png), auto;
}

.imprisonBtn,
.releaseBtn {
  cursor: url(../icon/cursor50-brown-pointer.png), pointer;
}
  • general 커서 입니다.

cursor50-white

  • pointer 시 커서 이미지를 따로 적용하면 됩니다.

cursor50-white-pointer

MPA vs SPA

  • MPA는 여러개의 독립페이지로 구성된 앱을 말합니다. 멀티~
  • SPA는 하나의 단일 페이지로 구성된 앱을 말하고요. 싱글~

MPA는 하나의 페이지씩 불러와서 초기 로딩은 빠르지만 이후 페이지를 이동할 때 마다 렌더링하고, 쿠키나 세션으로 현재 페이지의 상태를 유지해야 합니다.

SPA는 그 반대로 처음부터 다 불러오기 때문에 초기 로딩이 느릴 수 있으나, 페이지간 이동이 빠릅니다.

이렇게 알아본 뒤 저는 MPA와 SPA도 사용해보려고 했으나,

SPA는 발만 담군 정도로 메인 화면에서 모달로 CRUD만 사용해보았습니다.

MPA는 각 로그인 화면 부터 유저플로우에서 보이는 모습 그대로 각 화면을을 각기 다른 페이지로 작성해 사용했습니다.



📼video tag (용량 문제 해결방안)

비디오 태그를 활용해 웹을 디자인 하는 경우를 종종 확인할 수 있었습니다.

라인이나 야놀자에서도 사용하고 있습니다.

저는 아직 UI에 대해서 잘 알지 못하지만,

개발자이기전에 한 유저로서 동영상을 통해 서비스의 이미지, 혹은 정보를 직관적을 전달하는 방식을 경험하고 홀려버렸습니다...

그렇게 홀린듯 비디오 태그를 사용하고 보니.. 문제가 생겼습니다.

프로젝트 용량이 400mb에 가까워졌습니다.ㅋㅋㅋ

그래서 파이어베이스 스토리지에 올린 뒤 계속 네트워킹을 통해 참조할지

그대로 프로젝트에 담아서 진행할지 나름 열심히 고민하고 찾아봤습니다.

하지만 제일 좋은 방법은 역시 파일의 용량을 줄이는것입니다.

그래서 세가지 방법을 찾았습니다.

  1. 비메오 사용하기

    우리는 주로 유튜브의 링크나 로컬 스토리지를 통해 비디오 태그에 참조를 불러오는데요.

    유튜브는 이런 참조링크를 iframe으로 제한해둬서 사용성이 매우 낮습니다.

    하지만 비메오는 비디오 태그에도 사용할수 있습니다.

    다만 가장 큰 단점은 유료 입니다...
  2. gif 사용하기

    잘 아시다시피 mp4나 webm와 같은 영상의 데이터를 압축해서 만들어지느 파일확장자입니다.

    간단히 사용하는 색을 제한하거나 중복요소를 파악하고 제거하여 데이터를 줄이기 때문에 문서?같은 비교적 정적인 내용만 괜찮고

    우리의 현란한 동영상은 화질이 매우 깨지게 됩니다. 그게 아니라면 압축한 의미가 없을 정도의 데이터 크기를 가지고 있게 됩니다.

    따라서 gif도 단점이 어느정도 있습니다.
  3. 영상 길이 줄이고 무한 반복돌리고 만족하기

    간단하게 나의 욕심과 현실의 타협점을 찾는 것이 포인트 입니다.

    그래서 저는 타협을 선택했습니다.
  4. 그 외 iframe

    우리가 원하는 배경 역할을 못합니다.


반응형 vs 적응형

이번 프로젝트를 진행하기 전에 멘토님께서 반응형과 적응형에 대한 개념을 일러주셨습니다.

그래서 추가로 찾아본 결과 반응형과 적응형의 차이를 알 수 있었습니다.

  • 반응형

    어떤 화면이 주어져도, 혹은 디바이스가 주어져도 웹에서 그 화면에 맞게 알아서 레이아웃이 변형되어 적용되는 것을 말합니다.
  • 적응형

    정해진 화면과 디바이스에 맞춰서 각각의 정적의 레이아웃을 적용하는 것을 말합니다.
    (320, 480, 760, 960, 1200, 1600px)

얼핏보아도 반응형이 더 지속성이 좋아보이면서 유지보수에 드는 힘이 적어보입니다.

다만 처음 디자인을 할 때 고려할 점이 많고, 동적인 콘텐츠를 불러올때 성능저하가 올 수 있습니다.

하지만 어떤 것이든 단점과 장점이 있고,

진행하고 있는 프로젝트에 맞게 사용하는게 중요합니다.

그래서 저는 구현할 기능이 많지 않아서 이번 프로젝트에서 반응형 디자인을 사용했고,

최대한 미디어쿼리를 사용하지 않고 디자인을 해보았습니다.


🔥Firebase vs AWS

파이어베이스와 AWS는 아직도 잘 다루지 못합니다ㅠㅠ

하지만 두 서비스 모두 비슷한 기능들을 제공합니다.

데이터베이스

스토리지

인증

애널리틱스

등등 몇가지 기능들을 제공하고, 아직 프로젝트가 크지 않아서 서비스의 차이점을 잘 모르겠습니다.
AWS가 요금, 프로젝트에 적용할 수 있는 리소스 가공력? 파이어베이스는 직관성과 유지보수의 기능면에서 서로 방향이 다른 것 같았습니다.

기업에서는 자체 서버를 두고 개발을 한다고 들었습니다.

앞으로 서버와 관련된 공부를 추가로 해봐야겠습니다.



🧐느낀점

  • 지난 클론코딩 과제에 이어서 자바스크립트를 깊이있게 다루는 연습을 했습니다.
  • 배우는 것이 늘어날수록 그리고 욕심이 늘수록 코드도 비대해지는 것을 느껴습니다.
  • 하나의 파츠, 기능, 모듈로서 작동할 수 있도록 클래스의 중요성을 느꼈습니다.
  • 순수함수는 보던 것과는 다르게 단순하기만 한 것이 아니라 구조와 계획을 잘 짜야 가능하다는 것을 느꼈습니다.
  • 공식문서를 보면서 공부해보는게 처음이 아닌데도 파이어베이스에 익숙해지는데 오래걸렸습니다.
  • 이번에는 라이브러리를 사용해보거나 번들링을 욕심내서 사용해봤어야 했는데.. 컨셉에 너무 신경을 많이썼습니다.
  • 앞으로 혼자서도 프로젝트를 완성시킬 수 있을 거 같아서 의욕이 더 생겼습니다.
  • 프로젝트를 진행하면서 무료로 풀린 레퍼런스를 많이 사용하기도 했지만, 저작권에 저촉될만한 자료도 많이 사용 했습니다...이부분에 대해서 앞으로 경각심을 가지고 반성해야겠다고 느꼈습니다.
  • 한국어폰트를 못구해서 불가피하게 영어로만 작성하게됐는데, 프로젝트하면서 고려할 점이 너무 많았습니다.
  • 그리고 만약 폰트를 지정하지 않으면 각 디바이스마다 혹은 OS마다 지원하는 폰트의 크기가 달라서 원하는 레이아웃이 깨질 수 있다는 것을 알았습니다.(android에서는 괜찮은데..IOS에서 깨집니다.)

📜리팩토링 계획

  • 번들링 해보기(.env 적용하기)
  • 로그인 권한 적용해보기
  • 재밌는 라이브러리 찾아서 써보기
  • JS코드 모듈화 시도해보기
  • 유효성 검사해보기
  • 로딩 화면 넣어보기
  • 새로고침 해야만 다시 정보 변경 가능한 오류 고치기

@HOOOO98 HOOOO98 self-assigned this Aug 18, 2023
@developer-jyyun
Copy link

우와....사이트 너무 너무 멋져요 👍👍👍 저는 기능만 구현하기에도 짧은 시간이었는데 디테일한 요소들까지 컨셉에 맞게 적용하신 점 넘 대단해요!!(유저플로우마저도...)

@HOOOO98
Copy link
Author

HOOOO98 commented Aug 20, 2023

우와....사이트 너무 너무 멋져요 👍👍👍 저는 기능만 구현하기에도 짧은 시간이었는데 디테일한 요소들까지 컨셉에 맞게 적용하신 점 넘 대단해요!!(유저플로우마저도...) @developer-jyyun

칭찬 감사합니다!ㅎㅎ 이번과제에 사용했던 디테일한 부분은 추가로 PR에 업로드할 예정입니다!
대부분 CSS선에서 처리할 수 있는 부분이라 이후 프로젝트에 적용해도 재미있는 요소가 될 것 같습니다!

@junkue20
Copy link

처음에 보면서 감탄하다가 여자친구한테도 디코 화면 공유로 보여줬습니다..
다시봐도 진짜 끝내주네요

@HOOOO98
Copy link
Author

HOOOO98 commented Aug 22, 2023

처음에 보면서 감탄하다가 여자친구한테도 디코 화면 공유로 보여줬습니다.. 다시봐도 진짜 끝내주네요 @junkue20

오오! 감사합니다ㅎㅎ
다음 프로젝트는 끝내주는 코드로 돌아오겠습니다...!!

@JiHongkyu
Copy link

커서에 이미지 입히는 부분은 생소하면서 재밌네요! 저도 다음에 꼭 써봐야겠어요😊

@HOOOO98
Copy link
Author

HOOOO98 commented Aug 25, 2023

커서에 이미지 입히는 부분은 생소하면서 재밌네요! 저도 다음에 꼭 써봐야겠어요😊 @JiHongkyu

참고로 gif도 커서에 입힐 수 있다고 합니다! 다만 렌더링이 느려지는 단점이 있을 수 있어서 추천은 하지 않습니다ㅎㅎ
만약 동적인 커서를 원하시면 애니메이션을 적용하는 것도 방법이라고 하네요~!
다음 프로젝트도 기대하겠습니다~!🚀

@IAMISTP
Copy link

IAMISTP commented Aug 25, 2023

컨셉을 너무 잘 잡아주셔서 사용하는 내내 너무 흥미로운데요!
특히 커서도 그렇고 마우스를 따라오는 지팡이가 아주 대박이네요.. 클릭할때 빛나는거까지!!!
대단하시네요.. .
기능 사용을 해보면서 등록할때 버튼을 두번 누르면 2번 등록되는 경우가 있습니다!
그리고 상세페이지로 들어가는 부분이 안되는데요ㅠ 저만 안되는걸까요..? 에러는 안나는데,, 들어가지지가 않네요..,

Comment on lines +32 to +36
if (username === "aaa" && password === "bbb") {
window.location.href = "main.html";
} else {
alert("Check your Id and Password");
}

Choose a reason for hiding this comment

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

로그인이 성공했을 때 window.location.href를 사용해 페이지 이동을 하셨는데요, 로그인 페이지는 뒤로가기를 통해 진입할 일이 없으니 히스토리에 추가할 필요 없다는 점을 볼 때 window.location.replace를 사용하시는건 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

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

아하! 로그인 페이지가 진입점 이다보니 히스토리 자체를 지워서 뒤로 갈 수 없게 하는 거네요!!
음..그럼 추가로 로그아웃 버튼도 구현해야겠네요
할 일을..추가해 주셔서 감사..해요
다음 리팩토링 로그인 구현에 큰 힌트가 된거 같습니다ㅎㅎ👍

@yeongmins
Copy link

디자인 컨셉부터 기능 구현까지 너무 잘하셨네요~!
저도 구현하신 요소들 참고해서 적용 시켜보겠습니다!

@suyeonnnnnnn
Copy link

suyeonnnnnnn commented Aug 25, 2023

저는 이렇게 컨셉 잡을 생각을 하지도 않았는데...! 정말 대단하세요.👍👍 사이트 구경하는 재미가 있네요!
리드미 꼼꼼하게 읽어보았습니다~! 자세히 적어주신 덕분에 간접 경험 얻어갑니다~~!

@HOOOO98
Copy link
Author

HOOOO98 commented Aug 26, 2023

컨셉을 너무 잘 잡아주셔서 사용하는 내내 너무 흥미로운데요! 특히 커서도 그렇고 마우스를 따라오는 지팡이가 아주 대박이네요.. 클릭할때 빛나는거까지!!! 대단하시네요.. . 기능 사용을 해보면서 등록할때 버튼을 두번 누르면 2번 등록되는 경우가 있습니다! 그리고 상세페이지로 들어가는 부분이 안되는데요ㅠ 저만 안되는걸까요..? 에러는 안나는데,, 들어가지지가 않네요.., @IAMISTP

-아하! 디테일하게 봐주셔서 감사합니다!!
방금 코드를 확인해봤는데 main.html파일에 script태그에 이물질이 껴있어서...제대로 참조가 안됐던 거였습니다!
그리고 버튼을 두번 누르면 2번 등록되는 경우는 비동기 처리가 다 되고 나서 모달창을 닫도록 설계를 했는데..거기서 두번 누를 거라고는 생각을 못했었네요😂
어떻게 해결할지 조금 더 고민해보고 코드를 개선 시켜보겠습니다!!

@HOOOO98
Copy link
Author

HOOOO98 commented Aug 26, 2023

디자인 컨셉부터 기능 구현까지 너무 잘하셨네요~! 저도 구현하신 요소들 참고해서 적용 시켜보겠습니다!

감사합니다! 다음 과제에도 좋은 코드와 디자인 기대하겠습니다~!😊

@HOOOO98
Copy link
Author

HOOOO98 commented Aug 26, 2023

저는 이렇게 컨셉 잡을 생각을 하지도 않았는데...! 정말 대단하세요.👍👍 사이트 구경하는 재미가 있네요! 리드미 꼼꼼하게 읽어보았습니다~! 자세히 적어주신 덕분에 간접 경험 얻어갑니다~~!

이번 과제가 이미지를 업로드 하고 관리해보자는 취지였는데, CRUD까지만 생각하고 이미지 최적화는 고려하지 못했는데요..!
앞으로 디자인 뿐만이 아니라 조금 더 깊이 있는 사고를 통해 프로젝트를 진행해보겠습니다~!
리드미도 꼼꼼히 읽어주셔서 감사합니다!!!😁

Copy link

@jungHyeonS jungHyeonS left a comment

Choose a reason for hiding this comment

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

성후님 과제하시느라 고생하셨습니다~
디자인도 신박하게 잘해주셨고 코드도 적절히 분리해주신거같습니다~
리뷰 전달드린 내용들 참고해서 추후에는 코드 관리 및 이벤트 처리에 대한 부분을 고민해주시면 좋을꺼같습니다~

Comment on lines +5 to +12
const firebaseConfig = {
apiKey: "AIzaSyBmLvUo54Jzhiin0qNBWwut9AG3z5n1zdE",
authDomain: "azkaban-bef73.firebaseapp.com",
projectId: "azkaban-bef73",
storageBucket: "azkaban-bef73.appspot.com",
messagingSenderId: "61881098784",
appId: "1:61881098784:web:97038c5ce63f0d2ab95245"
};

Choose a reason for hiding this comment

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

동일한 firebaseConfig 가 js파일에서 반복적으로 나오는거같습니다 이러한 config 는 별도의 파일로 분리해서 관래해주시는게 좋습니다~

const newPrisonerCell = document.createElement('div');
newPrisonerCell.classList.add('prisonCell');
newPrisonerCell.style.backgroundImage = `url(${downloadURL})`;
newPrisonerCell.alt = `${prisonerName} Mugshot`;

Choose a reason for hiding this comment

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

기본적으로 div 태그에서는 alt 속성이 없습니다, 따라서 div 태그에 이미지에 대한 설명을 추가하신다면 aria-label 혹은 data-alt 와 같은 속성을 이용해주시는게 좋을꺼같습니다~

Comment on lines +166 to +170
lvOptions.forEach(option => option.removeAttribute('selected'));
detailMugshot.alt = '';
detailMugshot.src = '';
detailName.placeholder = '';
detailModal.classList.add('hidden');

Choose a reason for hiding this comment

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

이 코드가 resetDetailModal 함수와 동일해보여서 아래처럼 개선할수있을꺼같습니다~

detailModalBg.addEventListener('click', resetDetailModal);

Comment on lines +59 to +82
const saveNameClickHandler = async (event) => {
event.preventDefault();
const name = detailName.value;
const prisonerId = currentPrisonCell.getAttribute('dataId');

const prisonerDocRef = doc(db, "prisoner", prisonerId);
const prisonerData = {
name: name
};

try {
await setDoc(prisonerDocRef, prisonerData, { merge: true });
console.log("Name updated in Firestore: ", name);
} catch (error) {
console.error("Error updating name in Firestore: ", error);
}

const prisonerName = currentPrisonCell.querySelector('.prisonerName');
prisonerName.textContent = name;

detailMugshot.alt = name;
detailForm.reset();
resetDetailModal();
};

Choose a reason for hiding this comment

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

initPrisonerDetailModal 함수 안에 다양한 함수 와 이벤트 리스너가 작성되어있습니다 이렇게되면 추후에 코드 관리가 힘들어져서 함수 와 이벤트 리스너를 등록하는 부분을 최대한 분리해주시는게 좋습니다

const oldImageFileName = oldImageUrl.split('/').pop().split('?')[0];

if (oldImageUrl) {
const oldStorageRef = ref(storage, `mugshot/${oldImageFileName}`);

Choose a reason for hiding this comment

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

mugshot 이라는 문자열이 계속 반복적으로 나오고있습니다 이러한 문자열은 아래처럼 상수로 선언해주시는게 좋습니다~

const MUGSHOT = 'mugshot'

Comment on lines +173 to +176
imprisonBtn.addEventListener("click", () => {
const releaseWords = document.querySelectorAll('.releaseWord');
const isReleaseActive = [...releaseWords].some(word => !word.classList.contains('hidden'));
});

Choose a reason for hiding this comment

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

isReleaseActive 이 상단에도 선언이 되어있는거 같은데 여기에도 선언이 되어있어서 중복으로 들어간거같습니다~
const 여도 변수명은 최대한 구분해주시는게 좋습니다~

list-style: none;
padding: 66px;
text-align: center;
width: 30em;

Choose a reason for hiding this comment

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

em, rem은 폰트단위라서 절때로 width,height 에서는 em,rem 단위를 사용하시면 안됩니다~

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.

9 participants