아르바이트생의 인적사항을 간단하게 관리할 수 있도록 만들어본 프로젝트입니다.
초기 비밀번호는 1234입니다!!
2023.08.07 ~ 2023.08.16
1. 웰컴 페이지 | 2. 관리자인증 페이지 |
---|---|
3. 알바생 등록 페이지 | 4. 알바생 조회 페이지 | 5. 알바생 수정 페이지 |
---|---|---|
로딩 화면은 로딩바가 가로로 늘어나는 애니메이션을 무한히 반복하도록 했고,
로딩이 완료되면 addEventListener
를 통해 해당 화면이 사라지도록 했습니다.
<!-- 로딩 화면 추가 -->
<div class="loading-screen">
<div class="loading-bar"></div>
</div>
:root {
--display: flex;
}
.loading-screen {
display: var(--display);
position: fixed;
justify-content: center;
align-items: center;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #3da557;
transition: opacity 0.5s ease;
z-index: 1000;
}
.loading-bar {
width: 441px;
height: 5px;
background-color: #ffffff;
animation: loadingBar 2.5s infinite; /* 로딩 바 애니메이션 설정 */
text-align: center;
}
@keyframes loadingBar {
0% {
width: 0; /* 로딩 바 초기 길이 */
}
100% {
width: 100%; /* 로딩 바 최종 길이 */
}
}
document.addEventListener('DOMContentLoaded', function () {
setTimeout(() => {
loadingScreen.style.opacity = '0';
}, 1000);
const loadingScreen = document.querySelector('.loading-screen');
// 투명도 변화 이벤트 감지
loadingScreen.addEventListener(
'transitionend',
(handleTransitionEnd = () => {
document.documentElement.style.setProperty("--display", "none");
})
);
});
입력된 암호가 없을 시 | 잘못된 암호 입력시 |
---|---|
개인적으로 아쉬움이 많이 남았던 부분이었습니다.
위의 기능은 기본적으로 로그인을 한 상태
라는 가정하에 진행된 페이지입니다.
회원가입 및 로그인 기능을 구현하기에는 Firebase 숙련도와 시간적 한계에 부딪혀 본인인증
이라는 간단한 형태만 잡아둔 상태입니다.
<!-- 화면 중간 비밀번호 확인용 섹션 -->
<section class="password-check">
<h2>매장 관리자 비밀번호 확인</h2>
<input type="password" id="passwordInput" placeholder="비밀번호 입력"/>
<button id="loginButton">로그인 하기</button>
<!-- 비밀번호 오류시 에러메세지 출력 -->
<div class="error-message" id="errorMessage"></div>
const passwordInput = document.getElementById("passwordInput");
const errorMessage = document.getElementById("errorMessage");
// 유효성 검사 기능 추가
loginButton.addEventListener("click", () => {
const password = passwordInput.value;
if (password === "1234") {
// 로그인 성공 시 직원 관리페이지로 이동
window.location.href = "myAlba.html";
} else if (password === "") {
// 비밀번호 오류 메세지 1 (입력된 값이 없을때)
errorMessage.textContent = "비밀번호를 입력해주세요!";
setTimeout(()=>{
errorMessage.textContent = "";
}, 3000)
} else {
// 비밀번호 오류 메세지 2 (비밀번호가 틀렸을때)
errorMessage.textContent = "비밀번호를 다시 확인해주세요!";
setTimeout(()=>{
errorMessage.textContent = "";
}, 3000)
}
});
이미지를 등록할 시 사용자들이 등록한 이미지를 바로 확인할 수 있도록 미리보기 기능을 구현했습니다.
<img>
태그를 추가하여 이미지를 첨부하지 않은 상태에서는 기본 이미지가 출력되도록 하였고,
이미지를 첨부한 경우에는 FileReader 객체를 생성하여 미리보기 이미지의 데이터 URL을 변경합니다.
<div class="image-upload">
<img id="imagePreview" src="../assets/pictures/no-image.png" alt="아르바이트생 사진" />
<input type="file" name="image" id="photoInput" accept="image/*" />
</div>
const photoInput = document.getElementById('photoInput');
photoInput.addEventListener('change', (event) => handleImageChange(event));
// 이미지 등록 시 미리보기 기능
const handleImageChange = (event) => {
const imagePreview = document.getElementById('imagePreview');
const selectedImage = event.target.files[0];
let imageURL = '../assets/pictures/no-image.png';
if (selectedImage) {
// 이미지 등록 시
imageURL = URL.createObjectURL(selectedImage);
imagePreview.src = imageURL; // 등록한 파일로 미리보기 주소변경
imagePreview.onload = () => {
URL.revokeObjectURL(imageURL); // 이미지가 로드되면 URL 해제
};
}
};
데스크탑 화면 | 모바일 화면 |
---|---|
모달창 기능을 구현하는 도중, 누르려는 버튼의 행에 있는 데이터를 가져올 때 약간의 귀찮음(?)으로 탄생한 코드입니다.
사실 처음에 별 생각 없이 같은 행의 값들 중 이름
값을 불러와서
모달창을 구현하려고 하다보니, 등록된 데이터들 중 동명이인이 발생하게 되면 한사람의 프로필만 표시되는 오류가 발생했었습니다.
원래대로라면 DB에 저장된 데이터의 ID값
을 불러온 이후, 해당 데이터의 속성값들을 modal창에 띄우는 방식을 사용해야겠지만,
'굳이 추가적으로 ID 값을 불러오지 않고서도 현재 부모 행에 존재하는 전화번호
를 이용하면 되지 않을까' 라는 생각에
DB에 저장된 값들 중 전화번호가 일치하는 값을 들고와서 modal창에 띄우는 방식을 사용했습니다.
(전화번호는 지구상에 모든 사람들이 각기 다른 번호를 가지고 있으니까요!)
지금 PR을 작성하는 현재로써 돌이켜보면 단순한 편법이었다고 생각합니다..
// '조회하기' 버튼 클릭 이벤트 리스너 등록
$(document).on('click', '.edit-button', function () {
// 클릭한 버튼의 부모 요소에서 데이터 가져오기
const $parentRow = $(this).closest('tr');
const phoneNum = $parentRow.find('.alba-phone p').text(); // <--- 이부분. 사실 DB에 저장된 id 값으로 받아오는게 원래 올바른 방법이긴 하다.. ㅎㅎ
// 데이터베이스에서 해당하는 데이터 가져오기
// '조회하기' 버튼 클릭 이벤트 리스너 등록
$(document).on('click', '.edit-button', function () {
// 클릭한 버튼의 부모 요소에서 데이터 가져오기
const $parentRow = $(this).closest('tr');
const phoneNum = $parentRow.find('.alba-phone p').text();
// 데이터베이스에서 해당하는 데이터 가져오기
db.collection('albainfo')
.where('연락처', '==', phoneNum)
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
// 데이터가 없을경우 리턴.
return;
}
const doc = querySnapshot.docs[0];
const data = doc.data();
// 모달창에 데이터 채우기
document.querySelector('.modal-left-container img').src = data.이미지;
document.querySelectorAll('.modal-right-container p')[0].textContent = data.이름;
document.querySelectorAll('.modal-right-container p')[1].textContent = data.직급;
document.querySelectorAll('.modal-right-container p')[2].textContent = data.연락처;
document.querySelectorAll('.modal-right-container p')[3].textContent = data.근무시간;
// 모달창 띄우기
$('.modal-container').fadeIn();
// 모달창 버튼 클릭 이벤트 리스너 등록
$('.update-button').on('click', function () {
// 정보수정 이동
const id = doc.id;
window.location.href = `albaUpdate.html?idvalue=${id}`;
$('.modal-container').fadeOut();입
});
$('.close-button').on('click', function () {
// 모달창 닫기
$('.modal-container').fadeOut();
});
})
.catch((error) => {
console.error('Error getting document:', error);
});
});
'Restful.api에서 사용하는 방식처럼 url 끝에 조회하고자 하는 데이터의 id값을 넣어서 보내면 되겠다' 라는 아이디어로 시작하여 URL 끝에 id값을 포함하여 수정하고자 하는 데이터를 불러올 수 있도록 했습니다.
추가적으로 반복하여 db, storage를 불러오는 코드는 firebaseSDK.js
파일에 저장하여 import해오는 방식으로 코드의 반복을 최소한으로 했습니다.
// Firebase SDK
import { initializeFirebase } from './firebaseSDK.js';
const { db, storage } = initializeFirebase();
$(document).ready(function () {
const urlParams = new URLSearchParams(window.location.search);
const idValue = urlParams.get('idvalue');
if (idValue) {
const docRef = db.collection('albainfo').doc(idValue);
docRef
.get()
.then((doc) => {
if (doc.exists) {
const data = doc.data();
// 데이터를 이용하여 폼 필드에 값을 설정하거나 화면에 표시
$('#imagePreview').attr('src', data.이미지);
$('#name').val(data.이름);
$('#phone').val(data.연락처);
$('#position').val(data.직급);
$('#workingHours').val(data.근무시간);
} else {
console.error('오류발생! 데이터를 불러올 수 없음!');
}
})
.catch((error) => {
console.log('Error getting document:', error);
});
// 수정 버튼 클릭 시 데이터 수정
$('#sendButton').click(function () {
const updatedData = {
이름: $('#name').val(),
연락처: $('#phone').val(),
직급: $('#position').val(),
근무시간: $('#workingHours').val(),
// 기타 필요한 필드 추가
};
// 이미지 업로드 처리
const selectedImage = $('#photoInput')[0].files[0];
// 데이터 업로드 함수
const dataUpload = () => {
docRef
.update(updatedData)
.then(() => {
console.log('문서 업데이트 완료');
window.location.href = '/albaSelect.html';
})
.catch((error) => {
console.error('오류 발생:', error);
});
};
if (selectedImage) {
const storageRef = storage.ref(`images/${selectedImage.name}`);
storageRef
.put(selectedImage)
.then((snapshot) => {
return snapshot.ref.getDownloadURL();
})
.then((downloadURL) => {
// 업로드된 이미지 URL을 데이터와 함께 업데이트
updatedData.이미지 = downloadURL;
dataUpload();
})
.catch((error) => {
console.error('이미지 업로드 오류:', error);
});
} else {
// 이미지가 선택되지 않은 경우 데이터만 업데이트
dataUpload();
}
});
해당 부분에서는 삭제하고자 하는 알바생들의 정보를 체크박스를 통해 다중선택하여 지울 수 있도록 구현했습니다.
// 알바생 데이터 삭제
$(document).ready(function () {
// 삭제 버튼 누르기
$(document).on('click', '.alba-delete-button', function () {
// 선택한 알바생 데이터의 id값 추출하여 배열에 저장
const selectedIds = [];
// 체크박스 확인
$('.alba-list-body input[type="checkbox"]:checked').each(async function () {
const $parentRow = $(this).closest('tr');
const phoneNum = $parentRow.find('.alba-phone p').text();
const collection = db.collection('albainfo');
const docRef = collection.where('연락처', '==', phoneNum);
const querySnapshot = await docRef.get();
const storage = firebase.storage();
if (querySnapshot.size > 0) {
const doc = querySnapshot.docs[0];
const id = doc.id;
selectedIds.push(id);
}
const deleteButton = $('.alba-delete-button');
if (selectedIds.length > 0) {
deleteButton.removeClass('disabled-button').prop('disabled', false);
} else {
deleteButton.addClass('disabled-button').prop('disabled', true);
}
if (selectedIds.length > 0) {
console.log(123);
$('.confirm-modal-container').fadeIn();
// 삭제하기 버튼 클릭 이벤트 리스너 등록
$('.confirm-button').on('click', async function () {
// 선택한 알바생 데이터 삭제 처리
const deletePromises = selectedIds.map(async (id) => {
// Firestore에서 해당 데이터 가져오기
const docRef = db.collection('albainfo').doc(id);
const docRefData = await docRef.get();
// Firestore 문서에 저장된 이미지 URL주소 가져오기
const imageData = docRefData.data();
const imageUrl = imageData.이미지; // 속성값에서 이미지 파일 URL 추출
// Firestore DB에서 데이터 삭제
await docRef.delete();
// Storage에서 이미지 삭제
if (imageUrl) {
const storageRef = storage.refFromURL(imageUrl);
await storageRef.delete();
}
});
// 삭제 Promise 모두 완료될 때까지 기다림
await Promise.all(deletePromises);
window.location.href = 'albaSelect.html'; // 새로고침 기능
});
} else {
$('.no-selection-modal-container').fadeIn();
return;
}
});
});
});