
🥕 프리온보딩 - 패스트파이브
﹣ 2022.12.12~2022.12.22 (11일)


트렐로를 이용해서 진행상황을 공유하였고, 디스코드를 이용하여 오전에 회의 하였습니다!
[프론트] - React, Javascript, Router, Sass
[백엔드] - Javascript, Express(Node.js), Mysql, dbmate(DB scheme 버전관리), jsonwebtoken(토큰 발행), bcryptjs(비밀번호 암호화),Axios



//이메일 중복확인
const [duplicateEmail, setDuplicateEmail] = useState(true);
const duplicateCheck = e => {
fetch(`${process.env.REACT_APP_API_URI}/email`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
}),
})
.then(res => res.json())
.then(res => {
if (res.duplicateEmail === false) {
alert('사용 가능한 이메일 입니다.');
setDuplicateEmail(false);
} else {
alert('이미 존재하는 이메일 입니다.');
}
});
};
const emailCheck = e => {
const emailRegex =
/^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i;
if (emailRegex.test(e.target.value)) {
setEmailError(false);
setEmail(e.target.value);
} else {
setEmailError(true);
}
};
const passwordCheck = e => {
const passwordRegex =
/^(?=.*[a-zA-Z])(?=.*[!@#$%^*+=-])(?=.*[0-9]).{8,16}$/;
if (passwordRegex.test(e.target.value)) {
setPasswordError(false);
setPassword(e.target.value);
} else {
setPasswordError(true);
}
};
회원가입은 이메일 유효성 검사 및 비밀번호 유효성 검사와 모든 항목을 다 작성해야만 회원가입을 진행할 수 있도록 구현하였다. 이메일과 비밀번호는 실시간으로 인풋창 아래에서 알림이 뜨도록 만들었으며, 모든 조건을 충족했을 시 알림이 사라지도록 구현하였다. 이메일 중복확인은 버튼 클릭 시 fetch를 이용해 백엔드에서 중복되는 이메일 여부를 확인하였다. 중복이면 다시 이메일을 작성해야하고, 사용가능하면 버튼이 비활성화 되도록 구현하였다.

const onLogin = () => {
fetch(`${process.env.REACT_APP_API_URI}/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
password: password,
}),
})
.then(res => {
if (res.status === 200) {
return res.json();
} else {
return null;
}
})
.then(res => {
if (res !== null) {
localStorage.setItem('token', res.token);
alert('로그인에 성공하였습니다!');
window.location.href = '/';
} else {
alert('로그인에 실패하였습니다.');
}
});
};
const onLogout = () => {
window.localStorage.setItem('token', '');
window.location.href = '/';
setUserName('');
};
이메일 양식 검사를 실시간으로 하였고, 비밀번호 입력 후, fetch를 이용해 로그인 성공 시 성공하였다고 알림창이 뜨고, 아닐 시 실패하였다고 알림창이 뜨게 구현하였다. 로그아웃은 토큰 값을 없애주고, 메인화면으로 돌아가도록 하였다.

🥕 대표요청

🥕 멤버요청
//대표요청
useEffect(() => {
if (companyCheck) {
setValidation(true);
}
}, [companyCheck]);
const requestCheck = e => {
alert('회사 이름을 작성해주세요');
};
//캘린더
const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(new Date());
const startDateFormat = moment(startDate, 'YYYY.MM.DD').format('YYYY-MM-DD');
const endDateFormat = moment(endDate, 'YYYY.MM.DD').format('YYYY-MM-DD');
useEffect(() => {
setStartDateData(startDateFormat);
setEndDateData(endDateFormat);
}, [startDate, endDate]);
//멤버요청
useEffect(() => {
fetch(`${process.env.REACT_APP_API_URI}/company`)
.then(res => res.json())
.then(data => {
setCompanyData(data);
});
}, []);
const onCompanyData = e => {
setUserCompany(e.target.value);
};
대표요청에서는 캘린더(DatePicker)를 이용하여 이용기간을 설정할 수 있도록 하였으며 만료날짜는 시작 기한 이전은 선택할 수 없도록 만들었고, moment를 이용하여 원하는 포맷으로 변환시켜주었다. 대표는 자신의 회사를 요청하면 admin(관리자)가 승인 할 수 있다.
멤버요청에서는 등록된 회사들 중 자신의 회사를 선택할 수 있고, 선택 후 요청을 보내면 해당하는 회사의 대표가 승인할 수 있다.


로그인을 해야만 게시글 페이지로 이동이 가능하며, 일반 멤버는 우리회사 소개하기 버튼이 보이지 않으며, 대표나 관리자만 우리회사 소개하기 버튼이 보인다.
// 로그인 여부 확인
const toCompanyList = () => {
const token = localStorage.getItem('token');
if (token === '' || token === null) {
alert(`로그인 후 이용해주세요!`);
navigate(`/`);
} else {
navigate(`/companyList`);
}
};

게시글 전체보기 페이지에서는 지역필터, 카테고리필터, 상세 카테고리 필터 이렇게 3가지 필터가 들어가야했고, 선택할때마다 쿼리스트링을 사용해 실시간 필터링 되도록 하였다. 그리고 카테고리 필터 변경 시 이전의 상세 카테고리 필터데이터는 리셋 시켜주었다.
useEffect(() => {
const queryString = `${area ? `locationsId=${area}&` : ''}${
category ? `categoriesLv1Id=${category}` : ''
}${subCategory ? `&categoriesLv2Id=${subCategory}` : ''}`;
setQueryString(queryString);
}, [area, currentPage, category, subCategory, navigate, setQueryString]);

게시글 전체보기 페이지에서는 1차로 해당 카테고리를 클릭해서 들어가기 때문에 지역필터, 상세분야필터 두가지만 뜨며, 해당하는 카테고리 데이터에서 실시간 필터링 됩니다.
//카테고리 해당 데이터 가져오기
useEffect(() => {
const token = localStorage.getItem('token');
if (queryString !== '') {
fetch(
`${process.env.REACT_APP_API_URI}/post?categoriesLv1Id=${params.id}`,
{
headers: {
'Content-Type': 'application/json',
authorization: token,
},
}
)
.then(res => res.json())
.then(data => {
setAllData(data);
});
} else {
fetch(`${process.env.REACT_APP_API_URI}/post?${queryString}`, {
headers: {
'Content-Type': 'application/json',
authorization: token,
},
})
.then(res => res.json())
.then(data => {
setAllData(data);
});
}
}, [params.id, queryString]);

한페이지에 10개의 게시글을 불러오고 페이지네이션 기능으로 페이지를 넘기면 다음 10개의 게시글을 불러오도록 하였다.
//전체 게시글을 10개로 나누어 페이지 버튼 생성
const pagination = [];
for (let i = 1; i <= Math.ceil(allData.length / 10); i++) {
pagination.push(i);
}
{pagination.map(page => (
<button
className={
Number(currentPage) === page ? css.currentPage : css.page
}
key={page}
value={page}
onClick={onPages}
>
{page}
</button>
))}
// fetch로 현재 페이지의 10개의 데이터를 가져왔다.
fetch( `${process.env.REACT_APP_API_URI}/post?categoriesLv1Id=${params.id}&offset=10&page=${currentPage}`,
{
headers: {
'Content-Type': 'application/json',
authorization: token,
},
}
)
.then(res => res.json())
.then(data => {
setCompanyListData(data);
});
﹣ 기업의 기획문서를 토대로 개발하는것은 처음이라 지금까지 해왔던 프로젝트보다 훨씬 어려웠던 것 같다. 먼저 기획문서에서의 각 페이지마다 주어진 요구사항들을 구현하기 위해 많은 토론을 했으며, 문서 이해를 위해 하루종일 회의했었다. 전 프로젝트에서 구현해 본적이 없는 파트를 담당해보고 싶어 새로운 파트를 담당해보았는데 구현 하니 한층 성장한 느낌이 들어 뿌듯하고 재밌었다. 기한내에 구현하고자 후반부에 가서는 다들 새벽까지 열심히 코딩했는데 같이 한 팀원들 모두 수고하셨고 감사하다고 말하고 싶다!🥺 최고의 팀워크였고, 결과물 또한 너무 마음에 들어 힘들었지만 행복하고 뿌듯했던 2주였다 ❤️